Make EVP_new_raw_[private|public]_key provider aware
authorMatt Caswell <matt@openssl.org>
Fri, 24 Apr 2020 10:33:33 +0000 (11:33 +0100)
committerMatt Caswell <matt@openssl.org>
Mon, 4 May 2020 08:30:55 +0000 (09:30 +0100)
We also introduce variants which are OPENSSL_CTX aware

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11635)

crypto/evp/p_lib.c
include/openssl/evp.h
util/libcrypto.num

index bbeb727..ea74253 100644 (file)
@@ -28,6 +28,7 @@
 #include <openssl/cmac.h>
 #include <openssl/engine.h>
 #include <openssl/params.h>
+#include <openssl/param_build.h>
 #include <openssl/serializer.h>
 #include <openssl/core_names.h>
 
@@ -320,64 +321,156 @@ int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
     return -2;
 }
 
-EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *e,
-                                       const unsigned char *priv,
-                                       size_t len)
+
+static EVP_PKEY *new_raw_key_int(OPENSSL_CTX *libctx,
+                                 const char *strtype,
+                                 const char *propq,
+                                 int nidtype,
+                                 ENGINE *e,
+                                 const unsigned char *key,
+                                 size_t len,
+                                 int key_is_priv)
 {
-    EVP_PKEY *ret = EVP_PKEY_new();
+    EVP_PKEY *pkey = NULL;
+    EVP_PKEY_CTX *ctx = NULL;
+    const EVP_PKEY_ASN1_METHOD *ameth = NULL;
+    int result = 0;
 
-    if (ret == NULL
-        || !pkey_set_type(ret, e, type, NULL, -1, NULL)) {
-        /* EVPerr already called */
-        goto err;
-    }
+# ifndef OPENSSL_NO_ENGINE
+    /* Check if there is an Engine for this type */
+    if (e == NULL) {
+        ENGINE *tmpe = NULL;
 
-    if (ret->ameth->set_priv_key == NULL) {
-        EVPerr(EVP_F_EVP_PKEY_NEW_RAW_PRIVATE_KEY,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        goto err;
-    }
+        if (strtype != NULL)
+            ameth = EVP_PKEY_asn1_find_str(&tmpe, strtype, -1);
+        else if (nidtype != EVP_PKEY_NONE)
+            ameth = EVP_PKEY_asn1_find(&tmpe, nidtype);
 
-    if (!ret->ameth->set_priv_key(ret, priv, len)) {
-        EVPerr(EVP_F_EVP_PKEY_NEW_RAW_PRIVATE_KEY, EVP_R_KEY_SETUP_FAILED);
-        goto err;
+        /* If tmpe is NULL then no engine is claiming to support this type */
+        if (tmpe == NULL)
+            ameth = NULL;
+
+        ENGINE_finish(tmpe);
     }
+# endif
 
-    return ret;
+    if (e == NULL && ameth == NULL) {
+        /*
+         * No engine is claiming to support this type, so lets see if we have
+         * a provider.
+         */
+        ctx = EVP_PKEY_CTX_new_from_name(libctx,
+                                         strtype != NULL ? strtype
+                                                         : OBJ_nid2sn(nidtype),
+                                         propq);
+        if (ctx == NULL) {
+            EVPerr(0, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+        /* May fail if no provider available */
+        ERR_set_mark();
+        if (EVP_PKEY_key_fromdata_init(ctx) == 1) {
+            OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+            ERR_clear_last_mark();
+            params[0] = OSSL_PARAM_construct_octet_string(
+                            key_is_priv ? OSSL_PKEY_PARAM_PRIV_KEY
+                                        : OSSL_PKEY_PARAM_PUB_KEY,
+                            (void *)key, len);
+
+            if (EVP_PKEY_fromdata(ctx, &pkey, params) != 1) {
+                EVPerr(0, EVP_R_KEY_SETUP_FAILED);
+                goto err;
+            }
 
- err:
-    EVP_PKEY_free(ret);
-    return NULL;
-}
+            EVP_PKEY_CTX_free(ctx);
 
-EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *e,
-                                      const unsigned char *pub,
-                                      size_t len)
-{
-    EVP_PKEY *ret = EVP_PKEY_new();
+            return pkey;
+        }
+        ERR_pop_to_mark();
+        /* else not supported so fallback to legacy */
+    }
 
-    if (ret == NULL
-        || !pkey_set_type(ret, e, type, NULL, -1, NULL)) {
-        /* EVPerr already called */
+    /* Legacy code path */
+
+    pkey = EVP_PKEY_new();
+    if (pkey == NULL) {
+        EVPerr(0, ERR_R_MALLOC_FAILURE);
         goto err;
     }
 
-    if (ret->ameth->set_pub_key == NULL) {
-        EVPerr(EVP_F_EVP_PKEY_NEW_RAW_PUBLIC_KEY,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    if (!pkey_set_type(pkey, e, nidtype, strtype, -1, NULL)) {
+        /* EVPerr already called */
         goto err;
     }
 
-    if (!ret->ameth->set_pub_key(ret, pub, len)) {
-        EVPerr(EVP_F_EVP_PKEY_NEW_RAW_PUBLIC_KEY, EVP_R_KEY_SETUP_FAILED);
+    if (!ossl_assert(pkey->ameth != NULL))
         goto err;
-    }
 
-    return ret;
+    if (key_is_priv) {
+        if (pkey->ameth->set_priv_key == NULL) {
+            EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            goto err;
+        }
 
+        if (!pkey->ameth->set_priv_key(pkey, key, len)) {
+            EVPerr(0, EVP_R_KEY_SETUP_FAILED);
+            goto err;
+        }
+    } else {
+        if (pkey->ameth->set_pub_key == NULL) {
+            EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+            goto err;
+        }
+
+        if (!pkey->ameth->set_pub_key(pkey, key, len)) {
+            EVPerr(0, EVP_R_KEY_SETUP_FAILED);
+            goto err;
+        }
+    }
+
+    result = 1;
  err:
-    EVP_PKEY_free(ret);
-    return NULL;
+    if (!result) {
+        EVP_PKEY_free(pkey);
+        pkey = NULL;
+    }
+    EVP_PKEY_CTX_free(ctx);
+    return pkey;
+}
+
+EVP_PKEY *EVP_PKEY_new_raw_private_key_with_libctx(OPENSSL_CTX *libctx,
+                                                   const char *keytype,
+                                                   const char *propq,
+                                                   const unsigned char *priv,
+                                                   size_t len)
+{
+    return new_raw_key_int(libctx, keytype, propq, EVP_PKEY_NONE, NULL, priv,
+                           len, 1);
+}
+
+EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *e,
+                                       const unsigned char *priv,
+                                       size_t len)
+{
+    return new_raw_key_int(NULL, NULL, NULL, type, e, priv, len, 1);
+}
+
+EVP_PKEY *EVP_PKEY_new_raw_public_key_with_libctx(OPENSSL_CTX *libctx,
+                                                  const char *keytype,
+                                                  const char *propq,
+                                                  const unsigned char *pub,
+                                                  size_t len)
+{
+    return new_raw_key_int(libctx, keytype, propq, EVP_PKEY_NONE, NULL, pub,
+                           len, 0);
+}
+
+EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *e,
+                                      const unsigned char *pub,
+                                      size_t len)
+{
+    return new_raw_key_int(NULL, NULL, NULL, type, e, pub, len, 0);
 }
 
 int EVP_PKEY_get_raw_private_key(const EVP_PKEY *pkey, unsigned char *priv,
index 23cf52d..5dc29d1 100644 (file)
@@ -1518,9 +1518,19 @@ void EVP_PKEY_CTX_set0_keygen_info(EVP_PKEY_CTX *ctx, int *dat, int datlen);
 
 EVP_PKEY *EVP_PKEY_new_mac_key(int type, ENGINE *e,
                                const unsigned char *key, int keylen);
+EVP_PKEY *EVP_PKEY_new_raw_private_key_with_libctx(OPENSSL_CTX *libctx,
+                                                   const char *keytype,
+                                                   const char *propq,
+                                                   const unsigned char *priv,
+                                                   size_t len);
 EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *e,
                                        const unsigned char *priv,
                                        size_t len);
+EVP_PKEY *EVP_PKEY_new_raw_public_key_with_libctx(OPENSSL_CTX *libctx,
+                                                  const char *keytype,
+                                                  const char *propq,
+                                                  const unsigned char *pub,
+                                                  size_t len);
 EVP_PKEY *EVP_PKEY_new_raw_public_key(int type, ENGINE *e,
                                       const unsigned char *pub,
                                       size_t len);
index ec0e6a1..82ae2e7 100644 (file)
@@ -5081,3 +5081,5 @@ OSSL_PARAM_modified                     ? 3_0_0   EXIST::FUNCTION:
 OSSL_PARAM_set_all_unmodified           ?      3_0_0   EXIST::FUNCTION:
 EVP_default_properties_is_fips_enabled  ?      3_0_0   EXIST::FUNCTION:
 EVP_default_properties_enable_fips      ?      3_0_0   EXIST::FUNCTION:
+EVP_PKEY_new_raw_private_key_with_libctx ?     3_0_0   EXIST::FUNCTION:
+EVP_PKEY_new_raw_public_key_with_libctx ?      3_0_0   EXIST::FUNCTION: