From what I see in the documentation of MPMoviewPlayerController, NSURLCredentialStorage can be set up as an alternative of NSURLConnection authentication challenges (this is useful for higher level classes that load resources from URLs but abstract the NSURLConnection away and don't provide a delegate for handling authentication challenges). This seems similar to installing a certificate in the browser and having it auto select the required certificate when a certain address demands it.
To test this out I have set up my own certificate authority, server certificate and client certificate (a .p12 file). I've set up an https server and successfully tested the client certificate using a browser, from a separate machine.
Now I need to have the certificate integrated in my iPhone app.
I've bundled up the p12 file and on application launch I do this:
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"clientside" ofType:@"p12"];
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;
SecIdentityRef identity;
SecTrustRef trust;
extractIdentityAndTrust(inPKCS12Data, &identity, &trust);
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate);
const void *certs[] = {certificate};
CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
initWithHost: @"myhostname"
port: 443
protocol: @"https"
realm: nil
authenticationMethod: NSURLAuthenticationMethodClientCertificate];
[[NSURLCredentialStorage sharedCredentialStorage]
setDefaultCredential: credential
forProtectionSpace: protectionSpace];
The extractIdentityAndTrust function is simply copied form the 'Certificate, Key, and Trust Services Tasks for iOS' documentation page (I just replaced the certificate password with my own).
From what I can tell the identity and the certificate are loaded nicely. If I print the NSURLCredential object in the console I get something like this: <NSURLCredential: 0x140ea0>: (null)
(I can't tell if this is a good sign or not).
However when I execute setDefaultCredential the app crashes without giving much information.
The stacktrace looks something like this:
#0 0x350a41c8 in CFHash
#1 0x3515180c in __CFBasicHashStandardHashKey
#2 0x351534e4 in ___CFBasicHashFindBucket_Linear
#3 0x350a4000 in CFBasicHashFindBucket
#4 0x350a3ecc in CFDictionaryGetValue
#5 0x344a0df2 in URLCredentialStorage::setDefaultCredentialForProtectionSpace
#6 0x3446a5aa in CFURLCredentialStorageSetDefaultCredentialForProtectionSpace
#7 0x339ec79e in -[NSURLCredentialStorage setDefaultCredential:forProtectionSpace:]
#8 0x00002612 in -[AVPlayerExampleViewController awakeFromNib] at AVPlayerExampleViewController.m:84
Looks to me like there something not set up in the credential.
Any ideas on how to solve this?
EDIT:
Just for testing I installed the certificate on the iPhone by opening the file from Mail. I can access the pages over https through Safari, but not through my app.
The only thing that works is if I open an NSURLConnection to any resource on the protected domain, respond to didReceiveAuthenticationChallenge (where I load up my credential exactly like in the code above, only I send it directly to NSURLAuthenticationChallenge's sender) and then access the stuff I really need using the higher level class.