Search code examples
iosswiftsslhttpsself-signed

How do I accept a self-signed SSL certificate using iOS 7's NSURLSession


I have the following code (swift implementation):

func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace) -> Bool
{
    return protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
}

func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge)
{
    if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
    {

        if challenge.protectionSpace.host == "myDomain"
        {
            let credentials = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
            challenge.sender.useCredential(credentials, forAuthenticationChallenge: challenge)
        }
    }

    challenge.sender.continueWithoutCredentialForAuthenticationChallenge(challenge)

}

It works perfectly in iOS 8.x, but does not work iOS 7.x In iOS 7.x I have error:

NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

Any idea? thank you!!!


Solution

  • Both connection:canAuthenticateAgainstProtectionSpace: and connection:didReceiveAuthenticationChallenge: are deprecated in iOS 8 anyway so you should use other methods.

    What I am using in my projects is a delegate method of NSURLSessionDelegate. Adhere to that protocol then add this method:

    func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void) {
        completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust))
    }
    

    Then, when you use initialize NSURLSession with delegate set to self. For example:

    var session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
    

    Then use that session instance to call dataTaskWithRequest method on:

    var task = session.dataTaskWithRequest(request){
        (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
        if error != nil {
            callback("", error.localizedDescription)
        } else {
            var result = NSString(data: data, encoding:
                NSASCIIStringEncoding)!
        }
    }
    task.resume()
    

    Complete working example can be found here.

    For security reasons, if you use a self-signed certificate I recommend also implementing public key pinning (https://gist.github.com/edwardmp/df8517aa9f1752e73353)