Implement EVP_PKEY_dup() function
[openssl.git] / crypto / dsa / dsa_ameth.c
index e4c739daf91ec51995eb11be0898282520fd27fb..1009f1a5c7af44ee80b5e07cf9bed989e8449545 100644 (file)
@@ -475,7 +475,7 @@ static int dsa_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
     rv = evp_keymgmt_import(to_keymgmt, to_keydata, selection, params);
 
     OSSL_PARAM_BLD_free_params(params);
     rv = evp_keymgmt_import(to_keymgmt, to_keydata, selection, params);
 
     OSSL_PARAM_BLD_free_params(params);
-err:
+ err:
     OSSL_PARAM_BLD_free(tmpl);
     return rv;
 }
     OSSL_PARAM_BLD_free(tmpl);
     return rv;
 }
@@ -500,6 +500,63 @@ static int dsa_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
     return 1;
 }
 
     return 1;
 }
 
+static ossl_inline int dsa_bn_dup_check(BIGNUM **out, const BIGNUM *f)
+{
+    if (f != NULL && (*out = BN_dup(f)) == NULL)
+        return 0;
+    return 1;
+}
+
+static DSA *dsa_dup(const DSA *dsa)
+{
+    DSA *dupkey = NULL;
+
+    /* Do not try to duplicate foreign DSA keys */
+    if (DSA_get_method((DSA *)dsa) != DSA_OpenSSL())
+        return NULL;
+
+    if ((dupkey = ossl_dsa_new(dsa->libctx)) == NULL)
+        return NULL;
+
+    if (!ossl_ffc_params_copy(&dupkey->params, &dsa->params))
+        goto err;
+
+    dupkey->flags = dsa->flags;
+
+    if (!dsa_bn_dup_check(&dupkey->pub_key, dsa->pub_key))
+        goto err;
+    if (!dsa_bn_dup_check(&dupkey->priv_key, dsa->priv_key))
+        goto err;
+
+    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_DSA,
+                            &dupkey->ex_data, &dsa->ex_data))
+        goto err;
+
+    return dupkey;
+
+ err:
+    DSA_free(dupkey);
+    return NULL;
+}
+
+static int dsa_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
+{
+    DSA *dsa = from->pkey.dsa;
+    DSA *dupkey = NULL;
+    int ret;
+
+    if (dsa != NULL) {
+        dupkey = dsa_dup(dsa);
+        if (dupkey == NULL)
+            return 0;
+    }
+
+    ret = EVP_PKEY_assign_DSA(to, dupkey);
+    if (!ret)
+        DSA_free(dupkey);
+    return ret;
+}
+
 /* NB these are sorted in pkey_id order, lowest first */
 
 const EVP_PKEY_ASN1_METHOD ossl_dsa_asn1_meths[5] = {
 /* NB these are sorted in pkey_id order, lowest first */
 
 const EVP_PKEY_ASN1_METHOD ossl_dsa_asn1_meths[5] = {
@@ -564,6 +621,7 @@ const EVP_PKEY_ASN1_METHOD ossl_dsa_asn1_meths[5] = {
 
      dsa_pkey_dirty_cnt,
      dsa_pkey_export_to,
 
      dsa_pkey_dirty_cnt,
      dsa_pkey_export_to,
-     dsa_pkey_import_from
+     dsa_pkey_import_from,
+     dsa_pkey_copy
     }
 };
     }
 };