Skip to content

Return Complete from RequestClientCertificate when the client didn't offer post-handshake auth - #135049

Merged
rzikm merged 1 commit into
dotnet:mainfrom
caraioniurie47:issue-135047
Oct 2, 2026
Merged

rzikm merged 1 commit into
dotnet:mainfrom
caraioniurie47:issue-135047

Conversation

@caraioniurie47

Copy link
Copy Markdown
Contributor

RequestClientCertificateBufferedCore throws AuthenticationException for any failed token. When a TLS 1.3 client didn't offer post-handshake authentication, both PALs report NoRenegotiation (OpenSSL fails SSL_verify_client_post_handshake with SSL_R_EXTENSION_NOT_RECEIVED, SChannel returns SECURITY_STATUS.NoRenegotiation), so the method throws before reaching its own !staged branch, whose comment says such a decline returns Complete. This affects TlsBufferSession.RequestClientCertificate and, on Windows, TlsSocketSession.RequestClientCertificate, which runs the buffered core there. SslStream.NegotiateClientCertificateAsync and the Linux socket-bound path (TryFastRequestClientCertificate) already return.

Change. On NoRenegotiation, nothing is staged, the session stays in its completed state, and the method returns Complete with nothing written. Any other failed status still throws.

Docs. TlsBufferSession.RequestClientCertificate gets the remark TlsSocketSession.RequestClientCertificate already has about the decline, and that remark loses "On Linux". Both summaries described the method as TLS 1.3 post-handshake authentication only, and TlsBufferSession's InvalidOperationException entry listed "the current session is not TLS 1.3". The buffered core has no protocol check, and on TLS 1.2 the method starts a renegotiation: ServerSession_RequestClientCertificate_Tls12_ProducesHandshakeBytes and the Tls12 rows of both ..._RequestClientCertificate_DrivesSecondHandshakeToCompletion tests pass on Linux and Windows. The summaries now name both protocols, and the TLS 1.3 condition is dropped from the exception entry.

TLS 1.2. NoRenegotiation also comes back when renegotiation is disabled locally by an OpenSSL configuration with Options = NoRenegotiation, which makes SSL_renegotiate fail with SSL_R_NO_RENEGOTIATION. There the method now returns Complete with nothing written instead of throwing, as SslStream.NegotiateClientCertificateAsync already does. Checked on Linux x64 with OpenSSL 3.0.2 and 1.1.1f through OPENSSL_CONF.

Tests

  • New TlsSessionTests.ServerSession_RequestClientCertificate_Tls13PhaNotOffered_Completes, the buffered counterpart of SocketBoundSession_RequestClientCertificate_Tls13PhaNotOffered_Completes and Linux-only like it: an SslStream client without a certificate, which on Linux doesn't offer post-handshake authentication, then RequestClientCertificate must return Complete with 0 bytes written, the handshake must stay complete with no remote certificate, and data must flow both ways. Without the change it fails on OpenSSL 3.0.2 with AuthenticationException (inner error:0A000117:SSL routines::extension not received); with it, it passes on 3.0.2 and 1.1.1f.
  • Windows: an SslStream client offers post-handshake authentication even without a certificate, so the decline was produced with openssl s_client 3.5.7 without -enable_pha. With the change TlsBufferSession and TlsSocketSession return Complete and still deliver data to the client; without it TlsBufferSession throws AuthenticationException (inner Win32Exception: "The recipient rejected the renegotiation request.").
  • System.Net.Security.Tests compared by test name with and without the change: on Linux (OpenSSL 3.0.2) identical apart from the new test, with NegotiateAuthenticationKerberosTest failing in both runs; on Windows 11 identical.

Resolves #135047

Note

AI-generated, written at my direction and reviewed by me before posting. The tests ran on local builds of main at 12955c8, with and without this commit: clr+libs -rc release -lc release on Ubuntu 22.04 x64, where each run's test process memory map was checked for the libssl it loaded, and clr+libs -rc release on Windows 11 x64. The s_client checks ran the repro from the linked issue, and a larger scratch app for TlsSocketSession, on the Windows build. The TLS 1.2 check ran a scratch app with an OPENSSL_CONF file on the Linux build.

RequestClientCertificateBufferedCore threw AuthenticationException for
any failed token, including NoRenegotiation, which the OpenSSL and
SChannel PALs report when a TLS 1.3 client didn't offer post-handshake
authentication. This affected TlsBufferSession and, on Windows,
TlsSocketSession.

On NoRenegotiation, stage nothing and return Complete. Update the
RequestClientCertificate docs to describe that TLS 1.3 case on both
session types and to cover TLS 1.2 renegotiation.

Fix dotnet#135047

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dotnet-policy-service dotnet-policy-service Bot added the community-contribution Indicates that the PR has been added by a community member label Oct 1, 2026
@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.

@rzikm rzikm 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.

LGTM, Thanks!

@rzikm
rzikm merged commit c94f652 into dotnet:main Oct 2, 2026
91 of 94 checks passed
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 12.0-preview1 milestone Oct 3, 2026
@caraioniurie47
caraioniurie47 deleted the issue-135047 branch October 3, 2026 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Net.Security community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TlsBufferSession.RequestClientCertificate throws when the TLS 1.3 client didn't offer post-handshake auth

2 participants