[openssl] master update

Richard Levitte levitte at openssl.org
Thu Oct 17 11:03:38 UTC 2019


The branch master has been updated
       via  cd32a0f5894344b6c8739a3586a20683a6bf2d5a (commit)
       via  13aa5d29601683e0971763836ec37302fc7cece9 (commit)
       via  c8f2301629b06ef43767d7d2750afaadc3d55deb (commit)
       via  073f59c407b06c1b64d84808f1bee9f9457222f9 (commit)
       via  14e3e00fe2c20a8594e3e20545d9f001fd7fa850 (commit)
       via  02f060d17e667a2805eb0c71266c35de9e7e3864 (commit)
      from  c00d9311c1a8fc7f25a65dcfbdfc90d4e7709e23 (commit)


- Log -----------------------------------------------------------------
commit cd32a0f5894344b6c8739a3586a20683a6bf2d5a
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Oct 15 11:35:09 2019 +0200

    Don't abuse the API when that's not what is tested
    
    test_EVP_PKEY_CTX_get_set_params() in test/evp_extra_test.c abused
    previously sloppy checking in EVP_PKEY_sign_init_ex(), by passing a
    "key to sign with" that was really just domain parameters.
    
    Now that underlying provider import of key payload has become a bit
    more strict, that leads to errors, so we need to provide at least a
    public part (even though fake), and because this is a signing
    operation, a private part as well.
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10169)

commit 13aa5d29601683e0971763836ec37302fc7cece9
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Oct 14 10:37:08 2019 +0200

    DSA: Add export of keys and domain parameters from provider
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10169)

commit c8f2301629b06ef43767d7d2750afaadc3d55deb
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Oct 14 10:36:14 2019 +0200

    DH: Add export of keys and domain parameters from provider
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10169)

commit 073f59c407b06c1b64d84808f1bee9f9457222f9
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Oct 14 10:11:40 2019 +0200

    DSA: Add export of domain parameters to provider
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10169)

commit 14e3e00fe2c20a8594e3e20545d9f001fd7fa850
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Oct 14 10:10:58 2019 +0200

    DH: Add export of domain parameters to provider
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10169)

commit 02f060d17e667a2805eb0c71266c35de9e7e3864
Author: Richard Levitte <levitte at openssl.org>
Date:   Mon Oct 14 08:41:17 2019 +0200

    PKEY: adapt the export_to_provider funtions to handle domain params too
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/10169)

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

Summary of changes:
 crypto/dh/dh_ameth.c                          |  23 +++--
 crypto/dsa/dsa_ameth.c                        |  19 ++--
 crypto/evp/exchange.c                         |   7 +-
 crypto/evp/keymgmt_lib.c                      |  69 +++++++++-----
 crypto/evp/m_sigver.c                         |   3 +-
 crypto/evp/pmeth_fn.c                         |   3 +-
 include/crypto/asn1.h                         |   3 +-
 include/crypto/evp.h                          |  13 ++-
 providers/implementations/keymgmt/dh_kmgmt.c  | 121 +++++++++++++++++++++---
 providers/implementations/keymgmt/dsa_kmgmt.c | 127 ++++++++++++++++++++++----
 test/evp_extra_test.c                         |  17 ++--
 11 files changed, 314 insertions(+), 91 deletions(-)

diff --git a/crypto/dh/dh_ameth.c b/crypto/dh/dh_ameth.c
index a699afabbf..abb9bfdcbe 100644
--- a/crypto/dh/dh_ameth.c
+++ b/crypto/dh/dh_ameth.c
@@ -548,7 +548,8 @@ static size_t dh_pkey_dirty_cnt(const EVP_PKEY *pkey)
     return pkey->pkey.dh->dirty_cnt;
 }
 
-static void *dh_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
+static void *dh_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
+                               int want_domainparams)
 {
     DH *dh = pk->pkey.dh;
     OSSL_PARAM_BLD tmpl;
@@ -556,7 +557,7 @@ static void *dh_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     const BIGNUM *pub_key = DH_get0_pub_key(dh);
     const BIGNUM *priv_key = DH_get0_priv_key(dh);
     OSSL_PARAM *params;
-    void *provkey = NULL;
+    void *provdata = NULL;
 
     if (p == NULL || g == NULL)
         return NULL;
@@ -565,19 +566,15 @@ static void *dh_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_P, p)
         || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_G, g))
         return NULL;
