I dug into this issue as part of a DTS incident (s. 656775591) and my final conclusion was:
There’s no direct answer to this problem, so the other developer ended up filing an enhancement request about this (r. 29992970). Feel free to file your own bug report describing your own specific requirements here.
The
NSURLErrorClientCertificateRequired
error you see in this case is triggered by a specific sequence of events:
If the request fails with 403
And the delegate responded to the client identity authentication challenge
And the app has multiple digital identities in its keychain (this criteria is only applied on macOS; on iOS-based platforms it’s assumed to be true)
Fail the request with
NSURLErrorClientCertificateRequired
Otherwise, deliver the 403 response
If you have any control over the server then a good way to approach this issue is to have it set the
certificate_authorities
field in the CertificateRequest message (see Section 7.4.4 of RFC 5246). You can get this from the client identity authentication challenge (via the NSURLProtectionSpace’s distinguishedNames
property) and use this to guide the user’s certificate choice.If not, your workaround options are rather limited. The best I could come up with was to trap the
NSURLErrorClientCertificateRequired
error and then run a dummy request via CFHTTPStream, supplying the same digital identity as you used for the NSURLSession request. That should let you get at the 403 response, at which point you can retry the request with NSURLSession, using the 403 response to guide your digital identity choice.
IMPORTANT CFHTTPStream is missing a bunch of smarts that you’re used to from NSURLSession. Many of these don’t matter in this case (authentication challenges, caching, cookies) but there’s one that might: proxies. If you expect your app to run in an environment that uses proxies, you’ll have to get the current proxy configuration (via
<CFNetwork/CFProxySupport.h>
) and apply it to your CFHTTPStream.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"