fix(macos): clear accepted tls failures

This commit is contained in:
Nimrod Gutman
2026-04-30 14:04:49 +03:00
parent 6f544155c1
commit 35196f8f71
2 changed files with 18 additions and 16 deletions

View File

@@ -31,16 +31,16 @@ struct MacNodeModeCoordinatorTests {
}
@Test func `tls pin store key uses default wss port`() throws {
let url = try #require(URL(string: "wss://gutsy-home.tail06a72.ts.net"))
#expect(MacNodeModeCoordinator.tlsPinStoreKey(for: url) == "gutsy-home.tail06a72.ts.net:443")
let url = try #require(URL(string: "wss://gateway.example.ts.net"))
#expect(MacNodeModeCoordinator.tlsPinStoreKey(for: url) == "gateway.example.ts.net:443")
}
@Test func `auto repairs trusted tailscale serve pin mismatch`() throws {
let url = try #require(URL(string: "wss://gutsy-home.tail06a72.ts.net"))
let url = try #require(URL(string: "wss://gateway.example.ts.net"))
let failure = GatewayTLSValidationFailure(
kind: .pinMismatch,
host: "gutsy-home.tail06a72.ts.net",
storeKey: "gutsy-home.tail06a72.ts.net:443",
host: "gateway.example.ts.net",
storeKey: "gateway.example.ts.net:443",
expectedFingerprint: "old",
observedFingerprint: "new",
systemTrustOk: true)

View File

@@ -184,6 +184,12 @@ public final class GatewayTLSPinningSession: NSObject, WebSocketSessioning, URLS
self.failureLock.unlock()
}
private func clearTLSFailure() {
self.failureLock.lock()
self.lastTLSFailure = nil
self.failureLock.unlock()
}
public func makeWebSocketTask(url: URL) -> WebSocketTaskBox {
let task = self.session.webSocketTask(with: url)
task.maximumMessageSize = 16 * 1024 * 1024
@@ -205,9 +211,11 @@ public final class GatewayTLSPinningSession: NSObject, WebSocketSessioning, URLS
let host = challenge.protectionSpace.host
let systemTrustOk = SecTrustEvaluateWithError(trust, nil)
let expected = self.params.expectedFingerprint.map(normalizeFingerprint)
if let fingerprint = certificateFingerprint(trust) {
let fingerprint = certificateFingerprint(trust)
if let fingerprint {
if let expected {
if fingerprint == expected {
self.clearTLSFailure()
completionHandler(.useCredential, URLCredential(trust: trust))
} else {
self.recordTLSFailure(GatewayTLSValidationFailure(
@@ -225,28 +233,22 @@ public final class GatewayTLSPinningSession: NSObject, WebSocketSessioning, URLS
if let storeKey = params.storeKey {
GatewayTLSStore.saveFingerprint(fingerprint, stableID: storeKey)
}
self.clearTLSFailure()
completionHandler(.useCredential, URLCredential(trust: trust))
return
}
} else {
self.recordTLSFailure(GatewayTLSValidationFailure(
kind: .certificateUnavailable,
host: host,
storeKey: self.params.storeKey,
expectedFingerprint: expected,
observedFingerprint: nil,
systemTrustOk: systemTrustOk))
}
if systemTrustOk || !self.params.required {
self.clearTLSFailure()
completionHandler(.useCredential, URLCredential(trust: trust))
} else {
self.recordTLSFailure(GatewayTLSValidationFailure(
kind: .untrustedCertificate,
kind: fingerprint == nil ? .certificateUnavailable : .untrustedCertificate,
host: host,
storeKey: self.params.storeKey,
expectedFingerprint: expected,
observedFingerprint: nil,
observedFingerprint: fingerprint,
systemTrustOk: false))
completionHandler(.cancelAuthenticationChallenge, nil)
}