-
     if (q != NULL) {
         if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_Q, q))
             return NULL;
     }
 
-    /*
-     * This may be used to pass domain parameters only without any key data -
-     * so "pub_key" is optional. We can never have a "priv_key" without a
-     * corresponding "pub_key" though.
-     */
-    if (pub_key != NULL) {
-        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_PUB_KEY, pub_key))
+    if (!want_domainparams) {
+        /* A key must at least have a public part. */
+        if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DH_PUB_KEY,
+                                    pub_key))
             return NULL;
 
         if (priv_key != NULL) {
@@ -590,10 +587,12 @@ static void *dh_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     params = ossl_param_bld_to_param(&tmpl);
 
     /* We export, the provider imports */
-    provkey = evp_keymgmt_importkey(keymgmt, params);
+    provdata = want_domainparams
+        ? evp_keymgmt_importdomparams(keymgmt, params)
+        : evp_keymgmt_importkey(keymgmt, params);
 
     ossl_param_bld_free(params);
-    return provkey;
+    return provdata;
 }
 
 const EVP_PKEY_ASN1_METHOD dh_asn1_meth = {
diff --git a/crypto/dsa/dsa_ameth.c b/crypto/dsa/dsa_ameth.c
index b72005af2c..ddd262bdde 100644
--- a/crypto/dsa/dsa_ameth.c
+++ b/crypto/dsa/dsa_ameth.c
@@ -533,7 +533,8 @@ static size_t dsa_pkey_dirty_cnt(const EVP_PKEY *pkey)
     return pkey->pkey.dsa->dirty_cnt;
 }
 
-static void *dsa_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
+static void *dsa_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
+                                int want_domainparams)
 {
     DSA *dsa = pk->pkey.dsa;
     OSSL_PARAM_BLD tmpl;
@@ -541,7 +542,7 @@ static void *dsa_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     const BIGNUM *q = DSA_get0_q(dsa), *pub_key = DSA_get0_pub_key(dsa);
     const BIGNUM *priv_key = DSA_get0_priv_key(dsa);
     OSSL_PARAM *params;
-    void *provkey = NULL;
+    void *provdata = NULL;
 
     if (p == NULL || q == NULL || g == NULL)
         return NULL;
@@ -552,12 +553,8 @@ static void *dsa_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
         || !ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_FFC_G, g))
         return NULL;
 
-    /*
-     * This may be used to pass domain parameters only without any key data -
-     * so "pub_key" is optional. We can never have a "priv_key" without a
-     * corresponding "pub_key" though.
-     */
-    if (pub_key != NULL) {
+    if (!want_domainparams) {
+        /* A key must at least have a public part. */
         if (!ossl_param_bld_push_BN(&tmpl, OSSL_PKEY_PARAM_DSA_PUB_KEY,
                                     pub_key))
             return NULL;
@@ -572,10 +569,12 @@ static void *dsa_pkey_export_to(const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     params = ossl_param_bld_to_param(&tmpl);
 
     /* We export, the provider imports */
-    provkey = evp_keymgmt_importkey(keymgmt, params);
+    provdata = want_domainparams
+        ? evp_keymgmt_importdomparams(keymgmt, params)
+        : evp_keymgmt_importkey(keymgmt, params);
 
     ossl_param_bld_free(params);
-    return provkey;
+    return provdata;
 }
 
 /* NB these are sorted in pkey_id order, lowest first */
diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index faece8af3c..dfc309ecd7 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -224,7 +224,8 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange)
 
     ctx->op.kex.exchange = exchange;
     if (ctx->pkey != NULL) {
-        provkey = evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt);
+        provkey =
+            evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt, 0);
         if (provkey == NULL) {
             EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);
             goto err;
@@ -283,8 +284,8 @@ int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer)
         return -2;
     }
 
-    provkey = evp_keymgmt_export_to_provider(peer,
-                                             ctx->op.kex.exchange->keymgmt);
+    provkey =
+        evp_keymgmt_export_to_provider(peer, ctx->op.kex.exchange->keymgmt, 0);
     if (provkey == NULL) {
         EVPerr(EVP_F_EVP_PKEY_DERIVE_SET_PEER, ERR_R_INTERNAL_ERROR);
         return 0;
diff --git a/crypto/evp/keymgmt_lib.c b/crypto/evp/keymgmt_lib.c
index 0eb12ca317..87629157e2 100644
--- a/crypto/evp/keymgmt_lib.c
+++ b/crypto/evp/keymgmt_lib.c
@@ -52,6 +52,9 @@ static void *allocate_params_space(OSSL_PARAM *params)
     for (space = 0, p = params; p->key != NULL; p++)
         space += ((p->return_size + ALIGN_SIZE - 1) / ALIGN_SIZE) * ALIGN_SIZE;
 
+    if (space == 0)
+        return NULL;
+
     data = OPENSSL_zalloc(space);
 
     for (space = 0, p = params; p->key != NULL; p++) {
@@ -62,9 +65,10 @@ static void *allocate_params_space(OSSL_PARAM *params)
     return data;
 }
 
-void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
+void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
+                                     int want_domainparams)
 {
-    void *provkey = NULL;
+    void *provdata = NULL;
     size_t i, j;
 
     /*
@@ -90,8 +94,9 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
     for (i = 0;
          i < OSSL_NELEM(pk->pkeys) && pk->pkeys[i].keymgmt != NULL;
          i++) {
-        if (keymgmt == pk->pkeys[i].keymgmt)
-            return pk->pkeys[i].provkey;
+        if (keymgmt == pk->pkeys[i].keymgmt
+            && want_domainparams == pk->pkeys[i].domainparams)
+            return pk->pkeys[i].provdata;
     }
 
     if (pk->pkey.ptr != NULL) {
@@ -101,11 +106,11 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
         if (pk->ameth->export_to == NULL)
             return NULL;
 
-        /* Otherwise, simply use it */
-        provkey = pk->ameth->export_to(pk, keymgmt);
+        /* Otherwise, simply use it. */
+        provdata = pk->ameth->export_to(pk, keymgmt, want_domainparams);
 
         /* Synchronize the dirty count, but only if we exported successfully */
-        if (provkey != NULL)
+        if (provdata != NULL)
             pk->dirty_cnt_copy = pk->ameth->dirty_cnt(pk);
 
     } else {
@@ -116,10 +121,13 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
          * the new provider.
          */
 
+        void *(*importfn)(void *provctx, const OSSL_PARAM params[]) =
+            want_domainparams ? keymgmt->importdomparams : keymgmt->importkey;
+
         /*
          * If the given keymgmt doesn't have an import function, give up
          */
-        if (keymgmt->importkey == NULL)
+        if (importfn == NULL)
             return NULL;
 
         for (j = 0; j < i && pk->pkeys[j].keymgmt != NULL; j++) {
@@ -129,6 +137,14 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
                 void *data = NULL;
                 void *provctx =
                     ossl_provider_ctx(EVP_KEYMGMT_provider(keymgmt));
+                int (*exportfn)(void *provctx, OSSL_PARAM params[]) = NULL;
+
+                if (pk->pkeys[j].domainparams != want_domainparams)
+                    continue;
+
+                exportfn = want_domainparams
+                    ? pk->pkeys[j].keymgmt->exportdomparams
+                    : pk->pkeys[j].keymgmt->exportkey;
 
                 paramdefs = pk->pkeys[j].keymgmt->exportkey_types();
                 /*
@@ -138,29 +154,35 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
                  */
                 params = paramdefs_to_params(paramdefs);
                 /* Get 'return_size' filled */
-                pk->pkeys[j].keymgmt->exportkey(pk->pkeys[j].provkey, params);
+                exportfn(pk->pkeys[j].provdata, params);
 
                 /*
                  * Allocate space and assign 'data' to point into the
-                 * data block
+                 * data block.
+                 * If something goes wrong, go to the next cached key.
                  */
-                data = allocate_params_space(params);
+                if ((data = allocate_params_space(params)) == NULL)
+                    goto cont;
 
                 /*
                  * Call the exportkey function a second time, to get
-                 * the data filled
+                 * the data filled.
+                 * If something goes wrong, go to the next cached key.
                  */
-                pk->pkeys[j].keymgmt->exportkey(pk->pkeys[j].provkey, params);
+                if (!exportfn(pk->pkeys[j].provdata, params))
+                    goto cont;
 
                 /*
                  * We should have all the data at this point, so import
                  * into the new provider and hope to get a key back.
                  */
-                provkey = keymgmt->importkey(provctx, params);
+                provdata = importfn(provctx, params);
+
+             cont:
                 OPENSSL_free(params);
                 OPENSSL_free(data);
 
-                if (provkey != NULL)
+                if (provdata != NULL)
                     break;
             }
         }
@@ -173,12 +195,14 @@ void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
      */
     j = ossl_assert(i < OSSL_NELEM(pk->pkeys));
 
-    if (provkey != NULL) {
+    if (provdata != NULL) {
         EVP_KEYMGMT_up_ref(keymgmt);
         pk->pkeys[i].keymgmt = keymgmt;
-        pk->pkeys[i].provkey = provkey;
+        pk->pkeys[i].provdata = provdata;
+        pk->pkeys[i].domainparams = want_domainparams;
     }
-    return provkey;
+
+    return provdata;
 }
 
 void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk)
@@ -190,11 +214,14 @@ void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk)
              i < OSSL_NELEM(pk->pkeys) && pk->pkeys[i].keymgmt != NULL;
              i++) {
             EVP_KEYMGMT *keymgmt = pk->pkeys[i].keymgmt;
-            void *provkey = pk->pkeys[i].provkey;
+            void *provdata = pk->pkeys[i].provdata;
 
             pk->pkeys[i].keymgmt = NULL;
-            pk->pkeys[i].provkey = NULL;
-            keymgmt->freekey(provkey);
+            pk->pkeys[i].provdata = NULL;
+            if (pk->pkeys[i].domainparams)
+                keymgmt->freedomparams(provdata);
+            else
+                keymgmt->freekey(provdata);
             EVP_KEYMGMT_free(keymgmt);
         }
     }
diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c
index 7912c8dd59..c02325cf6b 100644
--- a/crypto/evp/m_sigver.c
+++ b/crypto/evp/m_sigver.c
@@ -94,7 +94,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
         ERR_raise(ERR_LIB_EVP,  EVP_R_INITIALIZATION_ERROR);
         goto err;
     }
-    provkey = evp_keymgmt_export_to_provider(locpctx->pkey, signature->keymgmt);
+    provkey =
+        evp_keymgmt_export_to_provider(locpctx->pkey, signature->keymgmt, 0);
     if (provkey == NULL) {
         ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
         goto err;
diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c
index a78839b992..d06edb218b 100644
--- a/crypto/evp/pmeth_fn.c
+++ b/crypto/evp/pmeth_fn.c
@@ -393,7 +393,8 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, EVP_SIGNATURE *signature,
 
     ctx->op.sig.signature = signature;
     if (ctx->pkey != NULL) {
-        provkey = evp_keymgmt_export_to_provider(ctx->pkey, signature->keymgmt);
+        provkey =
+            evp_keymgmt_export_to_provider(ctx->pkey, signature->keymgmt, 0);
         if (provkey == NULL) {
             EVPerr(0, EVP_R_INITIALIZATION_ERROR);
             goto err;
diff --git a/include/crypto/asn1.h b/include/crypto/asn1.h
index 674fa704a1..2581619831 100644
--- a/include/crypto/asn1.h
+++ b/include/crypto/asn1.h
@@ -70,7 +70,8 @@ struct evp_pkey_asn1_method_st {
      */
     /* Exports to providers */
     size_t (*dirty_cnt) (const EVP_PKEY *pk);
-    void *(*export_to) (const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt);
+    void *(*export_to) (const EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
+                        int want_domainparams);
 } /* EVP_PKEY_ASN1_METHOD */ ;
 
 DEFINE_STACK_OF_CONST(EVP_PKEY_ASN1_METHOD)
diff --git a/include/crypto/evp.h b/include/crypto/evp.h
index 22ef7e5602..dad7174bc5 100644
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -538,13 +538,15 @@ struct evp_pkey_st {
     /*
      * To support transparent export/import between providers that
      * support the methods for it, and still not having to do the
-     * export/import every time a key is used, we maintain a cache
-     * of imported key, indexed by provider address.
-     * pkeys[0] is *always* the "original" key.
+     * export/import every time a key or domain params are used, we
+     * maintain a cache of imported key / domain params, indexed by
+     * provider address.  pkeys[0] is *always* the "original" data.
      */
     struct {
         EVP_KEYMGMT *keymgmt;
-        void *provkey;
+        void *provdata;
+        /* 0 = provdata is a key, 1 = provdata is domain params */
+        int domainparams;
     } pkeys[10];
     /*
      * If there is a legacy key assigned to this structure, we keep
@@ -569,7 +571,8 @@ void evp_cleanup_int(void);
 void evp_app_cleanup_int(void);
 
 /* KEYMGMT helper functions */
-void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt);
+void *evp_keymgmt_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt,
+                                     int domainparams);
 void evp_keymgmt_clear_pkey_cache(EVP_PKEY *pk);
 
 /* KEYMGMT provider interface functions */
diff --git a/providers/implementations/keymgmt/dh_kmgmt.c b/providers/implementations/keymgmt/dh_kmgmt.c
index e2999bde18..4120155619 100644
--- a/providers/implementations/keymgmt/dh_kmgmt.c
+++ b/providers/implementations/keymgmt/dh_kmgmt.c
@@ -14,18 +14,67 @@
 #include <openssl/params.h>
 #include "prov/implementations.h"
 
+static OSSL_OP_keymgmt_importdomparams_fn dh_importdomparams;
+static OSSL_OP_keymgmt_exportdomparams_fn dh_exportdomparams;
 static OSSL_OP_keymgmt_importkey_fn dh_importkey;
+static OSSL_OP_keymgmt_exportkey_fn dh_exportkey;
 
-static int params_to_key(DH *dh, const OSSL_PARAM params[])
+static int params_to_domparams(DH *dh, const OSSL_PARAM params[])
 {
-    const OSSL_PARAM *param_p, *param_g, *param_priv_key, *param_pub_key;
-    BIGNUM *p = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL;
+    const OSSL_PARAM *param_p, *param_g;
+    BIGNUM *p = NULL, *g = NULL;
 
     if (dh == NULL)
         return 0;
 
     param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P);
     param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G);
+
+    if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
+        || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g)))
+        goto err;
+
+    if (!DH_set0_pqg(dh, p, NULL, g))
+        goto err;
+
+    return 1;
+
+ err:
+    BN_free(p);
+    BN_free(g);
+    return 0;
+}
+
+static int domparams_to_params(DH *dh, OSSL_PARAM params[])
+{
+    OSSL_PARAM *p;
+    const BIGNUM *dh_p = NULL, *dh_g = NULL;
+
+    if (dh == NULL)
+        return 0;
+
+    DH_get0_pqg(dh, &dh_p, NULL, &dh_g);
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_FFC_P)) != NULL
+        && !OSSL_PARAM_set_BN(p, dh_p))
+        return 0;
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_FFC_G)) != NULL
+        && !OSSL_PARAM_set_BN(p, dh_g))
+        return 0;
+
+    return 1;
+}
+
+static int params_to_key(DH *dh, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *param_priv_key, *param_pub_key;
+    BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+    if (dh == NULL)
+        return 0;
+
+    if (!params_to_domparams(dh, params))
+        return 0;
+
     param_priv_key =
         OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_KEY);
     param_pub_key =
@@ -40,31 +89,64 @@ static int params_to_key(DH *dh, const OSSL_PARAM params[])
     if (param_pub_key == NULL)
         return 0;
 
