Here's the code to add to NSURLConnectionDelegate
's connection:didReceiveAuthenticationChallenge:
. It loads a CA in DER format, and verifies a particular server's against that one CA.
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust])
{
do
{
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
if(nil == serverTrust)
break; /* failed */
NSData* caCert = [NSData dataWithContentsOfFile:@"ca-rsa-cert.der"];
if(nil == caCert)
break; /* failed */
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
if(nil == caRef)
break; /* failed */
NSArray* caArray = [NSArray arrayWithObject:(__bridge id)(caRef)];
if(nil == caArray)
break; /* failed */
OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
if(!(errSecSuccess == status))
break; /* failed */
SecTrustResultType result = -1;
status = SecTrustEvaluate(serverTrust, &result);
if(!(errSecSuccess == status))
break; /* failed */
/* https://developer.apple.com/library/ios/technotes/tn2232/_index.html */
/* https://developer.apple.com/library/mac/qa/qa1360/_index.html */
/* kSecTrustResultUnspecified and kSecTrustResultProceed are success */
if(result != kSecTrustResultUnspecified && result != kSecTrustResultProceed)
break; /* failed */
// The only good exit point
return [[challenge sender] useCredential: [NSURLCredential credentialForTrust: serverTrust]
forAuthenticationChallenge: challenge];
} while(0);
}
// Bad dog
return [[challenge sender] cancelAuthenticationChallenge: challenge];
If you call [connection cancel];
on the bad path, then connection:didFailWithError:
will not be invoked.