How to construct a NSAppTransportSecurity exception for error -9806

I support an SDK that connects to "api.sailthru.com". When I started testing with iOS9, it failed:


Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo=0x12e26d90 {NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorCodeKey=-9806, NSErrorFailingURLStringKey=https://api.sailthru.com/job, _kCFStreamErrorDomainKey=3, NSUnderlyingError=0xb01d990 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1200.)", NSErrorFailingURLKey=https://api.sailthru.com/job


I knew about the new entitlements, so I tried to construct one:


<key>NSAppTransportSecurity</key>

<dict>

<key>NSExceptionDomains</key>

<dict>

<key>api.sailthru.com</key>

<dict>

<!--Include to allow subdomains-->

<key>NSIncludesSubdomains</key>

<true/>

</dict>

</dict>

</dict>


First, I tried with the full dictionary - where I set a minimum number for the TLS version, etc. Then deleted items and tried again. In the end, I could not find a way to get connections to my server working.


FInally, I used the big hammer:


<key>NSAppTransportSecurity</key>

<dict>

<!--Include to allow all connections (DANGER)-->

<key>NSAllowsArbitraryLoads</key>

<true/>

</dict>


Then, it worked. But this is no solution for the SDK users.


The OPS guys think it might be related to ciphers.


I'd love some options to play with - right now no one has any idea how to drill down on this. Oh, here is the CFNETWORKING log:


Jun 22 11:43:00 Purser[49438] <Notice>: CFNetwork Diagnostics [1:1] 11:43:00.035 {

LoaderWhatToDo

Request: <CFURL 0x7cea9150 [0x223ff70]>{string = https:/

CachePolicy: 1

WhatToDo: originload

CreateToNow: 0.00049s

} [1:1]

Jun 22 11:43:00 Purser[49438] <Notice>: CFNetwork Diagnostics [1:2] 11:43:00.040 {

AddCookies Continue: request POST https:/

HTTPProtocol: Task: 7cee90f0

} [1:2]

Jun 22 11:43:00 Purser[49438] <Notice>: CFNetwork Diagnostics [1:3] 11:43:00.041 {

Protocol Enqueue: request POST https:/

Request: <CFURLRequest 0x7ced6c20 [0x223ff70]> {url = https:/

Message: POST https:/

} [1:3]

Jun 22 11:43:00 Purser[49438] <Notice>: CFNetwork Diagnostics [1:4] 11:43:00.123 {

Response Error

Request: <CFURLRequest 0x7ced6c20 [0x223ff70]> {url = https:/

Error: Error Domain=kCFErrorDomainCFNetwork Code=-1200 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1200.)" UserInfo=0x7bfae8c0 {_kCFNetworkCFStreamSSLErrorOriginalValue=-9806, _kCFStreamErrorCodeKey=-9806, _kCFStreamErrorDomainKey=3, _kCFStreamPropertySSLClientCertificateState=0}

} [1:4]

Jun 22 11:43:00 Purser[49438] <Notice>: CFNetwork Diagnostics [1:5] 11:43:00.129 {

Did Fail

Loader: <CFMutableURLRequest 0x7ceefcb0 [0x223ff70]> {url = https:/

Error: Error Domain=kCFErrorDomainCFNetwork Code=-1200 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1200.)" UserInfo=0x7bfae8c0 {_kCFNetworkCFStreamSSLErrorOriginalValue=-9806, _kCFStreamErrorCodeKey=-9806, _kCFStreamErrorDomainKey=3, _kCFStreamPropertySSLClientCertificateState=0}

init to origin load: 0.00281298s

total time: 0.0941499s

total bytes: 0

} [1:5]

Jun 22 11:43:00 Purser[49438] <Notice>: CFNetwork Diagnostics [1:6] 11:43:00.133 {

destroyReadStream: request POST https:/

Request: <CFURLRequest 0x7ced6c20 [0x223ff70]> {url = https:/

sent: <CFNumber 0x7c8657b0 [0x223ff70]>{value = +0, type = kCFNumberSInt32Type}

received: <CFNumber 0x7c8657b0 [0x223ff70]>{value = +0, type = kCFNumberSInt32Type}

cell sent: <CFNumber 0x7c8657b0 [0x223ff70]>{value = +0, type = kCFNumberSInt32Type}

cell received: <CFNumber 0x7c8657b0 [0x223ff70]>{value = +0, type = kCFNumberSInt32Type}

} [1:6]

Jun 22 11:43:00 Purser[49438] <Notice>: CFNetwork Diagnostics [1:7] 11:43:00.134 {

~HTTPProtocol: nullptr request

Request: null

sent: 0

received: 0

cell sent: 0

cell received: 0

} [1:7]

Accepted Reply

Please try again on b2 using the docs I referenced earlier to guide your Info.plist setup. If that doesn't work, post back and include your latest Info.plist settings.

Share and Enjoy

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

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

Replies

A good first step here is to use TLSTool on your Mac to connect to the server to see what TLS version and protocol are negotiated by default. For example, here's what I get when running on 10.10.3.


$ TLSTool s_client -connect api.sailthru.com:443
*  input stream did open
* output stream did open
* output stream has space
* protocol: TLS 1.2
* cipher: RSA_WITH_AES_256_CBC_SHA256
* trust result: unspecified
* certificate subjects:
*   0 *.sailthru.com
*   1 Symantec Class 3 Secure Server CA - G4
*   2 VeriSign Class 3 Public Primary Certification Authority - G5
^C


As you can see, we get TLS 1.2 just fine. OTOH, the cypher suite,

RSA_WITH_AES_256_CBC_SHA256
, is going to be a problem because it does not provide forward secrecy. Try disabling that (with NSExceptionRequiresForwardSecrecy) and see what you get.

Share and Enjoy

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

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

I tried adding that key, but still the same -9806 error:


  <key>NSAppTransportSecurity</key>
  <dict>
  <key>NSExceptionDomains</key>
  <dict>
  <key>api.sailthru.com</key>
  <dict>
  <key>NSIncludesSubdomains</key>
  <true/>
  <key>NSExceptionRequiresForwardSecrecy</key>
  <true/>
  </dict>
  </dict>
  </dict>

Please try again on b2 using the docs I referenced earlier to guide your Info.plist setup. If that doesn't work, post back and include your latest Info.plist settings.

Share and Enjoy

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

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

I had the wrong boolean for NSExceptionRequiresForwardSecrecy: this works just fine:


<key>NSExceptionDomains</key>
<dict>
  <key>sailthru.com</key>
  <dict>
  <key>NSIncludesSubdomains</key>
  <true/>
  <key>NSExceptionRequiresForwardSecrecy</key>
  <false/>
  </dict>
</dict>


Thank you very much!

I have downloaded the TLSTool from your link and I have built it, but it doesn't display the TLSVersion as in your example, see the output result below.

Where can I get the TLSTool displaying the TLSversion?


$ /Users/sebastien/Downloads/TLSTool/build/Products/Debug/TLSTool s_client -connect api.sailthru.com:443
*  input stream did open
* output stream did open
* output stream has space
* trust result: unspecified
* certificate subjects:
*   0 *.sailthru.com
*   1 Symantec Class 3 Secure Server CA - G4
*   2 VeriSign Class 3 Public Primary Certification Authority - G5
* output stream has space
* output stream has space
*  input stream has bytes
*  input stream has bytes
*  input stream end
* close

I have downloaded the TLSTool from your link and I have built it, but it doesn't display the TLSVersion as in your example, see the output result below.

Yeah, that's my bad. I'm using an updated version of the tool that contains features beyond that found in the public version. My apologies.

Where can I get the TLSTool displaying the TLSversion?

If you drop me a line at my individual email address (see my signature), I can send you a copy.

I also need to work on getting my latest code on the public web site. Hmmm, how to find the time...

Share and Enjoy

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

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

Have added the keys in Info.plist file, but still getting the same error.



2015-09-07 18:24:26.913 Glimpulse[22533:212686] CFNetwork SSLHandshake failed (-9806)

2015-09-07 18:24:27.385 Glimpulse[22533:212686] CFNetwork SSLHandshake failed (-9806)

2015-09-07 18:24:27.861 Glimpulse[22533:212686] CFNetwork SSLHandshake failed (-9806)

2015-09-07 18:24:27.862 Glimpulse[22533:212686] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9806)


Added following keys :

<key>NSAppTransportSecurity</key>

<dict>

<key>NSAllowsArbitraryLoads</key>

<true/>

<key>NSExceptionDomains</key>

<dict>

<key>sandbox.glimpulse.com:9021</key>

<dict>

<key>NSIncludesSubdomains</key>

<true/>

<key>NSExceptionRequiresForwardSecrecy</key>

<false/>

</dict>

</dict>

</dict>

Hey, it would be great if you update source code for TLSTool, because your logs contain stuff like "protocol" or "cipher" that is not implemented in TLSTool availalable at: TLSTool

Hey, it would be great if you update source code for TLSTool …

Yep. I’ve been working to get that update out the door but it’s taken longer than I’d hoped. In the meantime, the offer above still stands.

Share and Enjoy

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

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

Yep. I’ve been working to get that update out the door …

The updated TLSTool just landed on the developer web site. Sorry it took so long; I got right to the final stage of publication and then decided to rework it to provide even more help with ATS.

Consider this:

$ TLSTool s_client -connect forums.developer.apple.com:443
*  input stream did open
* output stream did open
* output stream has space
* protocol: TLS 1.2
* cipher: ECDHE_RSA_WITH_AES_256_CBC_SHA384
* trust result: unspecified
* certificate info:
*  0 rsaEncryption 2048 sha256-with-rsa-signature 'forums.developer.apple.com'
*  1 rsaEncryption 2048 sha256-with-rsa-signature 'Symantec Class 3 EV SSL CA - G3'
*  2 rsaEncryption 2048 sha1-with-rsa-signature 'VeriSign Class 3 Public Primary Certification Authority - G5'
^C

As you can see here, the new version of the tool shows you all the parameters that are relevant for ATS:

  • the TLS version,

    TLS 1.2
  • the cypher suite,

    ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • the RSA or EC key size of the leaf certificate,

    2048
  • the hashing algorithm of the key certificate, that is, the

    sha256
    in `sha256-with-rsa-signature
  • the certificate chain leading from the leaf to the root.

Share and Enjoy

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

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