diff --git a/eng/Versions.props b/eng/Versions.props
index 9053ba9ab77fae..3232cf0290a766 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -170,7 +170,7 @@
10.0.0-preview-20251006.1
- 2.5.11
+ 2.5.12
$(MicrosoftDotNetApiCompatTaskPackageVersion)
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 10b45fe3ec8b23..382555a98479d7 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
@@ -347,9 +347,17 @@ public SslApplicationProtocol NegotiatedApplicationProtocol
/// validation logic.
///
///
+ ///
/// Must be called only after returned
/// and before
/// is called.
+ ///
+ ///
+ /// Any associated with the session's certificate
+ /// context is used for chain validation unless a custom chain policy is specified by
+ /// or
+ /// .
+ ///
///
public SslPolicyErrors AcceptWithDefaultValidation()
{
@@ -384,7 +392,7 @@ public SslPolicyErrors AcceptWithDefaultValidation()
ref _connectionInfo,
_externalPendingCert,
chain,
- trust: null,
+ trust: SessionCertificateContext?.Trust,
ref alertToken,
ref sslPolicyErrors,
out _,
diff --git a/src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs b/src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs
index d3c70b49b78f7d..f8047990d65ad4 100644
--- a/src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs
+++ b/src/libraries/System.Net.Security/tests/FunctionalTests/TlsSessionTests.cs
@@ -1805,6 +1805,113 @@ await DriveHandshakeWithExternalValidationAsync(
}
}
+ [Theory]
+ [InlineData(false, null)]
+ [InlineData(false, true)]
+ [InlineData(false, false)]
+ [InlineData(true, null)]
+ [InlineData(true, true)]
+ [InlineData(true, false)]
+ public async Task AcceptWithDefaultValidation_CertificateContextTrust_HonorsChainPolicy(bool isServer, bool? chainPolicyTrustsPeer)
+ {
+ const string serverName = "localhost";
+ using TestCertificates.PkiHolder localPki = TestCertificates.GenerateCertificates(
+ serverName,
+ testName: $"{nameof(AcceptWithDefaultValidation_CertificateContextTrust_HonorsChainPolicy)}_local",
+ serverCertificate: isServer);
+ using TestCertificates.PkiHolder peerPki = TestCertificates.GenerateCertificates(
+ serverName,
+ testName: $"{nameof(AcceptWithDefaultValidation_CertificateContextTrust_HonorsChainPolicy)}_peer",
+ serverCertificate: !isServer);
+
+ X509Certificate2 peerRoot = peerPki.IssuerChain[peerPki.IssuerChain.Count - 1];
+ SslCertificateTrust trust = SslCertificateTrust.CreateForX509Collection(
+ new X509Certificate2Collection(peerRoot));
+ SslStreamCertificateContext certificateContext = SslStreamCertificateContext.Create(
+ localPki.EndEntity, localPki.IssuerChain, offline: true, trust: trust);
+ SslStreamCertificateContext peerCertificateContext = SslStreamCertificateContext.Create(
+ peerPki.EndEntity, peerPki.IssuerChain, offline: true);
+
+ X509ChainPolicy? chainPolicy = null;
+ if (chainPolicyTrustsPeer is bool trustsPeer)
+ {
+ chainPolicy = new X509ChainPolicy
+ {
+ TrustMode = trustsPeer ? X509ChainTrustMode.CustomRootTrust : X509ChainTrustMode.System,
+ RevocationMode = X509RevocationMode.NoCheck,
+ DisableCertificateDownloads = true,
+ };
+ if (trustsPeer)
+ {
+ chainPolicy.CustomTrustStore.Add(peerRoot);
+ }
+ }
+
+ // Accept policy errors so the untrusted-policy cases can finish the handshake.
+ RemoteCertificateValidationCallback? validationCallback =
+ chainPolicyTrustsPeer is false ? TestHelper.AllowAnyServerCertificate : null;
+ using TlsContext ctx = isServer
+ ? TlsContext.CreateServer(new SslServerAuthenticationOptions
+ {
+ ServerCertificateContext = certificateContext,
+ ClientCertificateRequired = true,
+ EnabledSslProtocols = SslProtocols.Tls12,
+ AllowTlsResume = false,
+ CertificateChainPolicy = chainPolicy,
+ RemoteCertificateValidationCallback = validationCallback,
+ })
+ : TlsContext.CreateClient(new SslClientAuthenticationOptions
+ {
+ TargetHost = serverName,
+ ClientCertificateContext = certificateContext,
+ EnabledSslProtocols = SslProtocols.Tls12,
+ AllowTlsResume = false,
+ CertificateChainPolicy = chainPolicy,
+ RemoteCertificateValidationCallback = validationCallback,
+ });
+ using TlsBufferSession session = NewBufferSession(ctx);
+
+ (Stream sessionStream, Stream peerStream) = TestHelper.GetConnectedStreams();
+ using (sessionStream)
+ using (peerStream)
+ using (SslStream peer = new SslStream(peerStream, leaveInnerStreamOpen: false, TestHelper.AllowAnyServerCertificate))
+ {
+ Task peerHandshake = isServer
+ ? peer.AuthenticateAsClientAsync(new SslClientAuthenticationOptions
+ {
+ TargetHost = serverName,
+ ClientCertificateContext = peerCertificateContext,
+ EnabledSslProtocols = SslProtocols.Tls12,
+ AllowTlsResume = false,
+ })
+ : peer.AuthenticateAsServerAsync(new SslServerAuthenticationOptions
+ {
+ ServerCertificateContext = peerCertificateContext,
+ ClientCertificateRequired = true,
+ EnabledSslProtocols = SslProtocols.Tls12,
+ AllowTlsResume = false,
+ });
+
+ int validationCalls = 0;
+ SslPolicyErrors observedErrors = SslPolicyErrors.RemoteCertificateNotAvailable;
+ Task sessionHandshake = DriveHandshakeWithExternalValidationAsync(
+ session, sessionStream,
+ onSuspend: () =>
+ {
+ validationCalls++;
+ observedErrors = session.AcceptWithDefaultValidation();
+ });
+ await TestConfiguration.WhenAllOrAnyFailedWithTimeout(peerHandshake, sessionHandshake);
+
+ Assert.Equal(1, validationCalls);
+ Assert.Equal(
+ chainPolicyTrustsPeer is false ? SslPolicyErrors.RemoteCertificateChainErrors : SslPolicyErrors.None,
+ observedErrors);
+ Assert.True(session.IsHandshakeComplete);
+ Assert.True(peer.IsAuthenticated);
+ }
+ }
+
[Fact]
public async Task ClientSession_ExternalCertificateValidation_AcceptWithDefaultValidation_FailsOnUntrustedCert()
{