Skip to content

Skip peer certificate revalidation on resumed TLS sessions by default - #133174

Open
rzikm wants to merge 14 commits into
mainfrom
rzikm/sslstream-skip-revalidate-on-resume
Open

rzikm wants to merge 14 commits into
mainfrom
rzikm/sslstream-skip-revalidate-on-resume

Conversation

@rzikm

@rzikm rzikm commented Sep 3, 2026 •

Copy link
Copy Markdown
Member

Summary

On a resumed (abbreviated) TLS handshake the peer does not resend its certificate — its identity was established and validated during the original full handshake that produced the session ticket / session id. Common TLS stacks (OpenSSL, SChannel) do not re-run certificate verification on resumption.

Today SslStream still rebuilds the chain and invokes the user validation callback on every resumed session. This PR changes the default so that, on a resumed initial handshake, SslStream adopts the cached peer certificate for the RemoteCertificate property but skips the chain build and the user validation callback — matching the underlying TLS libraries.

The shortcut is gated to the initial handshake only: during renegotiation or TLS 1.3 post-handshake authentication the peer can present a new certificate, which is always fully validated.

Opt-out switch

A new AppContext switch restores the previous behavior:

  • System.Net.Security.RevalidateCertificateOnTlsResume (config)
  • DOTNET_SYSTEM_NET_SECURITY_REVALIDATECERTIFICATEONTLSRESUME=1 (env)

When set, the peer certificate is re-validated on every successful resumption as before.

Cross-platform TlsResumed detection

The skip only fires when the backend can reliably report resumption:

Backend Platform Signal
SChannel Windows SECPKG_ATTR_SESSION_INFO / SSL_SESSION_RECONNECT
OpenSSL Linux SSL_session_reused
SecureTransport Apple (default) none available in current Apple SDK → always revalidates
Network Framework Apple (opt-in) none public → always revalidates
Conscrypt/Java Android none reliable → always revalidates

The Windows/Linux TlsResumed computation was previously #if DEBUG-only and is now unconditional. SecureTransport's SSLGetResumableSessionInfo has been removed from current Apple SDKs (it fails to compile as an undeclared function), so Apple — like Network Framework and Android — leaves TlsResumed unset and always revalidates on resumption (documented inline). The optimization therefore currently applies on Windows and Linux.

Performance

dotnet/performance ResumedHandshake benchmark, Windows x64, across a cert × protocol matrix. Revalidate = old behavior (RevalidateCertificateOnTlsResume=1); Skip = new default. Stabilized run (warmup 12 / 30 iterations / 500 ms, GCgen0size=256MB).

Cert Protocol Revalidate (mean) Skip / new default (mean) Time Δ Alloc Δ
Contoso (full chain) TLS 1.2 762.1 µs 628.4 µs −17.5% −0.99 KB
ECDSA P-256 TLS 1.2 850.2 µs 653.0 µs −23.2% −0.77 KB
RSA-2048 TLS 1.2 568.4 µs 490.3 µs −13.7% −0.77 KB
RSA-4096 TLS 1.2 711.1 µs 590.8 µs −16.9% −0.76 KB
Contoso (full chain) TLS 1.3 2,965.6 µs 2,905.3 µs −2.0% −0.94 KB
ECDSA P-256 TLS 1.3 3,022.5 µs 2,780.4 µs −8.0% −0.75 KB
RSA-2048 TLS 1.3 2,625.7 µs 2,688.5 µs +2.4% −0.72 KB
RSA-4096 TLS 1.3 2,899.1 µs 2,863.2 µs −1.2% −0.84 KB
  • TLS 1.2: consistent ~14–23% reduction in handshake time plus ~0.76–0.99 KB fewer allocations per resumed handshake.
  • TLS 1.3: handshake time is within run-to-run noise (most of the resumed-handshake cost there is native SSPI/SChannel work, not managed cert/chain crypto), but allocations still drop ~0.72–0.94 KB consistently.

Notes / open questions

  • ⚠️ This flips a security-relevant default. It likely needs design/API review and a breaking-change doc before merging, even prerelease-to-prerelease.
  • ⚠️ The user certificate-validation callback silently stops firing on resumed initial handshakes under the new default — this needs to be an intentional, documented decision.
  • No new tests added yet; existing resume/validation/renegotiation suites pass with the new default on Windows.

Note

This PR (including its description) was created with the assistance of GitHub Copilot.

