iossslhttp-status-code-403client-certificatesapp-transport-security

Bug in iOS 9 when using client SSL certs and generating HTTP 403 errors


I think we just discovered a bug on iOS 9 (version as of Oct 23rd 2015) when using client SSL certs to talk to a backend API. In common with a lot of REST services, our API generates 4xx error codes to communicate status. One of those is a 403 Forbidden error when a client tries to access paths that a specific client ID is not authorized to access. Note that this HTTP error occurs AFTER the client SSL cert has setup a valid connection & and the client ID has been authenticated.

In iOS 9, this sequence will generate an invalid client SSL error:

FAILED: Error Domain=NSURLErrorDomain Code=-1206 "The server “our.server.here” requires a client certificate."

(note: this a followup to my tweet here: https://twitter.com/ckmaresca/status/657576686318256128 - I figured SO is the place most people will search for this)


Solution

  • It took us days to finally figure out but it turns out that this particular error is generated by Apple's new Application Transport Layer security. Specifically, it seems that if you are using client certs and your backend API generates an HTTP 403 error, ATL believes that the cert is bad and kills the entire transaction.

    We know this because we can see in our server logs that the request goes through and executes properly. We've also observed that the socket stays alive trough the request and this error only shows up after the response from the server is received. We also know our client cert works since any path not returning a 403 works with zero errors and changing the HTTP error code to 401 makes this problem go away.

    This is problematic for a number of reasons, but mostly because HTTP errors are not SSL errors. The two can operate independently and it's perfectly possible to have a 403 error with a valid client side SSL certificate....

    The work around is to change all your 403 errors to something else. I would note that a large number of Oauth1/2 servers will generate various 403 errors, so this might be non-trivial. Alternatively, it might be possible to use a reverse proxy to remap HTTP 403 errors to a different HTTP code - we have not tested this.

    We have filed a bug with Apple, but I wanted to give people a heads up so maybe they can avoid banging their heads against a wall like we did for a week....

    Thanks to the Sherbit.io enginnering team (specifically Varun & Matt) for debugging this.