I'm fairly new to consuming webservices using SSL channel. After fairly good search I had found a way to perform SSL/HTTPS authentication using NSURLConnection delegate APIs. Following is the code snippet that does the actual authentication thing:
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
[self printLogToConsole:@"Authenticating...."];
[self printLogToConsole:[NSString stringWithFormat:@"\n%@\n", [challenge description]]];
NSLog(@"\n\nserverTrust: %@\n", [[challenge protectionSpace] serverTrust]);
/* Extract the server certificate for trust validation
*/
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
assert(protectionSpace);
SecTrustRef trust = [protectionSpace serverTrust];
assert(trust);
CFRetain(trust); // Make sure this thing stays around until we're done with it
NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];
/* On iOS
* we need to convert it to 'der' certificate. It can be done easily through Terminal as follows:
* $ openssl x509 -in certificate.pem -outform der -out rootcert.der
*/
NSString *path = [[NSBundle mainBundle] pathForResource:@"rootcert" ofType:@"der"];
assert(path);
NSData *data = [NSData dataWithContentsOfFile:path];
assert(data);
/* Set up the array of certificates, we will authenticate against and create credentials */
SecCertificateRef rtCertificate = SecCertificateCreateWithData(NULL, CFBridgingRetain(data));
const void *array[1] = { rtCertificate };
trustedCerts = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
CFRelease(rtCertificate); // for completeness, really does not matter
/* Build up the trust anchor using our root cert */
int err;
SecTrustResultType trustResult = 0;
err = SecTrustSetAnchorCertificates(trust, trustedCerts);
if (err == noErr) {
err = SecTrustEvaluate(trust, &trustResult);
}
CFRelease(trust); // OK, now we're done with it
[self printLogToConsole:[NSString stringWithFormat:@"trustResult: %d\n", trustResult]];
/* http://developer.apple.com/library/mac/#qa/qa1360/_index.html
*/
BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultConfirm) || (trustResult == kSecTrustResultUnspecified));
// Return based on whether we decided to trust or not
if (trusted) {
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
[self printLogToConsole:@"Success! Trust validation successful."];
} else {
[self printLogToConsole:@"Failed! Trust evaluation failed for service root certificate.\n"];
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
But I'm getting following error:
2012-06-11 17:10:12.541 SecureLogin[3424:f803] Error during connection: Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed. (NSURLErrorDomain error -1012.)" UserInfo=0x682c790 {NSErrorFailingURLKey=https://staging.esecure.url/authentication/signin/merchants, NSErrorFailingURLStringKey=https://staging.esecure.url/authentication/signin/merchants}
I'm using the same certificate that I got from the server and converted it to 'der' format. I'm building app for iOS 5.x.
I'm not sure whether I'm missing out on something. Let me know of your suggestions.
Thanks.
EDIT After examining the certificate here how the output looks:
Let me know if there is something wrong.
Thanks.