-    if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
-        || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g))
-        || (param_priv_key != NULL
-            && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
+    if ((param_priv_key != NULL
+         && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
         || !OSSL_PARAM_get_BN(param_pub_key, &pub_key))
         goto err;
 
-    if (!DH_set0_pqg(dh, p, NULL, g))
-        goto err;
-    p = g = NULL;
-
     if (!DH_set0_key(dh, pub_key, priv_key))
         goto err;
-    priv_key = pub_key = NULL;
 
     return 1;
 
  err:
-    BN_free(p);
-    BN_free(g);
     BN_free(priv_key);
     BN_free(pub_key);
     return 0;
 }
 
+static int key_to_params(DH *dh, OSSL_PARAM params[])
+{
+    OSSL_PARAM *p;
+    const BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+    if (dh == NULL)
+        return 0;
+    if (!domparams_to_params(dh, params))
+        return 0;
+
+    DH_get0_key(dh, &pub_key, &priv_key);
+    if ((p = OSSL_PARAM_locate(params,
+                                     OSSL_PKEY_PARAM_DH_PRIV_KEY)) != NULL
+        && !OSSL_PARAM_set_BN(p, priv_key))
+        return 0;
+    if ((p = OSSL_PARAM_locate(params,
+                                     OSSL_PKEY_PARAM_DH_PUB_KEY)) != NULL
+        && !OSSL_PARAM_set_BN(p, pub_key))
+        return 0;
+
+    return 1;
+}
+
+static void *dh_importdomparams(void *provctx, const OSSL_PARAM params[])
+{
+    DH *dh;
+
+    if ((dh = DH_new()) == NULL
+        || !params_to_domparams(dh, params)) {
+        DH_free(dh);
+        dh = NULL;
+    }
+    return dh;
+}
+
+static int dh_exportdomparams(void *domparams, OSSL_PARAM params[])
+{
+    DH *dh = domparams;
+
+    return dh != NULL && !domparams_to_params(dh, params);
+}
+
 static void *dh_importkey(void *provctx, const OSSL_PARAM params[])
 {
     DH *dh;
@@ -77,12 +159,23 @@ static void *dh_importkey(void *provctx, const OSSL_PARAM params[])
     return dh;
 }
 
+static int dh_exportkey(void *key, OSSL_PARAM params[])
+{
+    DH *dh = key;
+
+    return dh != NULL && !key_to_params(dh, params);
+}
+
 const OSSL_DISPATCH dh_keymgmt_functions[] = {
     /*
      * TODO(3.0) When implementing OSSL_FUNC_KEYMGMT_GENKEY, remember to also
      * implement OSSL_FUNC_KEYMGMT_EXPORTKEY.
      */
+    { OSSL_FUNC_KEYMGMT_IMPORTDOMPARAMS, (void (*)(void))dh_importdomparams },
+    { OSSL_FUNC_KEYMGMT_EXPORTDOMPARAMS, (void (*)(void))dh_exportdomparams },
+    { OSSL_FUNC_KEYMGMT_FREEDOMPARAMS, (void (*)(void))DH_free },
     { OSSL_FUNC_KEYMGMT_IMPORTKEY, (void (*)(void))dh_importkey },
+    { OSSL_FUNC_KEYMGMT_EXPORTKEY, (void (*)(void))dh_exportkey },
     { OSSL_FUNC_KEYMGMT_FREEKEY, (void (*)(void))DH_free },
     { 0, NULL }
 };
diff --git a/providers/implementations/keymgmt/dsa_kmgmt.c b/providers/implementations/keymgmt/dsa_kmgmt.c
index 818a451bb9..a3bf11a570 100644
--- a/providers/implementations/keymgmt/dsa_kmgmt.c
+++ b/providers/implementations/keymgmt/dsa_kmgmt.c
@@ -14,13 +14,15 @@
 #include <openssl/params.h>
 #include "prov/implementations.h"
 
+static OSSL_OP_keymgmt_importdomparams_fn dsa_importdomparams;
+static OSSL_OP_keymgmt_exportdomparams_fn dsa_exportdomparams;
 static OSSL_OP_keymgmt_importkey_fn dsa_importkey;
+static OSSL_OP_keymgmt_exportkey_fn dsa_exportkey;
 
-static int params_to_key(DSA *dsa, const OSSL_PARAM params[])
+static int params_to_domparams(DSA *dsa, const OSSL_PARAM params[])
 {
-    const OSSL_PARAM *param_p, *param_q, *param_g, *param_priv_key;
-    const OSSL_PARAM *param_pub_key;
-    BIGNUM *p = NULL, *q = NULL, *g = NULL, *priv_key = NULL, *pub_key = NULL;
+    const OSSL_PARAM *param_p, *param_q, *param_g;
+    BIGNUM *p = NULL, *q = NULL, *g = NULL;
 
     if (dsa == NULL)
         return 0;
@@ -28,6 +30,57 @@ static int params_to_key(DSA *dsa, const OSSL_PARAM params[])
     param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P);
     param_q = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_Q);
     param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G);
+
+    if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
+        || (param_q != NULL && !OSSL_PARAM_get_BN(param_q, &q))
+        || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g)))
+        goto err;
+
+    if (!DSA_set0_pqg(dsa, p, q, g))
+        goto err;
+
+    return 1;
+
+ err:
+    BN_free(p);
+    BN_free(q);
+    BN_free(g);
+    return 0;
+}
+
+static int domparams_to_params(DSA *dsa, OSSL_PARAM params[])
+{
+    OSSL_PARAM *p;
+    const BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL;
+
+    if (dsa == NULL)
+        return 0;
+
+    DSA_get0_pqg(dsa, &dsa_p, &dsa_q, &dsa_g);
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_FFC_P)) != NULL
+        && !OSSL_PARAM_set_BN(p, dsa_p))
+        return 0;
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_FFC_Q)) != NULL
+        && !OSSL_PARAM_set_BN(p, dsa_q))
+        return 0;
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_FFC_G)) != NULL
+        && !OSSL_PARAM_set_BN(p, dsa_g))
+        return 0;
+
+    return 1;
+}
+
+static int params_to_key(DSA *dsa, const OSSL_PARAM params[])
+{
+    const OSSL_PARAM *param_priv_key, *param_pub_key;
+    BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+    if (dsa == NULL)
+        return 0;
+
+    if (!params_to_domparams(dsa, params))
+        return 0;
+
     param_priv_key =
         OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DSA_PRIV_KEY);
     param_pub_key =
@@ -40,34 +93,63 @@ static int params_to_key(DSA *dsa, const OSSL_PARAM params[])
     if (param_priv_key != NULL && param_pub_key == NULL)
         return 0;
 
-    if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p))
-        || (param_q != NULL && !OSSL_PARAM_get_BN(param_q, &q))
-        || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g))
-        || (param_priv_key != NULL
-            && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
+    if ((param_priv_key != NULL
+         && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
         || (param_pub_key != NULL
             && !OSSL_PARAM_get_BN(param_pub_key, &pub_key)))
         goto err;
 
-    if (!DSA_set0_pqg(dsa, p, q, g))
-        goto err;
-    p = q = g = NULL;
-
     if (pub_key != NULL && !DSA_set0_key(dsa, pub_key, priv_key))
         goto err;
-    priv_key = pub_key = NULL;
 
     return 1;
 
  err:
-    BN_free(p);
-    BN_free(q);
-    BN_free(g);
     BN_free(priv_key);
     BN_free(pub_key);
     return 0;
 }
 
+static int key_to_params(DSA *dsa, OSSL_PARAM params[])
+{
+    OSSL_PARAM *p;
+    const BIGNUM *priv_key = NULL, *pub_key = NULL;
+
+    if (dsa == NULL)
+        return 0;
+    if (!domparams_to_params(dsa, params))
+        return 0;
+
+    DSA_get0_key(dsa, &pub_key, &priv_key);
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DSA_PRIV_KEY)) != NULL
+        && !OSSL_PARAM_set_BN(p, priv_key))
+        return 0;
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DSA_PUB_KEY)) != NULL
+        && !OSSL_PARAM_set_BN(p, pub_key))
+        return 0;
+
+    return 1;
+}
+
+static void *dsa_importdomparams(void *provctx, const OSSL_PARAM params[])
+{
+    DSA *dsa;
+
+    if ((dsa = DSA_new()) == NULL
+        || !params_to_domparams(dsa, params)) {
+        DSA_free(dsa);
+        dsa = NULL;
+    }
+    return dsa;
+}
+
+static int dsa_exportdomparams(void *domparams, OSSL_PARAM params[])
+{
+    DSA *dsa = domparams;
+
+    return dsa != NULL && !domparams_to_params(dsa, params);
+}
+
 static void *dsa_importkey(void *provctx, const OSSL_PARAM params[])
 {
     DSA *dsa;
@@ -80,12 +162,23 @@ static void *dsa_importkey(void *provctx, const OSSL_PARAM params[])
     return dsa;
 }
 
+static int dsa_exportkey(void *key, OSSL_PARAM params[])
+{
+    DSA *dsa = key;
+
+    return dsa != NULL && !key_to_params(dsa, params);
+}
+
 const OSSL_DISPATCH dsa_keymgmt_functions[] = {
     /*
      * TODO(3.0) When implementing OSSL_FUNC_KEYMGMT_GENKEY, remember to also
      * implement OSSL_FUNC_KEYMGMT_EXPORTKEY.
      */
+    { OSSL_FUNC_KEYMGMT_IMPORTDOMPARAMS, (void (*)(void))dsa_importdomparams },
+    { OSSL_FUNC_KEYMGMT_EXPORTDOMPARAMS, (void (*)(void))dsa_exportdomparams },
+    { OSSL_FUNC_KEYMGMT_FREEDOMPARAMS, (void (*)(void))DSA_free },
     { OSSL_FUNC_KEYMGMT_IMPORTKEY, (void (*)(void))dsa_importkey },
+    { OSSL_FUNC_KEYMGMT_EXPORTKEY, (void (*)(void))dsa_exportkey },
     { OSSL_FUNC_KEYMGMT_FREEKEY, (void (*)(void))DSA_free },
     { 0, NULL }
 };
diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c
index 3a843e6a43..cea1c318c6 100644
--- a/test/evp_extra_test.c
+++ b/test/evp_extra_test.c
@@ -1201,7 +1201,7 @@ static int test_EVP_PKEY_CTX_get_set_params(void)
     const OSSL_PARAM *params;
     OSSL_PARAM ourparams[2], *param = ourparams;
     DSA *dsa = NULL;
-    BIGNUM *p = NULL, *q = NULL, *g = NULL;
+    BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub = NULL, *priv = NULL;
     EVP_PKEY *pkey = NULL;
     int ret = 0;
     const EVP_MD *md;
@@ -1209,21 +1209,24 @@ static int test_EVP_PKEY_CTX_get_set_params(void)
     char ssl3ms[48];
 
     /*
-     * Setup the parameters for our DSA object. For our purposes they don't have
-     * to actually be *valid* parameters. We just need to set something. We
-     * don't even need a pub_key/priv_key.
+     * Setup the parameters for our DSA object. For our purposes they don't
+     * have to actually be *valid* parameters. We just need to set something.
      */
     dsa = DSA_new();
     p = BN_new();
     q = BN_new();
     g = BN_new();
+    pub = BN_new();
+    priv = BN_new();
     if (!TEST_ptr(dsa)
             || !TEST_ptr(p)
             || !TEST_ptr(q)
             || !TEST_ptr(g)
-            || !DSA_set0_pqg(dsa, p, q, g))
+            || !TEST_ptr(pub)
+            || !DSA_set0_pqg(dsa, p, q, g)
+        || !DSA_set0_key(dsa, pub, priv))
         goto err;
-    p = q = g = NULL;
+    p = q = g = pub = priv = NULL;
 
     pkey = EVP_PKEY_new();
     if (!TEST_ptr(pkey)
@@ -1331,6 +1334,8 @@ static int test_EVP_PKEY_CTX_get_set_params(void)
     BN_free(p);
     BN_free(q);
     BN_free(g);
+    BN_free(pub);
+    BN_free(priv);
 
     return ret;
 }


More information about the openssl-commits mailing list