Fix EVP_PKEY_new_mac_key()
authorMatt Caswell <matt@openssl.org>
Wed, 18 Mar 2020 14:46:33 +0000 (14:46 +0000)
committerMatt Caswell <matt@openssl.org>
Wed, 25 Mar 2020 10:56:35 +0000 (10:56 +0000)
EVP_PKEY_new_mac_key() was failing if the specified MAC was not available
in the default provider - even though that MAC is never actually needed
to successfully complete the function. The resulting EVP_PKEY can then
be used in some non-default libctx which *does* have the MAC loaded.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11360)

crypto/evp/pkey_mac.c

index c664a87..7430b62 100644 (file)
@@ -53,19 +53,25 @@ static int pkey_mac_init(EVP_PKEY_CTX *ctx)
     int nid = ctx->pmeth->pkey_id;
     EVP_MAC *mac = EVP_MAC_fetch(ctx->libctx, OBJ_nid2sn(nid), ctx->propquery);
 
-    if (mac == NULL) {
-        EVPerr(EVP_F_PKEY_MAC_INIT, EVP_R_FETCH_FAILED);
-        return 0;
-    }
+    /*
+     * mac == NULL may actually be ok in some situations. In an
+     * EVP_PKEY_new_mac_key() call a temporary EVP_PKEY_CTX is created with
+     * default libctx. We don't actually need the underlying MAC to be present
+     * to successfully set the key in that case. The resulting EVP_PKEY could
+     * then be used in some other libctx where the MAC *is* present
+     */
+
     if ((hctx = OPENSSL_zalloc(sizeof(*hctx))) == NULL) {
         EVPerr(EVP_F_PKEY_MAC_INIT, ERR_R_MALLOC_FAILURE);
         return 0;
     }
 
-    hctx->ctx = EVP_MAC_CTX_new(mac);
-    if (hctx->ctx == NULL) {
-        OPENSSL_free(hctx);
-        return 0;
+    if (mac != NULL) {
+        hctx->ctx = EVP_MAC_CTX_new(mac);
+        if (hctx->ctx == NULL) {
+            OPENSSL_free(hctx);
+            return 0;
+        }
     }
 
     if (nid == EVP_PKEY_CMAC) {
@@ -87,6 +93,13 @@ static int pkey_mac_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
     MAC_PKEY_CTX *sctx, *dctx;
 
     sctx = EVP_PKEY_CTX_get_data(src);
+
+    if (sctx->ctx == NULL) {
+        /* This actually means the fetch failed during the init call */
+        EVPerr(0, EVP_R_FETCH_FAILED);
+        return 0;
+    }
+
     if (sctx->ctx->data == NULL)
         return 0;
 
@@ -146,7 +159,7 @@ static void pkey_mac_cleanup(EVP_PKEY_CTX *ctx)
     MAC_PKEY_CTX *hctx = ctx == NULL ? NULL : EVP_PKEY_CTX_get_data(ctx);
 
     if (hctx != NULL) {
-        EVP_MAC *mac = EVP_MAC_CTX_mac(hctx->ctx);
+        EVP_MAC *mac = hctx->ctx != NULL ? EVP_MAC_CTX_mac(hctx->ctx) : NULL;
 
         switch (hctx->type) {
         case MAC_TYPE_RAW:
@@ -181,8 +194,15 @@ static int pkey_mac_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
         break;
     case MAC_TYPE_MAC:
         {
-            EVP_MAC_CTX *cmkey = EVP_MAC_CTX_dup(hctx->ctx);
+            EVP_MAC_CTX *cmkey;
 
+            if (hctx->ctx == NULL) {
+                /* This actually means the fetch failed during the init call */
+                EVPerr(0, EVP_R_FETCH_FAILED);
+                return 0;
+            }
+
+            cmkey = EVP_MAC_CTX_dup(hctx->ctx);
             if (cmkey == NULL)
                 return 0;
             if (!EVP_MAC_up_ref(EVP_MAC_CTX_mac(hctx->ctx)))
@@ -224,6 +244,12 @@ static int pkey_mac_signctx_init(EVP_PKEY_CTX *ctx, EVP_MD_CTX *mctx)
         hctx->type == MAC_TYPE_RAW
         && (ctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) != 0;
 
+    if (hctx->ctx == NULL) {
+        /* This actually means the fetch failed during the init call */
+        EVPerr(0, EVP_R_FETCH_FAILED);
+        return 0;
+    }
+
     if (set_key) {
         if (!EVP_MAC_is_a(EVP_MAC_CTX_mac(hctx->ctx),
                           OBJ_nid2sn(EVP_PKEY_id(EVP_PKEY_CTX_get0_pkey(ctx)))))
@@ -289,6 +315,14 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
                                                      ciphname, 0);
                 params[params_n] = OSSL_PARAM_construct_end();
 
+                if (hctx->ctx == NULL) {
+                    /*
+                     * This actually means the fetch failed during the init call
+                     */
+                    EVPerr(0, EVP_R_FETCH_FAILED);
+                    return 0;
+                }
+
                 if (!EVP_MAC_CTX_set_params(hctx->ctx, params)
                     || !EVP_MAC_init(hctx->ctx))
                     return 0;
@@ -340,6 +374,14 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
             params[0] =
                 OSSL_PARAM_construct_size_t(OSSL_MAC_PARAM_SIZE, &size);
 
+            if (hctx->ctx == NULL) {
+                /*
+                 * This actually means the fetch failed during the init call
+                 */
+                EVPerr(0, EVP_R_FETCH_FAILED);
+                return 0;
+            }
+
             if (!EVP_MAC_CTX_set_params(hctx->ctx, params))
                 return 0;
 
@@ -376,6 +418,14 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
                                                       p2, p1);
                 params[params_n] = OSSL_PARAM_construct_end();
 
+                if (hctx->ctx == NULL) {
+                    /*
+                     * This actually means the fetch failed during the init call
+                     */
+                    EVPerr(0, EVP_R_FETCH_FAILED);
+                    return 0;
+                }
+
                 return EVP_MAC_CTX_set_params(hctx->ctx, params);
             }
             break;
@@ -388,6 +438,12 @@ static int pkey_mac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
     case EVP_PKEY_CTRL_DIGESTINIT:
         switch (hctx->type) {
         case MAC_TYPE_RAW:
+            if (hctx->ctx == NULL) {
+                /* This actually means the fetch failed during the init call */
+                EVPerr(0, EVP_R_FETCH_FAILED);
+                return 0;
+            }
+
             /* Ensure that we have attached the implementation */
             if (!EVP_MAC_init(hctx->ctx))
                 return 0;
@@ -459,6 +515,13 @@ static int pkey_mac_ctrl_str(EVP_PKEY_CTX *ctx,
                                        type, value, strlen(value) + 1, NULL))
         return 0;
     params[1] = OSSL_PARAM_construct_end();
+
+    if (hctx->ctx == NULL) {
+        /* This actually means the fetch failed during the init call */
+        EVPerr(0, EVP_R_FETCH_FAILED);
+        return 0;
+    }
+
     ok = EVP_MAC_CTX_set_params(hctx->ctx, params);
     OPENSSL_free(params[0].data);
     return ok;