I'm working on a TLS implementation (using OpenSSL 1.0.1s) that currently employs 1024-bit RSA keys for both encryption and authentication. I want to upgrade to EC for performance reasons, but I need to remain backward compatible.

So I decided to use OpenSSL's EVP API to have as much common code as possible. But, I've run into a problem when I want to read certificates from my RAM (stored in ASN.1 DER format), I can't find a way to completely copy an EVP_PKEY struct (no PKEY_dup or PKEY_copy or anything of the sort).

I want to avoid switch-casing the EVP_PKEY.type so the next upgrade will be smoother, any suggestions?


I managed to duplicate by converting to DER and back. the general i2d/d2i functions call the specific ones.


error_code_ENUM read_evp_pkey_from_ram (int       index,
                                        int       DB_ID,
                                        EVP_PKEY  **pkey_ptr_PTR){
  EVP_PKEY           *pkey;
  unsigned char      *p;
  unsigned char      *DER_PTR;
  int                DER_size;
  int                pub_len, priv_len, type;

  *pkey_ptr_PTR = NULL;

   if ((pkey = sensitive_EVP_PKEY_data[DB_ID][index]) == NULL)
     return error_code_no_key;

   type = pkey->type;
   /*passing NULL to char *out returns the length only*/
   pub_len = i2d_PUBKEY(pkey, NULL);
   priv_len = i2d_PrivateKey(pkey, NULL);
   if (pub_len <= 0 || priv_len <= 0 )
       return error_code_general_error;

   DER_size = pub_len + priv_len + 2 * sizeof(UINT_16);
   if ((DER_PTR = OPENSSL_malloc(DER_size)) == NULL)
       return error_code_no_memory;

    * store the key in buffer as:
    * |public key length | public key | private key length | private key|
   p = DER_PTR;
   *(UINT_16*)p = pub_len;
   p += 2;
   pub_len = i2d_PUBKEY(pkey,&p);/*p is incremented here by the key size*/
   *(UINT_16*)p = priv_len;
   p += 2;
   priv_len = i2d_PrivateKey(pkey,&p);

   p = DER_PTR + 2;
   /*pass NULL to EVP_PKEY *key causes a fresh EVP_PKEY struct to be allocated and a pointer to it returned*/
   pkey = d2i_PUBKEY(NULL, (const unsigned char **)&p, pub_len);
   if (pkey == NULL){
      return error_code_general_error;

   priv_len = *(UINT_16 *)p;
   if (priv_len == 0){
       return error_code_general_error;

   p += 2;
   /*now pass &pkey*/
   if (d2i_PrivateKey(type, &pkey, (const unsigned char **)&p, priv_len) == NULL){
           return error_code_general_error;


   *pkey_ptr_PTR = pkey;

   return error_code_no_error;

note that i2d/d2i functions increment the pointers they are given

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.