On a resumed (abbreviated) TLS handshake the peer does not resend its
certificate; its identity was established during the original full
handshake. Common TLS stacks (OpenSSL, SChannel) do not re-run
certificate verification on resumption. Match that behavior: by default
SslStream now adopts the cached peer certificate without rebuilding the
chain or invoking the user validation callback on a resumed session.

Add the opt-in System.Net.Security.RevalidateCertificateOnTlsResume
AppContext switch (env DOTNET_SYSTEM_NET_SECURITY_REVALIDATECERTIFICATEONTLSRESUME)
to restore the previous revalidate-on-resume behavior.

Wire up TlsResumed detection across platforms:
- Windows (SChannel) / Linux (OpenSSL): un-guard the existing TlsResumed
  computation from DEBUG-only builds.
- Apple SecureTransport: new AppleCryptoNative_SslGetSessionResumed export
  using SSLGetResumableSessionInfo, plumbed through Interop.Ssl and
  SslConnectionInfo.OSX.
- Network Framework and Android expose no reliable resumption signal and
  keep the safe fallback of always revalidating (documented in code).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
Copilot AI lite review requested due to automatic review settings September 3, 2026 15:10
@azure-pipelines

Copy link
Copy Markdown
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.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/ncl, @bartonjs, @vcsjones
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The resumed-session validation skip can incorrectly apply during renegotiation/TLS 1.3 post-handshake auth, potentially accepting newly supplied certificates without validation.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR changes SslStream certificate-validation behavior on resumed (abbreviated) TLS handshakes: when a backend can reliably detect resumption, it can skip rebuilding the certificate chain and skip invoking the user validation callback by default, with an AppContext/env switch to restore the prior behavior. It also makes TlsResumed detection available cross-platform (Windows/Linux unconditional, Apple SecureTransport via a new native export; Android/Network Framework keep the “safe fallback” of always revalidating due to lack of a reliable signal).

Changes:

  • Add System.Net.Security.RevalidateCertificateOnTlsResume / DOTNET_SYSTEM_NET_SECURITY_REVALIDATECERTIFICATEONTLSRESUME to opt back into revalidation on session resumption.
  • Detect TlsResumed on Windows/Linux unconditionally and on Apple SecureTransport via AppleCryptoNative_SslGetSessionResumed.
  • Skip managed chain build + user validation callback when TlsResumed is true and the opt-out switch is not enabled.
File summaries
File Description
src/native/libs/System.Security.Cryptography.Native.Apple/pal_ssl.h Declares a new native export to query whether a SecureTransport session was resumed.
src/native/libs/System.Security.Cryptography.Native.Apple/pal_ssl.c Implements AppleCryptoNative_SslGetSessionResumed via SSLGetResumableSessionInfo.
src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs Adds the resumption fast-path to skip remote cert revalidation (chain build + user callback) by default.
src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Windows.cs Makes TlsResumed detection run in non-Debug builds (SChannel session-info flag).
src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.OSX.cs Adds SecureTransport-based TlsResumed detection and documents Network Framework’s lack of signal.
src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Linux.cs Makes TlsResumed detection run in non-Debug builds (OpenSSL SSL_session_reused).
src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.cs Makes TlsResumed a regular field/property (not Debug-only) with clarifying comment.
src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Android.cs Documents lack of a reliable resumption signal; keeps TlsResumed false (always revalidate).
src/libraries/System.Net.Security/src/System/Net/Security/LocalAppContextSwitches.cs Adds the new switch plumbing for RevalidateCertificateOnTlsResume.
src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Ssl.cs Adds managed LibraryImport for AppleCryptoNative_SslGetSessionResumed.
Review details
  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Lite

@bartonjs bartonjs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd expect a test, using RemoteExecutor, to confirm the default behavior and that the AppContext works as expected...

…Apple API

Address review feedback and fix Apple CI build:

- Only skip peer certificate revalidation on the *initial* resumed
  handshake. During renegotiation / TLS 1.3 post-handshake auth the peer
  can present a new certificate, which must always be validated. Thread
  an isInitialHandshake flag (SslStream passes !_isRenego; the TlsSession
  external-validation path passes false) into VerifyRemoteCertificateCore
  and gate the resumption shortcut on it.

- Revert the SecureTransport TlsResumed wiring: SSLGetResumableSessionInfo
  has been removed from current Apple SDKs and fails to compile ("call to
  undeclared function") across all Apple targets. Apple now leaves
  TlsResumed unset, matching the Network Framework and Android safe
  fallback of always revalidating on resumption.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
Copilot AI review requested due to automatic review settings September 4, 2026 07:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new resumed-handshake fast-path needs targeted coverage for the new default + opt-out behavior and should address the resource-lifetime implications of skipping the user callback while still collecting chain intermediates.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 8/8 changed files
  • Comments generated: 2
  • Review effort level: Lite

…itch tests

On a resumed handshake the certificate validation callback is skipped by
default, so the outer VerifyRemoteCertificate no longer had anything adopt the
peer-sent intermediate certificates that GetRemoteCertificate appends to the
chain's ExtraStore. Thread a certificateValidationSkippedOnResume flag out of
VerifyRemoteCertificateCore so those intermediates are disposed even when a
RemoteCertificateValidationCallback is configured, avoiding leaked
X509Certificate2 handles across repeated resumptions.

Add a RemoteExecutor-based test that verifies the client validation callback is
not invoked on a resumed handshake by default and that setting
RevalidateCertificateOnTlsResume restores callback invocation on resumption.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
Copilot AI review requested due to automatic review settings September 4, 2026 08:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes security-relevant certificate validation semantics on resumed TLS handshakes and still needs broader test coverage (notably server-side client-cert validation) and careful human review for compatibility impact.

Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 2
  • Review effort level: Lite

…validate test

Parametrize the revalidate-switch resume test over client-side (server cert) and server-side (client cert) validation so the shared skip default is exercised in both directions. When the environment cannot establish session resumption, signal a skip to the parent process via a marker file instead of hard-failing, matching the SkipTestException pattern used elsewhere in this file.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
Copilot AI review requested due to automatic review settings September 4, 2026 08:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

It changes a security-relevant default to skip certificate validation on resumed sessions (and introduces a Release-path perf regression on Windows via Enum.HasFlag boxing) which needs addressing/explicit opt-in alignment before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Windows.cs:88

  • Using Enum.HasFlag here boxes the enum value and can allocate; this code now runs in Release for every handshake, so it’s worth avoiding the overhead. Prefer a simple bit-test against SSL_SESSION_RECONNECT.

src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs:1262

  • This introduces a default-path validation bypass: on resumed initial handshakes, the user RemoteCertificateValidationCallback and chain build are skipped unless an AppContext switch opts out. This conflicts with the System.Net.Security guidance that certificate validation bypass must require explicit opt-in (i.e., keep the existing secure default and allow opting into the optimization).
            if (certificate != null &&
                isInitialHandshake &&
                connectionInfo.TlsResumed &&
                !LocalAppContextSwitches.RevalidateCertificateOnTlsResume)
            {
  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

Add explicit assertions after the field/type/property reflection lookups so a future rename of the internal members produces a clear diagnostic instead of a NullReferenceException.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
Copilot AI review requested due to automatic review settings September 4, 2026 08:33
TlsResumed is now evaluated on every handshake in Release builds, so replace the boxing Enum.HasFlag call with a direct bit-test against SSL_SESSION_RECONNECT to avoid the per-handshake allocation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
@rzikm

rzikm commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

Addressed the Copilot review feedback in the latest commits:

  • Enum.HasFlag boxing on the Windows resume-detection path (SslConnectionInfo.Windows.cs): replaced with a direct bit-test against SSL_SESSION_RECONNECT in 92776e8, since TlsResumed is now evaluated on every handshake in Release. (The identical pre-existing pattern in CertificateValidationPal.IsLocalCertificateUsed is outside this PR's scope and only runs when a local cert is used, so I left it untouched.)
  • Test coverage: the revalidate-switch resume test now also exercises the server-side (client-cert) validation callback, and skips cleanly when the environment can't establish resumption.
  • Reflection robustness: added explicit assertions on the internal field/type/property lookups.

On the note about skipping certificate re-validation on resumption being a security-relevant default change: that is the intended behavior of this PR — matching what mainstream TLS stacks (OpenSSL, SChannel, etc.) do, which don't re-invoke user validation on an abbreviated handshake. The previous behavior remains available via the System.Net.Security.RevalidateCertificateOnTlsResume AppContext switch, and the performance rationale/measurements are in the PR description.

Note

This comment was drafted with GitHub Copilot.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes a security-sensitive default (skipping user certificate validation callbacks on resumed sessions) and warrants careful human review of compatibility and security implications across platforms and scenarios.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/libraries/System.Net.Security/src/System/Net/Security/LocalAppContextSwitches.cs:27

  • The switch comment says the peer certificate is not re-validated on resumed TLS handshakes "by default", but the implementation only skips validation when resumption can be detected (currently Windows/SChannel and Linux/OpenSSL). On Apple/Android, TlsResumed remains false and validation still runs, so the comment is misleading.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Copilot AI review requested due to automatic review settings September 4, 2026 08:43
Session resumption is only detected on Windows and Linux; on other platforms TlsResumed stays false and the peer certificate is always re-validated. Note this in the switch comment so the default behavior is not read as universal.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964

@wfurt wfurt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally looks good to me. Do we know what is the perf impact?

… assert server resume flag

Address review feedback on the resume revalidation test:
- Enumerate supported protocols dynamically (TLS 1.2 + TLS 1.3) via
  SslProtocolSupport.EnumerateSupportedProtocols instead of hardcoding TLS 1.2,
  so the test keeps covering the negotiated versions as older ones are retired.
- Assert that the server observes the same resumption state as the client
  (IsResumed(server) == IsResumed(client)).
- PingPong after the handshake so the client consumes the post-handshake TLS 1.3
  session ticket, which is required to actually exercise TLS 1.3 resumption.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
Copilot AI review requested due to automatic review settings September 4, 2026 22:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

It changes security-relevant default certificate-validation semantics on resumed handshakes and needs careful human review for compatibility and security tradeoffs.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs:1262

  • The resumption fast-path depends on connectionInfo.TlsResumed, but connectionInfo may still be uninitialized during inline certificate validation (note the later connectionInfo.Protocol == 0 check before invoking the user callback). In that case TlsResumed will remain false and the new default will unexpectedly fall back to full revalidation + callback on resumed handshakes.

Consider populating connectionInfo (via SslStreamPal.QueryContextConnectionInfo) before checking TlsResumed, using the same Protocol == 0 guard used later for the callback path.

  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@rzikm

rzikm commented Sep 5, 2026

Copy link
Copy Markdown
Member Author

CI failure analysis (runtime build 1583816)

Same infra pattern as the previous run, on a different set of work items. The runtime leg failed only because the Monitor Helix Jobs task flagged failed work items, and the timeline reports server-side throttling again (The job is currently being throttled by the server).

The flagged work items this time are all WASM Mono System.Runtime.Tests (WasmTestOnChrome-MONO-ST-System.Runtime.Tests on browser-wasm linux/windows LibraryTests_Smoke_AOT) — unrelated to this PR, which only touches System.Net.Security. Across all 32 test runs the run-level failed count is 0: every first-attempt failure passed on retry.

No System.Net.Security test failed. This is transient Helix throttling / WASM flakiness, not a failure caused by this change, so I'm not retriggering CI to reclassify.

Note

This comment was generated by GitHub Copilot.

Copilot AI review requested due to automatic review settings September 18, 2026 10:11
@rzikm
rzikm requested a review from wfurt September 18, 2026 10:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

One or more issues must be addressed before approval.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (4)

src/libraries/System.Net.Security/src/System/Net/Security/LocalAppContextSwitches.cs:27

  • This changes the default certificate-validation behavior of the public SslStream contract: on Windows/Linux resumed handshakes, callers' RemoteCertificateValidationCallback is no longer invoked and hostname/trust checks are skipped. The repository's review requirements treat behavioral changes as requiring breaking-change documentation, but this PR adds only implementation comments and tests; please add the corresponding breaking-change entry (including the callback and opt-out-switch behavior) before merging.
        // By default the peer certificate is not re-validated on a resumed (abbreviated) TLS
        // handshake, matching the behavior of common TLS stacks (e.g. OpenSSL, SChannel) that
        // do not re-run certificate verification when a session is resumed. This optimization
        // only applies on platforms where session resumption can be detected (currently Windows
        // and Linux); elsewhere the peer certificate is always re-validated. Enabling this

src/libraries/System.Net.Security/src/System/Net/Security/SslConnectionInfo.Windows.cs:88

  • These queries are now executed for every completed handshake, including full handshakes; before this change the Windows/Linux resumption probes were DEBUG-only and therefore absent from Release builds. The performance data in the PR covers resumed handshakes but does not establish the cost on full handshakes, so this can regress the common non-resumed path. Please add a full-handshake comparison to the benchmark (or otherwise demonstrate that the added native query is negligible) before relying on the reported optimization.

[!NOTE] This review comment was created with assistance from GitHub Copilot.

            SecPkgContext_SessionInfo info = default;
            TlsResumed = SSPIWrapper.QueryBlittableContextAttributes(
                                    GlobalSSPI.SSPISecureChannel,
                                    securityContext,
                                    Interop.SspiCli.ContextAttribute.SECPKG_ATTR_SESSION_INFO,
                                    ref info) &&
               (info.dwFlags & (uint)SecPkgContext_SessionInfo.Flags.SSL_SESSION_RECONNECT) != 0;

src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs:1261

  • The new isInitialHandshake guard is security-critical, but the added matrix only exercises initial resumed handshakes; it does not verify that a certificate presented during TLS 1.2 renegotiation or TLS 1.3 post-handshake authentication still invokes the callback and is chain-validated. Add a focused regression case for the excluded path (or extend the existing renegotiation/PHA coverage) so a future change cannot accidentally broaden this shortcut.
            if (certificate != null &&
                isInitialHandshake &&
                connectionInfo.TlsResumed &&
                !LocalAppContextSwitches.RevalidateCertificateOnTlsResume)

src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamAllowTlsResumeTests.cs:543

  • The new test verifies only the callback count. It does not verify the other observable behavior introduced by the fast path: that the resumed connection's RemoteCertificate is populated with the cached peer certificate. A regression that returned success while leaving this property null would still pass; add an assertion for the resumed client/server RemoteCertificate (including the mutual-auth case) while the connection is alive.
                    // Establish a resumed session and measure whether the callback runs on it.
                    bool measuredResume = false;
                    for (int i = 0; i < 5 && !measuredResume; i++)
                    {
                        ResetMeasuredCount();
  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Lite

@rzikm rzikm added the breaking-change Issue or PR that represents a breaking API or functional change over a previous release. label Sep 18, 2026
@dotnet-policy-service dotnet-policy-service Bot added the needs-breaking-change-doc-created Breaking changes need an issue opened with https://github.com/dotnet/docs/issues/new?template=dotnet label Sep 18, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Added needs-breaking-change-doc-created label because this PR has the breaking-change label.

When you commit this breaking change:

  1. Create and link to this PR and the issue a matching issue in the dotnet/docs repo using the breaking change documentation template, then remove this needs-breaking-change-doc-created label.
  2. Ask a committer to mail the .NET Breaking Change Notification DL.

Tagging @dotnet/compat for awareness of the breaking change.

Assert exact client and server certificate validation callback counts across full and resumed handshakes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
Copilot AI review requested due to automatic review settings September 22, 2026 13:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

One or more issues must be addressed before approval.

Review effort: Lite
Findings: None

Resolved since last review (1)

@rzikm

rzikm commented Sep 23, 2026

Copy link
Copy Markdown
Member Author

Test failures seem related, there are some tests that rely on the cert validation callback firing.

Disable resumption in tests that require certificate validation callbacks to run on every connection, and remove an unrelated client certificate from the changed-host resumption test.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 5fc01286-cba3-4fbb-b19f-c323b7b4d964
Copilot AI review requested due to automatic review settings September 23, 2026 08:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved security, reauthentication, validation-policy, documentation, and test-coverage findings remain.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 High severity

Open (1)
Previously missed (1)

In code that hasn't changed since last review

Low severity Document resumed-handshake callback behavior as a breaking change

src/​libraries/​System.Net.Security/​src/​System/​Net/​Security/​LocalAppContextSwitches.cs:29

This changes the observable security contract for RemoteCertificateValidationCallback: on Windows/Linux, a resumed initial handshake now succeeds without invoking a callback that callers may use for pinning or authorization. The only explanation is an internal comment, while the public options docs do not describe this behavior and no breaking-change documentation is included. Add the required user-facing breaking-change documentation and clearly document the callback/switch behavior before merging.

return VerifyRemoteCertificate(certificate, chain, trust, ref alertToken, ref sslPolicyErrors, out chainStatus);
return VerifyRemoteCertificateCore(
this,
!_isRenego,

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Net.Security breaking-change Issue or PR that represents a breaking API or functional change over a previous release. needs-breaking-change-doc-created Breaking changes need an issue opened with https://github.com/dotnet/docs/issues/new?template=dotnet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants