I'm trying to accept self-signed certificates in a NSURLConnection, as many have before me. The catch is that I only want to accept certs from a whitelist of certs I trust. I'd settle for figuring out how to accept a single cert. Here's the code I've got so far in my NSURLConnectionDelegate:
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"trusted" ofType:@"der"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef myCertData = (__bridge_retained CFDataRef)certData;
SecCertificateRef myCert = SecCertificateCreateWithData(NULL, myCertData);
SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
SecCertificateRef certArray[1] = { myCert };
CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
SecTrustRef myTrust;
OSStatus status = SecTrustCreateWithCertificates(myCerts, myPolicy, &myTrust);
SecTrustResultType trustResult;
if (status == noErr) {
status = SecTrustEvaluate(myTrust, &trustResult);
}
BOOL trusted = NO;
if (trustResult == kSecTrustResultUnspecified) {
// I never get here. Instead, trustResult is always kSecTrustResultRecoverableTrustFailure
trusted = YES;
}
if (trusted) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]
forAuthenticationChallenge:challenge];
} else {
[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
}
CFRelease(myTrust);
CFRelease(myCerts);
CFRelease(myPolicy);
CFRelease(myCert);
CFRelease(myCertData);
} else {
[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
}
}
As you can see in the comment, I never actually get kSecTrustResultUnspecified, which is what I expect to get. I verified that my cert is correct, and in the correct format (DER).
If you want to turn on SSL/TLS trust for that certificate, go to Settings > General > About > Certificate Trust Settings. Under "Enable full trust for root certificates," turn on trust for the certificate. Apple recommends deploying certificates via Apple Configurator or Mobile Device Management (MDM).
Navigate to the site with the cert you want to trust, and click through the usual warnings for untrusted certificates. In the address bar, right click on the red warning triangle and "Not secure" message and, from the resulting menu, select "Certificate" to show the certificate.
The user can then trust the certificate on the device by going to Settings > General > About > Certificate Trust Settings.
Okay, figured it out. It turns out you just need to check the server trust, and actually use the cert data.
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
BOOL trusted = NO;
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"trusted" ofType:@"der"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef certDataRef = (__bridge_retained CFDataRef)certData;
SecCertificateRef cert = SecCertificateCreateWithData(NULL, certDataRef);
SecPolicyRef policyRef = SecPolicyCreateBasicX509();
SecCertificateRef certArray[1] = { cert };
CFArrayRef certArrayRef = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
SecTrustSetAnchorCertificates(serverTrust, certArrayRef);
SecTrustResultType trustResult;
SecTrustEvaluate(serverTrust, &trustResult);
trusted = (trustResult == kSecTrustResultUnspecified);
CFRelease(certArrayRef);
CFRelease(policyRef);
CFRelease(cert);
CFRelease(certDataRef);
}
if (trusted) {
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
} else {
[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With