Why does NSURLSession in iOS9 return -9802?

I had a related issue a while ago explained in this thread. Now, when trying to connect to s3.amazonaws.com, I'm getting a -9802 error. As per the other thread, I used TLSTool to help discover the security settings for the problematic URL, "https://s3.amazonaws.com/...":


$ TLSTool s_client -connect s3.amazonaws.com:443
*  input stream did open
* output stream did open
* output stream has space
* protocol: TLS 1.2
* cipher: ECDHE_RSA_WITH_AES_128_CBC_SHA
* trust result: unspecified
* certificate subjects:
*   0 s3.amazonaws.com
*   1 VeriSign Class 3 Secure Server CA - G3
*   2 VeriSign Class 3 Public Primary Certification Authority - G5
*  input stream has bytes
*  input stream end
* close
* bytes sent 0, bytes received 0


Note that the protocol is TLSv1.2 and that the cipher is in the approved list in the Apple Doc specifying the requirements.


Then, I tried playing around with exceptions settings in my plist, and found the magic values (actually, not sure I need the NSIncludesSubdomains):


<key>s3.amazonaws.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
</dict>


What's up? Why do I need NSExceptionRequiresForwardSecrecy when I the site uses ECDHE_RSA_WITH_AES_128_CBC_SHA (on the list of approved forward ciphers) - bug? Am I missing some other red flag in the TLSTool output?


[I'm using the latest Xcode 7b4 ...]

Here's a sample project that has NSExceptionAllowsInsecureHTTPLoads.

Thanks. It’s really helpful to have a simple example to play with. And, after a bit of spelunking, I have a rough idea what’s going on.

Your test app accesses

api.braintreegateway.com
, so I compared its TLS setup to dhoerl’s S3 example that I’ve been testing:
$ TLSTool s_client -connect api.braintreegateway.com:443
…
* protocol: TLS 1.2
* cipher: ECDHE_RSA_WITH_AES_128_CBC_SHA256
* trust result: unspecified
* certificate info:
*  0 rsaEncryption 2048 sha1-with-rsa-signature 'api.braintreegateway.com'
…
^C
$ TLSTool s_client -connect s3.amazonaws.com:443
…
* protocol: TLS 1.2
* cipher: ECDHE_RSA_WITH_AES_128_CBC_SHA
* trust result: unspecified
* certificate info:
*  0 rsaEncryption 2048 sha1-with-rsa-signature 's3.amazonaws.com'
…
^C

The results are very similar, with two things to note:

  • Your site uses

    ECDHE_RSA_WITH_AES_128_CBC_SHA256
    , which is ‘better’ than the
    ECDHE_RSA_WITH_AES_128_CBC_SHA
    used by S3. Both are explicitly allowed by ATS.
  • Both sites use

    sha1-with-rsa-signature
    , which is the ATS roadblock we’re trying to get around.

I then set up a test project with an ATS dictionary like this:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>s3.amazonaws.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
        <key>api.braintreegateway.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

Weirdly, this works for S3 and not for your domain. Why?

After some digging I worked this out: the OS thinks that your site requires HTTP Strict Transport Security (HSTS). Now, I don’t know why the OS thinks that, but the fact that it does overrides the ATS exception in the

Info.plist
. In short, HSTS trumps ATS.

Alas, I’ve totally run out of time to investigate this in the context of DevForums. I’d be happy to look into the HSTS side of things in the context of a DTS tech support incident.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

It turns out the domain I'm actually interested in has HSTS headers like Skunkworks example. That seems to be the key.

Why does NSURLSession in iOS9 return -9802?
 
 
Q