Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading PEM public key into iOS

I have a base64 public key that was generated by java using this code:

RSAPublicKeySpec rsaKS = new RSAPublicKeySpec(modulus, pubExponent);
RSAPublicKey rsaPubKey = (RSAPublicKey) kf.generatePublic(rsaKS);
byte[] encoded = rsaPubKey.getEncoded();
String base64 = Base64.encodeToString(encoded, Base64.DEFAULT);
Log.e(null, "base64: " + base64);

This results in a Base64 string.

In OSX I can get a SecKeyRef using this code:

// Create the SecKeyRef using the key data
CFErrorRef error = NULL;
CFMutableDictionaryRef parameters = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
CFDictionarySetValue(parameters, kSecAttrKeyType, kSecAttrKeyTypeRSA);
CFDictionarySetValue(parameters, kSecAttrKeyClass, kSecAttrKeyClassPublic);
SecKeyRef keyRef = SecKeyCreateFromData(parameters, (__bridge CFDataRef)[pubKey base64DecodedData], &error);

However in iOS there is no SecKeyCreateFromData method.

I can use the Base64 string in iOS using this code which adds it to the keychain, then retrieves it again as a SecKeyRef however i'd much rather not have to add the cert to the keychain just to be able to retrieve it to use it once.

Doing some research, it seems I should be able to use SecCertificateCreateWithData to create a certificate to use in iOS from the Base64 string I have, however I always get back a NULL cert when using this code:

NSString* pespublicKey = @"MIGfMA0GCSqGSIb3....DCUdz/y4B2sf+q5n+QIDAQAB";
NSData* certData = [pespublicKey dataUsingEncoding:NSUTF8StringEncoding];
SecCertificateRef cert;
if ([certData length]) {
    cert = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certData);
    if (cert != NULL) {
        CFStringRef certSummary = SecCertificateCopySubjectSummary(cert);
        NSString* summaryString = [[NSString alloc] initWithString:(__bridge NSString*)certSummary];
        NSLog(@"CERT SUMMARY: %@", summaryString);
        CFRelease(certSummary);
    } else {
        NSLog(@" *** ERROR *** trying to create the SSL certificate from data located at %@, but failed", pespublicKey);
    }
}
like image 491
Darren Avatar asked Apr 09 '15 15:04

Darren


People also ask

Is a PEM file a public key?

Privacy Enhanced Mail (PEM) files are a type of Public Key Infrastructure (PKI) file used for keys and certificates. PEM, initially invented to make e-mail secure, is now an Internet security standard.

What is PEM file IOS?

The SSL certificate available in your Apple Developer Program account contains a public key but not a private key. The private key exists only on the Mac that created the Certificate Signing Request uploaded to Apple. Both the public and private keys are necessary to export the Privacy Enhanced Mail (PEM) file.


1 Answers

You are not base64-decoding your key data first. You are passing base64-encoded data to SecCertificateCreateWithData(), and that function expects the raw, decoded data. Try something like this instead:

NSData *certData = [[NSData alloc] initWithBase64EncodedString:pespublicKey options:0];
cert = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certData);

Update:

What you are sending to your iOS code is the base64 DER-encoded key, not a DER- or PEM-encoded certificate. As such, the result you're seeing is expected -- you give it a DER-encoded data blob which doesn't contain a certificate and it gives you back a null certificate reference representing the non-existent certificate data.

You have two options:

  1. Use the code you have already found to add the key to the keychain and then fetch it out. That seems to be the "iOS way" to import keys for use on iOS.

  2. Use the public key and its associated private key to sign a certificate and import that into your app, create a temporary trust relationship with that certificate, then pull the public key out of the certificate's information (example: iOS SecKeyRef from NSString)

For the second option to work, your Java code is not only going to have to have the public key, it will also need the associated private key to generate a signed certificate.

Depending on what you plan to do with the SecKeyRef, you may run into problems. SecKeyRef values can be cast straight to SecKeychainItemRef values for use in Keychain Services functions. If the SecKeyRef value doesn't come from the keychain, your code will get errors. Read the docs for more info

like image 157
hrunting Avatar answered Oct 03 '22 11:10

hrunting