将PEM编码的X.509证书导入iOS KeyChain

时间:2013-01-31 23:52:24

标签: ios c encryption cryptography openssl

我从某个地方收到一个包含PEM编码的X.509证书的字符串。我想将此证书导入iOS的KeyChain。

我打算做以下事情:

  1. 将NSString转换为openssl X509
  2. 创建PKCS12
  3. 将PKCS12转换为NSData
  4. 使用SecPKCS12Import导入NSData
  5. 到目前为止,我想出了以下代码:

    const char *cert_chars = [certStr cStringUsingEncoding:NSUTF8StringEncoding];
    
    BIO *buffer = BIO_new(BIO_s_mem());
    BIO_puts(buffer, cert_chars);
    
    X509 *cert;
    cert = PEM_read_bio_X509(buffer, NULL, 0, NULL);
    if (cert == NULL) {
        NSLog(@"error");
    }
    X509_print_fp(stdout, cert);
    
    
    EVP_PKEY *privateKey;
    const unsigned char *privateBits = (unsigned char *) [privateKeyData bytes];
    int privateLength = [privateKeyData length];
    
    privateKey = d2i_AutoPrivateKey(NULL, &privateBits, privateLength);
    
    if (!X509_check_private_key(cert, privateKey)) {
        NSLog(@"PK error");
    }
    
    PKCS12 *p12 = PKCS12_create("test", "David's Cert", privateKey, cert, NULL, 0, 0, 0, 0, 0);
    

    不幸的是,即使X509_check_private_key成功并且X509_print_fp(stdout,cert)打印出有效证书,p12也为零。

    1. 是我的方法正确
    2. 为什么PKCS12_create似乎失败了?
    3. 更新

      调用PKCS12_create似乎在以下方法中失败:

      int EVP_PBE_CipherInit(ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
                 ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de)
      {
      const EVP_CIPHER *cipher;
      const EVP_MD *md;
      int cipher_nid, md_nid;
      EVP_PBE_KEYGEN *keygen;
      
      if (!EVP_PBE_find(EVP_PBE_TYPE_OUTER, OBJ_obj2nid(pbe_obj),
                      &cipher_nid, &md_nid, &keygen))
          {
          char obj_tmp[80];
          EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_PBE_ALGORITHM);
          if (!pbe_obj) BUF_strlcpy (obj_tmp, "NULL", sizeof obj_tmp);
          else i2t_ASN1_OBJECT(obj_tmp, sizeof obj_tmp, pbe_obj);
          ERR_add_error_data(2, "TYPE=", obj_tmp);
          return 0;
          }
      
      if(!pass)
          passlen = 0;
      else if (passlen == -1)
          passlen = strlen(pass);
      
      if (cipher_nid == -1)
          cipher = NULL;
      else
          {
          cipher = EVP_get_cipherbynid(cipher_nid);
          if (!cipher)
              {
              EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_CIPHER);
              return 0;
              }
          }
      
      if (md_nid == -1)
          md = NULL;
      else
          {
          md = EVP_get_digestbynid(md_nid);
          if (!md)
              {
              EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_DIGEST);
              return 0;
              }
          }
      
      if (!keygen(ctx, pass, passlen, param, cipher, md, en_de))
          {
          EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_KEYGEN_FAILURE);
          return 0;
          }
      return 1;   
      }
      

      检索密码

      cipher = EVP_get_cipherbynid(cipher_nid);
      

      以某种方式返回nil为" RC2-40-CBC"。

1 个答案:

答案 0 :(得分:4)

在创建PKCS12之前缺少以下调用:

OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();

这些解决了丢失密码的问题以及随后遗漏的问题。