简体   繁体   中英

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM