From 7cfa1717b812a126ce6f8e4cc32139164c89d789 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sat, 14 Sep 2019 16:35:08 +0200 Subject: [PATCH] Modify providers that keep track of underlying algorithms With some provider implementations, there are underlying ciphers, digests and macs. For some of them, the name was retrieved from the method, but since the methods do not store those any more, we add different mechanics. For code that needs to pass on the name of a cipher or diges via parameters, we simply locally store the name that was used when fetching said cipher or digest. This will ensure that any underlying code that needs to fetch that same cipher or digest does so with the exact same name instead of any random name from the set of names associated with the algorithm. For code that needs to check what kind of algorithm was passed, we provide EVP_{type}_is_a(), that returns true if the given method has the given name as one of its names. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/9897) --- crypto/evp/evp_fetch.c | 8 ++++++++ crypto/evp/evp_lib.c | 5 +++++ crypto/evp/evp_locl.h | 1 + crypto/evp/mac_meth.c | 5 +++++ crypto/evp/pkey_mac.c | 4 ++-- doc/man3/EVP_EncryptInit.pod | 5 +++++ doc/man3/EVP_MAC.pod | 10 +++++++++- include/openssl/evp.h | 2 ++ .../common/include/internal/provider_util.h | 16 ++++++++++++---- providers/common/kdfs/sskdf.c | 10 ++++------ providers/common/provider_util.c | 15 +++++++++++++++ util/libcrypto.num | 2 ++ 12 files changed, 70 insertions(+), 13 deletions(-) diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c index 79520c0b7f..6e31af79f2 100644 --- a/crypto/evp/evp_fetch.c +++ b/crypto/evp/evp_fetch.c @@ -385,3 +385,11 @@ const char *evp_first_name(OSSL_PROVIDER *prov, int name_id) return ossl_namemap_num2name(namemap, name_id, 0); } + +int evp_is_a(OSSL_PROVIDER *prov, int number, const char *name) +{ + OPENSSL_CTX *libctx = ossl_provider_library_context(prov); + OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx); + + return ossl_namemap_name2num(namemap, name) == number; +} diff --git a/crypto/evp/evp_lib.c b/crypto/evp/evp_lib.c index 000d6e9623..e48c63037e 100644 --- a/crypto/evp/evp_lib.c +++ b/crypto/evp/evp_lib.c @@ -448,6 +448,11 @@ int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx) return ctx->cipher->nid; } +int EVP_CIPHER_is_a(const EVP_CIPHER *cipher, const char *name) +{ + return evp_is_a(cipher->prov, cipher->name_id, name); +} + const char *EVP_CIPHER_name(const EVP_CIPHER *cipher) { if (cipher->prov != NULL) diff --git a/crypto/evp/evp_locl.h b/crypto/evp/evp_locl.h index cd58ba33b5..ebfa3acd08 100644 --- a/crypto/evp/evp_locl.h +++ b/crypto/evp/evp_locl.h @@ -250,3 +250,4 @@ void evp_pkey_ctx_free_old_ops(EVP_PKEY_CTX *ctx); /* OSSL_PROVIDER * is only used to get the library context */ const char *evp_first_name(OSSL_PROVIDER *prov, int name_id); +int evp_is_a(OSSL_PROVIDER *prov, int number, const char *name); diff --git a/crypto/evp/mac_meth.c b/crypto/evp/mac_meth.c index 3dc58c1f3b..8c47a6c6e8 100644 --- a/crypto/evp/mac_meth.c +++ b/crypto/evp/mac_meth.c @@ -168,6 +168,11 @@ void EVP_MAC_free(EVP_MAC *mac) evp_mac_free(mac); } +int EVP_MAC_is_a(const EVP_MAC *mac, const char *name) +{ + return evp_is_a(mac->prov, mac->name_id, name); +} + const char *EVP_MAC_name(const EVP_MAC *mac) { return evp_first_name(mac->prov, mac->name_id); diff --git a/crypto/evp/pkey_mac.c b/crypto/evp/pkey_mac.c index fc600fb845..1343e19e76 100644 --- a/crypto/evp/pkey_mac.c +++ b/crypto/evp/pkey_mac.c @@ -221,8 +221,8 @@ static int pkey_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx) && (ctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) != 0; if (set_key) { - if (strcmp(OBJ_nid2sn(EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx))), - EVP_MAC_name(EVP_MAC_CTX_mac(hctx->ctx))) != 0) + if (!EVP_MAC_is_a(EVP_MAC_CTX_mac(hctx->ctx), + OBJ_nid2sn(EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx))))) return 0; key = EVP_PKEY_get0(EVP_PKEY_CTX_get0_pkey(ctx)); if (key == NULL) diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod index 78f67bd643..a2ccc6f3d6 100644 --- a/doc/man3/EVP_EncryptInit.pod +++ b/doc/man3/EVP_EncryptInit.pod @@ -28,6 +28,7 @@ EVP_CipherFinal, EVP_get_cipherbyname, EVP_get_cipherbynid, EVP_get_cipherbyobj, +EVP_CIPHER_is_a, EVP_CIPHER_name, EVP_CIPHER_provider, EVP_CIPHER_nid, @@ -116,6 +117,7 @@ EVP_CIPHER_do_all_ex const EVP_CIPHER *EVP_get_cipherbyobj(const ASN1_OBJECT *a); int EVP_CIPHER_nid(const EVP_CIPHER *e); + int EVP_CIPHER_is_a(const EVP_CIPHER *cipher, const char *name); const char *EVP_CIPHER_name(const EVP_CIPHER *cipher); const OSSL_PROVIDER *EVP_CIPHER_provider(const EVP_CIPHER *cipher); int EVP_CIPHER_block_size(const EVP_CIPHER *e); @@ -315,6 +317,9 @@ IDENTIFIER as such it ignores the cipher parameters and 40 bit RC2 and identifier or does not have ASN1 support this function will return B. +EVP_CIPHER_is_a() returns 1 if the given I is an implementation of an +algorithm that's identifiable with I, otherwise 0. + EVP_CIPHER_name() and EVP_CIPHER_CTX_name() return the name of the passed cipher or context. diff --git a/doc/man3/EVP_MAC.pod b/doc/man3/EVP_MAC.pod index 2ab4c48fbf..df15a907ec 100644 --- a/doc/man3/EVP_MAC.pod +++ b/doc/man3/EVP_MAC.pod @@ -2,7 +2,8 @@ =head1 NAME -EVP_MAC, EVP_MAC_fetch, EVP_MAC_up_ref, EVP_MAC_free, EVP_MAC_name, +EVP_MAC, EVP_MAC_fetch, EVP_MAC_up_ref, EVP_MAC_free, +EVP_MAC_is_a, EVP_MAC_name, EVP_MAC_provider, EVP_MAC_get_params, EVP_MAC_gettable_params, EVP_MAC_CTX, EVP_MAC_CTX_new, EVP_MAC_CTX_free, EVP_MAC_CTX_dup, EVP_MAC_CTX_mac, EVP_MAC_CTX_get_params, EVP_MAC_CTX_set_params, @@ -21,6 +22,7 @@ EVP_MAC_do_all_ex - EVP MAC routines const char *properties); int EVP_MAC_up_ref(EVP_MAC *mac); void EVP_MAC_free(EVP_MAC *mac); + int EVP_MAC_is_a(const EVP_MAC *mac, const char *name); const char *EVP_MAC_name(const EVP_MAC *mac); const OSSL_PROVIDER *EVP_MAC_provider(const EVP_MAC *mac); int EVP_MAC_get_params(EVP_MAC *mac, OSSL_PARAM params[]); @@ -157,6 +159,9 @@ EVP_MAC_size() returns the MAC output size for the given context. EVP_MAC_name() returns the name of the given MAC implementation. +EVP_MAC_is_a() checks if the given I is an implementation of an +algorithm that's identifiable with I. + EVP_MAC_provider() returns the provider that holds the implementation of the given I. @@ -256,6 +261,9 @@ EVP_MAC_free() returns nothing at all. EVP_MAC_name() returns the name of the MAC, or NULL if NULL was passed. +EVP_MAC_is_a() returns 1 if the given method can be identified with +the given name, otherwise 0. + EVP_MAC_provider() returns a pointer to the provider for the MAC, or NULL on error. diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 2eb6802d3e..bbdc2b75c1 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -475,6 +475,7 @@ void *EVP_MD_CTX_md_data(const EVP_MD_CTX *ctx); int EVP_CIPHER_nid(const EVP_CIPHER *cipher); const char *EVP_CIPHER_name(const EVP_CIPHER *cipher); +int EVP_CIPHER_is_a(const EVP_CIPHER *cipher, const char *name); const OSSL_PROVIDER *EVP_CIPHER_provider(const EVP_CIPHER *cipher); int EVP_CIPHER_block_size(const EVP_CIPHER *cipher); int EVP_CIPHER_impl_ctx_size(const EVP_CIPHER *cipher); @@ -1034,6 +1035,7 @@ EVP_MAC *EVP_MAC_fetch(OPENSSL_CTX *libctx, const char *algorithm, int EVP_MAC_up_ref(EVP_MAC *mac); void EVP_MAC_free(EVP_MAC *mac); const char *EVP_MAC_name(const EVP_MAC *mac); +int EVP_MAC_is_a(const EVP_MAC *mac, const char *name); const OSSL_PROVIDER *EVP_MAC_provider(const EVP_MAC *mac); int EVP_MAC_get_params(EVP_MAC *mac, OSSL_PARAM params[]); diff --git a/providers/common/include/internal/provider_util.h b/providers/common/include/internal/provider_util.h index c25c65886e..9fe21c5ef6 100644 --- a/providers/common/include/internal/provider_util.h +++ b/providers/common/include/internal/provider_util.h @@ -21,6 +21,9 @@ typedef struct { /* Conditions for legacy EVP_CIPHER uses */ ENGINE *engine; /* cipher engine */ + + /* Name this was fetched by */ + char name[51]; /* A longer name would be unexpected */ } PROV_CIPHER; typedef struct { @@ -34,6 +37,9 @@ typedef struct { /* Conditions for legacy EVP_MD uses */ ENGINE *engine; /* digest engine */ + + /* Name this was fetched by */ + char name[51]; /* A longer name would be unexpected */ } PROV_DIGEST; /* Cipher functions */ @@ -43,19 +49,20 @@ typedef struct { * implementation used. If a provider cannot be found, it falls back to trying * non-provider based implementations. */ -int ossl_prov_cipher_load_from_params(PROV_CIPHER *pd, +int ossl_prov_cipher_load_from_params(PROV_CIPHER *pc, const OSSL_PARAM params[], OPENSSL_CTX *ctx); /* Reset the PROV_CIPHER fields and free any allocated cipher reference */ -void ossl_prov_cipher_reset(PROV_CIPHER *pd); +void ossl_prov_cipher_reset(PROV_CIPHER *pc); /* Clone a PROV_CIPHER structure into a second */ int ossl_prov_cipher_copy(PROV_CIPHER *dst, const PROV_CIPHER *src); /* Query the cipher and associated engine (if any) */ -const EVP_CIPHER *ossl_prov_cipher_cipher(const PROV_CIPHER *pd); -ENGINE *ossl_prov_cipher_engine(const PROV_CIPHER *pd); +const EVP_CIPHER *ossl_prov_cipher_cipher(const PROV_CIPHER *pc); +ENGINE *ossl_prov_cipher_engine(const PROV_CIPHER *pc); +const char *ossl_prov_cipher_name(const PROV_CIPHER *pc); /* Digest functions */ /* @@ -77,3 +84,4 @@ int ossl_prov_digest_copy(PROV_DIGEST *dst, const PROV_DIGEST *src); /* Query the digest and associated engine (if any) */ const EVP_MD *ossl_prov_digest_md(const PROV_DIGEST *pd); ENGINE *ossl_prov_digest_engine(const PROV_DIGEST *pd); +const char *ossl_prov_digest_name(const PROV_DIGEST *pd); diff --git a/providers/common/kdfs/sskdf.c b/providers/common/kdfs/sskdf.c index e7921bac35..49da1a690f 100644 --- a/providers/common/kdfs/sskdf.c +++ b/providers/common/kdfs/sskdf.c @@ -370,7 +370,6 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen) int ret; const unsigned char *custom = NULL; size_t custom_len = 0; - const char *macname; int default_salt_len; /* @@ -378,8 +377,7 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen) * Why does KMAC require a salt length that's shorter than the MD * block size? */ - macname = EVP_MAC_name(ctx->mac); - if (strcmp(macname, OSSL_MAC_NAME_HMAC) == 0) { + if (EVP_MAC_is_a(ctx->mac, OSSL_MAC_NAME_HMAC)) { /* H(x) = HMAC(x, salt, hash) */ if (md == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); @@ -388,12 +386,12 @@ static int sskdf_derive(void *vctx, unsigned char *key, size_t keylen) default_salt_len = EVP_MD_block_size(md); if (default_salt_len <= 0) return 0; - } else if (strcmp(macname, OSSL_MAC_NAME_KMAC128) == 0 - || strcmp(macname, OSSL_MAC_NAME_KMAC256) == 0) { + } else if (EVP_MAC_is_a(ctx->mac, OSSL_MAC_NAME_KMAC128) + || EVP_MAC_is_a(ctx->mac, OSSL_MAC_NAME_KMAC256)) { /* H(x) = KMACzzz(x, salt, custom) */ custom = kmac_custom_str; custom_len = sizeof(kmac_custom_str); - if (strcmp(macname, OSSL_MAC_NAME_KMAC128) == 0) + if (EVP_MAC_is_a(ctx->mac, OSSL_MAC_NAME_KMAC128)) default_salt_len = SSKDF_KMAC128_DEFAULT_SALT_SIZE; else default_salt_len = SSKDF_KMAC256_DEFAULT_SALT_SIZE; diff --git a/providers/common/provider_util.c b/providers/common/provider_util.c index 92cfb749c0..199544730a 100644 --- a/providers/common/provider_util.c +++ b/providers/common/provider_util.c @@ -17,6 +17,7 @@ void ossl_prov_cipher_reset(PROV_CIPHER *pc) pc->alloc_cipher = NULL; pc->cipher = NULL; pc->engine = NULL; + pc->name[0] = '\0'; } int ossl_prov_cipher_copy(PROV_CIPHER *dst, const PROV_CIPHER *src) @@ -26,6 +27,7 @@ int ossl_prov_cipher_copy(PROV_CIPHER *dst, const PROV_CIPHER *src) dst->engine = src->engine; dst->cipher = src->cipher; dst->alloc_cipher = src->alloc_cipher; + OPENSSL_strlcpy(dst->name, src->name, sizeof(dst->name)); return 1; } @@ -77,6 +79,7 @@ int ossl_prov_cipher_load_from_params(PROV_CIPHER *pc, EVP_CIPHER_free(pc->alloc_cipher); pc->cipher = pc->alloc_cipher = EVP_CIPHER_fetch(ctx, p->data, propquery); + OPENSSL_strlcpy(pc->name, p->data, sizeof(pc->name)); /* TODO legacy stuff, to be removed */ #ifndef FIPS_MODE /* Inside the FIPS module, we don't support legacy ciphers */ if (pc->cipher == NULL) @@ -95,12 +98,18 @@ ENGINE *ossl_prov_cipher_engine(const PROV_CIPHER *pc) return pc->engine; } +const char *ossl_prov_cipher_name(const PROV_CIPHER *pc) +{ + return pc->name; +} + void ossl_prov_digest_reset(PROV_DIGEST *pd) { EVP_MD_free(pd->alloc_md); pd->alloc_md = NULL; pd->md = NULL; pd->engine = NULL; + pd->name[0] = '\0'; } int ossl_prov_digest_copy(PROV_DIGEST *dst, const PROV_DIGEST *src) @@ -110,6 +119,7 @@ int ossl_prov_digest_copy(PROV_DIGEST *dst, const PROV_DIGEST *src) dst->engine = src->engine; dst->md = src->md; dst->alloc_md = src->alloc_md; + OPENSSL_strlcpy(dst->name, src->name, sizeof(dst->name)); return 1; } @@ -132,6 +142,7 @@ int ossl_prov_digest_load_from_params(PROV_DIGEST *pd, EVP_MD_free(pd->alloc_md); pd->md = pd->alloc_md = EVP_MD_fetch(ctx, p->data, propquery); + OPENSSL_strlcpy(pd->name, p->data, sizeof(pd->name)); /* TODO legacy stuff, to be removed */ #ifndef FIPS_MODE /* Inside the FIPS module, we don't support legacy digests */ if (pd->md == NULL) @@ -150,3 +161,7 @@ ENGINE *ossl_prov_digest_engine(const PROV_DIGEST *pd) return pd->engine; } +const char *ossl_prov_digest_name(const PROV_DIGEST *pd) +{ + return pd->name; +} diff --git a/util/libcrypto.num b/util/libcrypto.num index 71e650e933..1b14b440dc 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4762,3 +4762,5 @@ ERR_peek_error_all 4878 3_0_0 EXIST::FUNCTION: ERR_peek_last_error_func 4879 3_0_0 EXIST::FUNCTION: ERR_peek_last_error_data 4880 3_0_0 EXIST::FUNCTION: ERR_peek_last_error_all 4881 3_0_0 EXIST::FUNCTION: +EVP_CIPHER_is_a 4882 3_0_0 EXIST::FUNCTION: +EVP_MAC_is_a 4883 3_0_0 EXIST::FUNCTION: -- 2.34.1