From 5bf8a0cb3304401aacddde19b6b384aeb119c0f1 Mon Sep 17 00:00:00 2001 From: Iurie Caraion Date: Wed, 7 Oct 2026 20:23:16 +0300 Subject: [PATCH] Format net_ssl_io_cert_validation in TlsSession reject path TlsSession.SetRemoteCertificateValidationResult built its AuthenticationException from SR.net_ssl_io_cert_validation without SR.Format, so the message ended in a literal "{0}". Format it with the caller's SslPolicyErrors verdict, as SslStream does. Co-Authored-By: Claude Opus 5.5 --- .../src/System/Net/Security/TlsSession.cs | 4 ++-- .../tests/FunctionalTests/TlsSessionTests.cs | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/TlsSession.cs b/src/libraries/System.Net.Security/src/System/Net/Security/TlsSession.cs index 907f850f9b3c62..10b45fe3ec8b23 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/TlsSession.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/TlsSession.cs @@ -489,7 +489,7 @@ public void SetRemoteCertificateValidationResult(SslPolicyErrors errors) // are drained to the caller first). if (_isHandshakeComplete) { - _externalValidationFault = new AuthenticationException(SR.net_ssl_io_cert_validation); + _externalValidationFault = new AuthenticationException(SR.Format(SR.net_ssl_io_cert_validation, errors)); } else if (_resumeAfterCertValidation) { @@ -503,7 +503,7 @@ public void SetRemoteCertificateValidationResult(SslPolicyErrors errors) // which checks _externalValidationFault. On OpenSSL 3.0+ retry-verify the // fault will instead be set by the natural token-failed branch when // SSL_do_handshake emits the fatal alert. - _externalValidationFault = new AuthenticationException(SR.net_ssl_io_cert_validation); + _externalValidationFault = new AuthenticationException(SR.Format(SR.net_ssl_io_cert_validation, errors)); } // VerifyRemoteCertificateCore assigns _remoteCertificate to the candidate before it diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs index a58d6a25f131d8..d3c70b49b78f7d 100644 --- a/src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs +++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs @@ -1007,9 +1007,12 @@ await DriveHandshakeWithExternalValidationAsync( { byte[] pt = "blocked"u8.ToArray(); byte[] ct = new byte[CipherBufSize]; - Assert.Throws(() => session.Write(pt, ct, out _, out _)); + serverFault = Assert.Throws(() => session.Write(pt, ct, out _, out _)); } + // The fault message carries the caller's verdict, like SslStream's. + Assert.Contains(nameof(SslPolicyErrors.RemoteCertificateChainErrors), serverFault.Message); + Assert.DoesNotContain("{0}", serverFault.Message); } } [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows))]