如何在不知道基础算法的情况下复制EVP_PKEY结构?

时间:2016-08-08 11:04:43

标签: c openssl

我正在使用TLS实现(使用OpenSSL 1.0.1s),该实现当前使用1024位RSA密钥进行加密和身份验证。我想出于性能原因升级到EC,但我需要保持向后兼容。

所以我决定使用OpenSSL的EVP API来获得尽可能多的通用代码。但是,当我想从RAM中读取证书(以ASN.1 DER格式存储)时,我遇到了问题,我无法找到完全复制EVP_PKEY结构的方法(没有PKEY_dupPKEY_copy或任何类型的东西。

我想避免切换外壳EVP_PKEY.type所以下次升级会更顺畅,有什么建议吗?

2 个答案:

答案 0 :(得分:1)

我设法通过转换为DER并返回来复制。一般的i2d / d2i函数调用特定的函数。

代码:

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){
      OPENSSL_free(DER_PTR);
      return error_code_general_error;
   }

   priv_len = *(UINT_16 *)p;
   if (priv_len == 0){
       EVP_PKEY_free(pkey);
       OPENSSL_free(DER_PTR);
       return error_code_general_error;
   }

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

   OPENSSL_free(DER_PTR);

   *pkey_ptr_PTR = pkey;

   return error_code_no_error;

请注意,i2d / d2i函数会增加指定的指针

答案 1 :(得分:0)

根据您的问题,您可以尝试使用EVP_PKEY_up_ref()(增加'filter' value = '2'引用计数器),然后将指针传递给原始EVP_PKEY。通过这种方式,您可以安全地使用EVP_PKEY then(首先递减计数器,只有当它变为零时才真正释放)。