CA certificate pinning and how to generate correct NSError code?

Greetings,

we have an app in the app store that performs Man In The Middle attack detection by checking if the root certificate for a specific server certificate is what we expect. Please note that we are aware of this technique's shortcomings and advantages. However this logic works well for us.


When receiving a NSURLAuthenticationMethodServerTrust challenge, if the CA certificate is the right one we call:

[challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge];


if the CA certificate does not match our criteria we call:

[challenge.sender cancelAuthenticationChallenge:challenge];


The problem is that when cancelling the NSURLAuthenticationMethodServerTrust challenge the NSError that is passed to the connection:didFailWithError: has nothing to do with unknown/invalid root certificates but rather it is an NSError with the code set to NSURLErrorUserCancelledAuthentication (-1012).


Therefore the question we have is, what if anything has to be done in the NSURLConnectionDelegate's connection:willSendRequestForAuthenticationChallenge: instead of/in addition to cancelling the NSURLAuthenticationMethodServerTrust challenge to force a certificate related NSError to be generated? We've researched this and everything found points to cancelling the NSURLAuthenticationMethodServerTrust challenge being the right approach.


Note: We are aware that NSURLConnection is deprecated, but we assume that this issue is the same for when we migrate to NSURLSession, and we need to address this issue right now.


Thank you,

--Neal

Accepted Reply

The easiest solution to this problem is to have the delegate save that error in a property and then call

-cancelAuthenticationChallenge:
. When
-connection:didFailWithError:
, it can test that property first and, if it’s populated, ignore the error parameter and use that value instead.

We are aware that NSURLConnection is deprecated, but we assume that this issue is the same for when we migrate to NSURLSession …

This is actually trickier to fix in the NSURLSession space because the delegate is shared by all session tasks (a session task is roughly equivalent to the misnamed NSURLConnection).

Share and Enjoy

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

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

Replies

The easiest solution to this problem is to have the delegate save that error in a property and then call

-cancelAuthenticationChallenge:
. When
-connection:didFailWithError:
, it can test that property first and, if it’s populated, ignore the error parameter and use that value instead.

We are aware that NSURLConnection is deprecated, but we assume that this issue is the same for when we migrate to NSURLSession …

This is actually trickier to fix in the NSURLSession space because the delegate is shared by all session tasks (a session task is roughly equivalent to the misnamed NSURLConnection).

Share and Enjoy

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

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