EVP: Clarify the states of an EVP_PKEY
authorRichard Levitte <levitte@openssl.org>
Sat, 21 Mar 2020 05:03:39 +0000 (06:03 +0100)
committerRichard Levitte <levitte@openssl.org>
Wed, 25 Mar 2020 16:00:39 +0000 (17:00 +0100)
EVP_PKEY is rather complex, even before provider side keys entered the
stage.
You could have untyped / unassigned keys (pk->type == EVP_PKEY_NONE),
keys that had been assigned a type but no data (pk->pkey.ptr == NULL),
and fully assigned keys (pk->type != EVP_PKEY_NONE && pk->pkey.ptr != NULL).

For provider side keys, the corresponding states weren't well defined,
and the code didn't quite account for all the possibilities.

We also guard most of the legacy fields in EVP_PKEY with FIPS_MODE, so
they don't exist at all in the FIPS module.

Most of all, code needs to adapt to the case where an EVP_PKEY's
|keymgmt| is non-NULL, but its |keydata| is NULL.

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

crypto/evp/keymgmt_lib.c
crypto/evp/p_lib.c
crypto/evp/pmeth_check.c
crypto/evp/pmeth_lib.c
include/crypto/evp.h
providers/implementations/keymgmt/dh_kmgmt.c
providers/implementations/keymgmt/dsa_kmgmt.c
providers/implementations/keymgmt/ec_kmgmt.c
providers/implementations/keymgmt/ecx_kmgmt.c
providers/implementations/keymgmt/rsa_kmgmt.c

index 94be3c2..6e63c5a 100644 (file)
@@ -39,13 +39,26 @@ static int try_import(const OSSL_PARAM params[], void *arg)
 {
     struct import_data_st *data = arg;
 
+    /*
+     * It's fine if there was no data to transfer, we just end up with an
+     * empty destination key.
+     */
+    if (params[0].key == NULL)
+        return 1;
+
+    /* Just in time creation of keydata, if needed */
+    if (data->keydata == NULL
+        && (data->keydata = evp_keymgmt_newdata(data->keymgmt)) == NULL) {
+        ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
     return evp_keymgmt_import(data->keymgmt, data->keydata, data->selection,
                               params);
 }
 
 void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
 {
-    void *keydata = NULL;
     struct import_data_st import_data;
     size_t i = 0;
 
@@ -54,7 +67,7 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
         return NULL;
 
     /* If we have an unassigned key, give up */
-    if (pk->keymgmt == NULL)
+    if (pk->keydata == NULL)
         return NULL;
 
     /* If |keymgmt| matches the "origin" |keymgmt|, no more to do */
@@ -91,10 +104,6 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     if (!ossl_assert(match_type(pk->keymgmt, keymgmt)))
         return NULL;
 
-    /* Create space to import data into */
-    if ((keydata = evp_keymgmt_newdata(keymgmt)) == NULL)
-        return NULL;
-
     /*
      * We look at the already cached provider keys, and import from the
      * first that supports it (i.e. use its export function), and export
@@ -102,7 +111,7 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
      */
 
     /* Setup for the export callback */
-    import_data.keydata = keydata;
+    import_data.keydata = NULL;  /* try_import will create it */
     import_data.keymgmt = keymgmt;
     import_data.selection = OSSL_KEYMGMT_SELECT_ALL;
 
@@ -113,17 +122,17 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     if (!evp_keymgmt_export(pk->keymgmt, pk->keydata, OSSL_KEYMGMT_SELECT_ALL,
                             &try_import, &import_data)) {
         /* If there was an error, bail out */
-        evp_keymgmt_freedata(keymgmt, keydata);
+        evp_keymgmt_freedata(keymgmt, import_data.keydata);
         return NULL;
     }
 
     /* Add the new export to the operation cache */
-    if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, keydata)) {
-        evp_keymgmt_freedata(keymgmt, keydata);
+    if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, import_data.keydata)) {
+        evp_keymgmt_freedata(keymgmt, import_data.keydata);
         return NULL;
     }
 
-    return keydata;
+    return import_data.keydata;
 }
 
 void evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk)
@@ -175,7 +184,7 @@ void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk)
      *
      * This services functions like EVP_PKEY_size, EVP_PKEY_bits, etc
      */
