views:

2651

answers:

7

I'm building an iphone app that needs to access a web service over https using client certificates. If I put the client cert (in pkcs12 format) in the app bundle, I'm able to load it into the app and make the https call (largely thanks to stackoverflow.com).

However, I need a way to distribute the app without any certs and leave it to the user to provide his own certificate. I thought I would just do that by instructing the user to import the certificate in iphone's profiles (settings->general->profiles), which is what you get by opening a .p12 file in Mail.app and then I would access that item in my app. I would expect that the certificates in profiles are available through the keychain API, but I guess I'm wrong on that.

1) Is there a way to access a certificate that I've already loaded in iphone's profile in my app?

2) What other options I have for loading a user specified certificate in my app? The only thing I can come up with is providing some interface where the user can give an URL to his .p12 cerificate, which I can then load into the app's keychain for later use, but thats not exactly user-friednly. I'm looking for something that would allow the user to put the cert on phone (email it to himself) and then load it in my app.

A: 

Does the code suggested in Finding a Certificate In the Keychain work for you?

Adam Woś
No, I tried searching for kSecClass key with values kSecClassIdentity, kSecClassCertificate and kSecClassKey but I always get an empty result. Then I read on some more to find out that the iphone keychain is per-app, that is you can access only what you put in it and only your app (and other apps signed with a provisioning certificate with the same AppID) have access to that keychain.
Pavel Georgiev
Well, then to answer your second question - there is no API or AppStore-approvable way to load a file into iPhone other than specify an URL and download it...
Adam Woś
+1  A: 

If a .p12 file isn't too big you could encode it using Base64 and then embed a link in an email with a custom url scheme, e.g.:

myapp://certificate/<base 64 data>

User clicks the link, your app saves the certificate somewhere for future use. Just make sure that Mail.app on the iPhone won't mangle the email.

Sam Doshi
There is a reason behind this and I might end up trying it, but even if it works, the user has to encode the cert in Base64 and craft this email which is not user-friendly.
Pavel Georgiev
Thinking about it, the easiest way to get Mail.app to play ball, is to send an HTML email and use A tags for the link.
Sam Doshi
Could you not provide an application or a website to do it for them?
Sam Doshi
A: 

After some more research I have to say this is not currently possible. See e.g. here.

Adam Woś
+1  A: 

Can you tell me how load the .p12 into the app, please? I need to extract the publick key of the client certificate. Thanks

Pablo Alejandro
I got in touch with an Apple Security framework evangelist, who confirmed what has already been said here - certificates loaded in seting->general->profiles can only be used by the built-in apps (mail, safari). Your app can use only what you store in its keychain (or keychains of other 3rd party apps that share the same provisioning certificate). As for the actual loading, I've built an app bundled with the certificate (just for the test). I read the .p12 from my app bundle and I get the identity with SecPKCS12Import. You can then use it to get the private key with SecIdentityCopyPrivateKey.
Pavel Georgiev
I have tried with SecPKCS12Import but doesn't work... I have added an answer with the code
Pablo Alejandro
A: 

I've tried with this:

NSString *thePath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"p12"]; 
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath]; 
CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data; 
CFStringRef password = CFSTR("pass"); 
const void *keys[] = { kSecImportExportPassphrase }; 
const void *values[] = { password }; 
CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); 
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); 
SecPKCS12Import(inPKCS12Data, optionsDictionary, &items); 

inPKCS12Data is correct but items is empty. What is happening?

Pablo Alejandro
That same code works for me. SecPKCS12Import returns OSStatus status code - get that and see what the error is.
Pavel Georgiev
OSStatus returns -26275
Pablo Alejandro
Unable to decode the provided data.
Pablo Alejandro
Simulator can't decode, only the device. It's ok!
Pablo Alejandro
A: 

Not exactly the same problem but I have found that SecPKCS12Import cannot deal with a P12 file that was created with a DSA private key even though both the Mac OS and Windows are fine with these files.

James Wheeler
A: 

Oh man, this brings up painful memories from October/November 2009. I was able to successfully get client-side certs to work but I had to port libcurl to the iPhone (which wasn't easy since the NDA was still in effect at the time).

I haven't done iPhone app development in over a year so I don't know how much is changed, but if I were you I'd first try to get by without client-side certs and if you absolutely must have them you can use libcurl with PEM formatted certs.

guidoism