PROV: Fix EC_KEY exporters to allow domain parameter keys
authorRichard Levitte <levitte@openssl.org>
Tue, 24 Mar 2020 15:31:43 +0000 (16:31 +0100)
committerRichard Levitte <levitte@openssl.org>
Fri, 27 Mar 2020 11:49:17 +0000 (12:49 +0100)
The provider key export functions for EC_KEY assumed that a public key
is always present, and would fail if not.  This blocks any attempt to
export a key structure with only domain parameters.

This is similar to earlier work done in EVP_PKEY_ASN1_METHODs.

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

crypto/ec/ec_backend.c
providers/implementations/keymgmt/ec_kmgmt.c

index b4520a7c60a01a9399bb8e3f138659ac3254f5df..98dd0ecf5df213881910eb3c0268e5728ea02258 100644 (file)
@@ -63,7 +63,7 @@ int ec_set_param_ecdh_cofactor_mode(EC_KEY *ec, const OSSL_PARAM *p)
  */
 int ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_private)
 {
  */
 int ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_private)
 {
-    const OSSL_PARAM *param_priv_key, *param_pub_key;
+    const OSSL_PARAM *param_priv_key = NULL, *param_pub_key = NULL;
     BN_CTX *ctx = NULL;
     BIGNUM *priv_key = NULL;
     unsigned char *pub_key = NULL;
     BN_CTX *ctx = NULL;
     BIGNUM *priv_key = NULL;
     unsigned char *pub_key = NULL;
@@ -76,24 +76,25 @@ int ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_private)
     if (ecg == NULL)
         return 0;
 
     if (ecg == NULL)
         return 0;
 
-    param_priv_key =
-        OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
     param_pub_key =
         OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
     param_pub_key =
         OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
+    if (include_private)
+        param_priv_key =
+            OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
 
     ctx = BN_CTX_new_ex(ec_key_get_libctx(ec));
     if (ctx == NULL)
         goto err;
 
     ctx = BN_CTX_new_ex(ec_key_get_libctx(ec));
     if (ctx == NULL)
         goto err;
-    /*
-     * We want to have at least a public key either way, so we end up
-     * requiring it unconditionally.
-     */
-    if (param_pub_key == NULL
-            || !OSSL_PARAM_get_octet_string(param_pub_key,
-                                            (void **)&pub_key, 0, &pub_key_len)
+
+    /* OpenSSL decree: If there's a private key, there must be a public key */
+    if (param_priv_key != NULL && param_pub_key == NULL)
+        goto err;
+
+    if (param_pub_key != NULL)
+        if (!OSSL_PARAM_get_octet_string(param_pub_key,
+                                         (void **)&pub_key, 0, &pub_key_len)
             || (pub_point = EC_POINT_new(ecg)) == NULL
             || (pub_point = EC_POINT_new(ecg)) == NULL
-            || !EC_POINT_oct2point(ecg, pub_point,
-                                   pub_key, pub_key_len, ctx))
+            || !EC_POINT_oct2point(ecg, pub_point, pub_key, pub_key_len, ctx))
         goto err;
 
     if (param_priv_key != NULL && include_private) {
         goto err;
 
     if (param_priv_key != NULL && include_private) {
@@ -150,10 +151,11 @@ int ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_private)
     }
 
     if (priv_key != NULL
     }
 
     if (priv_key != NULL
-            && !EC_KEY_set_private_key(ec, priv_key))
+        && !EC_KEY_set_private_key(ec, priv_key))
         goto err;
 
         goto err;
 
-    if (!EC_KEY_set_public_key(ec, pub_point))
+    if (pub_point != NULL
+        && !EC_KEY_set_public_key(ec, pub_point))
         goto err;
 
     ok = 1;
         goto err;
 
     ok = 1;
index 354ca0c5bb6f4a0b525ae319bcb7524634aa207c..e2cc9ca7ede81564517756bfe8b3729d777fa772 100644 (file)
@@ -109,25 +109,23 @@ int key_to_params(const EC_KEY *eckey, OSSL_PARAM_BLD *tmpl, int include_private
     size_t pub_key_len = 0;
     int ret = 0;
 
     size_t pub_key_len = 0;
     int ret = 0;
 
-    if (eckey == NULL)
+    if (eckey == NULL
+        || (ecg = EC_KEY_get0_group(eckey)) == NULL)
         return 0;
 
         return 0;
 
-    ecg = EC_KEY_get0_group(eckey);
     priv_key = EC_KEY_get0_private_key(eckey);
     pub_point = EC_KEY_get0_public_key(eckey);
 
     priv_key = EC_KEY_get0_private_key(eckey);
     pub_point = EC_KEY_get0_public_key(eckey);
 
-    /* group and public_key must be present, priv_key is optional */
-    if (ecg == NULL || pub_point == NULL)
-        return 0;
-    if ((pub_key_len = EC_POINT_point2buf(ecg, pub_point,
-                                          POINT_CONVERSION_COMPRESSED,
-                                          &pub_key, NULL)) == 0)
-        return 0;
-
-    if (!ossl_param_bld_push_octet_string(tmpl,
-                                          OSSL_PKEY_PARAM_PUB_KEY,
-                                          pub_key, pub_key_len))
-        goto err;
+    if (pub_point != NULL) {
+        /* convert pub_point to a octet string according to the SECG standard */
+        if ((pub_key_len = EC_POINT_point2buf(ecg, pub_point,
+                                              POINT_CONVERSION_COMPRESSED,
+                                              &pub_key, NULL)) == 0
+            || !ossl_param_bld_push_octet_string(tmpl,
+                                                 OSSL_PKEY_PARAM_PUB_KEY,
+                                                 pub_key, pub_key_len))
+            goto err;
+    }
 
     if (priv_key != NULL && include_private) {
         size_t sz;
 
     if (priv_key != NULL && include_private) {
         size_t sz;