My app is using a self signed certificate and we are planning to use the same in production.
To avoid asking user to install the certificate manually, can I add the certificate to the list of trusted anchors using SecTrustSetAnchorCertificates(_: _:)
. Is this a correct approach ?
Please find the code below:
func addAnchorToTrust(trust: SecTrust, certificate: SecCertificate) -> SecTrust {
let array: NSMutableArray = NSMutableArray()
array.add(certificate)
SecTrustSetAnchorCertificates(trust, array)
return trust
}
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
return
}
let filePath = Bundle.main.path(forResource: "httpsPublicCertificate", ofType: "cer")
guard let file = filePath, let savedCertificateData = NSData(contentsOfFile: file), let rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, savedCertificateData) else {
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
return
}
let sslInput = addAnchorToTrust(trust: serverTrust, certificate: rootCert)
var result: SecTrustResultType = SecTrustResultType.unspecified
let error: OSStatus = SecTrustEvaluate(sslInput, &result)
if (error != 0){
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
return
}
guard self.validate(trust: serverTrust, with: SecPolicyCreateBasicX509()), let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0)
else {
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
return
}
let serverCertificateData = SecCertificateCopyData(serverCertificate)
let serverCertificateDataPtr = CFDataGetBytePtr(serverCertificateData);
let serverCertificateDataSize = CFDataGetLength(serverCertificateData);
let serverCertificateNSData = NSData(bytes: serverCertificateDataPtr, length: serverCertificateDataSize)
if serverCertificateNSData.isEqual(to: savedCertificateData as Data) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:serverTrust))
return
}
}
private func validate(trust: SecTrust, with policy: SecPolicy) -> Bool {
let status = SecTrustSetPolicies(trust, policy)
guard status == errSecSuccess else { return false }
return SecTrustEvaluateWithError(trust, nil)
}
The communication is between app and a local accessory
OK, well, that’s a critical tidbit.
The situation with accessories on the local network is a tricky one. It’s something I’ve discussed with developers many times before, so I took the time today to write it up properly. Please have a read through TLS For Accessory Developers and post back here if you have any questions.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"