0
votes

I've seen this error around before and it seems the remedy is to add info to the .plist file. I've tried each of the ones I've seen:

How do I load an HTTP URL with App Transport Security enabled in iOS 9?

NSURLSession/NSURLConnection HTTP load failed on iOS 9

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802) on a subdomain?

Still my program results in the same error thrown:

2017-05-08 08:29:37.781075-0400 xxxx[3256:408961] [] nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue: [-9812] 2017-05-08 08:29:37.781 xxxx[3256:408982] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

My relevant code is here:

    let username = "xxxx"
    let password = "xxxx"
    let loginString = String(format: "%@:%@", username, password)
    let loginData = loginString.data(using: String.Encoding.utf8)!
    let base64LoginString = loginData.base64EncodedString()

    let baseUrl = "https://xxxx"
    var request = URLRequest(url: URL(string: baseUrl)! as URL)

let baseUrl = "server i want.xml"
        let request = NSMutableURLRequest(url: NSURL(string: baseUrl)! as URL)
        request.httpMethod = "POST"
        request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")
        let session = URLSession.shared

        var err: NSError?

        let task = session.dataTask(with: request as URLRequest) {
            (data, response, error) in

            if data == nil {
                print("dataTaskWithRequest error: \(err)")
                return
            }

            let xml = SWXMLHash.parse(data!)
            let serialNumFromXML = xml["mobile_devices"]["mobile_device"]["serial_number"].element?.text

func urlSession(
    _ session: URLSession,
    didReceive challenge: URLAuthenticationChallenge,
    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
    completionHandler(
        .useCredential,
        URLCredential(trust: challenge.protectionSpace.serverTrust!))
}

I've read it may have to do with the certificate, but I can't change the server because I'm not in charge of it, so I can't get an appropriate certificate. Is there more to it than changing the plist?

My plist file had the Allow Arbitrary Loads and an exception domain for the domain that my XML file is on.

I can get the contents of a test file, like https://www.w3schools.com/xml/note.xml, but the file I need is behind a username/password "Authentication Required" popup.

I've also tried the Alamofire library, same thing occurs:

nw_coretls_callback_handshake_message_block_invoke_3 tls_handshake_continue: [-9807] 2017-05-08 09:42:08.452 xxx[6128:888398] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

1
@KKRocks Hmm. I just did the self-signed certificate and it didn't fix. nscurl results in all tests failing, but I don't control the server so I can't fix itAON

1 Answers

3
votes

Okay well I didn't know how to fix this but I discovered that Alamofire can be used to do what I needed. This is a local project for inventory management so I wasn't concerned about the security of bypassing the certificates. My code is here:

       Manager.delegate.sessionDidReceiveChallenge = { session, challenge in
        var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
        var credential: URLCredential?

        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, let trust = challenge.protectionSpace.serverTrust {
            disposition = URLSession.AuthChallengeDisposition.useCredential
            credential = URLCredential(trust: trust)
        } else {
            if challenge.previousFailureCount > 0 {
                disposition = .cancelAuthenticationChallenge
            } else {
                credential = Manager.session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)

                if credential != nil {
                    disposition = .useCredential
                }
            }
        }

        return (disposition, credential)
    }

private var Manager: Alamofire.SessionManager = {

// Create the server trust policies
let serverTrustPolicies: [String: ServerTrustPolicy] = [
    "https://SERVER:PORT": .disableEvaluation
]

// Create custom manager
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
let manager = Alamofire.SessionManager(
    configuration: URLSessionConfiguration.default,
    serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
let sessionManager = SessionManager(
    serverTrustPolicyManager: ServerTrustPolicyManager(
        policies: ["https://SERVER:PORT": .disableEvaluation]
    )
)
return manager
}()

open class MyServerTrustPolicyManager: ServerTrustPolicyManager {

// Override this function in order to trust any self-signed https
open override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
    return ServerTrustPolicy.disableEvaluation
 }

}