I recently came up against an issue in an iOS app where the development server for the web service I needed to access was using a self-signed SSL certificate.
If you've ever come across this scenario before, you'll know that iOS will not accept the certificate, as it is untrusted - so how do you access the web service?
NSURLConnection
provides a couple of delegate APIs to handle these kinds of situations:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
In the first method, you'll need to return YES or NO depending on whether or not your delegate object can authenticate against the different types of protection spaces. In this case, we're interested in a protection space that uses the authentication method: NSURLAuthenticationMethodServerTrust. So if it's that kind, return YES, like so:
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
Secondly, we need to manually tell the URL connection that the certificate is trusted by us, like this:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
{
if ([challenge.protectionSpace.host isEqualToString:@"myhostname.com"])
{
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}
}
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
Notice that the above code is checking the authentication challenge for the hostname provided in the authentication. If the hostname is equal to the hostname we are expecting, then we tell the authentication challenge that we'd like to trust the certificate.
Et voila! The URL connection now succeeds when using a self-signed SLL certificate!
It should be noted that this was for a development environment where I had no control over the cert being used or how it was originally signed. In no cases should a production server be using a self-signed untrusted cert.