Handle task-level server trust challenges with the same certificate pin

This commit is contained in:
2026-09-12 15:35:59 +03:00
parent a17a7f8027
commit 93f7c9cb4e
+17 -1
View File
@@ -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) {