0

I am responding to a challenge where the protectionSpace.authenticationMethod == "NSURLAuthenticationMethodServerTrust".

I'm creating the credential forTrust and adding it to the NSURLCredentialStorage.

But each time I restart the app (running in the simulator) I get the challenge again. During any one session it only asks once because I added the forTrust credential to the storage. Also, I can see that that protectionSpace in the NSURLCredential storage. But when I restart the App it's gone and I have to trust the server all over again.

The server is using a self signed certificate and I am access via HTTPS

Please help!

Thanks in advance.

Rob
  • 757
  • 1
  • 10
  • 26
  • " is using a self signed certificate". Are you performing a custom evaluation of the server trust as outlined in Technote 2232? https://developer.apple.com/library/mac/technotes/tn2232/_index.html#//apple_ref/doc/uid/DTS40012884 – quellish Sep 12 '14 at 22:36
  • I give the user an option to trust the source server or not. If they trust it, I create the credential forTrust, add it to the NSCredentialStorage and make it the default for that protectionSpace. I just can't figure out how to make that permanent so that the trust question does not come up each time they launch the App (after it has gone out of memory) – Rob Sep 13 '14 at 02:29
  • Yeah, you have to do a custom trust evaluation and store *that*, i.e. your self signed cert has to be an anchor in the trust you are storing. – quellish Sep 13 '14 at 03:37
  • Do you know where I could find an example of that to review? I'm using Swift now, but can translate from Obj-C if need be. – Rob Sep 13 '14 at 04:55

1 Answers1

1

Technical Note TN2232: HTTPS Server Trust Evaluation lays out the recommended best practices for using a self signed certificate in an iOS application. The recommended approach is to implement the TLS trust evaluation like SSL pinning: trusting a specific certificate or public key. Implementing this was demonstrated in the WWDC 2014 session Building Apps for Enterprise and Education. Unfortunately the code for SSL pinning has not been released as sample code, nor is it available in the slides - only the video. The process of evaluating the server trust is explained well in the session.

This does not solve your problem of persisting the evaluated server trust. The server trust provided by the authentication challenge represents the state of the SSL transaction, and as such cannot really be persisted in a meaningful way. This is why NSURLCredential's constructor for using a SecTrustRef does not have a parameter for NSURLCredentialPersistence : server trust must be per session or transaction.

That said, the URL loading system does allow for default handling of SSL/TLS server trust evaluation. Normally for HTTPS connections you do not need to implement an authentication challenge handler for NSURLAuthenticationMethodServerTrust. If the default trust evaluation failed your connection would fail with some familar errors - this is what happens when using a self signed certificate, because the certificate is not trusted. It may be possible to add your trusted, self signed certificate to the application's trust anchors (much as you do in trust evaluation for SSL pinning) and the default handling would "just work" from that point on. Unfortunately I do not currently have a test environment in which I can test this.

quellish
  • 21,123
  • 4
  • 76
  • 83
  • What I have done in the past, for good or bad, is when I receive the trust challenge I prompt the user to trust the server or not. If they trust the server I store the protectionSpace in my application database as trusted, then when I see the trust challenge again, I can compare it against my list of trusted servers and if there is a match I create the credential forTrust and use that to proceed without any further user interaction required. I also give the user the option to remove that trust from within the application so that the next time the App asks again. – Rob Sep 13 '14 at 13:58
  • @quellish I'm seeing the opposite behaviour to what you mention here. When I make a `NSURLSession` data task, I do not save the credentials (or make them persistent in any way) because I need to challenge every HTTPS request in my app. However, the delegate method `URLSession:didReceiveChallenge:completionHandler:` is only called for the first request, which tells me that the credentials *are* being persisted somewhere, I don't know where. – paulvs Nov 21 '14 at 17:04
  • @paulvs, there is only one "place" where they can be persisted: NSURLCredentialStorage. Is the challenge only happening on the first request, or the first request for a given *host*? The second scenario is common and can be affected by several things, and may *appear* to behave counter to the documentation depending on how you implemented the delegate, and wether it's a session delegate, a task delegate, and wether it's a different instance for each request. – quellish Nov 21 '14 at 17:13
  • It only happens for the first request for a given host. I'm using the session delegate `URLSession:didReceiveChallenge:completionHandler:` and in it's implementation I call `completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);`. – paulvs Nov 21 '14 at 17:28
  • It sounds like what you really want here is to use a *task* delegate. The session, which can encompass many tasks (i.e. connections), is being authenticated. When you pass the credential to the session the session manages it in-memory, which is why you're only seeing it happen "for the first request". The session gets the credential the first time, and uses it for subsequent requests but does not persist it. – quellish Nov 21 '14 at 17:38
  • I've switched to `URLSession:task:didReceiveChallenge:completionHandler:` but had the same behaviour unfortunately. If you're interested I'd asked [a question about this](http://stackoverflow.com/questions/27065372/why-is-a-https-nsurlsession-connection-only-challenged-once-per-domain) – paulvs Nov 21 '14 at 20:16