Import the PEM encoded X.509 certificate into iOS Keychain

I received a string containing a PEM-encoded X.509 certificate from somewhere. I want to import this certificate into the iOS KeyChain.

I plan to do the following:

>Convert NSString to openssl X509
>Create PKCS12
>Convert PKCS12 to NSData
>Use SecPKCS12Import to import NSData

So far, I came up with the following code:

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, N ULL, 0, 0, 0, 0, 0);

Unfortunately, even if X509_check_private_key succeeds and X509_print_fp(stdout,cert) prints out a valid certificate, p12 is also zero.

>My approach is correct.
>Why does PKCS12_create seem to fail?

Update:

Calling PKCS12_create seems to fail in the following methods:

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))
{
object );
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;< br />else
{
cipher = EVP_get_cipherbynid(cip her_nid);
if (!cipher)
{
EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_CIPHER);
return 0;
}
}
< br />if (md_nid == -1)
md = NULL;
else
{
md = EVP_get_digestbynid(md_nid);
if (!md)< br /> {
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;
}

Retrieve password

cipher = EVP_get_cipherbynid(cipher_nid);

Return for “RC2-40-CBC” in some way nil.

Before PKCS12 was created, the following call was missing:

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

These solve the problem of lost passwords and subsequent loss of digests.< /p>

I’m from somewhere Fang received a string containing a PEM-encoded X.509 certificate. I want to import this certificate into the iOS KeyChain.

I plan to do the following:

> Convert NSString to openssl X509
>Create PKCS12
>Convert PKCS12 to NSData
>Use SecPKCS12Import to import NSData

So far, I came up with the following code:

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);

Unfortunately, even if X 509_check_private_key succeeds and X509_print_fp(stdout,cert) prints out a valid certificate, and p12 is also zero.

>My method is correct.
>Why does PKCS12_create seem to fail?

Update:

Calling PKCS12_create seems to fail in the following methods:

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))
{
object );
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;< br />else
{
cipher = EVP_get_cipherbynid(cipher_ nid);
if (!cipher)
{
EVPerr(EVP_F_EVP_PBE_CIPHERINIT,EVP_R_UNKNOWN_CIPHER);
return 0;
}
}
< br />if (md_nid == -1)
md = NULL;
else
{
md = EVP_get_digestbynid(md_nid);
if (!md)< br /> {
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;
}

Retrieve password

cipher = EVP_get_cipherbynid(cipher_nid);

Return for “RC2-40-CBC” in some way nil.

Before creating PKCS12, the following calls were missing:

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

These solve the problem of lost passwords and subsequent loss of digests.

Leave a Comment

Your email address will not be published.