Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get SecKeyRef from DER/PEM file

Tags:

I need to integrate my iPhone app with a system, and they require to encrypt data by a given public key, there are 3 files in 3 different format .xml .der and .pem, I have researched and found some articles about getting SecKeyRef from DER/PEM, but they are always return nil. Below is my code:

NSString *pkFilePath = [[NSBundle mainBundle] pathForResource:@"PKFile" ofType:@"der"]; NSData *pkData = [NSData dataWithContentsOfFile:pkFilePath];   SecCertificateRef   cert;  cert = SecCertificateCreateWithData(NULL, (CFDataRef) pkData); assert(cert != NULL);  OSStatus err;      if (cert != NULL) {         err = SecItemAdd(                          (CFDictionaryRef) [NSDictionary dictionaryWithObjectsAndKeys:                                             (id) kSecClassCertificate,  kSecClass,                                              (id) cert,                  kSecValueRef,                                             nil                                             ],                           NULL                          );         if ( (err == errSecSuccess) || (err == errSecDuplicateItem) ) {             CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **) &cert, 1, NULL);              SecPolicyRef policy = SecPolicyCreateBasicX509();             SecTrustRef trust;             SecTrustCreateWithCertificates(certs, policy, &trust);             SecTrustResultType trustResult;             SecTrustEvaluate(trust, &trustResult);             if (certs) {                 CFRelease(certs);             }             if (trust) {                 CFRelease(trust);             }             return SecTrustCopyPublicKey(trust);         }     } return NULL; 

Problem happens at SecCertificateCreateWithData, it always return nil even through read file is ok. Anybody has done this please help me, thanks!

EDIT: The cert file was MD5 signature.

like image 334
Son Nguyen Avatar asked May 14 '12 08:05

Son Nguyen


People also ask

How do I view a PEM file?

Certificate Decoder A PEM encoded certificate is a block of encoded text that contains all of the certificate information and public key. Another simple way to view the information in a certificate on a Windows machine is to just double-click the certificate file.


1 Answers

I struggled a lot with the same problem and finally found a solution. My problem was that I needed to use both an external private and public key for encrypting/decrypting data in an iOS app and didn't want to use the keychain. It turns out you also need a signed certificate for the iOS security library to be able to read the key data and of course the files have to be in the correct format. The procedure is basically as follows:

Say you have a private key in PEM format (with the -----BEGIN RSA PRIVATE KEY----- and -----END RSA PRIVATE KEY----- markers): rsaPrivate.pem

//Create a certificate signing request with the private key openssl req -new -key rsaPrivate.pem -out rsaCertReq.csr  //Create a self-signed certificate with the private key and signing request openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey rsaPrivate.pem -out rsaCert.crt  //Convert the certificate to DER format: the certificate contains the public key openssl x509 -outform der -in rsaCert.crt -out rsaCert.der  //Export the private key and certificate to p12 file openssl pkcs12 -export -out rsaPrivate.p12 -inkey rsaPrivate.pem -in rsaCert.crt 

Now you have two files which are compatible with the iOS security framework: rsaCert.der (public key) and rsaPrivate.p12 (private key). The code below reads in the public key assuming the file is added to your bundle:

- (SecKeyRef)getPublicKeyRef {      NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"rsaCert" ofType:@"der"];     NSData *certData = [NSData dataWithContentsOfFile:resourcePath];     SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);     SecKeyRef key = NULL;     SecTrustRef trust = NULL;     SecPolicyRef policy = NULL;      if (cert != NULL) {         policy = SecPolicyCreateBasicX509();         if (policy) {             if (SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust) == noErr) {                 SecTrustResultType result;                 OSStatus res = SecTrustEvaluate(trust, &result);                  //Check the result of the trust evaluation rather than the result of the API invocation.                 if (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified) {                     key = SecTrustCopyPublicKey(trust);                 }             }         }     }     if (policy) CFRelease(policy);     if (trust) CFRelease(trust);     if (cert) CFRelease(cert);     return key; } 

To read in the private key use the following code:

SecKeyRef getPrivateKeyRef() {     NSString *resourcePath = [[NSBundle mainBundle] pathForResource:@"rsaPrivate" ofType:@"p12"];     NSData *p12Data = [NSData dataWithContentsOfFile:resourcePath];      NSMutableDictionary * options = [[NSMutableDictionary alloc] init];      SecKeyRef privateKeyRef = NULL;      //change to the actual password you used here     [options setObject:@"password_for_the_key" forKey:(id)kSecImportExportPassphrase];      CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);      OSStatus securityError = SecPKCS12Import((CFDataRef) p12Data,                                              (CFDictionaryRef)options, &items);      if (securityError == noErr && CFArrayGetCount(items) > 0) {         CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);         SecIdentityRef identityApp =         (SecIdentityRef)CFDictionaryGetValue(identityDict,                                              kSecImportItemIdentity);          securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);         if (securityError != noErr) {             privateKeyRef = NULL;         }     }     [options release];     CFRelease(items);     return privateKeyRef; } 
like image 152
Werner Altewischer Avatar answered Oct 06 '22 05:10

Werner Altewischer