diff --git a/crypto/context.c b/crypto/context.c index c25a0bd656..506ad84e2f 100644 --- a/crypto/context.c +++ b/crypto/context.c @@ -461,6 +461,19 @@ static int set_default_context(OSSL_LIB_CTX *defctx) } #endif +int OSSL_LIB_CTX_freeze(OSSL_LIB_CTX *ctx, const char *propq) +{ + OSSL_METHOD_STORE *store; + + store = ossl_lib_ctx_get_data(ctx, OSSL_LIB_CTX_EVP_METHOD_STORE_INDEX); + if (store == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + return ossl_method_store_freeze_cache(store, propq); +} + OSSL_LIB_CTX *OSSL_LIB_CTX_new(void) { OSSL_LIB_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); diff --git a/crypto/core_fetch.c b/crypto/core_fetch.c index 3293f70372..ab8ec59bde 100644 --- a/crypto/core_fetch.c +++ b/crypto/core_fetch.c @@ -162,14 +162,16 @@ void *ossl_method_construct(OSSL_LIB_CTX *libctx, int operation_id, ossl_method_construct_postcondition, &cbdata); - /* If there is a temporary store, try there first */ - if (cbdata.store != NULL) - method = mcm->get(cbdata.store, (const OSSL_PROVIDER **)provider_rw, - mcm_data); + if (mcm->get != NULL) { + /* If there is a temporary store, try there first */ + if (cbdata.store != NULL) + method = mcm->get(cbdata.store, (const OSSL_PROVIDER **)provider_rw, + mcm_data); - /* If no method was found yet, try the global store */ - if (method == NULL) - method = mcm->get(NULL, (const OSSL_PROVIDER **)provider_rw, mcm_data); + /* If no method was found yet, try the global store */ + if (method == NULL) + method = mcm->get(NULL, (const OSSL_PROVIDER **)provider_rw, mcm_data); + } return method; } diff --git a/crypto/encode_decode/decoder_meth.c b/crypto/encode_decode/decoder_meth.c index 4d460af1c2..466d910b67 100644 --- a/crypto/encode_decode/decoder_meth.c +++ b/crypto/encode_decode/decoder_meth.c @@ -202,7 +202,7 @@ static int put_decoder_in_store(void *store, void *method, return ossl_method_store_add(store, prov, id, propdef, method, ossl_decoder_up_ref, - ossl_decoder_free); + ossl_decoder_free, NULL, NULL); } /* Create and populate a decoder method */ @@ -396,7 +396,7 @@ inner_ossl_decoder_fetch(struct decoder_data_st *methdata, id = ossl_namemap_name2num(namemap, name); if (id != 0) ossl_method_store_cache_set(store, prov, id, propq, method, - up_ref_decoder, free_decoder); + up_ref_decoder, free_decoder, NULL, NULL); } /* diff --git a/crypto/encode_decode/encoder_meth.c b/crypto/encode_decode/encoder_meth.c index 0bae49fa90..c87935ba65 100644 --- a/crypto/encode_decode/encoder_meth.c +++ b/crypto/encode_decode/encoder_meth.c @@ -202,7 +202,7 @@ static int put_encoder_in_store(void *store, void *method, return ossl_method_store_add(store, prov, id, propdef, method, ossl_encoder_up_ref, - ossl_encoder_free); + ossl_encoder_free, NULL, NULL); } /* Create and populate a encoder method */ @@ -401,7 +401,7 @@ inner_ossl_encoder_fetch(struct encoder_data_st *methdata, if (id == 0) id = ossl_namemap_name2num(namemap, name); ossl_method_store_cache_set(store, prov, id, propq, method, - up_ref_encoder, free_encoder); + up_ref_encoder, free_encoder, NULL, NULL); } /* diff --git a/crypto/evp/asymcipher.c b/crypto/evp/asymcipher.c index 652303483d..0860f1d8a6 100644 --- a/crypto/evp/asymcipher.c +++ b/crypto/evp/asymcipher.c @@ -17,6 +17,14 @@ #include "crypto/evp.h" #include "evp_local.h" +static void evp_asym_cipher_free_int(EVP_ASYM_CIPHER *cipher) +{ + OPENSSL_free(cipher->type_name); + ossl_provider_free(cipher->prov); + CRYPTO_FREE_REF(&cipher->refcnt); + OPENSSL_free(cipher); +} + static void evp_asym_cipher_free(void *data) { EVP_ASYM_CIPHER_free(data); @@ -363,6 +371,47 @@ static EVP_ASYM_CIPHER *evp_asym_cipher_new(OSSL_PROVIDER *prov) return cipher; } +static void *evp_asym_cipher_dup_frozen(void *vin) +{ + EVP_ASYM_CIPHER *in = vin; + EVP_ASYM_CIPHER *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (out->prov == NULL || !ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; + +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_asym_cipher_frozen_free(void *vin) +{ + EVP_ASYM_CIPHER *rand = vin; + int ref = 0; + + if (rand == NULL || rand->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&rand->refcnt, &ref); + if (ref > 0) + return; + evp_asym_cipher_free_int(rand); +} + static void *evp_asym_cipher_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov) @@ -484,22 +533,20 @@ void EVP_ASYM_CIPHER_free(EVP_ASYM_CIPHER *cipher) { int i; - if (cipher == NULL) + if (cipher == NULL || cipher->origin != EVP_ORIG_DYNAMIC) return; CRYPTO_DOWN_REF(&cipher->refcnt, &i); if (i > 0) return; - OPENSSL_free(cipher->type_name); - ossl_provider_free(cipher->prov); - CRYPTO_FREE_REF(&cipher->refcnt); - OPENSSL_free(cipher); + evp_asym_cipher_free_int(cipher); } int EVP_ASYM_CIPHER_up_ref(EVP_ASYM_CIPHER *cipher) { int ref = 0; - CRYPTO_UP_REF(&cipher->refcnt, &ref); + if (cipher->origin == EVP_ORIG_DYNAMIC) + CRYPTO_UP_REF(&cipher->refcnt, &ref); return 1; } @@ -511,10 +558,26 @@ OSSL_PROVIDER *EVP_ASYM_CIPHER_get0_provider(const EVP_ASYM_CIPHER *cipher) EVP_ASYM_CIPHER *EVP_ASYM_CIPHER_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, const char *properties) { - return evp_generic_fetch(ctx, OSSL_OP_ASYM_CIPHER, algorithm, properties, + return evp_generic_fetch(ctx, + OSSL_OP_ASYM_CIPHER, + algorithm, + properties, evp_asym_cipher_from_algorithm, evp_asym_cipher_up_ref, - evp_asym_cipher_free); + evp_asym_cipher_free, + evp_asym_cipher_dup_frozen, + evp_asym_cipher_frozen_free); +} + +int evp_asym_cipher_fetch_all(OSSL_LIB_CTX *ctx) +{ + return evp_generic_fetch_all(ctx, + OSSL_OP_ASYM_CIPHER, + evp_asym_cipher_from_algorithm, + evp_asym_cipher_up_ref, + evp_asym_cipher_free, + evp_asym_cipher_dup_frozen, + evp_asym_cipher_frozen_free); } EVP_ASYM_CIPHER *evp_asym_cipher_fetch_from_prov(OSSL_PROVIDER *prov, @@ -525,7 +588,9 @@ EVP_ASYM_CIPHER *evp_asym_cipher_fetch_from_prov(OSSL_PROVIDER *prov, algorithm, properties, evp_asym_cipher_from_algorithm, evp_asym_cipher_up_ref, - evp_asym_cipher_free); + evp_asym_cipher_free, + evp_asym_cipher_dup_frozen, + evp_asym_cipher_frozen_free); } int EVP_ASYM_CIPHER_is_a(const EVP_ASYM_CIPHER *cipher, const char *name) diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index 7184f9a051..5e5bd2523d 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -20,6 +20,7 @@ #include "internal/common.h" #include "crypto/evp.h" #include "evp_local.h" +#include "openssl/crypto.h" static void cleanup_old_md_data(EVP_MD_CTX *ctx, int force) { @@ -1075,11 +1076,66 @@ static void evp_md_free(void *md) EVP_MD_free(md); } +static void *evp_md_dup_frozen(void *vin) +{ + EVP_MD *in = vin; + EVP_MD *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (!ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + + return out; +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_md_frozen_free(EVP_MD *md) +{ + int i; + + if (md == NULL || md->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&md->refcnt, &i); + if (i > 0) + return; + evp_md_free_int(md); +} + +int evp_md_fetch_all(OSSL_LIB_CTX *ctx) +{ + int ret = evp_generic_fetch_all(ctx, OSSL_OP_DIGEST, + evp_md_from_algorithm, + evp_md_up_ref, + evp_md_free, + evp_md_dup_frozen, + (void (*)(void *))evp_md_frozen_free); + return ret; +} + EVP_MD *EVP_MD_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, const char *properties) { EVP_MD *md = evp_generic_fetch(ctx, OSSL_OP_DIGEST, algorithm, properties, - evp_md_from_algorithm, evp_md_up_ref, evp_md_free); + evp_md_from_algorithm, + evp_md_up_ref, + evp_md_free, + evp_md_dup_frozen, + (void (*)(void *))evp_md_frozen_free); return md; } @@ -1123,7 +1179,9 @@ EVP_MD *evp_digest_fetch_from_prov(OSSL_PROVIDER *prov, algorithm, properties, evp_md_from_algorithm, evp_md_up_ref, - evp_md_free); + evp_md_free, + evp_md_dup_frozen, + (void (*)(void *))evp_md_frozen_free); } typedef struct { diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index 7716a1dbf2..bce9d8d2cb 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -1989,14 +1989,69 @@ static void evp_cipher_free(void *cipher) EVP_CIPHER_free(cipher); } +static void *evp_cipher_dup_frozen(void *vin) +{ + EVP_CIPHER *in = vin; + EVP_CIPHER *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (!ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_cipher_frozen_free(void *vin) +{ + EVP_CIPHER *cipher = vin; + int i; + + if (cipher == NULL || cipher->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&cipher->refcnt, &i); + if (i > 0) + return; + evp_cipher_free_int(cipher); +} + +int evp_cipher_fetch_all(OSSL_LIB_CTX *ctx) +{ + int ret = evp_generic_fetch_all(ctx, + OSSL_OP_CIPHER, + evp_cipher_from_algorithm, + evp_cipher_up_ref, + evp_cipher_free, + evp_cipher_dup_frozen, + evp_cipher_frozen_free); + + return ret; +} + EVP_CIPHER *EVP_CIPHER_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, const char *properties) { - EVP_CIPHER *cipher = evp_generic_fetch(ctx, OSSL_OP_CIPHER, algorithm, properties, - evp_cipher_from_algorithm, evp_cipher_up_ref, - evp_cipher_free); - - return cipher; + return evp_generic_fetch(ctx, OSSL_OP_CIPHER, + algorithm, properties, + evp_cipher_from_algorithm, + evp_cipher_up_ref, + evp_cipher_free, + evp_cipher_dup_frozen, + evp_cipher_frozen_free); } EVP_CIPHER *evp_cipher_fetch_from_prov(OSSL_PROVIDER *prov, @@ -2007,7 +2062,9 @@ EVP_CIPHER *evp_cipher_fetch_from_prov(OSSL_PROVIDER *prov, algorithm, properties, evp_cipher_from_algorithm, evp_cipher_up_ref, - evp_cipher_free); + evp_cipher_free, + evp_cipher_dup_frozen, + evp_cipher_frozen_free); } int EVP_CIPHER_can_pipeline(const EVP_CIPHER *cipher, int enc) diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c index 612e57e6f0..aae8f45a3a 100644 --- a/crypto/evp/evp_fetch.c +++ b/crypto/evp/evp_fetch.c @@ -39,6 +39,8 @@ struct evp_method_data_st { OSSL_PROVIDER *); int (*refcnt_up_method)(void *method); void (*destruct_method)(void *method); + void *(*dup_method)(void *method); + void (*free_frozen_method)(void *method); }; /* @@ -123,6 +125,37 @@ static uint32_t evp_method_id(int name_id, unsigned int operation_id) | (operation_id & METHOD_ID_OPERATION_MASK)); } +/* + * Reverse of evp_method_id(). + * + * Returns 1 on success and fills in |*name_id| and |*operation_id|. + * Returns 0 on invalid input. + */ +int evp_method_id2name_id_op_id(uint32_t meth_id, int *name_id, + unsigned int *operation_id) +{ + int n; + unsigned int op; + + /* Top bit must be zero (see evp_method_id() comment) */ + if ((meth_id & 0x80000000u) != 0) + return 0; + + op = (unsigned int)(meth_id & METHOD_ID_OPERATION_MASK); + n = (int)((meth_id & METHOD_ID_NAME_MASK) >> METHOD_ID_NAME_OFFSET); + + /* Sanity checks to match evp_method_id() requirements */ + if (op == 0 || op > METHOD_ID_OPERATION_MAX || n > METHOD_ID_NAME_MAX) + return 0; + + if (operation_id != NULL) + *operation_id = op; + if (name_id != NULL) + *name_id = n; + + return 1; +} + static void *get_evp_method_from_store(void *store, const OSSL_PROVIDER **prov, void *data) { @@ -200,7 +233,9 @@ static int put_evp_method_in_store(void *store, void *method, store, names, methdata->operation_id, meth_id, propdef ? propdef : ""); return ossl_method_store_add(store, prov, meth_id, propdef, method, methdata->refcnt_up_method, - methdata->destruct_method); + methdata->destruct_method, + methdata->dup_method, + methdata->free_frozen_method); } /* @@ -247,6 +282,38 @@ static void destruct_evp_method(void *method, void *data) methdata->destruct_method(method); } +static int +inner_evp_generic_fetch_all(struct evp_method_data_st *methdata, + OSSL_PROVIDER *prov) +{ + OSSL_METHOD_STORE *store = get_evp_method_store(methdata->libctx); + + if (store == NULL) { + ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + OSSL_METHOD_CONSTRUCT_METHOD mcm = { + get_tmp_evp_method_store, + reserve_evp_method_store, + unreserve_evp_method_store, + NULL, + put_evp_method_in_store, + construct_evp_method, + destruct_evp_method + }; + + ossl_method_construct(methdata->libctx, methdata->operation_id, + &prov, 0 /* !force_cache */, + &mcm, methdata); + if (methdata->flag_construct_error_occurred != 0) { + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + static void * inner_evp_generic_fetch(struct evp_method_data_st *methdata, OSSL_PROVIDER *prov, int operation_id, @@ -255,7 +322,9 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov), int (*up_ref_method)(void *), - void (*free_method)(void *)) + void (*free_method)(void *), + void *(*dup_method)(void *), + void (*dup_free_method)(void *)) { OSSL_METHOD_STORE *store = get_evp_method_store(methdata->libctx); OSSL_NAMEMAP *namemap = ossl_namemap_stored(methdata->libctx); @@ -288,6 +357,15 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, return NULL; } + if (ossl_method_store_is_frozen(store)) { + const char *store_propq = ossl_method_store_frozen_propq(store); + + if (*propq == '\0' || strcmp(store_propq, propq) == 0) { + ossl_frozen_method_store_cache_get(store, name, propq, operation_id, &method); + return method; + } + } + /* If we haven't received a name id yet, try to get one for the name */ name_id = name != NULL ? ossl_namemap_name2num(namemap, name) : 0; @@ -329,6 +407,8 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, methdata->method_from_algorithm = new_method; methdata->refcnt_up_method = up_ref_method; methdata->destruct_method = free_method; + methdata->free_frozen_method = dup_free_method; + methdata->dup_method = dup_method; methdata->flag_construct_error_occurred = 0; if ((method = ossl_method_construct(methdata->libctx, operation_id, &prov, 0 /* !force_cache */, @@ -357,7 +437,10 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata, meth_id = evp_method_id(name_id, operation_id); if (meth_id != 0) ossl_method_store_cache_set(store, prov, meth_id, propq, - method, up_ref_method, free_method); + method, + up_ref_method, + free_method, + dup_method, dup_free_method); } } @@ -394,7 +477,9 @@ void *evp_generic_fetch(OSSL_LIB_CTX *libctx, int operation_id, const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov), int (*up_ref_method)(void *), - void (*free_method)(void *)) + void (*free_method)(void *), + void *(*dup_method)(void *), + void (*dup_free_method)(void *)) { struct evp_method_data_st methdata; void *method; @@ -403,11 +488,41 @@ void *evp_generic_fetch(OSSL_LIB_CTX *libctx, int operation_id, methdata.tmp_store = NULL; method = inner_evp_generic_fetch(&methdata, NULL, operation_id, name, properties, - new_method, up_ref_method, free_method); + new_method, + up_ref_method, + free_method, + dup_method, + dup_free_method); dealloc_tmp_evp_method_store(methdata.tmp_store); return method; } +int evp_generic_fetch_all(OSSL_LIB_CTX *libctx, int operation_id, + void *(*new_method)(int name_id, + const OSSL_ALGORITHM *algodef, + OSSL_PROVIDER *prov), + int (*up_ref_method)(void *), + void (*free_method)(void *), + void *(*dup_method)(void *), + void (*dup_free_method)(void *)) +{ + int ret; + struct evp_method_data_st methdata = { + .libctx = libctx, + .name_id = -1, + .method_from_algorithm = new_method, + .refcnt_up_method = up_ref_method, + .destruct_method = free_method, + .dup_method = dup_method, + .free_frozen_method = dup_free_method, + .operation_id = operation_id, + }; + + ret = inner_evp_generic_fetch_all(&methdata, NULL); + dealloc_tmp_evp_method_store(methdata.tmp_store); + return ret; +} + /* * evp_generic_fetch_from_prov() is special, and only returns methods from * the given provider. @@ -420,7 +535,9 @@ void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id, const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov), int (*up_ref_method)(void *), - void (*free_method)(void *)) + void (*free_method)(void *), + void *(*dup_method)(void *), + void (*dup_free_method)(void *)) { struct evp_method_data_st methdata; void *method; @@ -429,7 +546,11 @@ void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id, methdata.tmp_store = NULL; method = inner_evp_generic_fetch(&methdata, prov, operation_id, name, properties, - new_method, up_ref_method, free_method); + new_method, + up_ref_method, + free_method, + dup_method, + dup_free_method); dealloc_tmp_evp_method_store(methdata.tmp_store); return method; } @@ -642,7 +763,7 @@ void evp_generic_do_all(OSSL_LIB_CTX *libctx, int operation_id, methdata.libctx = libctx; methdata.tmp_store = NULL; (void)inner_evp_generic_fetch(&methdata, NULL, operation_id, NULL, NULL, - new_method, up_ref_method, free_method); + new_method, up_ref_method, free_method, NULL, NULL); data.operation_id = operation_id; data.user_fn = user_fn; diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h index b3f9bafe23..2f002a2412 100644 --- a/crypto/evp/evp_local.h +++ b/crypto/evp/evp_local.h @@ -97,6 +97,7 @@ struct evp_keymgmt_st { const char *description; OSSL_PROVIDER *prov; CRYPTO_REF_COUNT refcnt; + int origin; /* Constructor(s), destructor, information */ OSSL_FUNC_keymgmt_new_fn *new; @@ -136,6 +137,7 @@ struct evp_keymgmt_st { struct evp_keyexch_st { int name_id; + int origin; char *type_name; const char *description; OSSL_PROVIDER *prov; @@ -197,8 +199,39 @@ struct evp_signature_st { OSSL_FUNC_signature_query_key_types_fn *query_key_types; } /* EVP_SIGNATURE */; +struct evp_rand_st { + OSSL_PROVIDER *prov; + int name_id; + int origin; + char *type_name; + const char *description; + CRYPTO_REF_COUNT refcnt; + + const OSSL_DISPATCH *dispatch; + OSSL_FUNC_rand_newctx_fn *newctx; + OSSL_FUNC_rand_freectx_fn *freectx; + OSSL_FUNC_rand_instantiate_fn *instantiate; + OSSL_FUNC_rand_uninstantiate_fn *uninstantiate; + OSSL_FUNC_rand_generate_fn *generate; + OSSL_FUNC_rand_reseed_fn *reseed; + OSSL_FUNC_rand_nonce_fn *nonce; + OSSL_FUNC_rand_enable_locking_fn *enable_locking; + OSSL_FUNC_rand_lock_fn *lock; + OSSL_FUNC_rand_unlock_fn *unlock; + OSSL_FUNC_rand_gettable_params_fn *gettable_params; + OSSL_FUNC_rand_gettable_ctx_params_fn *gettable_ctx_params; + OSSL_FUNC_rand_settable_ctx_params_fn *settable_ctx_params; + OSSL_FUNC_rand_get_params_fn *get_params; + OSSL_FUNC_rand_get_ctx_params_fn *get_ctx_params; + OSSL_FUNC_rand_set_ctx_params_fn *set_ctx_params; + OSSL_FUNC_rand_verify_zeroization_fn *verify_zeroization; + OSSL_FUNC_rand_get_seed_fn *get_seed; + OSSL_FUNC_rand_clear_seed_fn *clear_seed; +} /* EVP_RAND */; + struct evp_skeymgmt_st { int name_id; + int origin; char *type_name; const char *description; OSSL_PROVIDER *prov; @@ -222,6 +255,7 @@ struct evp_skeymgmt_st { struct evp_asym_cipher_st { int name_id; + int origin; char *type_name; const char *description; OSSL_PROVIDER *prov; @@ -242,6 +276,7 @@ struct evp_asym_cipher_st { struct evp_kem_st { int name_id; + int origin; char *type_name; const char *description; OSSL_PROVIDER *prov; @@ -301,14 +336,26 @@ void *evp_generic_fetch(OSSL_LIB_CTX *ctx, int operation_id, const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov), int (*up_ref_method)(void *), - void (*free_method)(void *)); + void (*free_method)(void *), + void *(*dup_method)(void *), + void (*dup_free_method)(void *)); +int evp_generic_fetch_all(OSSL_LIB_CTX *ctx, int operation_id, + void *(*new_method)(int name_id, + const OSSL_ALGORITHM *algodef, + OSSL_PROVIDER *prov), + int (*up_ref_method)(void *), + void (*free_method)(void *), + void *(*dup_method)(void *), + void (*dup_free_method)(void *)); void *evp_generic_fetch_from_prov(OSSL_PROVIDER *prov, int operation_id, const char *name, const char *properties, void *(*new_method)(int name_id, const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov), int (*up_ref_method)(void *), - void (*free_method)(void *)); + void (*free_method)(void *), + void *(*dup_method)(void *), + void (*dup_free_method)(void *)); void evp_generic_do_all_prefetched(OSSL_LIB_CTX *libctx, int operation_id, void (*user_fn)(void *method, void *arg), void *user_arg); @@ -410,3 +457,15 @@ int evp_names_do_all(OSSL_PROVIDER *prov, int number, void (*fn)(const char *name, void *data), void *data); int evp_cipher_cache_constants(EVP_CIPHER *cipher); +int evp_method_id2name_id_op_id(uint32_t meth_id, int *name_id, + unsigned int *operation_id); +int evp_md_fetch_all(OSSL_LIB_CTX *ctx); +int evp_cipher_fetch_all(OSSL_LIB_CTX *ctx); +int evp_kdf_fetch_all(OSSL_LIB_CTX *ctx); +int evp_rand_fetch_all(OSSL_LIB_CTX *ctx); +int evp_mac_fetch_all(OSSL_LIB_CTX *ctx); +int evp_keymgmt_fetch_all(OSSL_LIB_CTX *ctx); +int evp_kem_fetch_all(OSSL_LIB_CTX *ctx); +int evp_asym_cipher_fetch_all(OSSL_LIB_CTX *ctx); +int evp_keyexch_fetch_all(OSSL_LIB_CTX *ctx); +int evp_skeymgmt_fetch_all(OSSL_LIB_CTX *ctx); diff --git a/crypto/evp/evp_rand.c b/crypto/evp/evp_rand.c index 689243ef10..4d5036b2a6 100644 --- a/crypto/evp/evp_rand.c +++ b/crypto/evp/evp_rand.c @@ -21,41 +21,20 @@ #include "crypto/evp.h" #include "evp_local.h" -struct evp_rand_st { - OSSL_PROVIDER *prov; - int name_id; - char *type_name; - const char *description; - CRYPTO_REF_COUNT refcnt; - - const OSSL_DISPATCH *dispatch; - OSSL_FUNC_rand_newctx_fn *newctx; - OSSL_FUNC_rand_freectx_fn *freectx; - OSSL_FUNC_rand_instantiate_fn *instantiate; - OSSL_FUNC_rand_uninstantiate_fn *uninstantiate; - OSSL_FUNC_rand_generate_fn *generate; - OSSL_FUNC_rand_reseed_fn *reseed; - OSSL_FUNC_rand_nonce_fn *nonce; - OSSL_FUNC_rand_enable_locking_fn *enable_locking; - OSSL_FUNC_rand_lock_fn *lock; - OSSL_FUNC_rand_unlock_fn *unlock; - OSSL_FUNC_rand_gettable_params_fn *gettable_params; - OSSL_FUNC_rand_gettable_ctx_params_fn *gettable_ctx_params; - OSSL_FUNC_rand_settable_ctx_params_fn *settable_ctx_params; - OSSL_FUNC_rand_get_params_fn *get_params; - OSSL_FUNC_rand_get_ctx_params_fn *get_ctx_params; - OSSL_FUNC_rand_set_ctx_params_fn *set_ctx_params; - OSSL_FUNC_rand_verify_zeroization_fn *verify_zeroization; - OSSL_FUNC_rand_get_seed_fn *get_seed; - OSSL_FUNC_rand_clear_seed_fn *clear_seed; -} /* EVP_RAND */; +static void evp_rand_free_int(EVP_RAND *rand) +{ + OPENSSL_free(rand->type_name); + ossl_provider_free(rand->prov); + CRYPTO_FREE_REF(&rand->refcnt); + OPENSSL_free(rand); +} static int evp_rand_up_ref(void *vrand) { EVP_RAND *rand = (EVP_RAND *)vrand; int ref = 0; - if (rand != NULL) + if (rand != NULL && rand->origin == EVP_ORIG_DYNAMIC) return CRYPTO_UP_REF(&rand->refcnt, &ref); return 1; } @@ -65,15 +44,12 @@ static void evp_rand_free(void *vrand) EVP_RAND *rand = (EVP_RAND *)vrand; int ref = 0; - if (rand == NULL) + if (rand == NULL || rand->origin != EVP_ORIG_DYNAMIC) return; CRYPTO_DOWN_REF(&rand->refcnt, &ref); if (ref > 0) return; - OPENSSL_free(rand->type_name); - ossl_provider_free(rand->prov); - CRYPTO_FREE_REF(&rand->refcnt); - OPENSSL_free(rand); + evp_rand_free_int(rand); } static void *evp_rand_new(void) @@ -90,6 +66,47 @@ static void *evp_rand_new(void) return rand; } +static void *evp_rand_dup_frozen(void *vin) +{ + EVP_RAND *in = vin; + EVP_RAND *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (out->prov == NULL || !ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; + +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_rand_frozen_free(void *vin) +{ + EVP_RAND *rand = vin; + int ref = 0; + + if (rand == NULL || rand->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&rand->refcnt, &ref); + if (ref > 0) + return; + evp_rand_free_int(rand); +} + /* Enable locking of the underlying DRBG/RAND if available */ int EVP_RAND_enable_locking(EVP_RAND_CTX *rand) { @@ -282,9 +299,23 @@ static void *evp_rand_from_algorithm(int name_id, EVP_RAND *EVP_RAND_fetch(OSSL_LIB_CTX *libctx, const char *algorithm, const char *properties) { - return evp_generic_fetch(libctx, OSSL_OP_RAND, algorithm, properties, - evp_rand_from_algorithm, evp_rand_up_ref, - evp_rand_free); + return evp_generic_fetch(libctx, OSSL_OP_RAND, + algorithm, properties, + evp_rand_from_algorithm, + evp_rand_up_ref, + evp_rand_free, + evp_rand_dup_frozen, + evp_rand_frozen_free); +} + +int evp_rand_fetch_all(OSSL_LIB_CTX *ctx) +{ + return evp_generic_fetch_all(ctx, OSSL_OP_RAND, + evp_rand_from_algorithm, + evp_rand_up_ref, + evp_rand_free, + evp_rand_dup_frozen, + evp_rand_frozen_free); } int EVP_RAND_up_ref(EVP_RAND *rand) diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c index de2c966638..1346b4d4ae 100644 --- a/crypto/evp/exchange.c +++ b/crypto/evp/exchange.c @@ -19,6 +19,14 @@ #include "crypto/evp.h" #include "evp_local.h" +static void evp_keyexch_free_int(EVP_KEYEXCH *exchange) +{ + OPENSSL_free(exchange->type_name); + ossl_provider_free(exchange->prov); + CRYPTO_FREE_REF(&exchange->refcnt); + OPENSSL_free(exchange); +} + static void evp_keyexch_free(void *data) { EVP_KEYEXCH_free(data); @@ -47,6 +55,47 @@ static EVP_KEYEXCH *evp_keyexch_new(OSSL_PROVIDER *prov) return exchange; } +static void *evp_keyexch_dup_frozen(void *vin) +{ + EVP_KEYEXCH *in = vin; + EVP_KEYEXCH *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (out->prov == NULL || !ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; + +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_keyexch_frozen_free(void *vin) +{ + EVP_KEYEXCH *rand = vin; + int ref = 0; + + if (rand == NULL || rand->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&rand->refcnt, &ref); + if (ref > 0) + return; + evp_keyexch_free_int(rand); +} + static void *evp_keyexch_from_algorithm(int name_id, const OSSL_ALGORITHM *algodef, OSSL_PROVIDER *prov) @@ -162,22 +211,20 @@ void EVP_KEYEXCH_free(EVP_KEYEXCH *exchange) { int i; - if (exchange == NULL) + if (exchange == NULL || exchange->origin != EVP_ORIG_DYNAMIC) return; CRYPTO_DOWN_REF(&exchange->refcnt, &i); if (i > 0) return; - OPENSSL_free(exchange->type_name); - ossl_provider_free(exchange->prov); - CRYPTO_FREE_REF(&exchange->refcnt); - OPENSSL_free(exchange); + evp_keyexch_free_int(exchange); } int EVP_KEYEXCH_up_ref(EVP_KEYEXCH *exchange) { int ref = 0; - CRYPTO_UP_REF(&exchange->refcnt, &ref); + if (exchange->origin == EVP_ORIG_DYNAMIC) + CRYPTO_UP_REF(&exchange->refcnt, &ref); return 1; } @@ -189,10 +236,26 @@ OSSL_PROVIDER *EVP_KEYEXCH_get0_provider(const EVP_KEYEXCH *exchange) EVP_KEYEXCH *EVP_KEYEXCH_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, const char *properties) { - return evp_generic_fetch(ctx, OSSL_OP_KEYEXCH, algorithm, properties, + return evp_generic_fetch(ctx, + OSSL_OP_KEYEXCH, + algorithm, + properties, evp_keyexch_from_algorithm, evp_keyexch_up_ref, - evp_keyexch_free); + evp_keyexch_free, + evp_keyexch_dup_frozen, + evp_keyexch_frozen_free); +} + +int evp_keyexch_fetch_all(OSSL_LIB_CTX *ctx) +{ + return evp_generic_fetch_all(ctx, + OSSL_OP_KEYEXCH, + evp_keyexch_from_algorithm, + evp_keyexch_up_ref, + evp_keyexch_free, + evp_keyexch_dup_frozen, + evp_keyexch_frozen_free); } EVP_KEYEXCH *evp_keyexch_fetch_from_prov(OSSL_PROVIDER *prov, @@ -203,7 +266,9 @@ EVP_KEYEXCH *evp_keyexch_fetch_from_prov(OSSL_PROVIDER *prov, algorithm, properties, evp_keyexch_from_algorithm, evp_keyexch_up_ref, - evp_keyexch_free); + evp_keyexch_free, + evp_keyexch_dup_frozen, + evp_keyexch_frozen_free); } int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) diff --git a/crypto/evp/kdf_meth.c b/crypto/evp/kdf_meth.c index 5ac6a94013..bbf045b250 100644 --- a/crypto/evp/kdf_meth.c +++ b/crypto/evp/kdf_meth.c @@ -12,17 +12,27 @@ #include #include #include +#include #include "internal/provider.h" #include "internal/core.h" #include "crypto/evp.h" #include "evp_local.h" +static void evp_kdf_free_int(EVP_KDF *kdf) +{ + OPENSSL_free(kdf->type_name); + ossl_provider_free(kdf->prov); + CRYPTO_FREE_REF(&kdf->refcnt); + OPENSSL_free(kdf); +} + static int evp_kdf_up_ref(void *vkdf) { EVP_KDF *kdf = (EVP_KDF *)vkdf; int ref = 0; - CRYPTO_UP_REF(&kdf->refcnt, &ref); + if (kdf->origin == EVP_ORIG_DYNAMIC) + CRYPTO_UP_REF(&kdf->refcnt, &ref); return 1; } @@ -31,16 +41,52 @@ static void evp_kdf_free(void *vkdf) EVP_KDF *kdf = (EVP_KDF *)vkdf; int ref = 0; - if (kdf == NULL) + if (kdf == NULL || kdf->origin != EVP_ORIG_DYNAMIC) return; CRYPTO_DOWN_REF(&kdf->refcnt, &ref); if (ref > 0) return; - OPENSSL_free(kdf->type_name); - ossl_provider_free(kdf->prov); - CRYPTO_FREE_REF(&kdf->refcnt); - OPENSSL_free(kdf); + evp_kdf_free_int(kdf); +} + +static void *evp_kdf_dup_frozen(void *vin) +{ + EVP_KDF *in = vin; + EVP_KDF *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (out->prov == NULL || !ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_kdf_frozen_free(EVP_KDF *kdf) +{ + int ref; + + if (kdf == NULL || kdf->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&kdf->refcnt, &ref); + if (ref > 0) + return; + evp_kdf_free_int(kdf); } static void *evp_kdf_new(void) @@ -171,7 +217,18 @@ EVP_KDF *EVP_KDF_fetch(OSSL_LIB_CTX *libctx, const char *algorithm, { return evp_generic_fetch(libctx, OSSL_OP_KDF, algorithm, properties, evp_kdf_from_algorithm, evp_kdf_up_ref, - evp_kdf_free); + evp_kdf_free, evp_kdf_dup_frozen, + (void (*)(void *))evp_kdf_frozen_free); +} + +int evp_kdf_fetch_all(OSSL_LIB_CTX *ctx) +{ + return evp_generic_fetch_all(ctx, OSSL_OP_KDF, + evp_kdf_from_algorithm, + evp_kdf_up_ref, + evp_kdf_free, + evp_kdf_dup_frozen, + (void (*)(void *))evp_kdf_frozen_free); } int EVP_KDF_up_ref(EVP_KDF *kdf) diff --git a/crypto/evp/kem.c b/crypto/evp/kem.c index 6c36164760..3e6de42a2c 100644 --- a/crypto/evp/kem.c +++ b/crypto/evp/kem.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include "internal/cryptlib.h" @@ -22,11 +23,60 @@ static void evp_kem_free(void *data) EVP_KEM_free(data); } +static void evp_kem_free_int(EVP_KEM *kem) +{ + OPENSSL_free(kem->type_name); + ossl_provider_free(kem->prov); + CRYPTO_FREE_REF(&kem->refcnt); + OPENSSL_free(kem); +} + static int evp_kem_up_ref(void *data) { return EVP_KEM_up_ref(data); } +static void *evp_kem_dup_frozen(void *vin) +{ + EVP_KEM *in = vin; + EVP_KEM *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (out->prov != NULL && !ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; + +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_kem_frozen_free(void *vin) +{ + EVP_KEM *kem = vin; + int ref = 0; + + if (kem == NULL || kem->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&kem->refcnt, &ref); + if (ref > 0) + return; + evp_kem_free_int(kem); +} + static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation, const OSSL_PARAM params[], EVP_PKEY *authkey) { @@ -432,23 +482,21 @@ void EVP_KEM_free(EVP_KEM *kem) { int i; - if (kem == NULL) + if (kem == NULL || kem->origin != EVP_ORIG_DYNAMIC) return; CRYPTO_DOWN_REF(&kem->refcnt, &i); if (i > 0) return; - OPENSSL_free(kem->type_name); - ossl_provider_free(kem->prov); - CRYPTO_FREE_REF(&kem->refcnt); - OPENSSL_free(kem); + evp_kem_free_int(kem); } int EVP_KEM_up_ref(EVP_KEM *kem) { int ref = 0; - CRYPTO_UP_REF(&kem->refcnt, &ref); + if (kem->origin == EVP_ORIG_DYNAMIC) + CRYPTO_UP_REF(&kem->refcnt, &ref); return 1; } @@ -463,7 +511,9 @@ EVP_KEM *EVP_KEM_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, return evp_generic_fetch(ctx, OSSL_OP_KEM, algorithm, properties, evp_kem_from_algorithm, evp_kem_up_ref, - evp_kem_free); + evp_kem_free, + evp_kem_dup_frozen, + evp_kem_frozen_free); } EVP_KEM *evp_kem_fetch_from_prov(OSSL_PROVIDER *prov, const char *algorithm, @@ -472,7 +522,19 @@ EVP_KEM *evp_kem_fetch_from_prov(OSSL_PROVIDER *prov, const char *algorithm, return evp_generic_fetch_from_prov(prov, OSSL_OP_KEM, algorithm, properties, evp_kem_from_algorithm, evp_kem_up_ref, - evp_kem_free); + evp_kem_free, + evp_kem_dup_frozen, + evp_kem_frozen_free); +} + +int evp_kem_fetch_all(OSSL_LIB_CTX *ctx) +{ + return evp_generic_fetch_all(ctx, OSSL_OP_KEM, + evp_kem_from_algorithm, + evp_kem_up_ref, + evp_kem_free, + evp_kem_dup_frozen, + evp_kem_frozen_free); } int EVP_KEM_is_a(const EVP_KEM *kem, const char *name) diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c index 465e669a71..23ee404929 100644 --- a/crypto/evp/keymgmt_meth.c +++ b/crypto/evp/keymgmt_meth.c @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include #include #include @@ -22,11 +23,59 @@ static void evp_keymgmt_free(void *data) EVP_KEYMGMT_free(data); } +static void evp_keymgmt_free_int(EVP_KEYMGMT *keymgmt) +{ + OPENSSL_free(keymgmt->type_name); + ossl_provider_free(keymgmt->prov); + CRYPTO_FREE_REF(&keymgmt->refcnt); + OPENSSL_free(keymgmt); +} + static int evp_keymgmt_up_ref(void *data) { return EVP_KEYMGMT_up_ref(data); } +static void *evp_keymgmt_dup_frozen(void *vin) +{ + EVP_KEYMGMT *in = vin; + EVP_KEYMGMT *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (out->prov != NULL && !ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_keymgmt_frozen_free(void *vin) +{ + EVP_KEYMGMT *keymgmt = vin; + int ref = 0; + + if (keymgmt == NULL || keymgmt->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&keymgmt->refcnt, &ref); + if (ref > 0) + return; + evp_keymgmt_free_int(keymgmt); +} + static void *keymgmt_new(void) { EVP_KEYMGMT *keymgmt = NULL; @@ -274,7 +323,19 @@ EVP_KEYMGMT *evp_keymgmt_fetch_from_prov(OSSL_PROVIDER *prov, name, properties, keymgmt_from_algorithm, evp_keymgmt_up_ref, - evp_keymgmt_free); + evp_keymgmt_free, + evp_keymgmt_dup_frozen, + evp_keymgmt_frozen_free); +} + +int evp_keymgmt_fetch_all(OSSL_LIB_CTX *ctx) +{ + return evp_generic_fetch_all(ctx, OSSL_OP_KEYMGMT, + keymgmt_from_algorithm, + evp_keymgmt_up_ref, + evp_keymgmt_free, + evp_keymgmt_dup_frozen, + evp_keymgmt_frozen_free); } EVP_KEYMGMT *EVP_KEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, @@ -283,14 +344,17 @@ EVP_KEYMGMT *EVP_KEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, return evp_generic_fetch(ctx, OSSL_OP_KEYMGMT, algorithm, properties, keymgmt_from_algorithm, evp_keymgmt_up_ref, - evp_keymgmt_free); + evp_keymgmt_free, + evp_keymgmt_dup_frozen, + evp_keymgmt_frozen_free); } int EVP_KEYMGMT_up_ref(EVP_KEYMGMT *keymgmt) { int ref = 0; - CRYPTO_UP_REF(&keymgmt->refcnt, &ref); + if (keymgmt->origin == EVP_ORIG_DYNAMIC) + CRYPTO_UP_REF(&keymgmt->refcnt, &ref); return 1; } @@ -298,16 +362,13 @@ void EVP_KEYMGMT_free(EVP_KEYMGMT *keymgmt) { int ref = 0; - if (keymgmt == NULL) + if (keymgmt == NULL || keymgmt->origin != EVP_ORIG_DYNAMIC) return; CRYPTO_DOWN_REF(&keymgmt->refcnt, &ref); if (ref > 0) return; - OPENSSL_free(keymgmt->type_name); - ossl_provider_free(keymgmt->prov); - CRYPTO_FREE_REF(&keymgmt->refcnt); - OPENSSL_free(keymgmt); + evp_keymgmt_free_int(keymgmt); } const OSSL_PROVIDER *EVP_KEYMGMT_get0_provider(const EVP_KEYMGMT *keymgmt) diff --git a/crypto/evp/mac_meth.c b/crypto/evp/mac_meth.c index ee29f58b3e..201ebf7852 100644 --- a/crypto/evp/mac_meth.c +++ b/crypto/evp/mac_meth.c @@ -11,17 +11,27 @@ #include #include #include +#include #include "internal/provider.h" #include "internal/core.h" #include "crypto/evp.h" #include "evp_local.h" +static void evp_mac_free_int(EVP_MAC *mac) +{ + OPENSSL_free(mac->type_name); + ossl_provider_free(mac->prov); + CRYPTO_FREE_REF(&mac->refcnt); + OPENSSL_free(mac); +} + static int evp_mac_up_ref(void *vmac) { EVP_MAC *mac = vmac; int ref = 0; - CRYPTO_UP_REF(&mac->refcnt, &ref); + if (mac->origin == EVP_ORIG_DYNAMIC) + CRYPTO_UP_REF(&mac->refcnt, &ref); return 1; } @@ -30,16 +40,54 @@ static void evp_mac_free(void *vmac) EVP_MAC *mac = vmac; int ref = 0; - if (mac == NULL) + if (mac == NULL || mac->origin != EVP_ORIG_DYNAMIC) return; CRYPTO_DOWN_REF(&mac->refcnt, &ref); if (ref > 0) return; - OPENSSL_free(mac->type_name); - ossl_provider_free(mac->prov); - CRYPTO_FREE_REF(&mac->refcnt); - OPENSSL_free(mac); + evp_mac_free_int(mac); +} + +static void *evp_mac_dup_frozen(void *vin) +{ + EVP_MAC *in = vin; + EVP_MAC *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (out->prov == NULL || !ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; + +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_mac_frozen_free(void *vin) +{ + EVP_MAC *mac = vin; + int ref = 0; + + if (mac == NULL || mac->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&mac->refcnt, &ref); + if (ref > 0) + return; + evp_mac_free_int(mac); } static void *evp_mac_new(void) @@ -175,9 +223,23 @@ err: EVP_MAC *EVP_MAC_fetch(OSSL_LIB_CTX *libctx, const char *algorithm, const char *properties) { - return evp_generic_fetch(libctx, OSSL_OP_MAC, algorithm, properties, - evp_mac_from_algorithm, evp_mac_up_ref, - evp_mac_free); + return evp_generic_fetch(libctx, OSSL_OP_MAC, + algorithm, properties, + evp_mac_from_algorithm, + evp_mac_up_ref, + evp_mac_free, + evp_mac_dup_frozen, + evp_mac_frozen_free); +} + +int evp_mac_fetch_all(OSSL_LIB_CTX *ctx) +{ + return evp_generic_fetch_all(ctx, OSSL_OP_MAC, + evp_mac_from_algorithm, + evp_mac_up_ref, + evp_mac_free, + evp_mac_dup_frozen, + evp_mac_frozen_free); } int EVP_MAC_up_ref(EVP_MAC *mac) @@ -259,5 +321,7 @@ EVP_MAC *evp_mac_fetch_from_prov(OSSL_PROVIDER *prov, algorithm, properties, evp_mac_from_algorithm, evp_mac_up_ref, - evp_mac_free); + evp_mac_free, + evp_mac_dup_frozen, + evp_mac_frozen_free); } diff --git a/crypto/evp/signature.c b/crypto/evp/signature.c index c7fbb6e706..2e7a18f229 100644 --- a/crypto/evp/signature.c +++ b/crypto/evp/signature.c @@ -486,7 +486,7 @@ EVP_SIGNATURE *EVP_SIGNATURE_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, return evp_generic_fetch(ctx, OSSL_OP_SIGNATURE, algorithm, properties, evp_signature_from_algorithm, evp_signature_up_ref, - evp_signature_free); + evp_signature_free, NULL, NULL); } EVP_SIGNATURE *evp_signature_fetch_from_prov(OSSL_PROVIDER *prov, @@ -497,7 +497,9 @@ EVP_SIGNATURE *evp_signature_fetch_from_prov(OSSL_PROVIDER *prov, algorithm, properties, evp_signature_from_algorithm, evp_signature_up_ref, - evp_signature_free); + evp_signature_free, + NULL, + NULL); } int EVP_SIGNATURE_is_a(const EVP_SIGNATURE *signature, const char *name) diff --git a/crypto/evp/skeymgmt_meth.c b/crypto/evp/skeymgmt_meth.c index 46ea0c5443..c225151d3f 100644 --- a/crypto/evp/skeymgmt_meth.c +++ b/crypto/evp/skeymgmt_meth.c @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include #include #include @@ -17,6 +18,55 @@ #include "crypto/evp.h" #include "evp_local.h" +static void evp_skeymgmt_free_int(EVP_SKEYMGMT *skeymgmt) +{ + OPENSSL_free(skeymgmt->type_name); + ossl_provider_free(skeymgmt->prov); + CRYPTO_FREE_REF(&skeymgmt->refcnt); + OPENSSL_free(skeymgmt); +} + +static void *evp_skeymgmt_dup_frozen(void *vin) +{ + EVP_SKEYMGMT *in = vin; + EVP_SKEYMGMT *out; + + out = OPENSSL_malloc(sizeof(*out)); + if (out == NULL) + return NULL; + memcpy(out, in, sizeof(*out)); + if (!CRYPTO_NEW_REF(&out->refcnt, 1)) + goto err; + out->type_name = OPENSSL_strdup(in->type_name); + if (out->type_name == NULL) + goto err; + out->origin = EVP_ORIG_FROZEN; + if (out->prov == NULL || !ossl_provider_up_ref(out->prov)) { + OPENSSL_free(out->type_name); + goto err; + } + return out; + +err: + CRYPTO_FREE_REF(&out->refcnt); + OPENSSL_free(out); + return NULL; +} + +static void evp_skeymgmt_frozen_free(void *vin) +{ + EVP_SKEYMGMT *skeymgmt = vin; + int ref = 0; + + if (skeymgmt == NULL || skeymgmt->origin != EVP_ORIG_FROZEN) + return; + + CRYPTO_DOWN_REF(&skeymgmt->refcnt, &ref); + if (ref > 0) + return; + evp_skeymgmt_free_int(skeymgmt); +} + void *evp_skeymgmt_generate(const EVP_SKEYMGMT *skeymgmt, const OSSL_PARAM params[]) { void *provctx = ossl_provider_ctx(EVP_SKEYMGMT_get0_provider(skeymgmt)); @@ -136,7 +186,9 @@ EVP_SKEYMGMT *evp_skeymgmt_fetch_from_prov(OSSL_PROVIDER *prov, name, properties, skeymgmt_from_algorithm, (int (*)(void *))EVP_SKEYMGMT_up_ref, - (void (*)(void *))EVP_SKEYMGMT_free); + (void (*)(void *))EVP_SKEYMGMT_free, + evp_skeymgmt_dup_frozen, + evp_skeymgmt_frozen_free); } EVP_SKEYMGMT *EVP_SKEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, @@ -145,14 +197,28 @@ EVP_SKEYMGMT *EVP_SKEYMGMT_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, return evp_generic_fetch(ctx, OSSL_OP_SKEYMGMT, algorithm, properties, skeymgmt_from_algorithm, (int (*)(void *))EVP_SKEYMGMT_up_ref, - (void (*)(void *))EVP_SKEYMGMT_free); + (void (*)(void *))EVP_SKEYMGMT_free, + evp_skeymgmt_dup_frozen, + evp_skeymgmt_frozen_free); +} + +int evp_skeymgmt_fetch_all(OSSL_LIB_CTX *ctx) +{ + return evp_generic_fetch_all(ctx, + OSSL_OP_SKEYMGMT, + skeymgmt_from_algorithm, + (int (*)(void *))EVP_SKEYMGMT_up_ref, + (void (*)(void *))EVP_SKEYMGMT_free, + evp_skeymgmt_dup_frozen, + evp_skeymgmt_frozen_free); } int EVP_SKEYMGMT_up_ref(EVP_SKEYMGMT *skeymgmt) { int ref = 0; - CRYPTO_UP_REF(&skeymgmt->refcnt, &ref); + if (skeymgmt->origin == EVP_ORIG_DYNAMIC) + CRYPTO_UP_REF(&skeymgmt->refcnt, &ref); return 1; } @@ -160,16 +226,13 @@ void EVP_SKEYMGMT_free(EVP_SKEYMGMT *skeymgmt) { int ref = 0; - if (skeymgmt == NULL) + if (skeymgmt == NULL || skeymgmt->origin != EVP_ORIG_DYNAMIC) return; CRYPTO_DOWN_REF(&skeymgmt->refcnt, &ref); if (ref > 0) return; - OPENSSL_free(skeymgmt->type_name); - ossl_provider_free(skeymgmt->prov); - CRYPTO_FREE_REF(&skeymgmt->refcnt); - OPENSSL_free(skeymgmt); + evp_skeymgmt_free_int(skeymgmt); } const OSSL_PROVIDER *EVP_SKEYMGMT_get0_provider(const EVP_SKEYMGMT *skeymgmt) diff --git a/crypto/property/property.c b/crypto/property/property.c index 4c35d1eb7e..b086d0c056 100644 --- a/crypto/property/property.c +++ b/crypto/property/property.c @@ -12,19 +12,20 @@ #include #include #include -#include "internal/core.h" #include "internal/property.h" #include "internal/provider.h" +#include "internal/core.h" #include "internal/tsan_assist.h" -#include "crypto/ctype.h" +#include "internal/hashtable.h" #include #include #include -#include "internal/thread_once.h" -#include "crypto/lhash.h" #include "crypto/sparse_array.h" #include "property_local.h" #include "crypto/context.h" +#include "crypto/evp.h" +#include "crypto/evp/evp_local.h" +#include "internal/namemap.h" /* * The number of elements in the query cache before we initiate a flush. @@ -37,6 +38,8 @@ typedef struct { void *method; int (*up_ref)(void *); void (*free)(void *); + void *(*dup)(void *); + void (*free_dup)(void *); } METHOD; typedef struct { @@ -65,6 +68,9 @@ typedef struct { struct ossl_method_store_st { OSSL_LIB_CTX *ctx; SPARSE_ARRAY_OF(ALGORITHM) * algs; + + /* (nid, propq) -> method */ + HT *frozen_algs; /* * Lock to protect the |algs| array from concurrent writing, when * individual implementations or queries are inserted. This is used @@ -86,6 +92,12 @@ struct ossl_method_store_st { /* Flag: 1 if query cache entries for all algs need flushing */ int cache_need_flush; + + /* Flag: 1 if method store is frozen */ + int frozen; + + /* Property query associated with frozen state */ + char *frozen_propq; }; typedef struct { @@ -99,6 +111,13 @@ DEFINE_SPARSE_ARRAY_OF(ALGORITHM); DEFINE_STACK_OF(ALGORITHM) +HT_START_KEY_DEFN(frozen_cache_key) +HT_DEF_KEY_FIELD_CHAR_ARRAY(name, 64) +/* TODO(FREEZE): allow variable length propq */ +HT_DEF_KEY_FIELD_CHAR_ARRAY(propq, 64) +HT_DEF_KEY_FIELD(op_id, unsigned int) +HT_END_KEY_DEFN(FROZEN_CACHE_KEY) + typedef struct ossl_global_properties_st { OSSL_PROPERTY_LIST *list; #ifndef FIPS_MODULE @@ -169,6 +188,30 @@ static void ossl_method_free(METHOD *method) (*method->free)(method->method); } +static void ossl_method_free_frozen(METHOD *method) +{ + (*method->free_dup)(method->method); +} + +static METHOD *ossl_method_dup(METHOD *method) +{ + METHOD *dup; + + dup = OPENSSL_zalloc(sizeof(*dup)); + if (dup == NULL) + return NULL; + + memcpy(dup, method, sizeof(*dup)); + + dup->method = (*method->dup)(method->method); + if (dup->method == NULL) { + OPENSSL_free(dup); + return NULL; + } + + return dup; +} + static __owur int ossl_property_read_lock(OSSL_METHOD_STORE *p) { return p != NULL ? CRYPTO_THREAD_read_lock(p->lock) : 0; @@ -262,9 +305,12 @@ void ossl_method_store_free(OSSL_METHOD_STORE *store) if (store != NULL) { if (store->algs != NULL) ossl_sa_ALGORITHM_doall_arg(store->algs, &alg_cleanup, store); + if (store->frozen_algs != NULL) + ossl_ht_free(store->frozen_algs); ossl_sa_ALGORITHM_free(store->algs); CRYPTO_THREAD_lock_free(store->lock); CRYPTO_THREAD_lock_free(store->biglock); + OPENSSL_free(store->frozen_propq); OPENSSL_free(store); } } @@ -317,14 +363,16 @@ static int ossl_method_store_insert(OSSL_METHOD_STORE *store, ALGORITHM *alg) int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov, int nid, const char *properties, void *method, int (*method_up_ref)(void *), - void (*method_destruct)(void *)) + void (*method_destruct)(void *), + void *(*method_dup)(void *), + void (*free_frozen)(void *)) { ALGORITHM *alg = NULL; IMPLEMENTATION *impl; int ret = 0; int i; - if (nid <= 0 || method == NULL || store == NULL) + if (nid <= 0 || method == NULL || store == NULL || store->frozen == 1) return 0; if (properties == NULL) @@ -340,6 +388,8 @@ int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov, impl->method.method = method; impl->method.up_ref = method_up_ref; impl->method.free = method_destruct; + impl->method.dup = method_dup; + impl->method.free_dup = free_frozen; if (!ossl_method_up_ref(&impl->method)) { OPENSSL_free(impl); return 0; @@ -438,7 +488,7 @@ int ossl_method_store_remove(OSSL_METHOD_STORE *store, int nid, ALGORITHM *alg = NULL; int i; - if (nid <= 0 || method == NULL || store == NULL) + if (nid <= 0 || method == NULL || store == NULL || store->frozen == 1) return 0; if (!ossl_property_write_lock(store)) @@ -540,7 +590,7 @@ int ossl_method_store_remove_all_provided(OSSL_METHOD_STORE *store, { struct alg_cleanup_by_provider_data_st data; - if (!ossl_property_write_lock(store)) + if (store == NULL || store->frozen == 1 || !ossl_property_write_lock(store)) return 0; data.prov = prov; data.store = store; @@ -609,32 +659,9 @@ void ossl_method_store_do_all(OSSL_METHOD_STORE *store, } } -/** - * @brief Fetches a method from the method store matching the given properties. - * - * This function searches the method store for an implementation of a specified - * method, identified by its id (nid), and matching the given property query. If - * successful, it returns the method and its associated provider. - * - * @param store Pointer to the OSSL_METHOD_STORE from which to fetch the method. - * Must be non-null. - * @param nid (identifier) of the method to be fetched. Must be > 0 - * @param prop_query String containing the property query to match against. - * @param prov_rw Pointer to the OSSL_PROVIDER to restrict the search to, or - * to receive the matched provider. - * @param method Pointer to receive the fetched method. Must be non-null. - * - * @return 1 if the method is successfully fetched, 0 on failure. - * - * If tracing is enabled, a message is printed indicating the property query and - * the resolved provider. - * - * NOTE: The nid parameter here is _not_ a NID in the sense of the NID_* macros. - * It is a unique internal identifier value. - */ -int ossl_method_store_fetch(OSSL_METHOD_STORE *store, +static int ossl_method_store_fetch_best_impl(OSSL_METHOD_STORE *store, int nid, const char *prop_query, - const OSSL_PROVIDER **prov_rw, void **method) + const OSSL_PROVIDER **prov_rw, IMPLEMENTATION **rbest_impl) { OSSL_PROPERTY_LIST **plp; ALGORITHM *alg; @@ -644,7 +671,7 @@ int ossl_method_store_fetch(OSSL_METHOD_STORE *store, int ret = 0; int j, best = -1, score, optional; - if (nid <= 0 || method == NULL || store == NULL) + if (nid <= 0 || store == NULL || rbest_impl == NULL) return 0; #if !defined(FIPS_MODULE) && !defined(OPENSSL_NO_AUTOLOAD_CONFIG) @@ -729,8 +756,8 @@ int ossl_method_store_fetch(OSSL_METHOD_STORE *store, } } fin: - if (ret && ossl_method_up_ref(&best_impl->method)) { - *method = best_impl->method.method; + if (ret) { + *rbest_impl = best_impl; if (prov_rw != NULL) *prov_rw = best_impl->provider; } else { @@ -757,6 +784,48 @@ fin: return ret; } +/** + * @brief Fetches a method from the method store matching the given properties. + * + * This function searches the method store for an implementation of a specified + * method, identified by its id (nid), and matching the given property query. If + * successful, it returns the method and its associated provider. + * + * @param store Pointer to the OSSL_METHOD_STORE from which to fetch the method. + * Must be non-null. + * @param nid (identifier) of the method to be fetched. Must be > 0 + * @param prop_query String containing the property query to match against. + * @param prov_rw Pointer to the OSSL_PROVIDER to restrict the search to, or + * to receive the matched provider. + * @param method Pointer to receive the fetched method. Must be non-null. + * + * @return 1 if the method is successfully fetched, 0 on failure. + * + * If tracing is enabled, a message is printed indicating the property query and + * the resolved provider. + * + * NOTE: The nid parameter here is _not_ a NID in the sense of the NID_* macros. + * It is a unique internal identifier value. + */ +int ossl_method_store_fetch(OSSL_METHOD_STORE *store, + int nid, const char *prop_query, + const OSSL_PROVIDER **prov_rw, void **method) +{ + IMPLEMENTATION *best_impl = NULL; + int ret = 0; + + if (nid <= 0 || store == NULL || method == NULL) + return 0; + + ret = ossl_method_store_fetch_best_impl(store, nid, prop_query, prov_rw, &best_impl); + if (ret && ossl_method_up_ref(&best_impl->method)) + *method = best_impl->method.method; + else + ret = 0; + + return ret; +} + static void ossl_method_cache_flush_alg(OSSL_METHOD_STORE *store, ALGORITHM *alg) { @@ -774,7 +843,7 @@ static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid) int ossl_method_store_cache_flush_all(OSSL_METHOD_STORE *store) { - if (!ossl_property_write_lock(store)) + if (store == NULL || store->frozen == 1 || !ossl_property_write_lock(store)) return 0; ossl_sa_ALGORITHM_doall(store->algs, &impl_cache_flush_alg); store->cache_nelem = 0; @@ -889,7 +958,9 @@ err: int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov, int nid, const char *prop_query, void *method, int (*method_up_ref)(void *), - void (*method_destruct)(void *)) + void (*method_destruct)(void *), + void *(*method_dup)(void *), + void (*free_dup)(void *)) { QUERY elem, *old, *p = NULL; ALGORITHM *alg; @@ -926,6 +997,8 @@ int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov, p->method.method = method; p->method.up_ref = method_up_ref; p->method.free = method_destruct; + p->method.dup = method_dup; + p->method.free_dup = free_dup; if (!ossl_method_up_ref(&p->method)) goto err; memcpy((char *)p->query, prop_query, len + 1); @@ -947,3 +1020,193 @@ end: ossl_property_unlock(store); return res; } + +int ossl_frozen_method_store_cache_get(OSSL_METHOD_STORE *store, + const char *alg_name, const char *prop_query, unsigned int operation_id, + void **method) +{ + FROZEN_CACHE_KEY key; + HT_VALUE *val; + + if (store == NULL + || alg_name == NULL + || prop_query == NULL + || store->frozen_algs == NULL) + return 0; + + HT_INIT_KEY(&key); + HT_SET_KEY_STRING_CASE(&key, name, alg_name); + HT_SET_KEY_STRING(&key, propq, prop_query); + HT_SET_KEY_FIELD(&key, op_id, operation_id); + + val = ossl_ht_get(store->frozen_algs, TO_HT_KEY(&key)); + if (val == NULL) + return 1; + *method = ((METHOD *)val->value)->method; + + return 1; +} + +struct alg_freeze_st { + OSSL_METHOD_STORE *store; + int nid; + + int ret; +}; + +static void frozen_cache_free(HT_VALUE *val) +{ + METHOD *method = (METHOD *)val->value; + if (method == NULL || method->free_dup == NULL) + return; + ossl_method_free_frozen(method); + + OPENSSL_free(method); +} + +static int freeze_alg(OSSL_METHOD_STORE *store, ALGORITHM *alg, + const char *propq, const char *alg_name, int operation_id) +{ + int ret = 0; + IMPLEMENTATION *best_impl = NULL; + FROZEN_CACHE_KEY key; + HT_VALUE val = { 0 }; + const OSSL_PROVIDER *prov = NULL; + + HT_INIT_KEY(&key); + HT_SET_KEY_STRING_CASE(&key, name, alg_name); + HT_SET_KEY_STRING(&key, propq, propq); + HT_SET_KEY_FIELD(&key, op_id, operation_id); + + if (ossl_ht_get(store->frozen_algs, TO_HT_KEY(&key)) != NULL) + return 1; + + ret = ossl_method_store_fetch_best_impl(store, + alg->nid, propq, &prov, &best_impl); + if (ret == 0 || best_impl == NULL + || best_impl->method.dup == NULL + || best_impl->method.free_dup == NULL) + return 1; + + val.value = ossl_method_dup(&best_impl->method); + if (val.value == NULL) + return ret; + + ret = ossl_ht_insert(store->frozen_algs, TO_HT_KEY(&key), &val, NULL); + if (ret <= 0) { + frozen_cache_free(&val); + return 0; + } + + return 1; +} + +static void alg_freeze(ossl_uintmax_t idx, ALGORITHM *alg, void *arg) +{ + struct alg_freeze_st *af = arg; + OSSL_NAMEMAP *nm = ossl_namemap_stored(af->store->ctx); + int name_id; + unsigned int op_id; + const char *name; + int i = 0; + + if (alg == NULL + || !evp_method_id2name_id_op_id(alg->nid, &name_id, &op_id)) { + af->ret = 0; + return; + } + + for (;;) { + name = ossl_namemap_num2name(nm, name_id, i++); + if (name == NULL) + break; + if (*af->store->frozen_propq != '\0') { + af->ret = freeze_alg(af->store, alg, af->store->frozen_propq, name, op_id); + if (!af->ret) + return; + } + af->ret = freeze_alg(af->store, alg, "", name, op_id); + if (!af->ret) + return; + } +} + +/** + * @brief Freezes the method store's cache into a hash table. + * + * This function creates a frozen copy of the method store's cache, storing it + * in a hash table for efficient retrieval. Each entry in the cache is duplicated + * to ensure that the frozen cache is independent of the original store. + * + * @param store Pointer to the OSSL_METHOD_STORE to be frozen. + * + * @return 1 on success, 0 on failure. + * + * If the store is NULL or if any duplication fails, the function returns 0. + * On success, it returns 1 after populating the frozen cache. + */ +int ossl_method_store_freeze_cache(OSSL_METHOD_STORE *store, const char *propq) +{ + HT_CONFIG ht_conf = { + .ht_free_fn = frozen_cache_free, + .init_neighborhoods = store->cache_nelem, + .collision_check = 1, + .no_rcu = 1, + }; + struct alg_freeze_st af = { + .store = store, + .ret = 1, + }; + propq = propq != NULL ? propq : ""; + + if (store == NULL || store->frozen == 1) + return 0; + + store->frozen_propq = OPENSSL_strdup(propq); + if (store->frozen_propq == NULL) + goto err; + + store->frozen_algs = ossl_ht_new(&ht_conf); + if (store->frozen_algs == NULL) + goto err; + + if (evp_md_fetch_all(store->ctx) <= 0 + || evp_cipher_fetch_all(store->ctx) <= 0 + || evp_rand_fetch_all(store->ctx) <= 0 + || evp_mac_fetch_all(store->ctx) <= 0 + || evp_keymgmt_fetch_all(store->ctx) <= 0 + || evp_kdf_fetch_all(store->ctx) <= 0 + || evp_kem_fetch_all(store->ctx) <= 0 + || evp_asym_cipher_fetch_all(store->ctx) <= 0 + || evp_keyexch_fetch_all(store->ctx) <= 0 + || evp_skeymgmt_fetch_all(store->ctx) <= 0) + goto err; + + ossl_sa_ALGORITHM_doall_arg(store->algs, &alg_freeze, &af); + if (af.ret <= 0) + goto err; + + store->frozen = 1; + + return 1; + +err: + OPENSSL_free(store->frozen_propq); + ossl_ht_free(store->frozen_algs); + store->frozen_algs = NULL; + store->frozen_propq = NULL; + + return 0; +} + +int ossl_method_store_is_frozen(OSSL_METHOD_STORE *store) +{ + return store != NULL && store->frozen == 1; +} + +const char *ossl_method_store_frozen_propq(OSSL_METHOD_STORE *store) +{ + if (store == NULL) + return NULL; + return store->frozen_propq; +} diff --git a/crypto/store/store_meth.c b/crypto/store/store_meth.c index 3b60247f41..63f41741a8 100644 --- a/crypto/store/store_meth.c +++ b/crypto/store/store_meth.c @@ -172,7 +172,7 @@ static int put_loader_in_store(void *store, void *method, return 0; return ossl_method_store_add(store, prov, id, propdef, method, - up_ref_loader, free_loader); + up_ref_loader, free_loader, NULL, NULL); } static void *loader_from_algorithm(int scheme_id, const OSSL_ALGORITHM *algodef, @@ -339,7 +339,7 @@ inner_loader_fetch(struct loader_data_st *methdata, if (id == 0) id = ossl_namemap_name2num(namemap, scheme); ossl_method_store_cache_set(store, prov, id, propq, method, - up_ref_loader, free_loader); + up_ref_loader, free_loader, NULL, NULL); } /* diff --git a/doc/man3/OSSL_LIB_CTX.pod b/doc/man3/OSSL_LIB_CTX.pod index 215db61820..d9516195eb 100644 --- a/doc/man3/OSSL_LIB_CTX.pod +++ b/doc/man3/OSSL_LIB_CTX.pod @@ -5,7 +5,8 @@ OSSL_LIB_CTX, OSSL_LIB_CTX_get_data, OSSL_LIB_CTX_new, OSSL_LIB_CTX_new_from_dispatch, OSSL_LIB_CTX_new_child, OSSL_LIB_CTX_free, OSSL_LIB_CTX_load_config, -OSSL_LIB_CTX_get0_global_default, OSSL_LIB_CTX_set0_default +OSSL_LIB_CTX_get0_global_default, OSSL_LIB_CTX_set0_default, +OSSL_LIB_CTX_freeze - OpenSSL library context =head1 SYNOPSIS @@ -24,6 +25,7 @@ OSSL_LIB_CTX_get0_global_default, OSSL_LIB_CTX_set0_default OSSL_LIB_CTX *OSSL_LIB_CTX_get0_global_default(void); OSSL_LIB_CTX *OSSL_LIB_CTX_set0_default(OSSL_LIB_CTX *ctx); void *OSSL_LIB_CTX_get_data(OSSL_LIB_CTX *ctx, int index); + void *OSSL_LIB_CTX_freeze(OSSL_LIB_CTX *ctx, const char *propq); =head1 DESCRIPTION @@ -121,6 +123,32 @@ If ctx is NULL then the function operates on the default library context. OSSL_LIB_CTX_get_data() returns a memory address whose interpretation depends on the index. +OSSL_LIB_CTX_freeze() freezes the method store associated with the +library context, and builds a fast lookup cache which will be used by +subsequent EVP calls to fetch implementations. A frozen method store +may no longer be modified, and operations attempting to do so (such as +loading a new provider) will fail. This function must only be called +from a non-threaded context, before any worker threads have been +dispatched. A frozen method store can not be un-frozen, or frozen again. + +OSSL_LIB_CTX_freeze() builds the lookup cache using an optional propq +query string argument. OSSL_LIB_CTX_freeze() will build a cache of +methods for all algorithms for the NULL property query, and if propq +is non-NULL, it will also cache the methods for all algorithms +matching the propq query string. Once frozen, future method store +lookups using the the NULL propq or the provided propq will be +answered from the cache. Any method store lookups for an algorithm +using a different propq query string will not be answered from the +cache, and will be looked up by the normal slower method. + +OSSL_LIB_CTX_freeze() is intended for use where applications with +worker threads are not able to be structured to pre-fetch and retain +the algorithm methods from the method store prior to use, and which +therefore may pay a considerable performance penalty for the method +store lookup every time an algorithm is used. Applications which can +pre-fetch the methods they need before their use should not use +OSSL_LIB_CTX_freeze(). + =head1 RETURN VALUES OSSL_LIB_CTX_new(), OSSL_LIB_CTX_get0_global_default() and @@ -134,15 +162,20 @@ OSSL_LIB_CTX_load_config() returns 1 on success, 0 on error. OSSL_LIB_CTX_get_data() returns a memory address whose interpretation depends on the index. +OSSL_LIB_CTX_freeze() returns 1 on success, 0 on error. A frozen library context +cannot be frozen again. + =head1 HISTORY All of the functions described on this page were added in OpenSSL 3.0. OSSL_LIB_CTX_get_data() was introduced in OpenSSL 3.4. +OSSL_LIB_CTX_freeze() was introduced in OpenSSL 4.0. + =head1 COPYRIGHT -Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved. Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 43d4fdc527..805ae38ff9 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -207,6 +207,7 @@ const EVP_PKEY_METHOD *ossl_rsa_pss_pkey_method(void); struct evp_mac_st { OSSL_PROVIDER *prov; int name_id; + int origin; char *type_name; const char *description; @@ -230,6 +231,7 @@ struct evp_mac_st { struct evp_kdf_st { OSSL_PROVIDER *prov; int name_id; + int origin; char *type_name; const char *description; CRYPTO_REF_COUNT refcnt; @@ -252,6 +254,7 @@ struct evp_kdf_st { #define EVP_ORIG_DYNAMIC 0 #define EVP_ORIG_GLOBAL 1 #define EVP_ORIG_METH 2 +#define EVP_ORIG_FROZEN 3 struct evp_md_st { /* nid */ diff --git a/include/internal/property.h b/include/internal/property.h index b63634c678..2c7b5034ea 100644 --- a/include/internal/property.h +++ b/include/internal/property.h @@ -59,7 +59,9 @@ int ossl_method_unlock_store(OSSL_METHOD_STORE *store); int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov, int nid, const char *properties, void *method, int (*method_up_ref)(void *), - void (*method_destruct)(void *)); + void (*method_destruct)(void *), + void *(*method_dup)(void *), + void (*free_frozen)(void *)); int ossl_method_store_remove(OSSL_METHOD_STORE *store, int nid, const void *method); void ossl_method_store_do_all(OSSL_METHOD_STORE *store, @@ -81,7 +83,9 @@ int ossl_method_store_cache_get(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov, int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, OSSL_PROVIDER *prov, int nid, const char *prop_query, void *result, int (*method_up_ref)(void *), - void (*method_destruct)(void *)); + void (*method_destruct)(void *), + void *(*method_dup)(void *), + void (*free_frozen)(void *)); __owur int ossl_method_store_cache_flush_all(OSSL_METHOD_STORE *store); @@ -96,4 +100,12 @@ size_t ossl_property_list_to_string(OSSL_LIB_CTX *ctx, int ossl_global_properties_no_mirrored(OSSL_LIB_CTX *libctx); void ossl_global_properties_stop_mirroring(OSSL_LIB_CTX *libctx); +int ossl_method_store_freeze_cache(OSSL_METHOD_STORE *store, const char *propq); +int ossl_frozen_method_store_cache_get(OSSL_METHOD_STORE *store, + const char *name, const char *prop_query, unsigned int operation_id, + void **result); + +int ossl_method_store_is_frozen(OSSL_METHOD_STORE *store); +const char *ossl_method_store_frozen_propq(OSSL_METHOD_STORE *store); + #endif diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in index c9dc3706f3..7a6d1d7c94 100644 --- a/include/openssl/crypto.h.in +++ b/include/openssl/crypto.h.in @@ -586,6 +586,7 @@ OSSL_LIB_CTX *OSSL_LIB_CTX_get0_global_default(void); OSSL_LIB_CTX *OSSL_LIB_CTX_set0_default(OSSL_LIB_CTX *libctx); int OSSL_LIB_CTX_get_conf_diagnostics(OSSL_LIB_CTX *ctx); void OSSL_LIB_CTX_set_conf_diagnostics(OSSL_LIB_CTX *ctx, int value); +int OSSL_LIB_CTX_freeze(OSSL_LIB_CTX *ctx, const char *propq); void OSSL_sleep(uint64_t millis); diff --git a/test/evp_fetch_prov_test.c b/test/evp_fetch_prov_test.c index 2cde0049e8..78116e0a32 100644 --- a/test/evp_fetch_prov_test.c +++ b/test/evp_fetch_prov_test.c @@ -17,9 +17,13 @@ #include #include #include +#include +#include #include #include "internal/sizes.h" #include "testutil.h" +#include "crypto/evp.h" +#include "../crypto/evp/evp_local.h" static char *config_file = NULL; static char *alg = "digest"; @@ -219,6 +223,81 @@ err: return ret; } +static int test_EVP_MD_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_MD *md = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_LIB_CTX *ctx2 = OSSL_LIB_CTX_new(); + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(ctx2) + || !TEST_ptr(md = EVP_MD_fetch(ctx, "SHA256", NULL)) + || !TEST_true(test_md(md)) + || !TEST_int_ne(md->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_MD_free(md); + md = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(md = EVP_MD_fetch(ctx, "SHA256", NULL)) + || !TEST_true(test_md(md)) + || !TEST_int_eq(md->origin, EVP_ORIG_FROZEN) + || !TEST_ptr(md = EVP_MD_fetch(ctx, "SHA-256", NULL)) + || !TEST_true(test_md(md)) + || !TEST_int_eq(md->origin, EVP_ORIG_FROZEN) + || !TEST_ptr(md = EVP_MD_fetch(ctx, "2.16.840.1.101.3.4.2.1", NULL)) + || !TEST_true(test_md(md)) + || !TEST_int_eq(md->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_MD_free(md); + + if (!TEST_ptr(md = EVP_MD_fetch(ctx, "SHA256", "?fips=true")) + || !TEST_true(test_md(md)) + || !TEST_int_eq(md->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_MD_free(md); + + /* Falls back to slow path */ + if (!TEST_ptr(md = EVP_MD_fetch(ctx, "SHA256", "?provider=default")) + || !TEST_true(test_md(md)) + || !TEST_int_ne(md->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_MD_free(md); + + if (!TEST_ptr(md = EVP_MD_fetch(ctx, "SHA1", NULL)) + || !TEST_int_eq(md->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_MD_free(md); + + if (!TEST_ptr(md = EVP_MD_fetch(ctx2, "SHA1", "?fips=true")) + || !TEST_int_ne(md->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_MD_free(md); + if (!TEST_ptr(md = EVP_MD_fetch(ctx2, "SHA1", NULL)) + || !TEST_int_ne(md->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + unload_providers(&ctx, prov); + OSSL_LIB_CTX_free(ctx2); + EVP_MD_free(md); + return ret; +} + static int test_explicit_EVP_MD_fetch_by_name(void) { return test_explicit_EVP_MD_fetch("SHA256"); @@ -256,6 +335,312 @@ end: return ret; } +static int calculate_mac(const EVP_MAC *mac, const unsigned char *msg, size_t len, + const unsigned char *expected, size_t expected_len) +{ + unsigned char out[EVP_MAX_MD_SIZE]; + const unsigned char key[] = "0123456789abcd"; + EVP_MAC_CTX *ctx = NULL; + OSSL_PARAM params[2], *p = params; + size_t out_len = 0; + int ret = 0; + + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST, "SHA256", 0); + *p = OSSL_PARAM_construct_end(); + + if (!TEST_ptr(ctx = EVP_MAC_CTX_new((EVP_MAC *)mac)) + || !TEST_true(EVP_MAC_init(ctx, key, sizeof(key) - 1, params)) + || !TEST_true(EVP_MAC_update(ctx, msg, len)) + || !TEST_true(EVP_MAC_final(ctx, out, &out_len, sizeof(out))) + || !TEST_size_t_eq(out_len, expected_len) + || !TEST_mem_eq(out, out_len, expected, expected_len)) + goto err; + + ret = 1; +err: + EVP_MAC_CTX_free(ctx); + return ret; +} + +static int test_mac(const EVP_MAC *mac) +{ + const unsigned char testmsg[] = "Hello world"; + const unsigned char expected[] = { + 0xf2, 0x71, 0x5a, 0xad, 0x1d, 0x68, 0x3c, 0xdd, + 0xbc, 0xa7, 0x5a, 0x1e, 0x79, 0xed, 0xac, 0x57, + 0xf6, 0xb0, 0xd4, 0xbb, 0x15, 0xe1, 0x7f, 0x6b, + 0x47, 0x62, 0x58, 0xb1, 0xbc, 0x0d, 0xf4, 0x4f + }; + + return TEST_ptr(mac) + && TEST_true(EVP_MAC_is_a(mac, "HMAC")) + && TEST_true(calculate_mac(mac, testmsg, sizeof(testmsg) - 1, + expected, sizeof(expected))); +} + +static int test_EVP_MAC_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_MAC *mac = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(mac = EVP_MAC_fetch(ctx, "HMAC", NULL)) + || !TEST_true(test_mac(mac)) + || !TEST_int_ne(mac->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_MAC_free(mac); + mac = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(mac = EVP_MAC_fetch(ctx, "HMAC", NULL)) + || !TEST_true(test_mac(mac)) + || !TEST_int_eq(mac->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_MAC_free(mac); + mac = NULL; + + if (!TEST_ptr(mac = EVP_MAC_fetch(ctx, "HMAC", "?fips=true")) + || !TEST_true(test_mac(mac)) + || !TEST_int_eq(mac->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_MAC_free(mac); + mac = NULL; + + /* Falls back to slow path */ + if (!TEST_ptr(mac = EVP_MAC_fetch(ctx, "HMAC", "?provider=default")) + || !TEST_true(test_mac(mac)) + || !TEST_int_ne(mac->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_MAC_free(mac); + unload_providers(&ctx, prov); + return ret; +} + +static int test_implicit_EVP_MAC_fetch(void) +{ + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + EVP_MAC *mac = NULL; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(mac = EVP_MAC_fetch(ctx, "HMAC", NULL)) + || !TEST_true(test_mac(mac))) + goto err; + ret = 1; +err: + EVP_MAC_free(mac); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_MAC_fetch(const char *id) +{ + OSSL_LIB_CTX *ctx = NULL; + EVP_MAC *mac = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + mac = EVP_MAC_fetch(ctx, id, fetch_property); + if (expected_fetch_result != 0) { + if (!test_mac(mac)) + goto err; + + if (!TEST_true(EVP_MAC_up_ref(mac))) + goto err; + /* Ref count should now be 2. Release first one here */ + EVP_MAC_free(mac); + } else { + if (!TEST_ptr_null(mac)) + goto err; + } + ret = 1; +err: + EVP_MAC_free(mac); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_MAC_fetch_by_name(void) +{ + return test_explicit_EVP_MAC_fetch("HMAC"); +} + +static int derive_pbkdf2(EVP_KDF *kdf) +{ + int ret = 0; + EVP_KDF_CTX *ctx = NULL; + unsigned char out[25]; + static const unsigned char password[] = "passwordPASSWORDpassword"; + static const unsigned char salt[] = "saltSALTsaltSALTsaltSALTsaltSALTsalt"; + unsigned int iterations = 4096; + int mode = 0; + OSSL_PARAM params[6], *p = params; + static const unsigned char expected[sizeof(out)] = { + 0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f, + 0x32, 0xd8, 0x14, 0xb8, 0x11, 0x6e, 0x84, 0xcf, + 0x2b, 0x17, 0x34, 0x7e, 0xbc, 0x18, 0x00, 0x18, + 0x1c + }; + + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, + (void *)password, + sizeof(password) - 1); + *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, + (void *)salt, sizeof(salt) - 1); + *p++ = OSSL_PARAM_construct_uint(OSSL_KDF_PARAM_ITER, &iterations); + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, "sha256", 0); + *p++ = OSSL_PARAM_construct_int(OSSL_KDF_PARAM_PKCS5, &mode); + *p = OSSL_PARAM_construct_end(); + + if (!TEST_ptr(ctx = EVP_KDF_CTX_new(kdf)) + || !TEST_int_gt(EVP_KDF_derive(ctx, out, sizeof(out), params), 0) + || !TEST_mem_eq(out, sizeof(out), expected, sizeof(expected))) + goto err; + ret = 1; +err: + EVP_KDF_CTX_free(ctx); + return ret; +} + +static int test_kdf(EVP_KDF *kdf, const char *name) +{ + return TEST_ptr(kdf) + && TEST_ptr(EVP_KDF_get0_provider(kdf)) + && TEST_true(EVP_KDF_is_a(kdf, name)) + && TEST_true(derive_pbkdf2(kdf)); +} + +static int test_implicit_EVP_KDF_fetch(void) +{ + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + EVP_KDF *kdf = NULL; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(kdf = EVP_KDF_fetch(ctx, OSSL_KDF_NAME_PBKDF2, NULL)) + || !TEST_true(test_kdf(kdf, OSSL_KDF_NAME_PBKDF2))) + goto err; + ret = 1; +err: + EVP_KDF_free(kdf); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_KDF_fetch(const char *id) +{ + OSSL_LIB_CTX *ctx = NULL; + EVP_KDF *kdf = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + kdf = EVP_KDF_fetch(ctx, id, fetch_property); + if (expected_fetch_result != 0) { + if (!test_kdf(kdf, id)) + goto err; + + if (!TEST_true(EVP_KDF_up_ref(kdf))) + goto err; + /* Ref count should now be 2. Release first one here */ + EVP_KDF_free(kdf); + } else { + if (!TEST_ptr_null(kdf)) + goto err; + } + ret = 1; +err: + EVP_KDF_free(kdf); + unload_providers(&ctx, prov); + return ret; +} + +static int test_EVP_KDF_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_KDF *kdf = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(kdf = EVP_KDF_fetch(ctx, "PBKDF2", NULL)) + || !TEST_true(test_kdf(kdf, "PBKDF2")) + || !TEST_int_ne(kdf->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KDF_free(kdf); + kdf = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(kdf = EVP_KDF_fetch(ctx, "PBKDF2", NULL)) + || !TEST_true(test_kdf(kdf, "PBKDF2")) + || !TEST_int_eq(kdf->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_KDF_free(kdf); + kdf = NULL; + + if (!TEST_ptr(kdf = EVP_KDF_fetch(ctx, "PBKDF2", "?fips=true")) + || !TEST_true(test_kdf(kdf, "PBKDF2")) + || !TEST_int_eq(kdf->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KDF_free(kdf); + kdf = NULL; + + /* Falls back to slow path */ + if (!TEST_ptr(kdf = EVP_KDF_fetch(ctx, "PBKDF2", "?provider=default")) + || !TEST_true(test_kdf(kdf, "PBKDF2")) + || !TEST_int_ne(kdf->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_KDF_free(kdf); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_KDF_fetch_by_name(void) +{ + return test_explicit_EVP_KDF_fetch("PBKDF2"); +} + /* * Test EVP_CIPHER_fetch() */ @@ -292,6 +677,539 @@ static int test_cipher(const EVP_CIPHER *cipher) && TEST_true(encrypt_decrypt(cipher, testmsg, sizeof(testmsg))); } +static int test_ec_keyexch(OSSL_LIB_CTX *libctx, const char *propq) +{ + EVP_PKEY_CTX *gctx1 = NULL, *gctx2 = NULL, *dctx = NULL; + EVP_PKEY *key1 = NULL, *key2 = NULL; + unsigned char secret1[256], secret2[256]; + size_t secret1_len = 0, secret2_len = 0; + OSSL_PARAM params[2]; + int ret = 0; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + "prime256v1", 0); + params[1] = OSSL_PARAM_construct_end(); + + if (!TEST_ptr(gctx1 = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq)) + || !TEST_true(EVP_PKEY_keygen_init(gctx1)) + || !TEST_true(EVP_PKEY_CTX_set_params(gctx1, params)) + || !TEST_true(EVP_PKEY_keygen(gctx1, &key1)) + || !TEST_ptr(gctx2 = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq)) + || !TEST_true(EVP_PKEY_keygen_init(gctx2)) + || !TEST_true(EVP_PKEY_CTX_set_params(gctx2, params)) + || !TEST_true(EVP_PKEY_keygen(gctx2, &key2)) + || !TEST_ptr(dctx = EVP_PKEY_CTX_new_from_pkey(libctx, key1, propq)) + || !TEST_true(EVP_PKEY_derive_init(dctx)) + || !TEST_true(EVP_PKEY_derive_set_peer(dctx, key2)) + || !TEST_true(EVP_PKEY_derive(dctx, NULL, &secret1_len)) + || !TEST_size_t_le(secret1_len, sizeof(secret1)) + || !TEST_true(EVP_PKEY_derive(dctx, secret1, &secret1_len))) + goto end; + + EVP_PKEY_CTX_free(dctx); + dctx = NULL; + + if (!TEST_ptr(dctx = EVP_PKEY_CTX_new_from_pkey(libctx, key2, propq)) + || !TEST_true(EVP_PKEY_derive_init(dctx)) + || !TEST_true(EVP_PKEY_derive_set_peer(dctx, key1)) + || !TEST_true(EVP_PKEY_derive(dctx, NULL, &secret2_len)) + || !TEST_size_t_le(secret2_len, sizeof(secret2)) + || !TEST_true(EVP_PKEY_derive(dctx, secret2, &secret2_len)) + || !TEST_size_t_eq(secret1_len, secret2_len) + || !TEST_mem_eq(secret1, secret1_len, secret2, secret2_len)) + goto end; + + ret = 1; +end: + EVP_PKEY_CTX_free(dctx); + EVP_PKEY_CTX_free(gctx1); + EVP_PKEY_CTX_free(gctx2); + EVP_PKEY_free(key1); + EVP_PKEY_free(key2); + return ret; +} + +static int test_keymgmt(OSSL_LIB_CTX *libctx, const char *propq, + const EVP_KEYMGMT *keymgmt, const char *name) +{ + return TEST_ptr(keymgmt) + && TEST_ptr(EVP_KEYMGMT_get0_provider(keymgmt)) + && TEST_true(EVP_KEYMGMT_is_a(keymgmt, name)) + && test_ec_keyexch(libctx, propq); +} + +static int test_ml_kem_keyexch(OSSL_LIB_CTX *libctx, const char *propq) +{ + int ret = 0; + EVP_PKEY *privkey = NULL; + EVP_PKEY_CTX *pctx = NULL; + unsigned char *ciphertext = NULL, *secret_enc = NULL, *secret_dec = NULL; + size_t ciphertext_len = 0, secret_enc_len = 0, secret_dec_len = 0; + + if (!TEST_ptr(privkey = EVP_PKEY_Q_keygen(libctx, propq, "ML-KEM-768")) + || !TEST_ptr(pctx = EVP_PKEY_CTX_new_from_pkey(libctx, privkey, propq)) + || !TEST_int_eq(EVP_PKEY_encapsulate_init(pctx, NULL), 1) + || !TEST_int_eq(EVP_PKEY_encapsulate(pctx, NULL, &ciphertext_len, NULL, &secret_enc_len), 1)) + goto err; + + ciphertext = OPENSSL_zalloc(ciphertext_len); + secret_enc = OPENSSL_zalloc(secret_enc_len); + if (!TEST_ptr(ciphertext) + || !TEST_ptr(secret_enc) + || !TEST_int_gt(EVP_PKEY_encapsulate(pctx, ciphertext, &ciphertext_len, + secret_enc, &secret_enc_len), + 0)) + goto err; + + EVP_PKEY_CTX_free(pctx); + pctx = NULL; + + if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_from_pkey(libctx, privkey, propq)) + || !TEST_int_eq(EVP_PKEY_decapsulate_init(pctx, NULL), 1) + || !TEST_int_eq(EVP_PKEY_decapsulate(pctx, NULL, &secret_dec_len, ciphertext, ciphertext_len), 1) + || !TEST_size_t_eq(secret_dec_len, secret_enc_len)) + goto err; + + secret_dec = OPENSSL_zalloc(secret_dec_len); + if (!TEST_ptr(secret_dec) + || !TEST_int_gt(EVP_PKEY_decapsulate(pctx, secret_dec, &secret_dec_len, + ciphertext, ciphertext_len), + 0) + || !TEST_size_t_eq(secret_dec_len, secret_enc_len) + || !TEST_mem_eq(secret_dec, secret_dec_len, secret_enc, secret_enc_len)) + goto err; + ret = 1; +err: + EVP_PKEY_free(privkey); + OPENSSL_free(ciphertext); + OPENSSL_free(secret_enc); + OPENSSL_free(secret_dec); + EVP_PKEY_CTX_free(pctx); + + return ret; +} + +static int test_kem(OSSL_LIB_CTX *libctx, const char *propq, + const EVP_KEM *kem, const char *name) +{ + return TEST_ptr(kem) + && TEST_ptr(EVP_KEM_get0_provider(kem)) + && TEST_true(EVP_KEM_is_a(kem, name)) + && test_ml_kem_keyexch(libctx, propq); +} + +static int test_rsa_enc_dec(OSSL_LIB_CTX *libctx, const char *propq) +{ + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + unsigned char plaintext[] = "Hello world"; + unsigned char *ciphertext = NULL, *decrypted = NULL; + size_t ciphertext_len, decrypted_len; + int ret = 0; + + /* Encrypt */ + if (!TEST_ptr(pkey = EVP_PKEY_Q_keygen(libctx, propq, "RSA", 4096)) + || !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq)) + || !TEST_int_eq(EVP_PKEY_encrypt_init(ctx), 1) + || !TEST_int_eq(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING), 1) + || !TEST_int_eq(EVP_PKEY_encrypt(ctx, NULL, &ciphertext_len, + plaintext, sizeof(plaintext)), + 1) + || !TEST_ptr(ciphertext = OPENSSL_malloc(ciphertext_len)) + || !TEST_int_eq(EVP_PKEY_encrypt(ctx, ciphertext, &ciphertext_len, + plaintext, sizeof(plaintext)), + 1)) + goto err; + + /* Decrypt */ + if (!TEST_int_eq(EVP_PKEY_decrypt_init(ctx), 1) + || !TEST_int_eq(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING), 1) + || !TEST_int_eq(EVP_PKEY_decrypt(ctx, NULL, &decrypted_len, ciphertext, + ciphertext_len), + 1) + || !TEST_ptr(decrypted = OPENSSL_malloc(decrypted_len)) + || !TEST_int_eq(EVP_PKEY_decrypt(ctx, decrypted, &decrypted_len, + ciphertext, ciphertext_len), + 1) + || !TEST_int_eq(strcasecmp((const char *)plaintext, (const char *)decrypted), 0)) + goto err; + + ret = 1; +err: + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + OPENSSL_free(ciphertext); + OPENSSL_free(decrypted); + + return ret; +} + +static int test_asym_cipher(EVP_ASYM_CIPHER *cipher, const char *name, + OSSL_LIB_CTX *ctx, const char *propq) +{ + return TEST_ptr(cipher) + && TEST_ptr(EVP_ASYM_CIPHER_get0_provider(cipher)) + && TEST_true(EVP_ASYM_CIPHER_is_a(cipher, name)) + && TEST_true(test_rsa_enc_dec(ctx, propq)); +} + +static int test_EVP_KEYMGMT_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) || defined(OPENSSL_NO_EC) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_KEYMGMT *keymgmt = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(keymgmt = EVP_KEYMGMT_fetch(ctx, "EC", NULL)) + || !TEST_true(test_keymgmt(ctx, NULL, keymgmt, "EC")) + || !TEST_int_ne(keymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KEYMGMT_free(keymgmt); + keymgmt = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(keymgmt = EVP_KEYMGMT_fetch(ctx, "EC", NULL)) + || !TEST_true(test_keymgmt(ctx, NULL, keymgmt, "EC")) + || !TEST_int_eq(keymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KEYMGMT_free(keymgmt); + keymgmt = NULL; + + if (!TEST_ptr(keymgmt = EVP_KEYMGMT_fetch(ctx, "EC", "?fips=true")) + || !TEST_true(test_keymgmt(ctx, "?fips=true", keymgmt, "EC")) + || !TEST_int_eq(keymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KEYMGMT_free(keymgmt); + keymgmt = NULL; + + if (!TEST_ptr(keymgmt = EVP_KEYMGMT_fetch(ctx, "RSA", "?fips=true")) + || !TEST_int_eq(keymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + if (!TEST_ptr(keymgmt = EVP_KEYMGMT_fetch(ctx, "RSA", NULL)) + || !TEST_int_eq(keymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + + /* + * A mismatched propq should use the regular fetch path rather than the + * frozen fast path. + */ + if (!TEST_ptr(keymgmt = EVP_KEYMGMT_fetch(ctx, "EC", "?provider=default")) + || !TEST_true(test_keymgmt(ctx, "?provider=default", keymgmt, "EC")) + || !TEST_int_ne(keymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_KEYMGMT_free(keymgmt); + unload_providers(&ctx, prov); + return ret; +} + +static int test_implicit_EVP_KEYMGMT_fetch(void) +{ +#if defined(OPENSSL_NO_EC) + return 1; +#endif + + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + ret = test_ec_keyexch(ctx, NULL); +err: + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_KEYMGMT_fetch(const char *id) +{ +#if defined(OPENSSL_NO_EC) + return 1; +#endif + + OSSL_LIB_CTX *ctx = NULL; + EVP_KEYMGMT *keymgmt = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + keymgmt = EVP_KEYMGMT_fetch(ctx, id, fetch_property); + if (expected_fetch_result != 0) { + if (!test_keymgmt(ctx, fetch_property, keymgmt, id)) + goto err; + + if (!TEST_true(EVP_KEYMGMT_up_ref(keymgmt))) + goto err; + /* Ref count should now be 2. Release first one here */ + EVP_KEYMGMT_free(keymgmt); + } else { + if (!TEST_ptr_null(keymgmt)) + goto err; + } + ret = 1; +err: + EVP_KEYMGMT_free(keymgmt); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_KEYMGMT_fetch_by_name(void) +{ + return test_explicit_EVP_KEYMGMT_fetch("EC"); +} + +static int test_explicit_EVP_KEYMGMT_fetch_by_X509_ALGOR(int idx) +{ +#if defined(OPENSSL_NO_EC) + return 1; +#endif + + int ret = 0; + X509_ALGOR *algor = make_algor(NID_X9_62_id_ecPublicKey); + const ASN1_OBJECT *obj; + char id[OSSL_MAX_NAME_SIZE] = { 0 }; + + if (algor == NULL) + return 0; + + X509_ALGOR_get0(&obj, NULL, NULL, algor); + switch (idx) { + case 0: + if (!TEST_int_gt(OBJ_obj2txt(id, sizeof(id), obj, 0), 0)) + goto end; + break; + case 1: + if (!TEST_int_gt(OBJ_obj2txt(id, sizeof(id), obj, 1), 0)) + goto end; + break; + } + + ret = test_explicit_EVP_KEYMGMT_fetch(id); +end: + X509_ALGOR_free(algor); + return ret; +} + +static int test_EVP_KEM_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) || defined(OPENSSL_NO_ML_KEM) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_KEM *kem = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(kem = EVP_KEM_fetch(ctx, "ML-KEM-768", NULL)) + || !TEST_true(test_kem(ctx, NULL, kem, "ML-KEM-768")) + || !TEST_int_ne(kem->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KEM_free(kem); + kem = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(kem = EVP_KEM_fetch(ctx, "ML-KEM-768", NULL)) + || !TEST_true(test_kem(ctx, NULL, kem, "ML-KEM-768")) + || !TEST_int_eq(kem->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_KEM_free(kem); + kem = NULL; + + if (!TEST_ptr(kem = EVP_KEM_fetch(ctx, "ML-KEM-768", "?fips=true")) + || !TEST_true(test_kem(ctx, "?fips=true", kem, "ML-KEM-768")) + || !TEST_int_eq(kem->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KEM_free(kem); + kem = NULL; + + /* + * A mismatched propq should use the regular fetch path rather than the + * frozen fast path. + */ + if (!TEST_ptr(kem = EVP_KEM_fetch(ctx, "ML-KEM-768", "?provider=default")) + || !TEST_true(test_kem(ctx, "?provider=default", kem, "ML-KEM-768")) + || !TEST_int_ne(kem->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_KEM_free(kem); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_KEM_fetch(const char *id) +{ +#if defined(OPENSSL_NO_ML_KEM) + return 1; +#endif + + OSSL_LIB_CTX *ctx = NULL; + EVP_KEM *kem = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + kem = EVP_KEM_fetch(ctx, id, fetch_property); + if (expected_fetch_result != 0) { + if (!test_kem(ctx, fetch_property, kem, id)) + goto err; + + if (!TEST_true(EVP_KEM_up_ref(kem))) + goto err; + /* Ref count should now be 2. Release first one here */ + EVP_KEM_free(kem); + } else { + if (!TEST_ptr_null(kem)) + goto err; + } + ret = 1; +err: + EVP_KEM_free(kem); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_KEM_fetch_by_name(void) +{ +#if defined(OPENSSL_NO_ML_KEM) + return 1; +#endif + + return test_explicit_EVP_KEM_fetch("ML-KEM-768"); +} + +/* + * idx 0: Allow names from OBJ_obj2txt() + * idx 1: Force an OID in text form from OBJ_obj2txt() + */ +static int test_explicit_EVP_KEM_fetch_by_X509_ALGOR(int idx) +{ +#if defined(OPENSSL_NO_ML_KEM) + return 1; +#endif + + int ret = 0; + X509_ALGOR *algor = make_algor(NID_ML_KEM_768); + const ASN1_OBJECT *obj; + char id[OSSL_MAX_NAME_SIZE] = { 0 }; + + if (algor == NULL) + return 0; + + X509_ALGOR_get0(&obj, NULL, NULL, algor); + switch (idx) { + case 0: + if (!TEST_int_gt(OBJ_obj2txt(id, sizeof(id), obj, 0), 0)) + goto end; + break; + case 1: + if (!TEST_int_gt(OBJ_obj2txt(id, sizeof(id), obj, 1), 0)) + goto end; + break; + } + + ret = test_explicit_EVP_KEM_fetch(id); +end: + X509_ALGOR_free(algor); + return ret; +} + +static int test_EVP_CIPHER_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_CIPHER *cipher = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", NULL)) + || !TEST_true(test_cipher(cipher)) + || !TEST_int_ne(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_CIPHER_free(cipher); + + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", "?provider=default")) + || !TEST_true(test_cipher(cipher)) + || !TEST_int_ne(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_CIPHER_free(cipher); + cipher = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", NULL)) + || !TEST_true(test_cipher(cipher)) + || !TEST_int_eq(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_CIPHER_free(cipher); + + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", "?fips=true")) + || !TEST_true(test_cipher(cipher)) + || !TEST_int_eq(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_CIPHER_free(cipher); + + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", "?provider=default")) + || !TEST_true(test_cipher(cipher)) + || !TEST_int_ne(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_CIPHER_free(cipher); + + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(ctx, "AES-128-ECB", "?fips=true")) + || !TEST_true(test_cipher(cipher)) + || !TEST_int_eq(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_CIPHER_free(cipher); + if (!TEST_ptr(cipher = EVP_CIPHER_fetch(ctx, "AES-128-ECB", NULL)) + || !TEST_true(test_cipher(cipher)) + || !TEST_int_eq(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + unload_providers(&ctx, prov); + return ret; +} + static int test_implicit_EVP_CIPHER_fetch(void) { OSSL_LIB_CTX *ctx = NULL; @@ -372,6 +1290,541 @@ end: return ret; } +static int test_EVP_RAND_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_RAND *rand = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(rand = EVP_RAND_fetch(ctx, "HASH-DRBG", NULL)) + || !TEST_int_ne(rand->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_RAND_free(rand); + rand = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(rand = EVP_RAND_fetch(ctx, "HASH-DRBG", NULL)) + || !TEST_int_eq(rand->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_RAND_free(rand); + rand = NULL; + + if (!TEST_ptr(rand = EVP_RAND_fetch(ctx, "HASH-DRBG", "?fips=true")) + || !TEST_int_eq(rand->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_RAND_free(rand); + rand = NULL; + + /* Falls back to slow path */ + if (!TEST_ptr(rand = EVP_RAND_fetch(ctx, "HASH-DRBG", "?provider=default")) + || !TEST_int_ne(rand->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_RAND_free(rand); + unload_providers(&ctx, prov); + return ret; +} + +static int test_implicit_EVP_RAND_fetch(void) +{ + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + EVP_RAND *rand = NULL; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(rand = EVP_RAND_fetch(ctx, "HASH-DRBG", NULL))) + goto err; + ret = 1; +err: + EVP_RAND_free(rand); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_RAND_fetch(const char *id) +{ + OSSL_LIB_CTX *ctx = NULL; + EVP_RAND *rand = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + rand = EVP_RAND_fetch(ctx, id, fetch_property); + if (expected_fetch_result != 0) { + if (!TEST_true(EVP_RAND_up_ref(rand))) + goto err; + /* Ref count should now be 2. Release first one here */ + EVP_RAND_free(rand); + } else { + if (!TEST_ptr_null(rand)) + goto err; + } + ret = 1; +err: + EVP_RAND_free(rand); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_RAND_fetch_by_name(void) +{ + return test_explicit_EVP_RAND_fetch("HASH-DRBG"); +} + +static int test_EVP_ASYM_CIPHER_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) || defined(OPENSSL_NO_ML_KEM) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_ASYM_CIPHER *cipher = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(cipher = EVP_ASYM_CIPHER_fetch(ctx, "RSA", NULL)) + || !TEST_true(test_asym_cipher(cipher, "RSA", ctx, NULL)) + || !TEST_int_ne(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_ASYM_CIPHER_free(cipher); + cipher = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(cipher = EVP_ASYM_CIPHER_fetch(ctx, "RSA", NULL)) + || !TEST_true(test_asym_cipher(cipher, "RSA", ctx, NULL)) + || !TEST_int_eq(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_ASYM_CIPHER_free(cipher); + + if (!TEST_ptr(cipher = EVP_ASYM_CIPHER_fetch(ctx, "RSA", "?fips=true")) + || !TEST_true(test_asym_cipher(cipher, "RSA", ctx, "?fips=true")) + || !TEST_int_eq(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_ASYM_CIPHER_free(cipher); + + /* + * A mismatched propq should use the regular fetch path rather than the + * frozen fast path. + */ + if (!TEST_ptr(cipher = EVP_ASYM_CIPHER_fetch(ctx, "RSA", "?provider=default")) + || !TEST_true(test_asym_cipher(cipher, "RSA", ctx, "?provider=default")) + || !TEST_int_ne(cipher->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_ASYM_CIPHER_free(cipher); + unload_providers(&ctx, prov); + return ret; +} + +static int test_implicit_EVP_ASYM_CIPHER_fetch(void) +{ + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + EVP_ASYM_CIPHER *cipher = NULL; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(cipher = EVP_ASYM_CIPHER_fetch(ctx, "RSA", NULL))) + goto err; + ret = 1; +err: + EVP_ASYM_CIPHER_free(cipher); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_ASYM_CIPHER_fetch(const char *id) +{ + OSSL_LIB_CTX *ctx = NULL; + EVP_ASYM_CIPHER *cipher = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + cipher = EVP_ASYM_CIPHER_fetch(ctx, id, fetch_property); + if (expected_fetch_result != 0) { + if (!TEST_true(EVP_ASYM_CIPHER_up_ref(cipher))) + goto err; + /* Ref count should now be 2. Release first one here */ + EVP_ASYM_CIPHER_free(cipher); + } else { + if (!TEST_ptr_null(cipher)) + goto err; + } + ret = 1; +err: + EVP_ASYM_CIPHER_free(cipher); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_ASYM_CIPHER_fetch_by_name(void) +{ + return test_explicit_EVP_ASYM_CIPHER_fetch("RSA"); +} + +static EVP_PKEY *generate_dh_key(void) +{ + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey = NULL; + OSSL_PARAM params[] = { + OSSL_PARAM_construct_utf8_string("group", "ffdhe4096", 0), + OSSL_PARAM_construct_end() + }; + + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) + || !TEST_int_eq(EVP_PKEY_keygen_init(ctx), 1) + || !TEST_int_eq(EVP_PKEY_CTX_set_params(ctx, params), 1) + || !TEST_int_eq(EVP_PKEY_keygen(ctx, &pkey), 1)) { + EVP_PKEY_CTX_free(ctx); + return NULL; + } + + EVP_PKEY_CTX_free(ctx); + return pkey; +} + +static int derive_secret(EVP_PKEY *priv, EVP_PKEY *peer, + unsigned char **secret, size_t *secret_len) +{ + EVP_PKEY_CTX *ctx; + int ret = 0; + + *secret = NULL; + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(NULL, priv, NULL)) + || !TEST_int_eq(EVP_PKEY_derive_init(ctx), 1) + || !TEST_int_eq(EVP_PKEY_derive_set_peer(ctx, peer), 1) + || !TEST_int_eq(EVP_PKEY_derive(ctx, NULL, secret_len), 1) + || !TEST_ptr(*secret = OPENSSL_malloc(*secret_len)) + || !TEST_int_eq(EVP_PKEY_derive(ctx, *secret, secret_len), 1)) { + OPENSSL_free(*secret); + *secret = NULL; + *secret_len = 0; + goto err; + } + + ret = 1; +err: + EVP_PKEY_CTX_free(ctx); + return ret; +} + +static int test_dh_derive(OSSL_LIB_CTX *libctx, const char *propq) +{ + EVP_PKEY *alice = NULL, *bob = NULL; + unsigned char *secret1 = NULL, *secret2 = NULL; + size_t secret1_len = 0, secret2_len = 0; + int ret = 0; + + if (!TEST_ptr(alice = generate_dh_key()) + || !TEST_ptr(bob = generate_dh_key()) + || !TEST_int_eq(derive_secret(alice, bob, &secret1, &secret1_len), 1) + || !TEST_size_t_gt(secret1_len, 0) + || !TEST_int_eq(derive_secret(bob, alice, &secret2, &secret2_len), 1) + || !TEST_size_t_gt(secret2_len, 0) + || !TEST_size_t_eq(secret1_len, secret2_len) + || !TEST_int_eq(memcmp(secret1, secret2, secret1_len), 0)) + goto err; + + ret = 1; +err: + EVP_PKEY_free(alice); + EVP_PKEY_free(bob); + OPENSSL_free(secret1); + OPENSSL_free(secret2); + + return ret; +} + +static int test_keyexch(OSSL_LIB_CTX *ctx, const char *propq, EVP_KEYEXCH *exchange, const char *name) +{ + return TEST_ptr(exchange) + && TEST_ptr(EVP_KEYEXCH_get0_provider(exchange)) + && TEST_true(EVP_KEYEXCH_is_a(exchange, name)) + && TEST_true(test_dh_derive(ctx, propq)); +} + +static int test_EVP_KEYEXCH_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) || defined(OPENSSL_NO_DH) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_KEYEXCH *exchange = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(exchange = EVP_KEYEXCH_fetch(ctx, "DH", NULL)) + || !TEST_true(test_keyexch(ctx, NULL, exchange, "DH")) + || !TEST_int_ne(exchange->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KEYEXCH_free(exchange); + exchange = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(exchange = EVP_KEYEXCH_fetch(ctx, "DH", NULL)) + || !TEST_true(test_keyexch(ctx, NULL, exchange, "DH")) + || !TEST_int_eq(exchange->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_KEYEXCH_free(exchange); + + if (!TEST_ptr(exchange = EVP_KEYEXCH_fetch(ctx, "DH", "?fips=true")) + || !TEST_true(test_keyexch(ctx, "?fips=true", exchange, "DH")) + || !TEST_int_eq(exchange->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_KEYEXCH_free(exchange); + + /* + * A mismatched propq should use the regular fetch path rather than the + * frozen fast path. + */ + if (!TEST_ptr(exchange = EVP_KEYEXCH_fetch(ctx, "DH", "?provider=default")) + || !TEST_true(test_keyexch(ctx, "?provider=default", exchange, "DH")) + || !TEST_int_ne(exchange->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_KEYEXCH_free(exchange); + unload_providers(&ctx, prov); + return ret; +} + +static int test_implicit_EVP_KEYEXCH_fetch(void) +{ +#if defined(OPENSSL_NO_DH) + return 1; +#endif + + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + EVP_KEYEXCH *exchange = NULL; + int ret = 0; + + if (use_default_ctx == 0 && !TEST_true(load_providers(&ctx, prov))) + goto err; + + if (!TEST_ptr(exchange = EVP_KEYEXCH_fetch(ctx, "DH", NULL))) + goto err; + + ret = 1; +err: + EVP_KEYEXCH_free(exchange); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_KEYEXCH_fetch(const char *id) +{ + OSSL_LIB_CTX *ctx = NULL; + EVP_KEYEXCH *exchange = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !TEST_true(load_providers(&ctx, prov))) + goto err; + + exchange = EVP_KEYEXCH_fetch(ctx, id, fetch_property); + if (expected_fetch_result != 0) { + if (!TEST_true(EVP_KEYEXCH_up_ref(exchange))) + goto err; + /* Ref count should now be 2. Release first one here */ + EVP_KEYEXCH_free(exchange); + } else { + if (!TEST_ptr_null(exchange)) + goto err; + } + ret = 1; +err: + EVP_KEYEXCH_free(exchange); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_KEYEXCH_fetch_by_name(void) +{ +#if defined(OPENSSL_NO_DH) + return 1; +#endif + + return test_explicit_EVP_KEYEXCH_fetch("DH"); +} + +static int test_aes_skey(OSSL_LIB_CTX *libctx, const char *propq) +{ + unsigned char raw_key[16] = { 0 }; + EVP_SKEY *skey = NULL; + int ret = 0; + + if (!TEST_ptr(skey = EVP_SKEY_import_raw_key(libctx, "AES", raw_key, + sizeof(raw_key), propq))) + goto err; + + ret = 1; +err: + EVP_SKEY_free(skey); + return ret; +} + +static int test_skeymgmt(OSSL_LIB_CTX *libctx, const char *propq, + EVP_SKEYMGMT *skeymgmt, const char *name) +{ + return TEST_ptr(skeymgmt) + && TEST_ptr(EVP_SKEYMGMT_get0_provider(skeymgmt)) + && TEST_true(EVP_SKEYMGMT_is_a(skeymgmt, name)) + && TEST_true(test_aes_skey(libctx, propq)); +} + +static int test_EVP_SKEYMGMT_fetch_freeze(void) +{ +#if defined(OPENSSL_NO_CACHED_FETCH) + /* + * Test does not make sense if cached fetch is disabled. + * There's nothing to freeze, and test will fail. + */ + return 1; +#endif + + EVP_SKEYMGMT *skeymgmt = NULL; + int ret = 0; + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[2] = { NULL, NULL }; + + if (use_default_ctx == 0 && !load_providers(&ctx, prov)) + goto err; + + if (!TEST_ptr(skeymgmt = EVP_SKEYMGMT_fetch(ctx, "AES", NULL)) + || !TEST_true(test_skeymgmt(ctx, NULL, skeymgmt, "AES")) + || !TEST_int_ne(skeymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_SKEYMGMT_free(skeymgmt); + skeymgmt = NULL; + + if (!TEST_int_eq(OSSL_LIB_CTX_freeze(ctx, "?fips=true"), 1) + || !TEST_ptr(skeymgmt = EVP_SKEYMGMT_fetch(ctx, "AES", NULL)) + || !TEST_true(test_skeymgmt(ctx, NULL, skeymgmt, "AES")) + || !TEST_int_eq(skeymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + /* Technically, frozen version doesn't need to be freed */ + EVP_SKEYMGMT_free(skeymgmt); + + if (!TEST_ptr(skeymgmt = EVP_SKEYMGMT_fetch(ctx, "AES", "?fips=true")) + || !TEST_true(test_skeymgmt(ctx, "?fips=true", skeymgmt, "AES")) + || !TEST_int_eq(skeymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + EVP_SKEYMGMT_free(skeymgmt); + + /* + * A mismatched propq should use the regular fetch path rather than the + * frozen fast path. + */ + if (!TEST_ptr(skeymgmt = EVP_SKEYMGMT_fetch(ctx, "AES", "?provider=default")) + || !TEST_true(test_skeymgmt(ctx, "?provider=default", skeymgmt, "AES")) + || !TEST_int_ne(skeymgmt->origin, EVP_ORIG_FROZEN)) + goto err; + + ret = 1; +err: + EVP_SKEYMGMT_free(skeymgmt); + unload_providers(&ctx, prov); + return ret; +} + +static int test_implicit_EVP_SKEYMGMT_fetch(void) +{ + OSSL_LIB_CTX *ctx = NULL; + OSSL_PROVIDER *prov[] = { NULL, NULL }; + EVP_SKEYMGMT *skeymgmt = NULL; + int ret = 0; + + if (use_default_ctx == 0 && !TEST_true(load_providers(&ctx, prov))) + goto err; + + if (!TEST_ptr(skeymgmt = EVP_SKEYMGMT_fetch(ctx, "AES", NULL))) + goto err; + + ret = 1; +err: + EVP_SKEYMGMT_free(skeymgmt); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_SKEYMGMT_fetch(const char *id) +{ + OSSL_LIB_CTX *ctx = NULL; + EVP_SKEYMGMT *skeymgmt = NULL; + OSSL_PROVIDER *prov[] = { NULL, NULL }; + int ret = 0; + + if (use_default_ctx == 0 && !TEST_true(load_providers(&ctx, prov))) + goto err; + + skeymgmt = EVP_SKEYMGMT_fetch(ctx, id, fetch_property); + if (expected_fetch_result != 0) { + if (!TEST_true(EVP_SKEYMGMT_up_ref(skeymgmt))) + goto err; + /* Ref count should now be 2. Release first one here */ + EVP_SKEYMGMT_free(skeymgmt); + } else { + if (!TEST_ptr_null(skeymgmt)) + goto err; + } + ret = 1; +err: + EVP_SKEYMGMT_free(skeymgmt); + unload_providers(&ctx, prov); + return ret; +} + +static int test_explicit_EVP_SKEYMGMT_fetch_by_name(void) +{ + return test_explicit_EVP_SKEYMGMT_fetch("AES"); +} + int setup_tests(void) { OPTION_CHOICE o; @@ -402,13 +1855,51 @@ int setup_tests(void) } ADD_TEST(test_legacy_provider_unloaded); if (strcmp(alg, "digest") == 0) { + ADD_TEST(test_EVP_MD_fetch_freeze); ADD_TEST(test_implicit_EVP_MD_fetch); ADD_TEST(test_explicit_EVP_MD_fetch_by_name); ADD_ALL_TESTS_NOSUBTEST(test_explicit_EVP_MD_fetch_by_X509_ALGOR, 2); - } else { + } else if (strcmp(alg, "cipher") == 0) { + ADD_TEST(test_EVP_CIPHER_fetch_freeze); ADD_TEST(test_implicit_EVP_CIPHER_fetch); ADD_TEST(test_explicit_EVP_CIPHER_fetch_by_name); ADD_ALL_TESTS_NOSUBTEST(test_explicit_EVP_CIPHER_fetch_by_X509_ALGOR, 2); + } else if (strcmp(alg, "kdf") == 0) { + ADD_TEST(test_EVP_KDF_fetch_freeze); + ADD_TEST(test_implicit_EVP_KDF_fetch); + ADD_TEST(test_explicit_EVP_KDF_fetch_by_name); + } else if (strcmp(alg, "rand") == 0) { + ADD_TEST(test_EVP_RAND_fetch_freeze); + ADD_TEST(test_implicit_EVP_RAND_fetch); + ADD_TEST(test_explicit_EVP_RAND_fetch_by_name); + } else if (strcmp(alg, "mac") == 0) { + ADD_TEST(test_EVP_MAC_fetch_freeze); + ADD_TEST(test_implicit_EVP_MAC_fetch); + ADD_TEST(test_explicit_EVP_MAC_fetch_by_name); + } else if (strcmp(alg, "kmgmt") == 0) { + ADD_TEST(test_EVP_KEYMGMT_fetch_freeze); + ADD_TEST(test_implicit_EVP_KEYMGMT_fetch); + ADD_TEST(test_explicit_EVP_KEYMGMT_fetch_by_name); + ADD_ALL_TESTS_NOSUBTEST(test_explicit_EVP_KEYMGMT_fetch_by_X509_ALGOR, 2); + } else if (strcmp(alg, "kem") == 0) { + ADD_TEST(test_EVP_KEM_fetch_freeze); + ADD_TEST(test_explicit_EVP_KEM_fetch_by_name); + ADD_ALL_TESTS_NOSUBTEST(test_explicit_EVP_KEM_fetch_by_X509_ALGOR, 2); + } else if (strcmp(alg, "asymcipher") == 0) { + ADD_TEST(test_EVP_ASYM_CIPHER_fetch_freeze); + ADD_TEST(test_implicit_EVP_ASYM_CIPHER_fetch); + ADD_TEST(test_explicit_EVP_ASYM_CIPHER_fetch_by_name); + } else if (strcmp(alg, "evp_keyexch") == 0) { + ADD_TEST(test_EVP_KEYEXCH_fetch_freeze); + ADD_TEST(test_implicit_EVP_KEYEXCH_fetch); + ADD_TEST(test_explicit_EVP_KEYEXCH_fetch_by_name); + } else if (strcmp(alg, "skeymgmt") == 0) { + ADD_TEST(test_EVP_SKEYMGMT_fetch_freeze); + ADD_TEST(test_implicit_EVP_SKEYMGMT_fetch); + ADD_TEST(test_explicit_EVP_SKEYMGMT_fetch_by_name); + } else { + TEST_error("Unknown fetch type: %s", alg); + return 0; } return 1; } diff --git a/test/property_test.c b/test/property_test.c index eea1f28a19..a5ae9e9d21 100644 --- a/test/property_test.c +++ b/test/property_test.c @@ -392,7 +392,7 @@ static int test_register_deregister(void) for (i = 0; i < OSSL_NELEM(impls); i++) if (!TEST_true(ossl_method_store_add(store, &prov, impls[i].nid, impls[i].prop, impls[i].impl, - &up_ref, &down_ref))) { + &up_ref, &down_ref, NULL, NULL))) { TEST_note("iteration %zd", i + 1); goto err; } @@ -417,6 +417,41 @@ err: return ret; } +static int test_freeze_flag(void) +{ + int ret = 0, nid = 6; + const char *prop = "position=1", *prop2 = "position=2"; + char *impl = "a", *impl2 = "b"; + OSSL_METHOD_STORE *store; + OSSL_PROVIDER prov = { 1 }; + const OSSL_PROVIDER *fetched_prov = NULL; + void *fetched_meth = NULL; + + if (!TEST_ptr(store = ossl_method_store_new(NULL)) + || !TEST_true(add_property_names("position", NULL)) + || !TEST_true(ossl_method_store_add(store, &prov, nid, prop, impl, &up_ref, &down_ref, NULL, NULL)) + || !TEST_true(ossl_method_store_fetch(store, nid, prop, &fetched_prov, &fetched_meth)) + || !TEST_ptr_eq(&prov, fetched_prov) + || !TEST_str_eq((char *)fetched_meth, impl) + || !TEST_true(ossl_method_store_freeze_cache(store, NULL)) + || !TEST_false(ossl_method_store_remove(store, nid, impl)) + || !TEST_true(ossl_method_store_fetch(store, nid, prop, &fetched_prov, &fetched_meth)) + || !TEST_ptr_eq(&prov, fetched_prov) + || !TEST_str_eq((char *)fetched_meth, impl) + || !TEST_false(ossl_method_store_remove_all_provided(store, fetched_prov)) + || !TEST_true(ossl_method_store_fetch(store, nid, prop, &fetched_prov, &fetched_meth)) + || !TEST_ptr_eq(&prov, fetched_prov) + || !TEST_str_eq((char *)fetched_meth, impl) + || !TEST_false(ossl_method_store_add(store, &prov, nid, prop2, impl2, &up_ref, &down_ref, NULL, NULL)) + || !TEST_false(ossl_method_store_freeze_cache(store, NULL))) + goto err; + + ret = 1; +err: + ossl_method_store_free(store); + return ret; +} + static int test_property(void) { static OSSL_PROVIDER fake_provider1 = { 1 }; @@ -467,7 +502,7 @@ static int test_property(void) if (!TEST_true(ossl_method_store_add(store, *impls[i].prov, impls[i].nid, impls[i].prop, impls[i].impl, - &up_ref, &down_ref))) { + &up_ref, &down_ref, NULL, NULL))) { TEST_note("iteration %zd", i + 1); goto err; } @@ -578,13 +613,13 @@ static int test_query_cache_stochastic(void) v[i] = 2 * i; BIO_snprintf(buf, sizeof(buf), "n=%d\n", i); if (!TEST_true(ossl_method_store_add(store, &prov, i, buf, "abc", - &up_ref, &down_ref)) + &up_ref, &down_ref, NULL, NULL)) || !TEST_true(ossl_method_store_cache_set(store, &prov, i, buf, v + i, - &up_ref, &down_ref)) + &up_ref, &down_ref, NULL, NULL)) || !TEST_true(ossl_method_store_cache_set(store, &prov, i, "n=1234", "miss", - &up_ref, &down_ref))) { + &up_ref, &down_ref, NULL, NULL))) { TEST_note("iteration %d", i); goto err; } @@ -713,6 +748,7 @@ int setup_tests(void) ADD_TEST(test_property_defn_cache); ADD_ALL_TESTS(test_definition_compares, OSSL_NELEM(definition_tests)); ADD_TEST(test_register_deregister); + ADD_TEST(test_freeze_flag); ADD_TEST(test_property); ADD_TEST(test_query_cache_stochastic); ADD_TEST(test_fips_mode); diff --git a/test/recipes/30-test_evp_fetch_prov.t b/test/recipes/30-test_evp_fetch_prov.t index 63082dd311..85c7b794a7 100644 --- a/test/recipes/30-test_evp_fetch_prov.t +++ b/test/recipes/30-test_evp_fetch_prov.t @@ -21,7 +21,7 @@ use lib bldtop_dir('.'); my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); -my @types = ( "digest", "cipher" ); +my @types = ( "digest", "cipher", "rand", "mac", "kmgmt", "kem", "kdf", "asymcipher", "evp_keyexch", "skeymgmt" ); my @testdata = ( { config => srctop_file("test", "default.cnf"), diff --git a/util/libcrypto.num b/util/libcrypto.num index 155ba0f93d..5eb70de5bb 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5815,3 +5815,4 @@ OSSL_PARAM_clear_free ? 4_0_0 EXIST::FUNCTION: CMS_dataFinal_ex ? 4_0_0 EXIST::FUNCTION:CMS CMS_SignerInfo_verify_ex ? 4_0_0 EXIST::FUNCTION:CMS EVP_SIGNATURE_has_message_update ? 4_0_0 EXIST::FUNCTION: +OSSL_LIB_CTX_freeze ? 4_0_0 EXIST::FUNCTION: