]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - crypto/rsa/rsa_ameth.c
Implement EVP_PKEY_dup() function
[thirdparty/openssl.git] / crypto / rsa / rsa_ameth.c
index 7a747a33efab3c00b2e54f844c02a10742a34746..2155eaccd601b798b1cc9fc1c729566b84347bb3 100644 (file)
@@ -884,6 +884,116 @@ static int rsa_pss_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
     return rsa_int_import_from(params, vpctx, RSA_FLAG_TYPE_RSASSAPSS);
 }
 
+static ossl_inline int rsa_bn_dup_check(BIGNUM **out, const BIGNUM *f)
+{
+    if (f != NULL && (*out = BN_dup(f)) == NULL)
+        return 0;
+    return 1;
+}
+
+static RSA *rsa_dup(const RSA *rsa)
+{
+    RSA *dupkey = NULL;
+    int pnum, i;
+
+    /* Do not try to duplicate foreign RSA keys */
+    if (RSA_get_method(rsa) != RSA_PKCS1_OpenSSL())
+        return NULL;
+
+    if ((dupkey = ossl_rsa_new_with_ctx(rsa->libctx)) == NULL)
+        return NULL;
+
+    /* private and public key */
+    if (!rsa_bn_dup_check(&dupkey->n, rsa->n))
+        goto err;
+    if (!rsa_bn_dup_check(&dupkey->e, rsa->e))
+        goto err;
+    if (!rsa_bn_dup_check(&dupkey->d, rsa->d))
+        goto err;
+
+    /* factors and crt params */
+    if (!rsa_bn_dup_check(&dupkey->p, rsa->p))
+        goto err;
+    if (!rsa_bn_dup_check(&dupkey->q, rsa->q))
+        goto err;
+    if (!rsa_bn_dup_check(&dupkey->dmp1, rsa->dmp1))
+        goto err;
+    if (!rsa_bn_dup_check(&dupkey->dmq1, rsa->dmq1))
+        goto err;
+    if (!rsa_bn_dup_check(&dupkey->iqmp, rsa->iqmp))
+        goto err;
+
+    /* multiprime */
+    pnum = sk_RSA_PRIME_INFO_num(rsa->prime_infos);
+    if (pnum > 0) {
+        dupkey->prime_infos = sk_RSA_PRIME_INFO_new_reserve(NULL, pnum);
+        for (i = 0; i < pnum; i++) {
+            const RSA_PRIME_INFO *pinfo = NULL;
+            RSA_PRIME_INFO *duppinfo = NULL;
+
+            if ((duppinfo = OPENSSL_zalloc(sizeof(*duppinfo))) == NULL) {
+                ERR_raise(ERR_LIB_RSA, ERR_R_MALLOC_FAILURE);
+                goto err;
+            }
+            /* push first so cleanup in error case works */
+            (void)sk_RSA_PRIME_INFO_push(dupkey->prime_infos, duppinfo);
+
+            pinfo = sk_RSA_PRIME_INFO_value(rsa->prime_infos, i);
+            if (!rsa_bn_dup_check(&duppinfo->r, pinfo->r))
+                goto err;
+            if (!rsa_bn_dup_check(&duppinfo->d, pinfo->d))
+                goto err;
+            if (!rsa_bn_dup_check(&duppinfo->t, pinfo->t))
+                goto err;
+        }
+        if (!ossl_rsa_multip_calc_product(dupkey))
+            goto err;
+    }
+
+    dupkey->version = rsa->version;
+    dupkey->flags = rsa->flags;
+
+    dupkey->pss_params = rsa->pss_params;
+
+    if (rsa->pss != NULL) {
+        dupkey->pss = RSA_PSS_PARAMS_dup(rsa->pss);
+        if (rsa->pss->maskGenAlgorithm != NULL
+            && dupkey->pss->maskGenAlgorithm == NULL) {
+            dupkey->pss->maskHash = ossl_x509_algor_mgf1_decode(rsa->pss->maskGenAlgorithm);
+            if (dupkey->pss->maskHash == NULL)
+                goto err;
+        }
+    }
+
+    if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_RSA,
+                            &dupkey->ex_data, &rsa->ex_data))
+        goto err;
+
+    return dupkey;
+
+ err:
+    RSA_free(dupkey);
+    return NULL;
+}
+
+static int rsa_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
+{
+    RSA *rsa = from->pkey.rsa;
+    RSA *dupkey = NULL;
+    int ret;
+
+    if (rsa != NULL) {
+        dupkey = rsa_dup(rsa);
+        if (dupkey == NULL)
+            return 0;
+    }
+
+    ret = EVP_PKEY_assign(to, from->type, dupkey);
+    if (!ret)
+        RSA_free(dupkey);
+    return ret;
+}
+
 const EVP_PKEY_ASN1_METHOD ossl_rsa_asn1_meths[2] = {
     {
      EVP_PKEY_RSA,
@@ -923,7 +1033,8 @@ const EVP_PKEY_ASN1_METHOD ossl_rsa_asn1_meths[2] = {
 
      rsa_pkey_dirty_cnt,
      rsa_pkey_export_to,
-     rsa_pkey_import_from
+     rsa_pkey_import_from,
+     rsa_pkey_copy
     },
 
     {
@@ -969,5 +1080,6 @@ const EVP_PKEY_ASN1_METHOD ossl_rsa_pss_asn1_meth = {
 
      rsa_pkey_dirty_cnt,
      rsa_pss_pkey_export_to,
-     rsa_pss_pkey_import_from
+     rsa_pss_pkey_import_from,
+     rsa_pkey_copy
 };