Search code examples
iossslnginxapp-transport-security

iOS App Transport Security not accepting TLSv1.2 connection and plist exceptions not making any difference


I've got an iOS app which uses SSL/HTTPS to communicate with a server. The server is providing a certificate that works over TLSv1.2 (the main requirement of App Transport Security). An example URL that demonstrates this (where the TLSv1.2 can be verified by checking the certificate) is https://api.branon.co.uk/checkOnline.

However, the app is throwing errors relating to the App Transport Layer - errors that, when Googled - imply it's because the server isn't working over TLSv1.2. An example error is:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

and:

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)

I even added a bunch of exceptions to the plist file, such as:

<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key><my top level domain - the app uses a subdomain - allowed below></key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSTemporaryExceptionMinimumTLSVersion</key>
            <string>TLSv1.1</string>
        </dict>
    </dict>
</dict>
</plist>

but this doesn't change the result.

The certificate used is a free certificate issued from StartCom. My nginx config is below (just for reference).

server {
    listen [::]:443 ssl;
    listen 443 ssl;
    ssl on;
    ssl_certificate /root/ssl/<domain>.crt;
    ssl_certificate_key /root/ssl/server.key;
    server_name api.<domain>;
    access_log /var/log/nginx/api.access.log;
    error_log /var/log/nginx/api.error.log;
    location ~ ^/([a-zA-Z]+)$ {
        proxy_pass http://127.0.0.1:5000/$1;
    }
}

Does anybody have any idea why this is happening?

Thanks!

Update: Following the results of @Paulw11's suggested test (below) running nscurl, I decided just to try disabling App Transport Security entirely. I changed the App Transport Security dictionary in my plist to the below:

<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

and am still getting the same error! So if it's not App Transport Security, what could be causing this? That error I'm getting again is: NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)


Solution

  • The server does not provide a complete certificate chain in its SSL/TLS handshake. While some clients can handle this and build out a trust chain, others cannot.

    You can find the missing intermediate certificate via https://whatsmychaincert.com/?api.branon.co.uk and serve it along with your site's certificate in your SSL configuration in nginx.

    Do remember to remove any ATS exceptions that you may have put in place!