Since no one answered this, and I finally came to a working solution, here it is.
Server trust is not a call from server to client, it allows the client to verify the trust offered by the server. With that in mind, the code below does not test trust, but it can.
Usually you get NSURLAuthenticationMethodServerTrust and then get NSURLAuthenticationMethodClientCertificate. This is not so - or. Here is the working code.
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { NSURLProtectionSpace *protectionSpace = [challenge protectionSpace]; NSString *authenticationMethod = [protectionSpace authenticationMethod]; if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate] && self.accountCertKeychainRef != nil) { SecIdentityRef identity = [KeychainUtilities retrieveIdentityWithPersistentRef:self.accountCertKeychainRef]; NSURLCredential* credential = [CertificateUtilities getCredentialFromCert:identity]; if ( credential == nil ) { [[challenge sender] cancelAuthenticationChallenge:challenge]; } else { [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; } } else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; } else if ([authenticationMethod isEqualToString:NSURLAuthenticationMethodNTLM] || [authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic]) { self.lastProtSpace = [challenge protectionSpace]; if ([challenge previousFailureCount] > 2) { [[challenge sender] cancelAuthenticationChallenge:challenge]; } else { [[challenge sender] useCredential:[self buildCredential] forAuthenticationChallenge:challenge]; } } else { [[challenge sender] cancelAuthenticationChallenge:challenge]; } }
For the question below, how can you get an identity:
+ (SecIdentityRef)copyIdentityAndTrustWithCertData:(CFDataRef)inPKCS12Data password:(CFStringRef)keyPassword { SecIdentityRef extractedIdentity = nil; OSStatus securityError = errSecSuccess; const void *keys[] = {kSecImportExportPassphrase}; const void *values[] = {keyPassword}; CFDictionaryRef optionsDictionary = NULL; optionsDictionary = CFDictionaryCreate(NULL, keys, values, (keyPassword ? 1 : 0), NULL, NULL); CFArrayRef items = NULL; securityError = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items); if (securityError == errSecSuccess) { CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
For those who are interested, here is getCredentialForCert:
+ (NSURLCredential *)getCredentialFromCert:(SecIdentityRef)identity { SecCertificateRef certificateRef = NULL; SecIdentityCopyCertificate(identity, &certificateRef); NSArray *certificateArray = [[NSArray alloc] initWithObjects:(__bridge_transfer id)(certificateRef), nil]; NSURLCredentialPersistence persistence = NSURLCredentialPersistenceForSession; NSURLCredential *credential = [[NSURLCredential alloc] initWithIdentity:identity certificates:certificateArray persistence:persistence]; return credential; }
source share