Passing URLAuthenticationChallenge with cert installed on device

Hello!

I have a quirky situation that I am looking for a solution to. The iOS app I am working on needs to be able to communicate with systems that do not have valid root certs. Furthermore, these systems addresses will be sent to the user at run time. The use case is that administrators will provide a self signed certificate (.pem) for the iPhones to download which will then be used to pass the authentication challenge.

I am fairly new to customizing trust and my understanding is that it is very easy to do it incorrectly and expose the app unintentionally.

Here is our users expected workflow:

  1. An administrator creates a public ip server.
  2. The ip server is then configured with dns.
  3. A .pem file that includes a self signed certificate is created for the new dns domain.
  4. The pem file is distributed to iOS devices to download and enable trust for.
  5. When they run the app and attempt to establish connection with the server, it will not error with an SSL error.

When I run the app without modification to the URLSessionDelegate method(s) I do get an SSL error.

Curiously, attempting to hit the same address in Safari will not show the insecure warning and proceed without incident.

What is the best way to parity the Safari use case for our app? Do I need to modify the

urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

method to examine the NSURLAuthenticationMethodServerTrust? Maybe there is a way to have the delegate look through all the certs in keychain or something to find a match? What would you advise here?

Sincerely thank you for taking the time to help me, ~Puzzled iOS Dev

Answered by DTS Engineer in 848006022
For now, the user would need to install manually.

OK.

Just to be clear, this is not a great approach. Historically iOS made it hard for site admins to provision credentials to specific apps. However, that changed in iOS 18.4 with the advent of the ManagedApp framework. That would be a great path forward for you.

However, if you want to do this manually then things get tricky. If the site admin sends a certificate to a user and the user installs it, the system puts that certificate in one of two places:

  • If it’s a root certificate, the system adds it to the per-device trust store.
  • If not, the system adds it to an Apple keychain access group.

Neither of these is ideal. In the first case, the user has to explicitly trust the root, with lots of scary warnings. And those scary warnings are justified. Installing a root is a massive extension of trust.

In the second case, your app can’t access items in the Apple keychain access group. This is the limitation described in the old QA1745 Making Certificates and Keys Available To Your App and now resolved by the ManagedApp framework.

Probably the best way to make this work is for you to tweak the process so that the site admin doesn’t send the user a .pem, but rather a custom document that opens in your app. So, when the user opens the doc, your app launches and runs through its own certificate ingestion process. It can then store the certificate wherever it wants — an obvious place would be in the keychain, using a keychain access group that it has access to — and thence use it in its URLSession authentication challenge handler.

Note that you can still use the PEM file format, you just need to change the extension from .pem to something custom. OTOH, it might be nice to change the file format so that you can include supplemental information.

Finally, I want to drop a link to TLS For Accessory Developers. This explains my suggestions for how to handle situations like this in a non-managed environment, and it’s worth a read just in case you’re will to entertain alternative approaches.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

The pem file is distributed to iOS devices to download and enable trust for.

How? Is the admin pushing the certificate to the device via MDM? Or is the user installing it manually? Or something else?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

How? Is the admin pushing the certificate to the device via >MDM? Or is the user installing it manually? Or something >else?

For now, the user would need to install manually.

Accepted Answer
For now, the user would need to install manually.

OK.

Just to be clear, this is not a great approach. Historically iOS made it hard for site admins to provision credentials to specific apps. However, that changed in iOS 18.4 with the advent of the ManagedApp framework. That would be a great path forward for you.

However, if you want to do this manually then things get tricky. If the site admin sends a certificate to a user and the user installs it, the system puts that certificate in one of two places:

  • If it’s a root certificate, the system adds it to the per-device trust store.
  • If not, the system adds it to an Apple keychain access group.

Neither of these is ideal. In the first case, the user has to explicitly trust the root, with lots of scary warnings. And those scary warnings are justified. Installing a root is a massive extension of trust.

In the second case, your app can’t access items in the Apple keychain access group. This is the limitation described in the old QA1745 Making Certificates and Keys Available To Your App and now resolved by the ManagedApp framework.

Probably the best way to make this work is for you to tweak the process so that the site admin doesn’t send the user a .pem, but rather a custom document that opens in your app. So, when the user opens the doc, your app launches and runs through its own certificate ingestion process. It can then store the certificate wherever it wants — an obvious place would be in the keychain, using a keychain access group that it has access to — and thence use it in its URLSession authentication challenge handler.

Note that you can still use the PEM file format, you just need to change the extension from .pem to something custom. OTOH, it might be nice to change the file format so that you can include supplemental information.

Finally, I want to drop a link to TLS For Accessory Developers. This explains my suggestions for how to handle situations like this in a non-managed environment, and it’s worth a read just in case you’re will to entertain alternative approaches.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Passing URLAuthenticationChallenge with cert installed on device
 
 
Q