-    if (pk->keymgmt != NULL) {
+    if (pk->keydata != NULL) {
         int bits = 0;
         int security_bits = 0;
         int size = 0;
@@ -254,7 +263,17 @@ int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection)
     keydata2 = pk2->keydata;
 
     if (keymgmt1 != keymgmt2) {
-        void *tmp_keydata = NULL;
+        /*
+         * The condition for a successful cross export is that the
+         * keydata to be exported is NULL (typed, but otherwise empty
+         * EVP_PKEY), or that it was possible to export it with
+         * evp_keymgmt_util_export_to_provider().
+         *
+         * We use |ok| to determine if it's ok to cross export one way,
+         * but also to determine if we should attempt a cross export
+         * the other way.  There's no point doing it both ways.
+         */
+        int ok = 1;
 
         /* Complex case, where the keymgmt differ */
         if (keymgmt1 != NULL
@@ -270,17 +289,35 @@ int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection)
          */
         if (keymgmt2 != NULL
             && keymgmt2->match != NULL) {
-            tmp_keydata = evp_keymgmt_util_export_to_provider(pk1, keymgmt2);
-            if (tmp_keydata != NULL) {
+            void *tmp_keydata = NULL;
+
+            ok = 1;
+            if (keydata1 != NULL) {
+                tmp_keydata =
+                    evp_keymgmt_util_export_to_provider(pk1, keymgmt2);
+                ok = (tmp_keydata != NULL);
+            }
+            if (ok) {
                 keymgmt1 = keymgmt2;
                 keydata1 = tmp_keydata;
             }
         }
-        if (tmp_keydata == NULL
+        /*
+         * If we've successfully cross exported one way, there's not point
+         * doing it the other way, hence the |!ok| check.
+         */
+        if (!ok
             && keymgmt1 != NULL
             && keymgmt1->match != NULL) {
-            tmp_keydata = evp_keymgmt_util_export_to_provider(pk2, keymgmt1);
-            if (tmp_keydata != NULL) {
+            void *tmp_keydata = NULL;
+
+            ok = 1;
+            if (keydata2 != NULL) {
+                tmp_keydata =
+                    evp_keymgmt_util_export_to_provider(pk2, keymgmt1);
+                ok = (tmp_keydata != NULL);
+            }
+            if (ok) {
                 keymgmt2 = keymgmt1;
                 keydata2 = tmp_keydata;
             }
@@ -291,6 +328,13 @@ int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection)
     if (keymgmt1 != keymgmt2)
         return -2;
 
+    /* If both keydata are NULL, then they're the same key */
+    if (keydata1 == NULL && keydata2 == NULL)
+        return 1;
+    /* If only one of the keydata is NULL, then they're different keys */
+    if (keydata1 == NULL || keydata2 == NULL)
+        return 0;
+    /* If both keydata are non-NULL, we let the backend decide */
     return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
 }
 
@@ -301,23 +345,21 @@ int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection)
     void *to_keydata = to->keydata, *alloc_keydata = NULL;
 
     /* An unassigned key can't be copied */
-    if (from == NULL || from->keymgmt == NULL)
-        return 0;
-
-    /* If |from| doesn't support copying, we fail */
-    if (from->keymgmt->copy == NULL)
+    if (from == NULL || from->keydata == NULL)
         return 0;
 
-    /* If |to| doesn't have a provider side "origin" yet, create one */
-    if (to_keymgmt == NULL) {
-        to_keydata = alloc_keydata = evp_keymgmt_newdata(from->keymgmt);
-        if (to_keydata == NULL)
+    if (to_keymgmt == from->keymgmt && to_keymgmt->copy != NULL) {
+        /* Make sure there's somewhere to copy to */
+        if (to_keydata == NULL
+            && (to_keydata = evp_keymgmt_newdata(to_keymgmt)) == NULL) {
+            ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE);
             return 0;
-        to_keymgmt = from->keymgmt;
-    }
+        }
 
-    if (to_keymgmt == from->keymgmt) {
-        /* |to| and |from| have the same keymgmt, just copy and be done */
+        /*
+         * |to| and |from| have the same keymgmt, and the copy function is
+         * implemented, so just copy and be done
+         */
         if (!evp_keymgmt_copy(to_keymgmt, to_keydata, from->keydata,
                               selection))
             return 0;
@@ -333,6 +375,12 @@ int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection)
             evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
             return 0;
         }
+
+        /*
+         * In this case to_keydata was previously unallocated, try_import()
+         * may have created it for us.
+         */
+        to_keydata = import_data.keydata;
     } else {
         ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
         return 0;
index a2bb2b7..1603f29 100644 (file)
@@ -1069,13 +1069,16 @@ void EVP_PKEY_free(EVP_PKEY *x)
 
 int EVP_PKEY_size(const EVP_PKEY *pkey)
 {
+    int size = 0;
+
     if (pkey != NULL) {
-        if (pkey->ameth == NULL)
-            return pkey->cache.size;
-        else if (pkey->ameth->pkey_size != NULL)
-            return pkey->ameth->pkey_size(pkey);
+        size = pkey->cache.size;
+#ifndef FIPS_MODE
+        if (pkey->ameth != NULL && pkey->ameth->pkey_size != NULL)
+            size = pkey->ameth->pkey_size(pkey);
+#endif
     }
-    return 0;
+    return size;
 }
 
 void *evp_pkey_export_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
@@ -1085,10 +1088,20 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
     EVP_KEYMGMT *allocated_keymgmt = NULL;
     EVP_KEYMGMT *tmp_keymgmt = NULL;
     void *keydata = NULL;
+    int check;
 
     if (pk == NULL)
         return NULL;
 
+    /* No key data => nothing to export */
+    check = 1;
+#ifndef FIPS_MODE
+    check = check && pk->pkey.ptr == NULL;
+#endif
+    check = check && pk->keydata == NULL;
+    if (check)
+        return NULL;
+
 #ifndef FIPS_MODE
     if (pk->pkey.ptr != NULL) {
         /*
index c02353d..587e8ae 100644 (file)
@@ -35,19 +35,24 @@ int EVP_PKEY_public_check(EVP_PKEY_CTX *ctx)
         return evp_keymgmt_validate(keymgmt, key,
                                     OSSL_KEYMGMT_SELECT_PUBLIC_KEY);
 
+    if (pkey->type == EVP_PKEY_NONE)
+        goto not_supported;
+
+#ifndef FIPS_MODE
     /* legacy */
     /* call customized public key check function first */
     if (ctx->pmeth->public_check != NULL)
         return ctx->pmeth->public_check(pkey);
 
     /* use default public key check function in ameth */
-    if (pkey->ameth == NULL || pkey->ameth->pkey_public_check == NULL) {
-        EVPerr(EVP_F_EVP_PKEY_PUBLIC_CHECK,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
-    }
+    if (pkey->ameth == NULL || pkey->ameth->pkey_public_check == NULL)
+        goto not_supported;
 
     return pkey->ameth->pkey_public_check(pkey);
+#endif
+ not_supported:
+    EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
 }
 
 int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx)
@@ -68,19 +73,24 @@ int EVP_PKEY_param_check(EVP_PKEY_CTX *ctx)
         return evp_keymgmt_validate(keymgmt, key,
                                     OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
 
+    if (pkey->type == EVP_PKEY_NONE)
+        goto not_supported;
+
+#ifndef FIPS_MODE
+    /* legacy */
     /* call customized param check function first */
     if (ctx->pmeth->param_check != NULL)
         return ctx->pmeth->param_check(pkey);
 
-    /* legacy */
     /* use default param check function in ameth */
-    if (pkey->ameth == NULL || pkey->ameth->pkey_param_check == NULL) {
-        EVPerr(EVP_F_EVP_PKEY_PARAM_CHECK,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
-    }
+    if (pkey->ameth == NULL || pkey->ameth->pkey_param_check == NULL)
+        goto not_supported;
 
     return pkey->ameth->pkey_param_check(pkey);
+#endif
+ not_supported:
+    EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
 }
 
 int EVP_PKEY_private_check(EVP_PKEY_CTX *ctx)
@@ -101,6 +111,7 @@ int EVP_PKEY_private_check(EVP_PKEY_CTX *ctx)
         return evp_keymgmt_validate(keymgmt, key,
                                     OSSL_KEYMGMT_SELECT_PRIVATE_KEY);
     /* not supported for legacy keys */
+    EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return -2;
 }
 
@@ -121,6 +132,7 @@ int EVP_PKEY_pairwise_check(EVP_PKEY_CTX *ctx)
     if (key != NULL && keymgmt != NULL)
         return evp_keymgmt_validate(keymgmt, key, OSSL_KEYMGMT_SELECT_KEYPAIR);
     /* not supported for legacy keys */
+    EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
     return -2;
 }
 
@@ -141,18 +153,23 @@ int EVP_PKEY_check(EVP_PKEY_CTX *ctx)
     if (key != NULL && keymgmt != NULL)
         return evp_keymgmt_validate(keymgmt, key, OSSL_KEYMGMT_SELECT_ALL);
 
+    if (pkey->type == EVP_PKEY_NONE)
+        goto not_supported;
+
+#ifndef FIPS_MODE
     /* legacy */
     /* call customized check function first */
     if (ctx->pmeth->check != NULL)
         return ctx->pmeth->check(pkey);
 
     /* use default check function in ameth */
-    if (pkey->ameth == NULL || pkey->ameth->pkey_check == NULL) {
-        EVPerr(EVP_F_EVP_PKEY_CHECK,
-               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-        return -2;
-    }
+    if (pkey->ameth == NULL || pkey->ameth->pkey_check == NULL)
+        goto not_supported;
 
     return pkey->ameth->pkey_check(pkey);
+#endif
+ not_supported:
+    EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return -2;
 }
 
index f5e1131..ecaaec4 100644 (file)
@@ -157,7 +157,7 @@ static EVP_PKEY_CTX *int_ctx_new(OPENSSL_CTX *libctx,
      * If the key doesn't contain anything legacy, then it must be provided,
      * so we extract the necessary information and use that.
      */
-    if (pkey != NULL && pkey->ameth == NULL) {
+    if (pkey != NULL && pkey->type == EVP_PKEY_NONE) {
         /* If we have an engine, something went wrong somewhere... */
         if (!ossl_assert(e == NULL))
             return NULL;
index 2e0322f..e5f9aad 100644 (file)
@@ -502,14 +502,31 @@ const EVP_CIPHER *EVP_##cname##_ecb(void) { return &cname##_ecb; }
                              cipher##_init_key, NULL, NULL, NULL, NULL)
 
 /*
- * Type needs to be a bit field Sub-type needs to be for variations on the
- * method, as in, can it do arbitrary encryption....
+ * An EVP_PKEY can have the following states:
+ *
+ * untyped & empty:
+ *
+ *     type == EVP_PKEY_NONE && keymgmt == NULL
+ *
+ * typed & empty:
+ *
+ *     (type != EVP_PKEY_NONE && pkey.ptr == NULL)      ## legacy (libcrypto only)
+ *     || (keymgmt != NULL && keydata == NULL)          ## provider side
+ *
+ * fully assigned:
+ *
+ *     (type != EVP_PKEY_NONE && pkey.ptr != NULL)      ## legacy (libcrypto only)
+ *     || (keymgmt != NULL && keydata != NULL)          ## provider side
+ *
+ * The easiest way to detect a legacy key is:           type != EVP_PKEY_NONE
+ * The easiest way to detect a provider side key is:    keymgmt != NULL
  */
 struct evp_pkey_st {
     /* == Legacy attributes == */
     int type;
     int save_type;
 
+# ifndef FIPS_MODE
     /*
      * Legacy key "origin" is composed of a pointer to an EVP_PKEY_ASN1_METHOD,
      * a pointer to a low level key and possibly a pointer to an engine.
@@ -519,20 +536,21 @@ struct evp_pkey_st {
     ENGINE *pmeth_engine; /* If not NULL public key ENGINE to use */
     union {
         void *ptr;
-# ifndef OPENSSL_NO_RSA
+#  ifndef OPENSSL_NO_RSA
         struct rsa_st *rsa;     /* RSA */
-# endif
-# ifndef OPENSSL_NO_DSA
+#  endif
+#  ifndef OPENSSL_NO_DSA
         struct dsa_st *dsa;     /* DSA */
-# endif
-# ifndef OPENSSL_NO_DH
+#  endif
+#  ifndef OPENSSL_NO_DH
         struct dh_st *dh;       /* DH */
-# endif
-# ifndef OPENSSL_NO_EC
+#  endif
+#  ifndef OPENSSL_NO_EC
         struct ec_key_st *ec;   /* ECC */
         ECX_KEY *ecx;           /* X25519, X448, Ed25519, Ed448 */
-# endif
+#  endif
     } pkey;
+# endif
 
     /* == Common attributes == */
     CRYPTO_REF_COUNT references;
index 6a6a06c..c9aef88 100644 (file)
@@ -159,15 +159,17 @@ static int dh_has(void *keydata, int selection)
     DH *dh = keydata;
     int ok = 0;
 
-    if ((selection & DH_POSSIBLE_SELECTIONS) != 0)
-        ok = 1;
-
-    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
-        ok = ok && (DH_get0_pub_key(dh) != NULL);
-    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
-        ok = ok && (DH_get0_priv_key(dh) != NULL);
-    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
-        ok = ok && (DH_get0_p(dh) != NULL && DH_get0_g(dh) != NULL);
+    if (dh != NULL) {
+        if ((selection & DH_POSSIBLE_SELECTIONS) != 0)
+            ok = 1;
+
+        if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+            ok = ok && (DH_get0_pub_key(dh) != NULL);
+        if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+            ok = ok && (DH_get0_priv_key(dh) != NULL);
+        if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+            ok = ok && (DH_get0_p(dh) != NULL && DH_get0_g(dh) != NULL);
+    }
     return ok;
 }
 
index a4821f9..a8ef074 100644 (file)
@@ -164,15 +164,17 @@ static int dsa_has(void *keydata, int selection)
     DSA *dsa = keydata;
     int ok = 0;
 
-    if ((selection & DSA_POSSIBLE_SELECTIONS) != 0)
-        ok = 1;
-
-    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
-        ok = ok && (DSA_get0_pub_key(dsa) != NULL);
-    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
-        ok = ok && (DSA_get0_priv_key(dsa) != NULL);
-    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
-        ok = ok && (DSA_get0_p(dsa) != NULL && DSA_get0_g(dsa) != NULL);
+    if (dsa != NULL) {
+        if ((selection & DSA_POSSIBLE_SELECTIONS) != 0)
+            ok = 1;
+
+        if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+            ok = ok && (DSA_get0_pub_key(dsa) != NULL);
+        if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+            ok = ok && (DSA_get0_priv_key(dsa) != NULL);
+        if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+            ok = ok && (DSA_get0_p(dsa) != NULL && DSA_get0_g(dsa) != NULL);
+    }
     return ok;
 }
 
index 4787255..4f8f44d 100644 (file)
@@ -432,21 +432,22 @@ int ec_has(void *keydata, int selection)
     EC_KEY *ec = keydata;
     int ok = 0;
 
-    if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
-        ok = 1;
-
-    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
-        ok = ok && (EC_KEY_get0_public_key(ec) != NULL);
-    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
-        ok = ok && (EC_KEY_get0_private_key(ec) != NULL);
-    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
-        ok = ok && (EC_KEY_get0_group(ec) != NULL);
-    /*
-     * We consider OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS to always be available,
-     * so no extra check is needed other than the previous one against
-     * EC_POSSIBLE_SELECTIONS.
-     */
-
+    if (ec != NULL) {
+        if ((selection & EC_POSSIBLE_SELECTIONS) != 0)
+            ok = 1;
+
+        if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+            ok = ok && (EC_KEY_get0_public_key(ec) != NULL);
+        if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+            ok = ok && (EC_KEY_get0_private_key(ec) != NULL);
+        if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+            ok = ok && (EC_KEY_get0_group(ec) != NULL);
+        /*
+         * We consider OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS to always be
+         * available, so no extra check is needed other than the previous one
+         * against EC_POSSIBLE_SELECTIONS.
+         */
+    }
     return ok;
 }
 
index 6450fbb..121980e 100644 (file)
@@ -56,17 +56,18 @@ static void *ed448_new_key(void *provctx)
 static int ecx_has(void *keydata, int selection)
 {
     ECX_KEY *key = keydata;
-    int ok = 1;
+    int ok = 0;
 
-    if ((selection & ECX_POSSIBLE_SELECTIONS) == 0)
-        return 0;
-
-    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
-        ok = ok && key->haspubkey;
+    if (key != NULL) {
+        if ((selection & ECX_POSSIBLE_SELECTIONS) != 0)
+            ok = 1;
 
-    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
-        ok = ok && key->privkey != NULL;
+        if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+            ok = ok && key->haspubkey;
 
+        if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+            ok = ok && key->privkey != NULL;
+    }
     return ok;
 }
 
index 4e77f5c..2826d33 100644 (file)
@@ -198,14 +198,19 @@ static int rsa_has(void *keydata, int selection)
     RSA *rsa = keydata;
     int ok = 0;
 
-    if ((selection & RSA_POSSIBLE_SELECTIONS) != 0)
-        ok = 1;
-
-    ok = ok && (RSA_get0_e(rsa) != NULL);
-    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
-        ok = ok && (RSA_get0_n(rsa) != NULL);
-    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
-        ok = ok && (RSA_get0_d(rsa) != NULL);
+    if (rsa != NULL) {
+        if ((selection & RSA_POSSIBLE_SELECTIONS) != 0)
+            ok = 1;
+
+        if ((selection & OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS) != 0)
+            ok = ok && 0;     /* This will change with PSS and OAEP */
+        if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)
+            ok = ok && (RSA_get0_e(rsa) != NULL);
+        if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+            ok = ok && (RSA_get0_n(rsa) != NULL);
+        if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+            ok = ok && (RSA_get0_d(rsa) != NULL);
+    }
     return ok;
 }