DH: Add export of domain parameters to provider
authorRichard Levitte <levitte@openssl.org>
Mon, 14 Oct 2019 08:10:58 +0000 (10:10 +0200)
committerRichard Levitte <levitte@openssl.org>
Thu, 17 Oct 2019 11:01:14 +0000 (13:01 +0200)
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10169)

crypto/dh/dh_ameth.c
providers/implementations/keymgmt/dh_kmgmt.c

index a699afa..abb9bfd 100644 (file)
@@ -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 = {
index e2999bd..cb9502f 100644 (file)
 #include <openssl/params.h>
 #include "prov/implementations.h"
 
+static OSSL_OP_keymgmt_importdomparams_fn dh_importdomparams;
 static OSSL_OP_keymgmt_importkey_fn dh_importkey;
 
-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 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 +68,34 @@ 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 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 void *dh_importkey(void *provctx, const OSSL_PARAM params[])
 {
     DH *dh;
@@ -82,6 +113,8 @@ 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_FREEDOMPARAMS, (void (*)(void))DH_free },
     { OSSL_FUNC_KEYMGMT_IMPORTKEY, (void (*)(void))dh_importkey },
     { OSSL_FUNC_KEYMGMT_FREEKEY, (void (*)(void))DH_free },
     { 0, NULL }