I am working on code to handle connections to servers, handle the trust evaluation, policy management, and general authentication.
As part of the Server Authentication challenge, when the delegate method URLSession:didReceiveChallenge:completionHandler receives a NSURLAuthenticationMethodServerTrust challenge, I add a trusted certificate anchor to the trust object using the method SecTrustSetAnchorCertificates. This allows the trust to pass its evaluation when applying the SSL Policy; because it can find the intermediate certificate (the anchor certificate I just configured in the SecTrustSetAnchorCertificates method).
Everytime a new session is created, the authentication process repeats and the code loads the anchor certificate. Then I read this:
Section: Missing Intermediate Certificates
"On iOS, if your app adds the intermediate certificate to its keychain, the trust object will use it automatically."
So, I thought this implied if I add the trusted anchor certificate to the app's keychain, the trust object would use it automatically and I would not have to use the SecTrustSetAnchorCertificates everytime. However, this fails with:
TrustResultDetails :
MissingIntermediate : 0
Policy requirements not met:
MissingIntermediate : Could not find a certificate in the chain.
I have correctly added the certificate to the KeyChain using the API method: SecItemAdd and have verified the certificate is indeed in the keychain using the method: SecItemCopyMatching. So, even though the certificate is loaded correctly in the Keychain, the trust object is not using it.
Is there some other API to configure to get this to work? Do I have to configure the URLSession to look in the KeyChain for certificates? Do I have to set an attribute when loading the anchor certificate that it is to be trusted?
My fallback is to use the original method. This enhancement seemed to have made the process more efficient though.
NB: the original method, the SecTrustSetAnchorCertificates method, configures a single anchor certificate that is allowed to be trusted ('certificate pinning'). I don't know how the Security API uses built-in anchor certificates when evaluating trust and whether 'certificate pinning' would be lost if I add the certificate to the Keychain. Does the trust look at my app's keychain for certificates as well as the built-in set of certificates (i.e. its no longer just looking for a single certificate)?
I am working on the iOS platform.
iOS-based platforms make a strong distinction between the keychain and the trust store, that is, the place where the system holds trusted anchors [1]. The keychain has a public API, the trust store does not. The only way to add an anchor to the trust store is via a
com.apple.security.root
configuration profile payload. It’s fine, indeed,
recommended, to do that in some circumstances — most notably, enterprise deployment and
test environments — but it’s not appropriate for a general-purpose app. If you’re deploying to a wide range of users, the correct way to override HTTPS server trust evaluation is via the
NSURLAuthenticationMethodServerTrust
authentication challenge.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
[1] On macOS trusted anchors can be stored as certificate items in the keychain, but there’s a separate subsystem, trust settings, that determines whether the certificate is considered an anchor.