Repository navigation
Scope the Network.framework mTLS identity to its origin - #19
Merged
Merged
Conversation
`tlsLocalIdentityNetworkFramework` is a single client-wide identity, so every connection opened by a client that uses Network.framework presented it to any server that asked for a client certificate, including the target of a redirect to a different host. Apple's own URLSession (and browsers) choose the certificate per challenge/origin instead. Add `tlsLocalIdentityProviderNetworkFramework`, a closure that receives the host and port of the origin a connection is opened to and returns the identity to present (or nil for none). Connections are per origin, so a redirect to another host asks the provider again with that host and an identity meant for the original host is never sent to it. The provider takes precedence over the unscoped property, which is kept for source compatibility and documented as not origin-scoped. The tests build the SecIdentity from an in-memory PKCS#12 bundle (kSecImportToMemoryOnly) rather than a Keychain round-trip, which failed to find the key it had just added and made every identity test skip, and configure the client not to verify the self-signed test server so the handshake can complete. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Same change as #18 (draft against
main), applied torelease, which already contains the mTLS identity hook (#12) and the trust-verification hooks; this is the single fix commit cherry-picked on top ofrelease.Problem
HTTPClient.Configuration.tlsLocalIdentityNetworkFrameworkis one client-wide identity. On the Network.framework (NIOTS) backend every connection presented it to any server that requested a client certificate — including the target of a redirect to a different host.URLSessionand browsers choose the certificate per challenge/origin; only the NIOTS path leaked.Change
tlsLocalIdentityProviderNetworkFramework: (@Sendable (_ host: String, _ port: Int) -> SecIdentity?)?, asked for the origin each connection is opened to (nil= present none). Connections are per origin, so a redirect to another host asks again with that host.tlsLocalIdentityNetworkFramework, which is kept for source compatibility (it ships in the 1.38.x/1.39.x tags request-dl-nio pins) and now documents that it is not origin-scoped. Adopting the provider is a caller-side change; nothing breaks for existing users.releasealso passescustomVerification. Both arguments are kept.Tests
LocalIdentityNetworkFrameworkTests+TrustCustomVerificationTests: 13 tests, 0 failures, 0 skipped. The redirect-to-another-host test fails if the scoping is removed. The identity tests now build theSecIdentityfrom an in-memory PKCS#12 import (macOS 15 / iOS 18+, otherwiseXCTSkip) instead of a Keychain round-trip that never worked here, so they actually run.Not covered:
.nio(NIOSSL) still has one client-widecertificateChain/privateKey; separate change. I ran the targeted suites on this branch, not the full suite. Note thattestConnectTimeout(HTTPClientTests and AsyncAwaitEndToEndTests) fails locally with "connection reset by peer", also on a cleanmain, so it is pre-existing and unrelated.🤖 Generated with Claude Code