Hi everyone,
I'm trying to establish a connection to a server that requires mutual TLS (mTLS) using NSURLSession in an iOS app. The server is configured with a self-signed root CA (in the project, we are using ca.cer
) and requires clients to present a valid certificate during the TLS handshake.
What I’ve done so far:
Server trust is working:
I manually trust the custom root CA using SecTrustSetAnchorCertificates and SecTrustEvaluateWithError.
I also configured the necessary NSAppTransportSecurity exception in Info.plist to allow the server certificate to pass ATS.
This is confirmed by logs showing: Server trust succeeded
The .p12 identity is correctly created: Contains the client certificate and private key.
Loaded using SecPKCS12Import with the correct password.
I implemented the delegate method:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
// Server trust override code (working)
...
}
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate {
print("🔐 Client cert challenge triggered")
if let identity = loadIdentity() {
let credential = URLCredential(identity: identity, certificates: nil, persistence: .forSession)
completionHandler(.useCredential, credential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
return
}
completionHandler(.performDefaultHandling, nil)
}
The session is correctly created using my custom delegate:
let delegate = MTLSDelegate(identity: identity, certificates: certs)
let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)
Despite everything above, the client certificate is never sent, and the request fails with:
Error Domain=NSURLErrorDomain Code=-1206 "The server requires a client certificate."
From logs, it's clear the delegate is being hit for NSURLAuthenticationMethodServerTrust, but not for NSURLAuthenticationMethodClientCertificate.