do_sigver_init: Allow reinitialization of an existing operation.
authorTomas Mraz <tomas@openssl.org>
Thu, 4 Nov 2021 10:06:26 +0000 (11:06 +0100)
committerTomas Mraz <tomas@openssl.org>
Fri, 12 Nov 2021 15:39:33 +0000 (16:39 +0100)
Fixes #16936

Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/16964)

crypto/evp/m_sigver.c
providers/implementations/signature/mac_legacy_sig.c
test/evp_extra_test.c

index 80570973dd17fefe0e4b21518ba5a1b563142a40..9188edbc215fbbaf64a2909e8b3718577388ade0 100644 (file)
@@ -49,7 +49,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
     const char *supported_sig = NULL;
     char locmdname[80] = "";     /* 80 chars should be enough */
     void *provkey = NULL;
-    int ret, iter;
+    int ret, iter, reinit = 1;
 
     if (ctx->algctx != NULL) {
         if (!ossl_assert(ctx->digest != NULL)) {
@@ -62,6 +62,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
     }
 
     if (ctx->pctx == NULL) {
+        reinit = 0;
         if (e == NULL)
             ctx->pctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, props);
         else
@@ -71,22 +72,37 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
         return 0;
 
     locpctx = ctx->pctx;
-    evp_pkey_ctx_free_old_ops(locpctx);
-
-    if (props == NULL)
-        props = locpctx->propquery;
-
     ERR_set_mark();
 
     if (evp_pkey_ctx_is_legacy(locpctx))
         goto legacy;
 
+    /* do not reinitialize if pkey is set or operation is different */
+    if (reinit
+        && (pkey != NULL
+            || locpctx->operation != (ver ? EVP_PKEY_OP_VERIFYCTX
+                                          : EVP_PKEY_OP_SIGNCTX)
+            || (signature = locpctx->op.sig.signature) == NULL
+            || locpctx->op.sig.algctx == NULL))
+        reinit = 0;
+
+    if (props == NULL)
+        props = locpctx->propquery;
+
     if (locpctx->pkey == NULL) {
         ERR_clear_last_mark();
         ERR_raise(ERR_LIB_EVP, EVP_R_NO_KEY_SET);
         goto err;
     }
 
+    if (!reinit) {
+        evp_pkey_ctx_free_old_ops(locpctx);
+    } else {
+        if (mdname == NULL && type == NULL)
+            mdname = canon_mdname(EVP_MD_get0_name(ctx->reqdigest));
+        goto reinitialize;
+    }
+
     /*
      * Try to derive the supported signature from |locpctx->keymgmt|.
      */
@@ -183,9 +199,6 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
 
     /* No more legacy from here down to legacy: */
 
-    if (pctx != NULL)
-        *pctx = locpctx;
-
     locpctx->op.sig.signature = signature;
     locpctx->operation = ver ? EVP_PKEY_OP_VERIFYCTX
                              : EVP_PKEY_OP_SIGNCTX;
@@ -195,12 +208,17 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
         ERR_raise(ERR_LIB_EVP,  EVP_R_INITIALIZATION_ERROR);
         goto err;
     }
+
+ reinitialize:
+    if (pctx != NULL)
+        *pctx = locpctx;
+
     if (type != NULL) {
         ctx->reqdigest = type;
         if (mdname == NULL)
             mdname = canon_mdname(EVP_MD_get0_name(type));
     } else {
-        if (mdname == NULL) {
+        if (mdname == NULL && !reinit) {
             if (evp_keymgmt_util_get_deflt_digest_name(tmp_keymgmt, provkey,
                                                        locmdname,
                                                        sizeof(locmdname)) > 0) {
index 06f79505ff4c827fdb701dca5878e7bf7afc832d..0866e68d9b754b0052d93b83d84d9da657ff9e15 100644 (file)
@@ -101,13 +101,16 @@ static int mac_digest_sign_init(void *vpmacctx, const char *mdname, void *vkey,
     const char *ciphername = NULL, *engine = NULL;
 
     if (!ossl_prov_is_running()
-            || pmacctx == NULL
-            || vkey == NULL
-            || !ossl_mac_key_up_ref(vkey))
+        || pmacctx == NULL
+        || (pmacctx->key == NULL && vkey == NULL))
         return 0;
 
-    ossl_mac_key_free(pmacctx->key);
-    pmacctx->key = vkey;
+    if (vkey != NULL) {
+        if (!ossl_mac_key_up_ref(vkey))
+            return 0;
+        ossl_mac_key_free(pmacctx->key);
+        pmacctx->key = vkey;
+    }
 
     if (pmacctx->key->cipher.cipher != NULL)
         ciphername = (char *)EVP_CIPHER_get0_name(pmacctx->key->cipher.cipher);
index df97f448ab3aec9871dafc3f5e13a367fe2f486b..a8ae3e44e019bafa0d486aeb929f28eeb4c9b89a 100644 (file)
@@ -1316,6 +1316,13 @@ static int test_EVP_DigestVerifyInit(void)
             || !TEST_true(EVP_DigestVerifyFinal(md_ctx, kSignature,
                                                  sizeof(kSignature))))
         goto out;
+
+    /* test with reinitialization */
+    if (!TEST_true(EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, NULL))
+            || !TEST_true(EVP_DigestVerifyUpdate(md_ctx, kMsg, sizeof(kMsg)))
+            || !TEST_true(EVP_DigestVerifyFinal(md_ctx, kSignature,
+                                                 sizeof(kSignature))))
+        goto out;
     ret = 1;
 
  out: