swiftxcodesslalamofireapp-transport-security

Alamofire https request only works if NSExceptionAllowsInsecureHTTPLoads is set to true


I have developed an app in Xcode10 with Swift (app name: "TerminalsPOC"). I am making an https request to my organization’s internal web api (let's call the url "https://example.com:50001/RESTAdapter/toolbox/getMyData") using Alamofire. I have a class with a class-level variable to reference a session manager:

// Swift code
    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        “example.com": .pinCertificates(
            certificates: ServerTrustPolicy.certificates(in: Bundle(for: type(of: self))),
            validateCertificateChain: false,
            validateHost: true
        )
    ]

     sessionManager = SessionManager(
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )

    sessionManager.request(url, method: .get) ... 

I have imported the necessary .cer certificate into the app’s bundle. I have left the default ATS settings, but have added an NSExceptionDomain. The relevant info.plist section looks like

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoadsInWebContent</key>
    <false/>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>example.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSIncludesSubdomains</key>
            <true/>
        </dict>

This works so long as the NSExceptionAllowsInsecureHTTPLoads setting is set to true. If I set it to false, the request fails with the message: An SSL error has occurred and a secure connection to the server cannot be made. [-1200]

2018-12-07 11:55:42.122423-0700 TerminalsPOC[27191:371810] ATS failed system trust 2018-12-07 11:55:42.122530-0700 TerminalsPOC[27191:371810] System Trust failed for [2:0x600001fad740]

2018-12-07 11:55:42.122637-0700 TerminalsPOC[27191:371810] TIC SSL Trust Error [2:0x600001fad740]: 3:0

2018-12-07 11:55:42.125928-0700 TerminalsPOC[27191:371810] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

2018-12-07 11:55:42.126109-0700 TerminalsPOC[27191:371810] Task <54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1> HTTP load failed (error code: -1200 [3:-9802])

2018-12-07 11:55:42.126872-0700 TerminalsPOC[27191:371812] Task <54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1> finished with error - code: -1200

2018-12-07 11:55:42.140600-0700 TerminalsPOC[27191:371810] Task <54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1> load failed with error Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSErrorPeerCertificateChainKey=( "", "" ), NSErrorClientCertificateStateKey=0, NSErrorFailingURLKey=https://example.com:50001/RESTAdapter/toolbox/getMyData, NSErrorFailingURLStringKey=https://example.com:50001/RESTAdapter/toolbox/getMyData, NSUnderlyingError=0x6000024e89f0 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=( "", "" )}}, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1>" ), _kCFStreamErrorCodeKey=-9802, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <54567E3C-2BBC-4227-9C0A-FC60370A10AA>.<1>, NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made.} [-1200]

I tried running “nscurl --ats-diagnostics https://example.com:50001/RESTAdapter/toolbox/getMyData”, and the response included the following:

Default ATS Secure Connection

--- ATS Default Connection Result : PASS

========

Allowing Arbitrary Loads

--- Allow All Loads Result : PASS

========= Configuring TLS exceptions for example.com

--- TLSv1.3 2018-12-07 10:59:17.492 nscurl[24303:331847] NSURLSession/NSURLConnection HTTP load failed

(kCFStreamErrorDomainSSL, -9800) Result : FAIL

--- TLSv1.2 Result : PASS

--- TLSv1.1 Result : PASS

--- TLSv1.0 Result : PASS

============ Configuring PFS exceptions for example.com

--- Disabling Perfect Forward Secrecy Result : PASS

========== Configuring PFS exceptions and allowing insecure HTTP for example.com

--- Disabling Perfect Forward Secrecy and Allowing Insecure HTTP Result : PASS

This all looks OK to me. I must be missing something.

So my questions are:

1. Why does setting the NSExceptionAllowsInsecureHTTPLoads to true cause the call to work, given that it is an https request (with no redirect)? I thought this setting only affects http calls, and should not affect https calls.

2. How can I get this web request to work without setting NSExceptionAllowsInsecureHTTPLoads (which seems to be a hack/work-around, doesn’t it)?


Solution

  • The problem in this case was that the app was running on a simulator on which the required certificate had not been installed.

    Once the correct (root) certificate had been installed and trusted, the pinned certificate check passed, and it was then possible to set the NSExceptionAllowsInsecureHTTPLoads info.plist setting back to "NO".

    I wish the error message had been more explicit. :-/