Modify providers that keep track of underlying algorithms
authorRichard Levitte <levitte@openssl.org>
Sat, 14 Sep 2019 14:35:08 +0000 (16:35 +0200)
committerRichard Levitte <levitte@openssl.org>
Thu, 19 Sep 2019 12:58:17 +0000 (14:58 +0200)
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 <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9897)

12 files changed:
crypto/evp/evp_fetch.c
crypto/evp/evp_lib.c
crypto/evp/evp_locl.h
crypto/evp/mac_meth.c
crypto/evp/pkey_mac.c
doc/man3/EVP_EncryptInit.pod
doc/man3/EVP_MAC.pod
include/openssl/evp.h
providers/common/include/internal/provider_util.h
providers/common/kdfs/sskdf.c
providers/common/provider_util.c
util/libcrypto.num

index 79520c0b7f9ccee550d9a900a08480ce60600569..6e31af79f2ef67844446fe20bcd9cf3930e7e598 100644 (file)
@@ -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;
+}
index 000d6e9623a1fc8e97590a30d0e748d77dcb6de1..e48c63037e220f10a65af33df57ec2aa862aa3ad 100644 (file)
@@ -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)
index cd58ba33b526f40d4fb649e91695783ae2d7fd41..ebfa3acd085bc9e423cb760c022209d9c6d18732 100644 (file)
@@ -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);
index 3dc58c1f3be896f612020e8dbd8e9efcdbf2da0c..8c47a6c6e8a97765f193daccb4d8aeb639e41e35 100644 (file)
@@ -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);
index fc600fb8456a2e0070fd6552eefb512f4bb12632..1343e19e760213b7e1037711c6ca4d79637ca3f1 100644 (file)
@@ -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)
index 78f67bd6433a4aec0eec2bba788af484d9914b10..a2ccc6f3d66187e8151566ebc5d538d85450bc4e 100644 (file)
@@ -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<NID_undef>.
 
+EVP_CIPHER_is_a() returns 1 if the given I<cipher> is an implementation of an
+algorithm that's identifiable with I<name>, otherwise 0.
+
 EVP_CIPHER_name() and EVP_CIPHER_CTX_name() return the name of the passed
 cipher or context.
 
index 2ab4c48fbf66588e9f55c4890517ef3652ad0d2b..df15a907ecbe2a1a4ba665fc6d7929931e62b40f 100644 (file)
@@ -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<mac> is an implementation of an
+algorithm that's identifiable with I<name>.
+
 EVP_MAC_provider() returns the provider that holds the implementation
 of the given I<mac>.
 
@@ -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.
 
index 2eb6802d3ec399f92fbfbc3fe8aa02bb06d32b79..bbdc2b75c187baf5529184cf340bf67cc05d95f9 100644 (file)
@@ -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[]);
 
index c25c65886e501327c42151e2a394927ae3b9b775..9fe21c5ef6092c90ce078bba7fd7074253c3ecd8 100644 (file)
@@ -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);
index e7921bac35c0554c81e0e3160f8a3f31444cfdcf..49da1a690f99ee1390b8604216ecb67ee03a647e 100644 (file)
@@ -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;
index 92cfb749c032a1bf29ab148bde1ff63a6add4271..199544730a1c6e3e27e37ef08c61f01a3f7fd6f3 100644 (file)
@@ -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;
+}
index 71e650e93347ab3b3be168027fc2c847568ebfd8..1b14b440dc7c42e2ae7dc73462d8ba43a225f074 100644 (file)
@@ -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: