[openssl] master update

Richard Levitte levitte at openssl.org
Mon Mar 2 02:28:55 UTC 2020


The branch master has been updated
       via  2888fc1590ad31633be7a99e7288dcecd35e800c (commit)
       via  ff3b59e1705a40f7cfc6df8d788d08b0a525aa58 (commit)
       via  13697f1c62e98a4c1365fd85cb39ada0f47dce5f (commit)
       via  1e9101c404b92b1fd32e8f0308ddc20742285135 (commit)
       via  bee5d6cd3fa2f8bcc7e1153e4dc26aa26144bee0 (commit)
       via  157ded39ee68c1c00814165f79f9b2f000996884 (commit)
      from  ccceeb48000d5fae95f38d2c4dd02cdd89ca1ee1 (commit)


- Log -----------------------------------------------------------------
commit 2888fc1590ad31633be7a99e7288dcecd35e800c
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Feb 6 09:53:15 2020 +0100

    PROV: Add a OP_keymgmt_match() function to our DH, DSA, RSA and EC_KEY impl
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/11158)

commit ff3b59e1705a40f7cfc6df8d788d08b0a525aa58
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Feb 5 16:30:21 2020 +0100

    EVP: Add support for copying provided EVP_PKEYs
    
    This adds evp_keymgmt_util_copy() and affects EVP_PKEY_copy_parameters()
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/11158)

commit 13697f1c62e98a4c1365fd85cb39ada0f47dce5f
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Feb 5 15:41:58 2020 +0100

    KEYMGMT: Add a keydata copy function
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/11158)

commit 1e9101c404b92b1fd32e8f0308ddc20742285135
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Feb 5 12:55:43 2020 +0100

    EVP: Add support for comparing provided EVP_PKEYs
    
    This adds evp_keymgmt_util_match() and affects EVP_PKEY_cmp() and
    EVP_PKEY_cmp_parameters().
    
    The word 'match' was used for the new routines because many associate
    'cmp' with comparison functions that allows sorting, i.e. return -1, 0
    or 1 depending on the order in which the two compared elements should
    be sorted.  EVP_PKEY_cmp() and EVP_PKEY_cmp_parameters() don't quite
    do that.
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/11158)

commit bee5d6cd3fa2f8bcc7e1153e4dc26aa26144bee0
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Feb 5 12:53:14 2020 +0100

    KEYMGMT: Add a keydata matching function
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/11158)

commit 157ded39ee68c1c00814165f79f9b2f000996884
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Feb 5 10:18:51 2020 +0100

    EVP: Adapt EVP_PKEY_missing_parameters() for provider keys
    
    Reviewed-by: Shane Lontis <shane.lontis at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/11158)

-----------------------------------------------------------------------

Summary of changes:
 crypto/dsa/dsa_lib.c                          |   5 +
 crypto/evp/evp_local.h                        |   2 +
 crypto/evp/keymgmt_lib.c                      | 136 ++++++++++++++++++++
 crypto/evp/keymgmt_meth.c                     |  24 ++++
 crypto/evp/p_lib.c                            | 173 +++++++++++++++++++++++---
 doc/man7/provider-keymgmt.pod                 |  19 ++-
 include/crypto/dsa.h                          |   4 +
 include/crypto/evp.h                          |   9 ++
 include/openssl/core_numbers.h                |  14 ++-
 providers/implementations/keymgmt/dh_kmgmt.c  |  21 ++++
 providers/implementations/keymgmt/dsa_kmgmt.c |  23 ++++
 providers/implementations/keymgmt/ec_kmgmt.c  |  28 +++++
 providers/implementations/keymgmt/rsa_kmgmt.c |  17 +++
 13 files changed, 459 insertions(+), 16 deletions(-)

diff --git a/crypto/dsa/dsa_lib.c b/crypto/dsa/dsa_lib.c
index 4b048d48c5..154048a3a3 100644
--- a/crypto/dsa/dsa_lib.c
+++ b/crypto/dsa/dsa_lib.c
@@ -337,3 +337,8 @@ int DSA_bits(const DSA *dsa)
 {
     return BN_num_bits(dsa->params.p);
 }
+
+FFC_PARAMS *dsa_get0_params(DSA *dsa)
+{
+    return &dsa->params;
+}
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index 9b4ab29fda..774db4da8f 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -85,12 +85,14 @@ struct evp_keymgmt_st {
     OSSL_OP_keymgmt_query_operation_name_fn *query_operation_name;
     OSSL_OP_keymgmt_has_fn *has;
     OSSL_OP_keymgmt_validate_fn *validate;
+    OSSL_OP_keymgmt_match_fn *match;
 
     /* Import and export routines */
     OSSL_OP_keymgmt_import_fn *import;
     OSSL_OP_keymgmt_import_types_fn *import_types;
     OSSL_OP_keymgmt_export_fn *export;
     OSSL_OP_keymgmt_export_types_fn *export_types;
+    OSSL_OP_keymgmt_copy_fn *copy;
 } /* EVP_KEYMGMT */ ;
 
 struct evp_keyexch_st {
diff --git a/crypto/evp/keymgmt_lib.c b/crypto/evp/keymgmt_lib.c
index a88d65dc5e..68ccdbb8ee 100644
--- a/crypto/evp/keymgmt_lib.c
+++ b/crypto/evp/keymgmt_lib.c
@@ -214,3 +214,139 @@ void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
 
     return keydata;
 }
+
+int evp_keymgmt_util_has(EVP_PKEY *pk, int selection)
+{
+    /* Check if key is even assigned */
+    if (pk->keymgmt == NULL)
+        return 0;
+
+    return evp_keymgmt_has(pk->keymgmt, pk->keydata, selection);
+}
+
+/*
+ * evp_keymgmt_util_match() doesn't just look at the provider side "origin",
+ * but also in the operation cache to see if there's any common keymgmt that
+ * supplies OP_keymgmt_match.
+ *
+ * evp_keymgmt_util_match() adheres to the return values that EVP_PKEY_cmp()
+ * and EVP_PKEY_cmp_parameters() return, i.e.:
+ *
+ *  1   same key
+ *  0   not same key
+ * -1   not same key type
+ * -2   unsupported operation
+ */
+int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection)
+{
+    EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL;
+    void *keydata1 = NULL, *keydata2 = NULL;
+
+    if (pk1 == NULL || pk2 == NULL) {
+        if (pk1 == NULL && pk2 == NULL)
+            return 1;
+        return 0;
+    }
+
+    keymgmt1 = pk1->keymgmt;
+    keydata1 = pk1->keydata;
+    keymgmt2 = pk2->keymgmt;
+    keydata2 = pk2->keydata;
+
+    if (keymgmt1 != keymgmt2) {
+        void *tmp_keydata = NULL;
+
+        /* Complex case, where the keymgmt differ */
+        if (keymgmt1 != NULL
+            && keymgmt2 != NULL
+            && !match_type(keymgmt1, keymgmt2)) {
+            ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
+            return -1;           /* Not the same type */
+        }
+
+        /*
+         * The key types are determined to match, so we try cross export,
+         * but only to keymgmt's that supply a matching function.
+         */
+        if (keymgmt2 != NULL
+            && keymgmt2->match != NULL) {
+            tmp_keydata = evp_keymgmt_util_export_to_provider(pk1, keymgmt2);
+            if (tmp_keydata != NULL) {
+                keymgmt1 = keymgmt2;
+                keydata1 = tmp_keydata;
+            }
+        }
+        if (tmp_keydata == NULL
+            && keymgmt1 != NULL
+            && keymgmt1->match != NULL) {
+            tmp_keydata = evp_keymgmt_util_export_to_provider(pk2, keymgmt1);
+            if (tmp_keydata != NULL) {
+                keymgmt2 = keymgmt1;
+                keydata2 = tmp_keydata;
+            }
+        }
+    }
+
+    /* If we still don't have matching keymgmt implementations, we give up */
+    if (keymgmt1 != keymgmt2)
+        return -2;
+
+    return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
+}
+
+int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection)
+{
+    /* Save copies of pointers we want to play with without affecting |to| */
+    EVP_KEYMGMT *to_keymgmt = to->keymgmt;
+    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)
+        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)
+            return 0;
+        to_keymgmt = from->keymgmt;
+    }
+
+    if (to_keymgmt == from->keymgmt) {
+        /* |to| and |from| have the same keymgmt, just copy and be done */
+        if (!evp_keymgmt_copy(to_keymgmt, to_keydata, from->keydata,
+                              selection))
+            return 0;
+    } else if (match_type(to_keymgmt, from->keymgmt)) {
+        struct import_data_st import_data;
+
+        import_data.keymgmt = to_keymgmt;
+        import_data.keydata = to_keydata;
+        import_data.selection = selection;
+
+        if (!evp_keymgmt_export(from->keymgmt, from->keydata, selection,
+                                &try_import, &import_data)) {
+            evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
+            return 0;
+        }
+    } else {
+        ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
+        return 0;
+    }
+
+    if (to->keymgmt == NULL
+        && !EVP_KEYMGMT_up_ref(to_keymgmt)) {
+        evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
+        return 0;
+    }
+    evp_keymgmt_util_clear_operation_cache(to);
+    to->keymgmt = to_keymgmt;
+    to->keydata = to_keydata;
+    evp_keymgmt_util_cache_keyinfo(to);
+
+    return 1;
+}
diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c
index 3fcc073a5a..f80e6e29b5 100644
--- a/crypto/evp/keymgmt_meth.c
+++ b/crypto/evp/keymgmt_meth.c
@@ -95,6 +95,10 @@ static void *keymgmt_from_dispatch(int name_id,
             if (keymgmt->validate == NULL)
                 keymgmt->validate = OSSL_get_OP_keymgmt_validate(fns);
             break;
+        case OSSL_FUNC_KEYMGMT_MATCH:
+            if (keymgmt->match == NULL)
+                keymgmt->match = OSSL_get_OP_keymgmt_match(fns);
+            break;
         case OSSL_FUNC_KEYMGMT_IMPORT:
             if (keymgmt->import == NULL) {
                 importfncnt++;
@@ -290,6 +294,16 @@ int evp_keymgmt_validate(const EVP_KEYMGMT *keymgmt, void *keydata,
     return keymgmt->validate(keydata, selection);
 }
 
+int evp_keymgmt_match(const EVP_KEYMGMT *keymgmt,
+                      const void *keydata1, const void *keydata2,
+                      int selection)
+{
+    /* We assume no match if the implementation doesn't have a function */
+    if (keymgmt->match == NULL)
+        return 0;
+    return keymgmt->match(keydata1, keydata2, selection);
+}
+
 int evp_keymgmt_import(const EVP_KEYMGMT *keymgmt, void *keydata,
                        int selection, const OSSL_PARAM params[])
 {
@@ -321,3 +335,13 @@ const OSSL_PARAM *evp_keymgmt_export_types(const EVP_KEYMGMT *keymgmt,
         return NULL;
     return keymgmt->export_types(selection);
 }
+
+int evp_keymgmt_copy(const EVP_KEYMGMT *keymgmt,
+                     void *keydata_to, const void *keydata_from,
+                     int selection)
+{
+    /* We assume no copy if the implementation doesn't have a function */
+    if (keymgmt->copy == NULL)
+        return 0;
+    return keymgmt->copy(keydata_to, keydata_from, selection);
+}
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 621d99d171..586ffaf041 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -86,12 +86,25 @@ int EVP_PKEY_save_parameters(EVP_PKEY *pkey, int mode)
 
 int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
 {
-    if (to->type == EVP_PKEY_NONE) {
-        if (EVP_PKEY_set_type(to, from->type) == 0)
-            return 0;
-    } else if (to->type != from->type) {
-        EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_DIFFERENT_KEY_TYPES);
-        goto err;
+    /*
+     * TODO: clean up legacy stuff from this function when legacy support
+     * is gone.
+     */
+
+    /*
+     * Only check that type match this early when both keys are legacy.
+     * If either of them is provided, we let evp_keymgmt_util_copy()
+     * do this check, after having exported either of them that isn't
+     * provided.
+     */
+    if (to->keymgmt == NULL && from->keymgmt == NULL) {
+        if (to->type == EVP_PKEY_NONE) {
+            if (EVP_PKEY_set_type(to, from->type) == 0)
+                return 0;
+        } else if (to->type != from->type) {
+            EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_DIFFERENT_KEY_TYPES);
+            goto err;
+        }
     }
 
     if (EVP_PKEY_missing_parameters(from)) {
@@ -106,7 +119,56 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
         return 0;
     }
 
-    if (from->ameth && from->ameth->param_copy)
+    /*
+     * If |from| is provided, we upgrade |to| to be provided as well.
+     * This drops the legacy key from |to|.
+     * evp_pkey_upgrade_to_provider() checks if |to| is already provided,
+     * we don't need to do that here.
+     *
+     * TODO(3.0) We should investigate if that's too aggressive and make
+     * this scenario unsupported instead.
+     */
+    if (from->keymgmt != NULL) {
+        EVP_KEYMGMT *tmp_keymgmt = from->keymgmt;
+
+        /*
+         * The returned pointer is known to be cached, so we don't have to
+         * save it.  However, if it's NULL, something went wrong and we can't
+         * copy.
+         */
+        if (evp_pkey_upgrade_to_provider(to, NULL,
+                                         &tmp_keymgmt, NULL) == NULL) {
+            ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+    }
+
+    /* For purely provided keys, we just call the keymgmt utility */
+    if (to->keymgmt != NULL && from->keymgmt != NULL)
+        return evp_keymgmt_util_copy(to, (EVP_PKEY *)from,
+                                     OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
+
+    /*
+     * If |to| is provided, we know that |from| is legacy at this point.
+     * Try exporting |from| to |to|'s keymgmt, then use evp_keymgmt_copy()
+     * to copy the appropriate data to |to|'s keydata.
+     */
+    if (to->keymgmt != NULL) {
+        EVP_KEYMGMT *to_keymgmt = to->keymgmt;
+        void *from_keydata =
+            evp_pkey_export_to_provider((EVP_PKEY *)from, NULL, &to_keymgmt,
+                                        NULL);
+
+        if (from_keydata == NULL) {
+            ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
+            return 0;
+        }
+        return evp_keymgmt_copy(to->keymgmt, to->keydata, from_keydata,
+                                OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
+    }
+
+    /* Both keys are legacy */
+    if (from->ameth != NULL && from->ameth->param_copy != NULL)
         return from->ameth->param_copy(to, from);
  err:
     return 0;
@@ -114,35 +176,118 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
 
 int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey)
 {
-    if (pkey != NULL && pkey->ameth && pkey->ameth->param_missing)
-        return pkey->ameth->param_missing(pkey);
+    if (pkey != NULL) {
+        if (pkey->keymgmt != NULL)
+            return !evp_keymgmt_util_has((EVP_PKEY *)pkey,
+                                         OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
+        else if (pkey->ameth != NULL && pkey->ameth->param_missing != NULL)
+            return pkey->ameth->param_missing(pkey);
+    }
     return 0;
 }
 
+/*
+ * This function is called for any mixture of keys except pure legacy pair.
+ * TODO When legacy keys are gone, we replace a call to this functions with
+ * a call to evp_keymgmt_util_match().
+ */
+static int evp_pkey_cmp_any(const EVP_PKEY *a, const EVP_PKEY *b,
+                            int selection)
+{
+    EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL;
+    void *keydata1 = NULL, *keydata2 = NULL, *tmp_keydata = NULL;
+
+    /* If none of them are provided, this function shouldn't have been called */
+    if (!ossl_assert(a->keymgmt != NULL || b->keymgmt != NULL))
+        return -2;
+
+    /* For purely provided keys, we just call the keymgmt utility */
+    if (a->keymgmt != NULL && b->keymgmt != NULL)
+        return evp_keymgmt_util_match((EVP_PKEY *)a, (EVP_PKEY *)b, selection);
+
+    /*
+     * Here, we know that we have a mixture of legacy and provided keys.
+     * Try cross export and compare the resulting key data.
+     */
+    keymgmt1 = a->keymgmt;
+    keydata1 = a->keydata;
+    keymgmt2 = b->keymgmt;
+    keydata2 = b->keydata;
+
+    if ((keymgmt1 == NULL
+         && !EVP_KEYMGMT_is_a(keymgmt2, OBJ_nid2sn(a->type)))
+        || (keymgmt2 == NULL
+            && !EVP_KEYMGMT_is_a(keymgmt1, OBJ_nid2sn(b->type))))
+        return -1;               /* not the same key type */
+
+    if (keymgmt2 != NULL && keymgmt2->match != NULL) {
+        tmp_keydata =
+            evp_pkey_export_to_provider((EVP_PKEY *)a, NULL, &keymgmt2, NULL);
+        if (tmp_keydata != NULL) {
+            keymgmt1 = keymgmt2;
+            keydata1 = tmp_keydata;
+        }
+    }
+    if (tmp_keydata == NULL && keymgmt1 != NULL && keymgmt1->match != NULL) {
+        tmp_keydata =
+            evp_pkey_export_to_provider((EVP_PKEY *)b, NULL, &keymgmt1, NULL);
+        if (tmp_keydata != NULL) {
+            keymgmt2 = keymgmt1;
+            keydata2 = tmp_keydata;
+        }
+    }
+
+    /* If we still don't have matching keymgmt implementations, we give up */
+    if (keymgmt1 != keymgmt2)
+        return -2;
+
+    return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
+}
+
 int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
 {
+    /*
+     * TODO: clean up legacy stuff from this function when legacy support
+     * is gone.
+     */
+
+    if (a->keymgmt != NULL || b->keymgmt != NULL)
+        return evp_pkey_cmp_any(a, b, OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
+
+    /* All legacy keys */
     if (a->type != b->type)
         return -1;
-    if (a->ameth && a->ameth->param_cmp)
+    if (a->ameth != NULL && a->ameth->param_cmp != NULL)
         return a->ameth->param_cmp(a, b);
     return -2;
 }
 
 int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
 {
+    /*
+     * TODO: clean up legacy stuff from this function when legacy support
+     * is gone.
+     */
+
+    if (a->keymgmt != NULL || b->keymgmt != NULL)
+        return evp_pkey_cmp_any(a, b,
+                                OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
+                                | OSSL_KEYMGMT_SELECT_PUBLIC_KEY);
+
+    /* All legacy keys */
     if (a->type != b->type)
         return -1;
 
-    if (a->ameth) {
+    if (a->ameth != NULL) {
         int ret;
         /* Compare parameters if the algorithm has them */
-        if (a->ameth->param_cmp) {
+        if (a->ameth->param_cmp != NULL) {
             ret = a->ameth->param_cmp(a, b);
             if (ret <= 0)
                 return ret;
         }
 
-        if (a->ameth->pub_cmp)
+        if (a->ameth->pub_cmp != NULL)
             return a->ameth->pub_cmp(a, b);
     }
 
@@ -870,7 +1015,7 @@ int EVP_PKEY_up_ref(EVP_PKEY *pkey)
 static void evp_pkey_free_legacy(EVP_PKEY *x)
 {
     if (x->ameth != NULL) {
-        if (x->ameth->pkey_free)
+        if (x->ameth->pkey_free != NULL)
             x->ameth->pkey_free(x);
         x->pkey.ptr = NULL;
         x->ameth = NULL;
diff --git a/doc/man7/provider-keymgmt.pod b/doc/man7/provider-keymgmt.pod
index 5141ffdebc..91b87cecdc 100644
--- a/doc/man7/provider-keymgmt.pod
+++ b/doc/man7/provider-keymgmt.pod
@@ -26,6 +26,8 @@ provider-keymgmt - The KEYMGMT library E<lt>-E<gt> provider functions
 
  /* Key object content checks */
  int OP_keymgmt_has(void *keydata, int selection);
+ int OP_keymgmt_match(const void *keydata1, const void *keydata2,
+                      int selection);
 
  /* Discovery of supported operations */
  const char *OP_keymgmt_query_operation_name(int operation_id);
@@ -37,6 +39,9 @@ provider-keymgmt - The KEYMGMT library E<lt>-E<gt> provider functions
                        OSSL_CALLBACK *param_cb, void *cbarg);
  const OSSL_PARAM *OP_keymgmt_export_types(int selection);
 
+ /* Key object copy */
+ int OP_keymgmt_copy(void *keydata_to, const void *keydata_from, int selection);
+
  /* Key object validation */
  int OP_keymgmt_validate(void *keydata, int selection);
 
@@ -84,12 +89,14 @@ macros in L<openssl-core_numbers.h(7)>, as follows:
 
  OP_keymgmt_has                  OSSL_FUNC_KEYMGMT_HAS
  OP_keymgmt_validate             OSSL_FUNC_KEYMGMT_VALIDATE
+ OP_keymgmt_match                OSSL_FUNC_KEYMGMT_MATCH
 
  OP_keymgmt_import               OSSL_FUNC_KEYMGMT_IMPORT
  OP_keymgmt_import_types         OSSL_FUNC_KEYMGMT_IMPORT_TYPES
  OP_keymgmt_export               OSSL_FUNC_KEYMGMT_EXPORT
  OP_keymgmt_export_types         OSSL_FUNC_KEYMGMT_EXPORT_TYPES
 
+ OP_keymgmt_copy                 OSSL_FUNC_KEYMGMT_COPY
 
 =head2 Key Objects
 
@@ -239,7 +246,12 @@ B<OSSL_KEYMGMT_SELECT_PUBLIC_KEY> (or B<OSSL_KEYMGMT_SELECT_KEYPAIR>
 for short) is expected to check that the pairwise consistency of
 I<keydata> is valid.
 
-=head2 Key Object Import and Export Functions
+OP_keymgmt_match() should check if the data subset indicated by
+I<selection> in I<keydata1> and I<keydata2> match.  It is assumed that
+the caller has ensured that I<keydata1> and I<keydata2> are both owned
+by the implementation of this function.
+
+=head2 Key Object Import, Export and Copy Functions
 
 OP_keymgmt_import() should import data indicated by I<selection> into
 I<keydata> with values taken from the B<OSSL_PARAM> array I<params>.
@@ -256,6 +268,11 @@ OP_keymgmt_export_types() should return a constant array of descriptor
 B<OSSL_PARAM> for data indicated by I<selection>, that the
 OP_keymgmt_export() callback can expect to receive.
 
+OP_keymgmt_copy() should copy data subsets indicated by I<selection>
+from I<keydata_from> to I<keydata_to>.  It is assumed that the caller
+has ensured that I<keydata_to> and I<keydata_from> are both owned by
+the implementation of this function.
+
 =head2 Built-in RSA Import/Export Types
 
 The following Import/Export types are available for the built-in RSA algorithm:
diff --git a/include/crypto/dsa.h b/include/crypto/dsa.h
index 1da23a8a7b..eab5d44603 100644
--- a/include/crypto/dsa.h
+++ b/include/crypto/dsa.h
@@ -8,6 +8,7 @@
  */
 
 #include <openssl/dsa.h>
+#include "internal/ffc.h"
 
 #define DSA_PARAMGEN_TYPE_FIPS_186_2   1   /* Use legacy FIPS186-2 standard */
 #define DSA_PARAMGEN_TYPE_FIPS_186_4   2   /* Use FIPS186-4 standard */
@@ -21,6 +22,9 @@ int dsa_generate_ffc_parameters(DSA *dsa, int type,
 int dsa_sign_int(int type, const unsigned char *dgst,
                  int dlen, unsigned char *sig, unsigned int *siglen, DSA *dsa);
 const unsigned char *dsa_algorithmidentifier_encoding(int md_nid, size_t *len);
+
+FFC_PARAMS *dsa_get0_params(DSA *dsa);
+
 int dsa_generate_public_key(BN_CTX *ctx, const DSA *dsa, const BIGNUM *priv_key,
                             BIGNUM *pub_key);
 int dsa_check_params(const DSA *dsa, int *ret);
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
index ddba4083e9..7da0258279 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -619,6 +619,9 @@ int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk, size_t index,
 void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk);
 void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
                                 int selection, const OSSL_PARAM params[]);
+int evp_keymgmt_util_has(EVP_PKEY *pk, int selection);
+int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection);
+int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection);
 
 
 /*
@@ -637,6 +640,9 @@ const OSSL_PARAM *evp_keymgmt_settable_params(const EVP_KEYMGMT *keymgmt);
 int evp_keymgmt_has(const EVP_KEYMGMT *keymgmt, void *keyddata, int selection);
 int evp_keymgmt_validate(const EVP_KEYMGMT *keymgmt, void *keydata,
                          int selection);
+int evp_keymgmt_match(const EVP_KEYMGMT *keymgmt,
+                      const void *keydata1, const void *keydata2,
+                      int selection);
 
 int evp_keymgmt_import(const EVP_KEYMGMT *keymgmt, void *keydata,
                        int selection, const OSSL_PARAM params[]);
@@ -646,6 +652,9 @@ int evp_keymgmt_export(const EVP_KEYMGMT *keymgmt, void *keydata,
                        int selection, OSSL_CALLBACK *param_cb, void *cbarg);
 const OSSL_PARAM *evp_keymgmt_export_types(const EVP_KEYMGMT *keymgmt,
                                            int selection);
+int evp_keymgmt_copy(const EVP_KEYMGMT *keymgmt,
+                     void *keydata_to, const void *keydata_from,
+                     int selection);
 
 /* Pulling defines out of C source files */
 
diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h
index 3fd462a8d6..3314a0f665 100644
--- a/include/openssl/core_numbers.h
+++ b/include/openssl/core_numbers.h
@@ -412,7 +412,13 @@ OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_has, (void *keydata, int selection))
 # define OSSL_FUNC_KEYMGMT_VALIDATE                   22
 OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_validate, (void *keydata, int selection))
 
-/* Import and export functions, with ddiscovery */
+/* Key checks - matching */
+# define OSSL_FUNC_KEYMGMT_MATCH                      23
+OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_match,
+                    (const void *keydata1, const void *keydata2,
+                     int selection))
+
+/* Import and export functions, with discovery */
 # define OSSL_FUNC_KEYMGMT_IMPORT                     40
 # define OSSL_FUNC_KEYMGMT_IMPORT_TYPES               41
 # define OSSL_FUNC_KEYMGMT_EXPORT                     42
@@ -427,6 +433,12 @@ OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_export,
 OSSL_CORE_MAKE_FUNC(const OSSL_PARAM *, OP_keymgmt_export_types,
                     (int selection))
 
+/* Copy function, only works for matching keymgmt */
+# define OSSL_FUNC_KEYMGMT_COPY                       44
+OSSL_CORE_MAKE_FUNC(int, OP_keymgmt_copy,
+                    ( void *keydata_to, const void *keydata_from,
+                     int selection))
+
 /* Key Exchange */
 
 # define OSSL_FUNC_KEYEXCH_NEWCTX                      1
diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c
index f4f04eeab8..90a583e7db 100644
--- a/providers/implementations/keymgmt/dh_kmgmt.c
+++ b/providers/implementations/keymgmt/dh_kmgmt.c
@@ -29,6 +29,7 @@ static OSSL_OP_keymgmt_free_fn dh_freedata;
 static OSSL_OP_keymgmt_get_params_fn dh_get_params;
 static OSSL_OP_keymgmt_gettable_params_fn dh_gettable_params;
 static OSSL_OP_keymgmt_has_fn dh_has;
+static OSSL_OP_keymgmt_match_fn dh_match;
 static OSSL_OP_keymgmt_import_fn dh_import;
 static OSSL_OP_keymgmt_import_types_fn dh_import_types;
 static OSSL_OP_keymgmt_export_fn dh_export;
@@ -169,6 +170,25 @@ static int dh_has(void *keydata, int selection)
     return ok;
 }
 
+static int dh_match(const void *keydata1, const void *keydata2, int selection)
+{
+    const DH *dh1 = keydata1;
+    const DH *dh2 = keydata2;
+    int ok = 1;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        ok = ok && BN_cmp(DH_get0_pub_key(dh1), DH_get0_pub_key(dh2)) == 0;
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+        ok = ok && BN_cmp(DH_get0_priv_key(dh1), DH_get0_priv_key(dh2)) == 0;
+    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
+        FFC_PARAMS *dhparams1 = dh_get0_params((DH *)dh1);
+        FFC_PARAMS *dhparams2 = dh_get0_params((DH *)dh2);
+
+        ok = ok && ffc_params_cmp(dhparams1, dhparams2, 1);
+    }
+    return ok;
+}
+
 static int dh_import(void *keydata, int selection, const OSSL_PARAM params[])
 {
     DH *dh = keydata;
@@ -302,6 +322,7 @@ const OSSL_DISPATCH dh_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params },
     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has },
+    { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match },
     { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dh_import },
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dh_import_types },
     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dh_export },
diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c
index 0781f13760..494f284111 100644
--- a/providers/implementations/keymgmt/dsa_kmgmt.c
+++ b/providers/implementations/keymgmt/dsa_kmgmt.c
@@ -29,6 +29,7 @@ static OSSL_OP_keymgmt_free_fn dsa_freedata;
 static OSSL_OP_keymgmt_get_params_fn dsa_get_params;
 static OSSL_OP_keymgmt_gettable_params_fn dsa_gettable_params;
 static OSSL_OP_keymgmt_has_fn dsa_has;
+static OSSL_OP_keymgmt_match_fn dsa_match;
 static OSSL_OP_keymgmt_import_fn dsa_import;
 static OSSL_OP_keymgmt_import_types_fn dsa_import_types;
 static OSSL_OP_keymgmt_export_fn dsa_export;
@@ -175,6 +176,27 @@ static int dsa_has(void *keydata, int selection)
     return ok;
 }
 
+static int dsa_match(const void *keydata1, const void *keydata2, int selection)
+{
+    const DSA *dsa1 = keydata1;
+    const DSA *dsa2 = keydata2;
+    int ok = 1;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        ok = ok
+            && BN_cmp(DSA_get0_pub_key(dsa1), DSA_get0_pub_key(dsa2)) == 0;
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+        ok = ok
+            && BN_cmp(DSA_get0_priv_key(dsa1), DSA_get0_priv_key(dsa2)) == 0;
+    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) {
+        FFC_PARAMS *dsaparams1 = dsa_get0_params((DSA *)dsa1);
+        FFC_PARAMS *dsaparams2 = dsa_get0_params((DSA *)dsa2);
+
+        ok = ok && ffc_params_cmp(dsaparams1, dsaparams2, 1);
+    }
+    return ok;
+}
+
 static int dsa_import(void *keydata, int selection, const OSSL_PARAM params[])
 {
     DSA *dsa = keydata;
@@ -313,6 +335,7 @@ const OSSL_DISPATCH dsa_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dsa_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dsa_gettable_params },
     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dsa_has },
+    { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dsa_match },
     { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))dsa_import },
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))dsa_import_types },
     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))dsa_export },
diff --git a/providers/implementations/keymgmt/ec_kmgmt.c b/providers/implementations/keymgmt/ec_kmgmt.c
index 794dd92499..6a358aa93b 100644
--- a/providers/implementations/keymgmt/ec_kmgmt.c
+++ b/providers/implementations/keymgmt/ec_kmgmt.c
@@ -31,6 +31,7 @@ static OSSL_OP_keymgmt_gettable_params_fn ec_gettable_params;
 static OSSL_OP_keymgmt_set_params_fn ec_set_params;
 static OSSL_OP_keymgmt_settable_params_fn ec_settable_params;
 static OSSL_OP_keymgmt_has_fn ec_has;
+static OSSL_OP_keymgmt_match_fn ec_match;
 static OSSL_OP_keymgmt_import_fn ec_import;
 static OSSL_OP_keymgmt_import_types_fn ec_import_types;
 static OSSL_OP_keymgmt_export_fn ec_export;
@@ -442,6 +443,32 @@ int ec_has(void *keydata, int selection)
     return ok;
 }
 
+static int ec_match(const void *keydata1, const void *keydata2, int selection)
+{
+    const EC_KEY *ec1 = keydata1;
+    const EC_KEY *ec2 = keydata2;
+    const EC_GROUP *group_a = EC_KEY_get0_group(ec1);
+    const EC_GROUP *group_b = EC_KEY_get0_group(ec2);
+    int ok = 1;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0)
+        ok = ok && group_a != NULL && group_b != NULL
+            && EC_GROUP_cmp(group_a, group_b, NULL) == 0;
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+        const BIGNUM *pa = EC_KEY_get0_private_key(ec1);
+        const BIGNUM *pb = EC_KEY_get0_private_key(ec2);
+
+        ok = ok && BN_cmp(pa, pb) == 0;
+    }
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+        const EC_POINT *pa = EC_KEY_get0_public_key(ec1);
+        const EC_POINT *pb = EC_KEY_get0_public_key(ec2);
+
+        ok = ok && EC_POINT_cmp(group_b, pa, pb, NULL);
+    }
+    return ok;
+}
+
 static
 int ec_import(void *keydata, int selection, const OSSL_PARAM params[])
 {
@@ -711,6 +738,7 @@ const OSSL_DISPATCH ec_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))ec_set_params },
     { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))ec_settable_params },
     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ec_has },
+    { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ec_match },
     { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ec_import },
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))ec_import_types },
     { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))ec_export },
diff --git a/providers/implementations/keymgmt/rsa_kmgmt.c b/providers/implementations/keymgmt/rsa_kmgmt.c
index 8f3f25eb60..8c7673ad49 100644
--- a/providers/implementations/keymgmt/rsa_kmgmt.c
+++ b/providers/implementations/keymgmt/rsa_kmgmt.c
@@ -32,6 +32,7 @@ static OSSL_OP_keymgmt_free_fn rsa_freedata;
 static OSSL_OP_keymgmt_get_params_fn rsa_get_params;
 static OSSL_OP_keymgmt_gettable_params_fn rsa_gettable_params;
 static OSSL_OP_keymgmt_has_fn rsa_has;
+static OSSL_OP_keymgmt_match_fn rsa_match;
 static OSSL_OP_keymgmt_validate_fn rsa_validate;
 static OSSL_OP_keymgmt_import_fn rsa_import;
 static OSSL_OP_keymgmt_import_types_fn rsa_import_types;
@@ -203,6 +204,21 @@ static int rsa_has(void *keydata, int selection)
     return ok;
 }
 
+static int rsa_match(const void *keydata1, const void *keydata2, int selection)
+{
+    const RSA *rsa1 = keydata1;
+    const RSA *rsa2 = keydata2;
+    int ok = 1;
+
+    /* There is always an |e| */
+    ok = ok && BN_cmp(RSA_get0_e(rsa1), RSA_get0_e(rsa2)) == 0;
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        ok = ok && BN_cmp(RSA_get0_n(rsa1), RSA_get0_n(rsa2)) == 0;
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)
+        ok = ok && BN_cmp(RSA_get0_d(rsa1), RSA_get0_d(rsa2)) == 0;
+    return ok;
+}
+
 static int rsa_import(void *keydata, int selection, const OSSL_PARAM params[])
 {
     RSA *rsa = keydata;
@@ -399,6 +415,7 @@ const OSSL_DISPATCH rsa_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))rsa_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))rsa_gettable_params },
     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))rsa_has },
+    { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))rsa_match },
     { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))rsa_validate },
     { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))rsa_import },
     { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))rsa_import_types },


More information about the openssl-commits mailing list