Search code examples
iossslswift3

Certificate for this server is invalid for self signed cert on swift 3


I am using swift 3 and hitting a web service for the first time. My web service runs over HTTPS and I want to test with encryption in place.

Here's my code so far:

    let config = URLSessionConfiguration.default // Session Configuration
    let session = URLSession(configuration: config) // Load configuration into Session
    let url = URL(string: webService.getLoginUrl())!

    let task = session.dataTask(with: url, completionHandler: {
        (data, response, error) in

        if error == nil {
            do {
                if let json =
                    try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String: Any]{
                    //Implement your logic
                    print(json)
                }
            } catch {
                print("error in JSONSerialization")
            }
        } else {
            print(error!.localizedDescription)
        }

    })
    task.resume()

When I run this against my test server, which is self-signed, I get:

The certificate for this server is invalid. You might be connecting to a server that is pretending to be “10.0.0.51” which could put your confidential information at risk.

So what I'd like to do is accept all certificates when testing, but not in production.

I've found a couple of sites like:

http://www.byteblocks.com/Post/Use-self-signed-SSL-certificate-in-iOS-application https://github.com/socketio/socket.io-client-swift/issues/326

But these appear to predate swift 3.

How do I solve this problem?


Solution

  • After much research, I learned about how delegates work with URLSession objects in swift 3. Too many pieces to post a link, but in the end, this was the most helpful: https://gist.github.com/stinger/420107a71a02995c312036eb7919e9f9

    So, to fix the problem, I inherited my class from URLSessionDelegate and then added the following function:

    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    
        //accept all certs when testing, perform default handling otherwise
        if webService.isTesting() {
            print("Accepting cert as always")
            completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
        }
        else {
            print("Using default handling")
            completionHandler(.performDefaultHandling, URLCredential(trust: challenge.protectionSpace.serverTrust!))
        }
    }
    

    The isTesting() call determines if I'm using the test server, and then we accept all certificates if we're in testing mode.