iOS9 App Transport Security (ATS)

App Transport Security (ATS) enforces best practices in the secure connections between an app and its back end. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt; it is also on by default in iOS 9 and OS X v10.11. Apple suggests you to adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one.

However the most work to be done is to ensure your backend fulfils all requirements. At first it must use TLS version 1.2 with forward secrecy. If you try to make a connection that doesn’t follow this requirement, an error is thrown. Moreover you have to be carful about certificates used on your servers and the enabled cipher suites.

With ATS fully enabled, your app’s HTTP connections must use HTTPS and must satisfy the following security requirements[CocoaKeys]:

  • The server certificate must meet at least one of the following trust requirements:
    • Issued by a certificate authority (CA) whose root certificate is incorporated into the operating system
    • Issued by a trusted root CA and installed by the user or a system administrator
  • The negotiated Transport Layer Security version must be TLS 1.2
  • The negotiated TLS connection cipher suite must support forward secrecy (FS) and be one of the following:
    • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
    • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
    • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
    • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
    • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
    • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
  • The leaf server certificate must be signed with one of the following types of keys:
    • Rivest-Shamir-Adleman (RSA) key with a length of at least 2048 bits
    • Elliptic-Curve Cryptography (ECC) key with a size of at least 256 bits

    In addition, the leaf server certificate hashing algorithm must be Secure Hash Algorithm 2 (SHA-2) with a digest length of at least 256 (that is, SHA-256 or greater).

Note: If your backend supports GCM Mode for encryption you should decide to install this cipher. Galois/Counter Mode (GCM) is a mode of operation for symmetric key cryptographic block ciphers that has been widely adopted because of its efficiency and performance. GCM throughput rates for state of the art, high speed communication channels can be achieved with reasonable hardware resources. GCM can take full advantage of parallel processing and implementing GCM can make efficient use of an instruction pipeline or a hardware pipeline. In contrast, the cipher block chaining (CBC) mode of operation incurs significant pipeline stalls that hamper its efficiency and performance.

How to solve Connectivity Problems

If you encounter  CFNetwork SSLHandshake failed errors  follow theses steps to figure out why.

CFNetwork Logging

As a first step you can turn on CFNetwork Diagnostic Logging. Edit the Xcode scheme and add the CFNETWORK_DIAGNOSTICS environment variable. I set the logging level to 3 which is the most verbose. You can also set the variable directly in code as early as possible i.e. in your main.c file.

setenv(CFNETWORK_DIAGNOSTICS,3 1);

The Xcode console shows the location of the log file:

CFNetwork diagnostics log file created at: /private/var/mobile/Containers/ Data/Application/B378AC40-A5E1-44D0-A7F1-B3BB254D1405/Library/Logs/ CrashReporter/CFNetwork_com.useyourloaf.TwitterSearch_703.nwlrb.log

If you tether the device to a Mac, you can run Xcode and see the log directly in the Devices window.

Using Curl (or NSCurl)

A better approach than CFNetwork logging is to use NSCurl which provides some App Transport Security specific diagnostics.

nscurl --ats-diagnostics https://vidia.swisscom.ch

You can also stick with plain old curl for now:


* Rebuilt URL to: https://vidia.swisscom.ch/
*   Trying 212.243.171.7...
* Connected to vidia.swisscom.ch (212.243.171.7) port 443 (#0)
* TLS 1.2 connection using TLS_RSA_WITH_AES_256_CBC_SHA256
* Server certificate: vidia.swisscom.ch
* Server certificate: thawte SSL CA - G2
* Server certificate: thawte Primary Root CA
> GET / HTTP/1.1
> Host: vidia.swisscom.ch
> User-Agent: curl/7.43.0
> Accept: */*
>
* HTTP 1.0, assume close after body
< HTTP/1.0 301 Moved Permanently
< Location: https://vidia.swisscom.ch/app/
< Connection: close
< Content-Length: 0
<
* Closing connection 0

This tells us that Swisscom is using TLS 1.2 which is necessary for App Transport Security. It also tells us the cipher suite that it is using (TLS_RSA_WITH_AES_256_CBC_SHA256). You can check this against the supported cipher suites in the App Transport Security Technote. This cipher does not support forward secrecy – another requirement for App Transport Security. So this makes the SSL handshake fail!

Testing with SSL Labs

You can get a more detailed analysis using the free site testing tool from Qualys SSL Labs. Testing again with  vidia.swisscom.ch. The site gets an “A” rating but there is a warning about a certificate with a weak signature.

Certificate uses a weak signature. When renewing, ensure you upgrade to SHA2.

The detailed report on the certificate confirms the SHA1 algorithm which is now considered to be weak.

Signature algorithm SHA1withRSA WEAK

However this is not the leaf certificate so we are on the safe side.

Qualys SSL Labs  will also generate a useful report about ciphers interoperability  check out the client interoperability section in “Apple ATS / iOS9”.

Enabling Exceptions to App Transport Security

Knowing that our problem is a weakly signed certificate together with no forward secrecy is interesting but not so helpful when the web service is owned by a company we do not belong. Until Swisscom upgrades the certificate security we need to create an exception to the default policy.

A quick fix is to globally disable App Transport Security. In the App Info.plist file add the dictionary key NSAppTransportSecurity with a boolean key NSAllowsArbitraryLoads set to YES.
This gets us a working connection to vidia.swisscom backend but has the disadvantage of disabling App Transport Security for any other connections the App creates. A better approach is to only create exceptions for the insecure domains.

To create a domain specific exception add the dictionary key NSExceptionDomains to the NSAppTransportSecurity dictionary. Then add a dictionary entry for each domain that needs an exception. The key for the entry should be the domain name (e.g. video.swisscom.ch). You specify the details of the exception with one or more keys:

  • NSIncludesSubdomains (Boolean): Use YES if the exception applies to all subdomains.
  • NSExceptionMinimumTLSVersion (String): Valid values are “TLSv1.0”, “TLSv1.1” and the default “TLS1.2”.
  • NSExceptionRequiresForwardSecrecy (Boolean): Use NO if you need to use a cipher suite that does not support forward secrecy. This allows some extra cipher suites for the widely used RSA key exchange algorithm – see the App Transport Security Technote for details.
  • NSExceptionAllowsInsecureHTTPLoads (Boolean): Use YES for connections not using HTTPS or with incorrectly or weakly signed certificates.

There are also versions of the above keys for domains owned by a third party:

  • NSThirdPartyExceptionMinimumTLSVersion
  • NSThirdPartyExceptionRequiresForwardSecrecy
  • NSThirdPartyExceptionAllowsInsecureHTTPLoads

The problem  is a weakly signed certificate so we can create an exception for that domain using the NSThirdPartyExceptionAllowsInsecureHTTPLoads key:

This fixes the problem and keeps App Transport Security active for any other connections the App might use in the future

tomkausch

Leave a Reply

Your email address will not be published. Required fields are marked *