Repository navigation
Conversation
On macOS the PAL does not install a client certificate before the handshake. SecureTransport stops at the server's CertificateRequest and the PAL reports CredentialsNeeded. SslStream answers that by installing the certificate with TryUpdateClintCertificate and continuing. TlsSession did not install the certificate in either of these cases: - With a ClientCertificateContext on the TlsContext, it returned CertificateRequested to the caller. - After SetClientCertificateContext, it resumed the handshake without installing the certificate, so the server received none. TlsSession now installs the configured certificate in both cases. On Windows TryUpdateClintCertificate does nothing, and SChannel already has the certificate. On Linux the OpenSSL PAL already installs it inside the handshake call; on resume TlsSession now installs it just before that call, with the same result. Tests: - New: a configured client certificate reaches a server that requires one. - Two SetClientCertificateContext tests now run on macOS. Their skip reason said SecureTransport never asks for a deferred credential, but it does. - The handshake driver now fails on a status it does not handle, instead of waiting for the 60-second timeout. Found through dotnet#136205: the macOS legs timed out in AcceptWithDefaultValidation_CertificateContextTrust_HonorsChainPolicy until dotnet#136139 stopped that test's server from requesting a client certificate.
|
Azure Pipelines: Successfully started running 4 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Contributor
|
Tagging subscribers to this area: @dotnet/ncl, @bartonjs, @vcsjones |
rzikm
requested review from
rzikm and
wfurt
and
a balanced review from Copilot
October 21, 2026 10:14
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
Security-sensitive cross-platform handshake changes warrant maintainer review and confirmation of Windows validation; builds and tests were not independently run here.
No open issues 🎉
What changed in this PR
Fixes macOS TlsSession client-certificate delivery by following the existing SslStream installation flow.
Changes:
- Installs configured and deferred client certificates before continuing the handshake.
- Adds regression coverage and enables two existing tests on macOS.
- Makes the test handshake driver fail immediately on unexpected statuses.
| File | Description |
|---|---|
| src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs | Adds certificate-delivery coverage, enables macOS tests, and improves failure reporting. |
| src/libraries/System.Net.Security/src/System/Net/Security/TlsSession.cs | Installs client certificates during initial and resumed handshakes. |
Review effort: Balanced
rzikm
requested changes
Oct 21, 2026
rzikm
left a comment
Member
There was a problem hiding this comment.
LGTM in general, but I have couple of questions
The two TryUpdateClintCertificate blocks in the client handshake path cover different cases. The comments now explain when each block runs. The block before InitializeSecurityContext runs when the handshake resumes after CertificateRequested, because SecureTransport does not stop a second time. The block after InitializeSecurityContext runs when the certificate was configured before the handshake, in which case SecureTransport still stops. Comments only; no code change.
The comment on each TryUpdateClintCertificate block now names its case and says why the other block cannot cover it. On a resume after CertificateRequested, SecureTransport does not stop again, so the CredentialsNeeded path never runs. With a certificate configured before the handshake, SecureTransport still stops, so the install follows that stop. Comments only; no code change.
rzikm
approved these changes
Oct 22, 2026
Contributor
Author
wfurt
approved these changes
Oct 26, 2026
Member
|
/ba-g test failures unrelated |
Contributor
Author
|
Thank you for the review and merge! |
pcshrosbree
deleted the
fix/tlssession-osx-configured-client-certificate
branch
October 26, 2026 23:04
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.
Fixes #136213.
On macOS, SecureTransport stops the handshake at the server's CertificateRequest, and the PAL reports
CredentialsNeeded. This happens even when a client certificate is configured.SslStreaminstalls the certificate withSslStreamPal.TryUpdateClintCertificateand continues.TlsSessionreturnedCertificateRequestedto the caller instead. AfterSetClientCertificateContext, it resumed without installing the certificate, so the server received none. #136213 has the details. This is also why the macOS legs of #136096 and #136205 timed out.Change
TlsSession.HandshakeBufferedCore, client side:CredentialsNeededwith a configured certificate, install it withTryUpdateClintCertificateand callInitializeSecurityContextagain.SslStream.GenerateTokendoes the same.SetClientCertificateContext, install the certificate before callingInitializeSecurityContext.TryUpdateClintCertificatereturns false, so neither step changes anything. On Linux, the OpenSSL PAL already installs a configured certificate inside the handshake call, so the first step does not run. On resume, the certificate is now installed just before that call instead of inside it.TlsSessionTests:ClientSession_ConfiguredClientCertificate_SentWhenServerRequestsIt, on all platforms.ClientSession_WantCredentials_SetClientCertificateContext_ResumesHandshakeandSetClientCertificateContext_ConcurrentSessionsOnSharedContext_DoNotRace. Their skip reason said SecureTransport does not surface a deferred credential prompt, but it does. The TLS 1.3 row of the first test returns early where TLS 1.3 is unavailable, like the other theories in the file.DriveHandshakeWithExternalValidationAsyncnow throws on a status it does not handle. A test like the one in System.Net.Security.Tests.TlsSessionTests fail with timeouts #136205 then fails within seconds instead of after the 60-second timeout.Testing
I ran
TlsSessionTestsin Release on osx-arm64 (macOS 27.0.1) and linux-x64, pairing test and product versions as below. In the table,mainis commitb3c0988064f5:mainisServer: Falsecases ofAcceptWithDefaultValidation_CertificateContextTrust_HonorsChainPolicytime out after 60 smainCertificateRequested; the 2 re-enabled tests fail because the server receives no certificateI removed each of the two install steps in turn. Each removal fails only the tests for its own path on macOS.
With this PR, the
System.Net.Security.Testsrun excluding theOuterLoopandfailingcategories has no failures on either platform: 5,035 passed and 27 skipped on macOS, and 5,071 passed and 12 skipped on Linux.I have not run this on Windows; the Windows legs of this PR will.
Note
This change was prepared with AI assistance (Anthropic Claude, checked by OpenAI Codex) at my request. I reviewed the change and the test runs before opening.