S/MIME email encryption library for iOS - ios

I am trying to find a S/MIME email encryption library for an iOS email app I am creating in Swift. I have been having trouble trying to find a library for the encryption, has anyone had any experience with this?
I have tried OpenSSL but have run into issues with importing all the files in need in the bridging header, for example I need to use functions in pem.h but if I try import pem.h the bridging header fails to be imported altogether.
Any help with this would be greatly appreciated.

I had a similar requirement. Eventually I had to import openSSL and write my own code to handle the decrypt of PKCS7. I made a small github repo which should help
https://github.com/zkrige/iOS-pkcs7-decrypt
here is the gist of the code
#include <openssl/bio.h>
#include <openssl/cms.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/crypto.h>
#include <openssl/rand.h>
X509 *getCert(const char *certificate) {
BIO *membuf = BIO_new(BIO_s_mem());
BIO_puts(membuf, certificate);
X509 *x509 = PEM_read_bio_X509(membuf, NULL, NULL, NULL);
return x509;
}
EVP_PKEY *getKey(const char *privateKey) {
BIO *membuf = BIO_new(BIO_s_mem());
BIO_puts(membuf, privateKey);
EVP_PKEY *key = PEM_read_bio_PrivateKey(membuf, NULL, 0, NULL);
return key;
}
PKCS7 *getContainer(const char *encrypted) {
BIO* membuf = BIO_new(BIO_s_mem());
BIO_set_mem_eof_return(membuf, 0);
BIO_puts(membuf, encrypted);
PKCS7* pkcs7 = SMIME_read_PKCS7(membuf, NULL);
if (!pkcs7) {
fprintf(stderr, "error: %ld\n", ERR_get_error());
}
return pkcs7;
}
char *decrypt(PKCS7 *pkcs7, EVP_PKEY *pkey, X509 *cert) {
BIO *out = BIO_new(BIO_s_mem());
if (PKCS7_decrypt(pkcs7, pkey, cert, out, 0) != 1) {
X509_free(cert);
EVP_PKEY_free(pkey);
PKCS7_free(pkcs7);
fprintf(stderr, "Error decrypting PKCS#7 object: %ld\n", ERR_get_error());
return NULL;
}
BUF_MEM* mem;
BIO_get_mem_ptr(out, &mem);
char *data = malloc(mem->length + 1);
memcpy(data, mem->data, mem->length + 1);
BIO_flush(out);
BIO_free(out);
return data;
}
char *decrypt_smime(const char *encrypted, const char *privateKey, const char *certificate) {
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
X509 *cert = getCert(certificate);
if (!cert) {
return NULL;
}
EVP_PKEY *pkey = getKey(privateKey);
if (!pkey) {
X509_free(cert);
return NULL;
}
PKCS7 *pkcs7 = getContainer(encrypted);
if (!pkcs7) {
X509_free(cert);
EVP_PKEY_free(pkey);
return NULL;
}
char *data = decrypt(pkcs7, pkey, cert);
X509_free(cert);
EVP_PKEY_free(pkey);
PKCS7_free(pkcs7);
return data;
}

Related

Verify PKCS7 in DER format using PEM certificate in C using openssl

I have working command line:
openssl cms -inform DER -cmsout -in sod.pkcs7 -verify -CAfile cert.pem
but I'm stragling to make this work in C (under iOS).
I found example which is using PKCS7_verify but with SMIME informat. So I guess I should use CMS_verify but not really sure...
My tests:
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h> /* open() */
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/pkcs7.h>
#include <openssl/safestack.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h> /* X509_PURPOSE_ANY */
#include <openssl/x509_vfy.h>
#include <openssl/cms.h>
#include <openssl/pem.h>
int testssl(const char* cert_path, const char* sod_path)
{
X509_STORE *trusted_store;
X509_STORE_CTX *ctx;
STACK_OF(X509) *cert_chain;
X509 *root, *intermediate, *signing;
BIO *in;
int purpose, ret;
X509_VERIFY_PARAM *verify_params;
PKCS7 *p7;
FILE *fp;
int fd;
SSL_library_init();
SSL_load_error_strings();
fd = open(sod_path, O_RDONLY);
in = BIO_new_fd(fd, BIO_NOCLOSE);
p7 = SMIME_read_PKCS7(in, NULL);
cert_chain = sk_X509_new_null();
fp = fopen(cert_path, "r");
root = PEM_read_X509(fp, NULL, NULL, NULL);
sk_X509_push(cert_chain, root);
// <C> not sure what this is good for...
// fp = fopen("intermediate.pem", "r");
fp = fopen(cert_path, "r");
intermediate = PEM_read_X509(fp, NULL, NULL, NULL);
sk_X509_push(cert_chain, intermediate);
trusted_store = X509_STORE_new();
X509_STORE_add_cert(trusted_store, root);
// fp = fopen("signing-ext-no-smimesign.pem", "r");
// signing = PEM_read_X509(fp, NULL, NULL, NULL);
BIO *cont = NULL;
CMS_ContentInfo *cms = NULL;
// cms = d2i_CMS_bio(in, NULL);
// cms = PEM_read_bio_CMS(in, NULL, NULL, NULL);
cms = SMIME_read_CMS(in, &cont);
// <C> all of above return NULL thus CMS_verify() fails
// 1st attempt
//
ret = CMS_verify(cms, cert_chain,trusted_store, NULL, NULL, 0);
printf("CMS_verify: %s\n", ret ? "OK" : "failure");
// 2nd attempt
//
ret = PKCS7_verify(p7, cert_chain, trusted_store, NULL, NULL, 0);
printf("Verification without specifying params: %s\n", ret ? "OK" : "failure");
/* Now set a suitable OpenSSL's "purpose", or disable its checking.
* Note: since OpenSSL 1.1.0, we'd not need `ctx`, but could just use:
* verify_params = X509_STORE_get0_param(trusted_store); */
ctx = X509_STORE_CTX_new();
X509_STORE_CTX_init(ctx, trusted_store, signing, cert_chain);
verify_params = X509_STORE_CTX_get0_param(ctx);
purpose = X509_PURPOSE_get_by_sname("crlsign"); /* Or: purpose = X509_PURPOSE_ANY */
X509_VERIFY_PARAM_set_purpose(verify_params, purpose);
X509_STORE_set1_param(trusted_store, verify_params);
// 3rd attempt
//
ret = PKCS7_verify(p7, cert_chain, trusted_store, NULL, NULL, 0);
printf("Verification with 'crlsign' purpose: %s\n", ret ? "OK" : "failure");
return 0;
}
Figured it out.
int testcms (const char* cert_path, const char* sod_path)
{
BIO *in = NULL, *out = NULL, *tbio = NULL, *cont = NULL;
X509_STORE *st = NULL;
X509 *cacert = NULL;
CMS_ContentInfo *cms = NULL;
int ret = 1;
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
st = X509_STORE_new();
tbio = BIO_new_file(cert_path, "r");
if (!tbio) {
fprintf(stderr, "Cert file not opened: path=%s;\n", cert_path);
goto err;
}
cacert = PEM_read_bio_X509(tbio, NULL, 0, NULL);
if (!cacert) {
fprintf(stderr, "PEM_read_bio_X509 FAILED: cert.path=%s;\n", cert_path);
goto err;
}
if (!X509_STORE_add_cert(st, cacert)) {
fprintf(stderr, "X509_STORE_add_cert FAILED: cert.path=%s;\n", cert_path);
goto err;
}
in = BIO_new_file(sod_path, "r");
if (!in) {
fprintf(stderr, "PKCS7 file not opened: path=%s;\n", sod_path);
goto err;
}
//cms = SMIME_read_CMS(in, &cont);
cms = d2i_CMS_bio(in, NULL);
if (!cms) {
fprintf(stderr, "SMIME_read_CMS FAILED: pkcs7.path=%s;\n", sod_path);
goto err;
}
if (!CMS_verify(cms, NULL, st, cont, NULL, 0)) {
fprintf(stderr, "Verification Failure\n");
goto err;
}
fprintf(stderr, "Verification Successful\n");
ret = 0;
err:
if (ret) {
fprintf(stderr, "Error Verifying Data\n");
ERR_print_errors_fp(stderr);
}
CMS_ContentInfo_free(cms);
X509_free(cacert);
BIO_free(in);
BIO_free(out);
BIO_free(tbio);
return ret;
}

How to create certificate request with OpenSSL library

