2


    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: Portecle app Examination


Let me know if there is something wrong.

Thanks.

2
  • And no I'm not using ASIHTTPRequest APIs. I'm using NSURLConnection APIs and cannot change to some other third party library at this moment. I'm using self-signed certificate from server created using OpenSSL. Commented Jun 12, 2012 at 9:08
  • possible duplicate of Problem with NSURLConnection Commented Mar 13, 2013 at 23:57

2 Answers 2

2

I cannot tell if your code is valid or not, because I use RestKit for consuming REST interfaces, however the most common problem that results in NSURLErrorDomain Code=-1012 is that the self-signed certificate does not have subject alternative name extension pointing to the web service if address.

To examine your certificate, download the Portecle app, very useful if you need to look inside ssl certificates. Run it and choose Examine->Examine Certificate from the menu and navigate to your certificate. You will see basic information about your certificate, now press the Examine button, then Subject alternative name, and make sure proper ip address of your web service is there. If not, you need to create the certificate again with this information in place.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks @lawicko. I downloaded the Portecle app and examined the certificate.
As you can see, the 'Extensions' button is grayed out, which means your certificate doesn't have any. That was the direct reason the certificate didn't validate in my case. All I did was to ask the guy responsible for the web service to create new certificate. Unfortunately all I know is that he used openssl for that, so I can't help more, but I think it's worth investigating further.
1

I did figure out how to resolve this issue.

I ended up comparing the client and server trust certificates, byte-by-byte. Although there could be another way to resolve such issues of self-signed certificate, but for this solution did work. Here is how I'm doing comparison of the client and server certificates, byte-by-byte, using their CFData objects(you can also reference 'AdvancedURLConnections' example code provided by Apple):

success = NO; pServerCert = SecTrustGetLeafCertificate(trust); if (clientCert != NULL) { CFDataRef clientCertData; CFDataRef serverCertData; clientCertData = SecCertificateCopyData(clientCert); serverCertData = SecCertificateCopyData(pServerCert); assert(clientCertData != NULL); assert(serverCertData != NULL); success = CFEqual(clientCertData, serverCertData); CFRelease(clientCertData); CFRelease(serverCertData); } if (success) { [[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]; } 

Hope this will help someone, who is looking for solution of similar issue,

Thanks.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.