I'm creating a web application where the main purpose of the iOS app is to be a thin client that displays a web site. To protect the privacy of my users, only trusted devices should be able to communicate with the web server. I'm accomplishing this by storing a client certificate in the app keychain and sending it to the web server when the server issues a challenge. The following is the code where I send the certificate to the web server:
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust)
{
let certificate = Certificate.RetrieveCertificate()
if (certificate != nil) {
var secTrust: SecTrust?
let secPolicy = SecPolicyCreateSSL(false, nil)
let status = SecTrustCreateWithCertificates(certificate!, secPolicy, &secTrust)
if (status == errSecSuccess) {
var resultType: SecTrustResultType = SecTrustResultType(rawValue: UInt32(0))!
SecTrustEvaluate(secTrust!, &resultType)
let properties = SecTrustCopyProperties(secTrust!)
let credentials = URLCredential(trust: secTrust!)
completionHandler(URLSession.AuthChallengeDisposition.useCredential, credentials)
}
}
}
}
I retrieve the correct certificate from the app keychain, but "credentials" gets set to nil and when I print properties.debugDescription in the immediate window, the output says, "Root certificate is not trusted." But the root certificate is installed on my iPad, and it shows up as a verified configuration profile in General > Profiles & Device Management.