From c9a2ce61118c7f73bc4898eedec64c2bde8bb7a0 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 23 Jan 2025 11:01:39 -0500 Subject: [PATCH] Prefer DRBG ciphers from the same provider Signed-off-by: Simo Sorce Reviewed-by: Tomas Mraz Reviewed-by: Tim Hudson Reviewed-by: Dmitry Belyavskiy (Merged from https://github.com/openssl/openssl/pull/26542) --- crypto/evp/evp_enc.c | 11 ++++++ crypto/evp/evp_local.h | 3 ++ crypto/rand/rand_lib.c | 8 +++- providers/implementations/rands/drbg_ctr.c | 46 ++++++++++++++++++++-- 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index 17320191340..833ebdee287 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -1886,6 +1886,17 @@ EVP_CIPHER *EVP_CIPHER_fetch(OSSL_LIB_CTX *ctx, const char *algorithm, return cipher; } +EVP_CIPHER *evp_cipher_fetch_from_prov(OSSL_PROVIDER *prov, + const char *algorithm, + const char *properties) +{ + return evp_generic_fetch_from_prov(prov, OSSL_OP_CIPHER, + algorithm, properties, + evp_cipher_from_algorithm, + evp_cipher_up_ref, + evp_cipher_free); +} + int EVP_CIPHER_can_pipeline(const EVP_CIPHER *cipher, int enc) { if (((enc && cipher->p_einit != NULL) || (!enc && cipher->p_dinit != NULL)) diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h index 352f4ff2e52..278e5515520 100644 --- a/crypto/evp/evp_local.h +++ b/crypto/evp/evp_local.h @@ -317,6 +317,9 @@ EVP_KEYEXCH *evp_keyexch_fetch_from_prov(OSSL_PROVIDER *prov, EVP_KEM *evp_kem_fetch_from_prov(OSSL_PROVIDER *prov, const char *name, const char *properties); +EVP_CIPHER *evp_cipher_fetch_from_prov(OSSL_PROVIDER *prov, + const char *algorithm, + const char *properties); /* Internal structure constructors for fetched methods */ EVP_MD *evp_md_new(void); diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c index ce7dfb12c80..566504f3ff1 100644 --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -21,6 +21,7 @@ #include "crypto/cryptlib.h" #include "rand_local.h" #include "crypto/context.h" +#include "internal/provider.h" #ifndef OPENSSL_DEFAULT_SEED_SRC # define OPENSSL_DEFAULT_SEED_SRC SEED-SRC @@ -724,8 +725,9 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, EVP_RAND *rand; RAND_GLOBAL *dgbl = rand_get_global(libctx); EVP_RAND_CTX *ctx; - OSSL_PARAM params[8], *p = params; + OSSL_PARAM params[9], *p = params; const OSSL_PARAM *settables; + const char *prov_name; char *name, *cipher; int use_df = 1; @@ -737,6 +739,7 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, ERR_raise(ERR_LIB_RAND, RAND_R_UNABLE_TO_FETCH_DRBG); return NULL; } + prov_name = ossl_provider_name(EVP_RAND_get0_provider(rand)); ctx = EVP_RAND_CTX_new(rand, parent); EVP_RAND_free(rand); if (ctx == NULL) { @@ -754,6 +757,9 @@ static EVP_RAND_CTX *rand_new_drbg(OSSL_LIB_CTX *libctx, EVP_RAND_CTX *parent, && OSSL_PARAM_locate_const(settables, OSSL_DRBG_PARAM_DIGEST)) *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_DIGEST, dgbl->rng_digest, 0); + if (prov_name != NULL) + *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_CORE_PROV_NAME, + (char *)prov_name, 0); if (dgbl->rng_propq != NULL) *p++ = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_PROPERTIES, dgbl->rng_propq, 0); diff --git a/providers/implementations/rands/drbg_ctr.c b/providers/implementations/rands/drbg_ctr.c index abd0b1a1c89..4aa1aa907e4 100644 --- a/providers/implementations/rands/drbg_ctr.c +++ b/providers/implementations/rands/drbg_ctr.c @@ -20,6 +20,9 @@ #include "prov/providercommon.h" #include "prov/provider_ctx.h" #include "drbg_local.h" +#include "crypto/evp.h" +#include "crypto/evp/evp_local.h" +#include "internal/provider.h" static OSSL_FUNC_rand_newctx_fn drbg_ctr_new_wrapper; static OSSL_FUNC_rand_freectx_fn drbg_ctr_free; @@ -709,6 +712,7 @@ static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]) PROV_DRBG *ctx = (PROV_DRBG *)vctx; PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)ctx->data; OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx); + OSSL_PROVIDER *prov = NULL; const OSSL_PARAM *p; char *ecb; const char *propquery = NULL; @@ -728,32 +732,66 @@ static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]) propquery = (const char *)p->data; } + if ((p = OSSL_PARAM_locate_const(params, + OSSL_PROV_PARAM_CORE_PROV_NAME)) != NULL) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) + return 0; + if ((prov = ossl_provider_find(libctx, + (const char *)p->data, 1)) == NULL) + return 0; + } + if ((p = OSSL_PARAM_locate_const(params, OSSL_DRBG_PARAM_CIPHER)) != NULL) { const char *base = (const char *)p->data; size_t ctr_str_len = sizeof("CTR") - 1; size_t ecb_str_len = sizeof("ECB") - 1; if (p->data_type != OSSL_PARAM_UTF8_STRING - || p->data_size < ctr_str_len) + || p->data_size < ctr_str_len) { + ossl_provider_free(prov); return 0; + } if (OPENSSL_strcasecmp("CTR", base + p->data_size - ctr_str_len) != 0) { ERR_raise(ERR_LIB_PROV, PROV_R_REQUIRE_CTR_MODE_CIPHER); + ossl_provider_free(prov); return 0; } - if ((ecb = OPENSSL_strndup(base, p->data_size)) == NULL) + if ((ecb = OPENSSL_strndup(base, p->data_size)) == NULL) { + ossl_provider_free(prov); return 0; + } strcpy(ecb + p->data_size - ecb_str_len, "ECB"); EVP_CIPHER_free(ctr->cipher_ecb); EVP_CIPHER_free(ctr->cipher_ctr); - ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery); - ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery); + /* + * Try to fetch algorithms from our own provider code, fallback + * to generic fetch only if that fails + */ + (void)ERR_set_mark(); + ctr->cipher_ctr = evp_cipher_fetch_from_prov(prov, base, NULL); + if (ctr->cipher_ctr == NULL) { + (void)ERR_pop_to_mark(); + ctr->cipher_ctr = EVP_CIPHER_fetch(libctx, base, propquery); + } else { + (void)ERR_clear_last_mark(); + } + (void)ERR_set_mark(); + ctr->cipher_ecb = evp_cipher_fetch_from_prov(prov, ecb, NULL); + if (ctr->cipher_ecb == NULL) { + (void)ERR_pop_to_mark(); + ctr->cipher_ecb = EVP_CIPHER_fetch(libctx, ecb, propquery); + } else { + (void)ERR_clear_last_mark(); + } OPENSSL_free(ecb); if (ctr->cipher_ctr == NULL || ctr->cipher_ecb == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_UNABLE_TO_FIND_CIPHERS); + ossl_provider_free(prov); return 0; } cipher_init = 1; } + ossl_provider_free(prov); if (cipher_init && !drbg_ctr_init(ctx)) return 0; -- 2.47.2