6

I found the function EVP_PKEY_copy_parameters, which can copy EVP_PKEY. But some documentations about this function says it can only be used for DSA/ECC algorithms. The official documentation (from openssl.org) does not mention whether the function can be used for RSA EVP_PKEYs.

Another implementation for EVP_PKEY (that contains an RSA key) could be this:

EVP_PKEY_assign_RSA(RSAPrivateKey_dup(EVP_PKEY_get1_RSA(pkey)));

Do you have any suggestions?

jweyrich
  • 31,198
  • 5
  • 66
  • 97
uping
  • 61
  • 1
  • 5

2 Answers2

6

If you don't really need to duplicate the key, you can just increment its reference count, like this:

CRYPTO_add(&your_evp_pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);

Otherwise, a similar (almost identical) approach to what you suggested would be the following:

int pkey_rsa_dup(EVP_PKEY *dst_pkey, EVP_PKEY *src_key) {
    // Validate underlying key type - Only allow a RSA key
    if (src_key->type != EVP_PKEY_RSA)
        return -1;

    RSA *rsa = EVP_PKEY_get1_RSA(src_key); // Get the underlying RSA key
    RSA *dup_rsa = RSAPrivateKey_dup(rsa); // Duplicate the RSA key
    RSA_free(rsa); // Decrement reference count

    EVP_PKEY_set1_RSA(dst_pkey, dup_rsa); // Set the underlying RSA key in dst_pkey
    // EVP_PKEY_set1_RSA also adjusts the other members in dst_pkey

    return 0;
}

Reference: Re: How to duplicate an EVP_PKEY -> As @X-Istence says below, the RSA_dup method suggested in this reference thread doesn't exist in OpenSSL (at least until the date of this update).

jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • RSA_dup doesn't exist anywhere in the OpenSSL source code. Specifically in that same email thread, the follow-up by the same poster says as much: http://www.mail-archive.com/openssl-users@openssl.org/msg17617.html – X-Istence Apr 03 '13 at 11:49
  • `dst_pkey` leaks – Tomilov Anatoliy May 12 '17 at 18:04
  • @Orient you're right. Thanks! I had a bogus/unnecessary allocation for `dst_pkey`. The passed argument must reference a pre-allocated pkey. – jweyrich May 12 '17 at 20:59
2

In OpenSSL 1.0.0d, EVP_PKEY_copy_parameters should work. However, judging from the implementation, it just seems to copy the public parameters:

static int pkey_rsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) {
    RSA_PKEY_CTX *dctx, *sctx;
    if (!pkey_rsa_init(dst))
        return 0;
    sctx = src->data;
    dctx = dst->data;
    dctx->nbits = sctx->nbits;
    if (sctx->pub_exp) {
        dctx->pub_exp = BN_dup(sctx->pub_exp);
        if (!dctx->pub_exp)
            return 0;
    }
    dctx->pad_mode = sctx->pad_mode;
    dctx->md = sctx->md;
    return 1;
}

Apart from jweyrich's solution, another simple method is to first i2d_RSAPrivateKey your RSA key then d2i_RSAPrivateKey it again - there's your copy :)

emboss
  • 38,880
  • 7
  • 101
  • 108
  • 1
    Instead of i2d/d2i methods that require you to know what the underlying type is, use PEM_write_PrivateKey/PEM_read_PrivateKey instead. This way RSA, DH, EC, and DSA private keys are all copied without explicitly knowing the underlying type. – X-Istence Apr 03 '13 at 11:51
  • I'll use i2d/d2i for another purpose. This answer really saved me days and days of work... Now, i'll fit to tomorrow's deadline.... Thanks a lot, man – Petro Korienev Nov 12 '13 at 15:55