Мы пытаемся создать приложение, которое будет взаимодействовать с несколькими серверами по протоколу HTTPS с использованием NSURLSession, поскольку мы используем наш собственный корневой центр сертификации, который входит в наше приложение, и ATS полностью включен (для NSAllowsArbitraryLoads установлено значение False).
При вызове делегата аутентификации NSURLSession, т.е. «URLAuthenticationChallenge», мы устанавливаем сертификат привязки через «SecTrustSetAnchorCertificates», который проверяет сертификат путем проверки его подписи плюс подписи сертификатов в его цепочке сертификатов, вплоть до сертификата привязки.Также используется SecTrustSetAnchorCertificatesOnly для исключения других якорей.
После успешного выполнения SecTrustEvaluate получена ошибка в завершении SessionDataTask дополнения, которая упоминается ниже:
[4704:1445043] ATS failed system trust
[4704:1445043] System Trust failed for [1:0x1c41678c0]
[4704:1445043] TIC SSL Trust Error [1:0x1c41678c0]: 3:0
[4704:1445043] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
(Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."
Примечание:
Когда Root CA Certificate установлен и доверен на устройстве, тогда связь HTTPS с включенной ATS работает без каких-либо ошибок. Но я не хочу, чтобы пользователь вручную устанавливал и доверял Root CA на устройстве.
Фрагмент кода:
func getRequest(){
let requestUrl = “https://server.test.com/hi.php” //url modified
let configuration = URLSessionConfiguration.default
var request = try! URLRequest(url: requestUrl, method: .get)
let session = URLSession(configuration: configuration,
delegate: self,
delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
print("Data = \(data)")
print("Response = \(response)")
print("Error = \(error)")
})
task.resume()
}
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping(URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void){
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
let trust = challenge.protectionSpace.serverTrust
let rootCa = “root"
if let rootCaPath = NSBundle.mainBundle().pathForResource(rootCa, ofType: "der") {
if let rootCaData = NSData(contentsOfFile: rootCaPath) {
let rootCert = SecCertificateCreateWithData(nil, rootCaData).takeRetainedValue()
SecTrustSetAnchorCertificates(trust, [rootCert])
SecTrustSetAnchorCertificatesOnly(trust, true)
}
var trustResult: SecTrustResultType = 0
SecTrustEvaluate(trust, &trustResult)
if (Int(trustResult) == kSecTrustResultUnspecified ||
Int(trustResult) == kSecTrustResultProceed) {
// Trust certificate.
} else {
NSLog("Invalid server certificate.")
}
} else {
challenge.sender.cancelAuthenticationChallenge(challenge)
}
}