Question

I realize that there are a lot of similar questions to the one I am about to ask already on Stack Overflow, but none of them have clear answers that really satisfy my needs, so here we go:

My program receives an ASN.1 encoded RSA public key over the network. I have the data stored in a simple NSData instance. I wish to use that public key to encode 16 bytes of data and return those over the network. From my research the best way to do this seems to be to use a SecKeyRef. According to the ridiculously vague documentation provided by Apple this can be done using some code. However, their code presents a problem. Every time I want to use a public key I need to add it to the keychain and give it a unique identifier. The problem with this is that this key is to be used only once. I am looking for a way to obtain a SecKeyRef for a key that is not in the keychain and is created from an ASN.1 encoded key.

I have also considered the possibility of converting it to common PEM by base64-encoding and wrapping it in '-----BEGIN PUBLIC KEY-----' and '-----END PUBLIC KEY-----' and then loading it into a SecKeyRef, but I haven't seen a way to do this either.

Also, I don't have much of a choice in the type of key, key format, etc. Its from a 3rd party java server. Yay.

I currently have this alternate method of loading keys that (maybe) doesn't add them to the key chain but the key evidently (by trial and error :D) is not in DER format and therefore I can't load it like this.

SecCertificateRef certificateRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)data); //data contains the public key - received over the network
SecPolicyRef policyRef = SecPolicyCreateBasicX509();
SecTrustRef trustRef;

OSStatus status = SecTrustCreateWithCertificates(certificateRef, policyRef, &trustRef);
NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates failed.");

SecTrustResultType trustResult;
status = SecTrustEvaluate(trustRef, &trustResult);
NSAssert(status == errSecSuccess, @"SecTrustEvaluate failed.");

SecKeyRef publicKey = SecTrustCopyPublicKey(trustRef); //The Result :)
NSAssert(publicKey != NULL, @"SecTrustCopyPublicKey failed.");

if (certificateRef) CFRelease(certificateRef);
if (policyRef) CFRelease(policyRef);
if (trustRef) CFRelease(trustRef);

PS: Why does apple make this so hard? Statically linking OpenSSL would be easy, but then all sorts of export regulations and other problems apply.

Was it helpful?

Solution

The problem was apparently with the source of the "certificate", which really wasn't much more than the key wrapped in some DER tags.

On the plus side thanks to the black magic in this http://blog.wingsofhermes.org/?p=75 blog post, I have successfully managed to achieve most of my goals.

Success:

  • Key loaded from data, not a file
  • Encryption of secret (AES) key successfully read by java server.

Less success:

  • Had to use a unique identifier, but I reuse it, so no need for a crazy naming scheme.
  • Key temporarily added to keychain, but I remove it after its one time use, so that works out too.

I am still not too clear on what the array of if statements mixed with loops and tons of magic numbers does exactly, but at least it works and since the key will always come from the same source, it shouldn't break unless they change the java security provider...oh wait thats actually kinda likely...oh well...at least its a little bit specific in the Java 7 standards.

*crosses fingers* *hopes nothing breaks*

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top