Handle task-level server trust challenges with the same certificate pin
This commit is contained in:
@@ -9,6 +9,9 @@ final class PinnedDelegate: NSObject, URLSessionDelegate, URLSessionTaskDelegate
|
||||
|
||||
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
|
||||
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
|
||||
#if DEBUG
|
||||
print("MusicBridge TLS: received server authentication challenge")
|
||||
#endif
|
||||
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
|
||||
challenge.protectionSpace.host == connection.endpoint.host,
|
||||
challenge.protectionSpace.port == (connection.endpoint.port ?? 443),
|
||||
@@ -19,18 +22,31 @@ final class PinnedDelegate: NSObject, URLSessionDelegate, URLSessionTaskDelegate
|
||||
let digest = SHA256.hash(data: SecCertificateCopyData(leaf) as Data)
|
||||
.map { String(format: "%02X", $0) }.joined()
|
||||
guard digest == connection.fingerprint else {
|
||||
#if DEBUG
|
||||
print("MusicBridge TLS: fingerprint mismatch")
|
||||
#endif
|
||||
completionHandler(.cancelAuthenticationChallenge, nil); return
|
||||
}
|
||||
// Trust only this exact out-of-band certificate, while checking its validity dates.
|
||||
SecTrustSetAnchorCertificates(trust, [leaf] as CFArray)
|
||||
SecTrustSetAnchorCertificatesOnly(trust, true)
|
||||
SecTrustSetPolicies(trust, SecPolicyCreateBasicX509())
|
||||
guard SecTrustEvaluateWithError(trust, nil) else {
|
||||
var trustError: CFError?
|
||||
guard SecTrustEvaluateWithError(trust, &trustError) else {
|
||||
#if DEBUG
|
||||
print("MusicBridge TLS: pinned certificate rejected: \(String(describing: trustError))")
|
||||
#endif
|
||||
completionHandler(.cancelAuthenticationChallenge, nil); return
|
||||
}
|
||||
completionHandler(.useCredential, URLCredential(trust: trust))
|
||||
}
|
||||
|
||||
func urlSession(_ session: URLSession, task: URLSessionTask,
|
||||
didReceive challenge: URLAuthenticationChallenge,
|
||||
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
|
||||
urlSession(session, didReceive: challenge, completionHandler: completionHandler)
|
||||
}
|
||||
|
||||
func urlSession(_ session: URLSession, task: URLSessionTask,
|
||||
willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest,
|
||||
completionHandler: @escaping (URLRequest?) -> Void) {
|
||||
|
||||
Reference in New Issue
Block a user