I am trying to create certificate request programmatically in iOS using openSSL. I got testKey.pem(private key) and test.csr finally and the first works well in linux(by openssl command), however test.csr seams strange and cannot be recognized and used properly. here is my code in OC.
- (void)genCertReq {
if (!X509_REQ_set_version(csr.req, csr.ver)) {
LOG(#"set_version failed");
goto error;
}
[self fillDN];
/* subject name */
if (!X509_REQ_set_subject_name(csr.req, csr.subject)) {
LOG(#"subject_name failed");
goto error;
}
rsaPair = RSA_generate_key(bits, e, NULL, NULL);
const char *keyPathChar = [SPFileManager openFile:testKey];
BIO *bp = NULL;
bp = BIO_new_file(keyPathChar, "w");
PEM_write_bio_RSAPrivateKey(bp, rsaPair, NULL, NULL, 0, NULL, NULL);
BIO_free(bp);
/* pub key */
if (1 != EVP_PKEY_assign_RSA(evpKey, rsaPair)) {
LOG(#"assign_RSA failed");
goto error;
}
if (!X509_REQ_set_pubkey(csr.req, evpKey)) {
LOG(#"set_pubkey failed");
goto error;
}
/* attribute */
csr.md = EVP_sha1();
if (!X509_REQ_digest(csr.req, csr.md, (unsigned char *)csr.mdout, (unsigned int *)&csr.mdlen)) {
LOG(#"req_digest failed");
goto error;
}
if (!X509_REQ_sign(csr.req, evpKey, csr.md)) {
LOG(#"req_sign failed");
goto error;
}
const char *csrPathChar = [SPFileManager openFile:csrName];
bp = BIO_new_file(csrPathChar, "w");
PEM_write_bio_X509_REQ(bp, csr.req);
BIO_free(bp);
OpenSSL_add_all_algorithms();
if (X509_REQ_verify(csr.req, evpKey) < 0) {
LOG(#"req_verify failed");
goto error;
}
X509_REQ_free(csr.req);
return;
error:
X509_REQ_free(csr.req);
return;
}
testKey.pem is in PKCS1 format and looks like --BEGIN RSA PRIVATE KEY---, and test.csr looks like ---BEGIN CERTIFICATE REQUEST--- which however I don't think is right.
Any help will be appreciated, thanks.

One function gives several results in swift

I have a method in objective-C which I call from swift. It worked pretty well in swift 2, but in swift 3 the behaviour has changed. It gives me 3 different results, even though I send the same parameters.
Sometimes it doesnt find pfile, sometimes it fails on pin checking, sometimes works good and gives me x509.
char* ParsePKCS12(unsigned char* pkcs12_path, unsigned char * pin) {
printf("PARSE PATH: %s\n", pkcs12_path);
printf("PASSWORD: %s\n", pin);
NSString *pfile = [NSString stringWithUTF8String:pkcs12_path];
FILE *fp;
PKCS12 *p12;
EVP_PKEY *pkey;
X509 *cert;
BIO *databio = BIO_new(BIO_s_mem());
STACK_OF(X509) *ca = NULL;
if([[NSFileManager defaultManager] fileExistsAtPath:pfile]) {
NSLog(#"ok, pfile exists!");
} else {
NSLog(#"error, pfile does not exists!");
return "-1";
}
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
fp = fopen([pfile UTF8String], "rb");
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12) {
fprintf(stderr, "Error reading PKCS#12 file\n");
ERR_print_errors_fp(stderr);
return "-1";
}
if (!PKCS12_parse(p12, (const char *)pin, &pkey, &cert, &ca)) { //Error at parsing or pin error
fprintf(stderr, "Error parsing PKCS#12 file\n");
ERR_print_errors_fp(stderr);
ERR_print_errors(databio);
return "-1";
}
BIO *bio = NULL;
char *pem = NULL;
if (NULL == cert) {
//return NULL;
return "-1";
}
bio = BIO_new(BIO_s_mem());
if (NULL == bio) {
return "-1";
}
if (0 == PEM_write_bio_X509(bio, cert)) {
BIO_free(bio);
//return NULL;
}
pem = (char *) malloc(bio->num_write + 1);
if (NULL == pem) {
BIO_free(bio);
return "-1";
}
memset(pem, 0, bio->num_write + 1);
BIO_read(bio, pem, bio->num_write);
BIO_free(bio);
PKCS12_free(p12);
return pem;
}
this code I call in swift like this:
self.x509 = String(cString:ParsePKCS12(UnsafeMutablePointer<UInt8>(mutating: self.path),
UnsafeMutablePointer<UInt8>(mutating: "123456"))!)
Your call
self.x509 = String(cString:ParsePKCS12(UnsafeMutablePointer<UInt8>(mutating: self.path),
UnsafeMutablePointer<UInt8>(mutating: "123456"))!)
does not work reliably because in both
UnsafeMutablePointer<UInt8>(mutating: someSwiftString)
calls, the compiler creates a temporary C string representation of
the Swift string and passes that to the function. But that C string
is only valid until the UnsafeMutablePointer constructor returns, which means that the second
string conversion can overwrite the first, or any other undefined
behaviour.
The simplest solution would be to change the C function to
take constant C strings (and use the default signedness):
char* ParsePKCS12(const char * pkcs12_path, const char * pin)
Then you can simply call it as
self.x509 = String(cString: ParsePKCS12(self.path, "123456"))
and the compiler creates temporary C strings which are valid during
the call of ParsePKCS12().

Issue with digital signature generated using Podofo library

I'm using OpenSSL to generate digital signature for a PDF by PoDoFo library.
Here is the logic for signature handler
OpenSSLSignatureHandler.h
#import <Foundation/Foundation.h>
// OpenSSL includes
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pkcs12.h>
#include <openssl/pkcs7.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#interface OpenSSLSignatureHandler : NSObject
{
SHA_CTX m_sha_ctx;
EVP_PKEY* mp_pkey; // private key
X509* mp_x509; // signing certificate
STACK_OF(X509)* mp_ca; // certificate chain up to the CA
}
- (id) initWithCert:(NSString*) p12file password: (NSString*) password;
- (void) AppendData: (NSData*)data;
- (NSData*) getSignature;
#end
OpenSSLSignatureHandler.m
#import "OpenSSLSignatureHandler.h"
#include <string>
#implementation OpenSSLSignatureHandler
- (id) initWithCert:(NSString*) p12file password: (NSString*) password{
if (self = [super init]) {
// Initialize OpenSSL library
CRYPTO_malloc_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
FILE* fp = fopen([p12file cStringUsingEncoding: NSASCIIStringEncoding], "rb");
if (fp == NULL)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot open private key." userInfo: nil]);
PKCS12* p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
if (p12 == NULL)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot parse private key." userInfo: nil]);
mp_pkey = NULL;
mp_x509 = NULL;
mp_ca = NULL;
int parseResult = PKCS12_parse(p12, [password cStringUsingEncoding: NSASCIIStringEncoding], &mp_pkey, &mp_x509, &mp_ca);
PKCS12_free(p12);
if (parseResult == 0)
#throw ([NSException exceptionWithName: #"PDFNet Exception" reason: #"Cannot parse private key." userInfo: nil]);
//initialize sha context
SHA1_Init(&m_sha_ctx);
}
return self;
}
- (void) AppendData: (NSData*)data
{
SHA1_Update(&m_sha_ctx, [data bytes], [data length]);
return;
}
- (BOOL) Reset
{
SHA1_Init(&m_sha_ctx);
return (YES);
}
- (NSData*) getSignature
{
unsigned char sha_buffer[SHA_DIGEST_LENGTH];
memset((void*) sha_buffer, 0, SHA_DIGEST_LENGTH);
SHA1_Final(sha_buffer, &m_sha_ctx);
PKCS7* p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed);
PKCS7_SIGNER_INFO* p7Si = PKCS7_add_signature(p7, mp_x509, mp_pkey, EVP_sha1());
PKCS7_add_attrib_content_type(p7Si, OBJ_nid2obj(NID_pkcs7_data));
PKCS7_add0_attrib_signing_time(p7Si, NULL);
PKCS7_add1_attrib_digest(p7Si, (const unsigned char*) sha_buffer, SHA_DIGEST_LENGTH);
PKCS7_add_certificate(p7, mp_x509);
int c = 0;
for ( ; c < sk_X509_num(mp_ca); c++) {
X509* cert = sk_X509_value(mp_ca, c);
PKCS7_add_certificate(p7, cert);
}
PKCS7_set_detached(p7, 1);
PKCS7_content_new(p7, NID_pkcs7_data);
PKCS7_SIGNER_INFO_sign(p7Si);
int p7Len = i2d_PKCS7(p7, NULL);
NSMutableData* signature = [NSMutableData data];
unsigned char* p7Buf = (unsigned char*) malloc(p7Len);
if (p7Buf != NULL) {
unsigned char* pP7Buf = p7Buf;
i2d_PKCS7(p7, &pP7Buf);
[signature appendBytes: (const void*) p7Buf length: p7Len];
free(p7Buf);
}
PKCS7_free(p7);
return (signature);
}
- (void) dealloc
{
sk_X509_free(mp_ca);
X509_free(mp_x509);
EVP_PKEY_free(mp_pkey);
// Release OpenSSL resource usage
ERR_free_strings();
EVP_cleanup();
[super dealloc];
}
#end
Using podofo to embed signature
void CreateSimpleForm( PoDoFo::PdfPage* pPage, PoDoFo::PdfStreamedDocument* pDoc, const PoDoFo::PdfData &signatureData )
{
PoDoFo::PdfPainter painter;
PoDoFo::PdfFont* pFont = pDoc->CreateFont( "Courier" );
painter.SetPage( pPage );
painter.SetFont( pFont );
painter.DrawText( 10000 * CONVERSION_CONSTANT, 280000 * CONVERSION_CONSTANT, "PoDoFo Sign Test" );
painter.FinishPage();
PoDoFo::PdfSignatureField signField( pPage, PoDoFo::PdfRect( 0, 0, 0, 0 ), pDoc );
signField.SetFieldName("SignatureFieldName");
signField.SetSignature(signatureData);
signField.SetSignatureReason("Document verification");
// Set time of signing
signField.SetSignatureDate( PoDoFo::PdfDate() );
}
+(void)addDigitalSignatureOnPage:(NSInteger)pageIndex outpath:(NSString*)path/*doc:(PoDoFo::PdfMemDocument*)aDoc*/{
PoDoFo::PdfPage* pPage;
PoDoFo::PdfSignOutputDevice signer([path UTF8String]);
// Reserve space for signature
signer.SetSignatureSize(1024);
if([[NSFileManager defaultManager] fileExistsAtPath:path]){
PoDoFo::PdfStreamedDocument writer( &signer, PoDoFo::ePdfVersion_1_5 );
// Disable default appearance
writer.GetAcroForm(PoDoFo::ePdfCreateObject, PoDoFo::PdfAcroForm::ePdfAcroFormDefaultAppearance_None);
pPage = writer.CreatePage(PoDoFo::PdfPage::CreateStandardPageSize(PoDoFo::ePdfPageSize_A4 ) );
TEST_SAFE_OP( CreateSimpleForm( pPage, &writer, *signer.GetSignatureBeacon() ) );
TEST_SAFE_OP( writer.Close() );
}
// Check if position of signature was found
if(signer.HasSignaturePosition()) {
// Adjust ByteRange for signature
signer.AdjustByteRange();
// Read data for signature and count it
// We have to seek at the beginning of the file
signer.Seek(0);
//OpenSSLSignatureHandler
NSString * p12certpath = [[NSBundle mainBundle] pathForResource:#"iphone-cert" ofType:#"p12"];
OpenSSLSignatureHandler*signatureHandler = [[OpenSSLSignatureHandler alloc] initWithCert:p12certpath password:#"test123$"];
char buff[65536];
size_t len;
while( (len = signer.ReadForSignature(buff, 65536))>0 )
{
NSData* data = [NSData dataWithBytes:(const void *)buff length:len];
[signatureHandler AppendData:data];
}
const PoDoFo::PdfData *pSignature = NULL;
// NSString *pkcsMessage = [[signatureHandler getSignature] base64EncodedString];
// NSLog(#"OpenSSLSignatureHandler signature message = %#",pkcsMessage);
// const char * cstr = [pkcsMessage UTF8String];
// if(pSignature==NULL)pSignature = new PoDoFo::PdfData(cstr, sizeof(cstr));
unsigned char *bytePtr = (unsigned char *)[[signatureHandler getSignature] bytes];
std::string str;
str.append(reinterpret_cast<const char*>(bytePtr));
// Paste signature to the file
if(pSignature==NULL)pSignature = new PoDoFo::PdfData(str.c_str(), sizeof(str));
NSLog(#"str = %s",str.c_str());
NSLog(#"sizeof(str) = %lu",sizeof(str));
signer.SetSignature(*pSignature);
}
signer.Flush();
}
But the signature that's embeded in the PDF is always empty
can some help with this issue ?

Import PEM encoded X.509 certificate into iOS KeyChain

I'm receiving a String containing a PEM encoded X.509 certificate from somewhere. I'd like to import this certificate into the KeyChain of iOS.
I'm planning to do the following:
convert NSString to openssl X509
create PKCS12
convert PKCS12 to NSData
import NSData with SecPKCS12Import
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, p12 is nil even though X509_check_private_key was successful and X509_print_fp(stdout, cert) prints a valid certificate.
is my approach correct
how come PKCS12_create seems to fail?
Update:
The call PKCS12_create seems to fail in the following method:
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;
}
Retrieving the cipher
cipher = EVP_get_cipherbynid(cipher_nid);
somehow returns nil for "RC2-40-CBC".
The following calls were missing before creating the PKCS12:
OpenSSL_add_all_algorithms();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
These solved the problems with the missing cipher and also a subsequent problem of a missing digest.

Resources