Skip to content

Commit

Permalink
allow late certificate with disabled renegotiation (#53719)
Browse files Browse the repository at this point in the history
  • Loading branch information
wfurt committed Jun 7, 2021
1 parent 5c0a1fa commit eaa3dff
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -914,11 +914,12 @@ private async ValueTask<int> ReadAsyncInternal<TIOAdapter>(TIOAdapter adapter, M
// If that happen before EncryptData() runs, _handshakeWaiter will be set to null
// and EncryptData() will work normally e.g. no waiting, just exclusion with DecryptData()

if (_sslAuthenticationOptions!.AllowRenegotiation || SslProtocol == SslProtocols.Tls13)
if (_sslAuthenticationOptions!.AllowRenegotiation || SslProtocol == SslProtocols.Tls13 || _nestedAuth != 0)
{
// create TCS only if we plan to proceed. If not, we will throw in block bellow outside of the lock.
// Tls1.3 does not have renegotiation. However on Windows this error code is used
// for session management e.g. anything lsass needs to see.
// We also allow it when explicitly requested using RenegotiateAsync().
_handshakeWaiter = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,78 @@ await TestConfiguration.WhenAllOrAnyFailedWithTimeout(
}
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))]
[InlineData(true)]
[InlineData(false)]
[PlatformSpecific(TestPlatforms.Windows)]
public async Task SslStream_NegotiateClientCertificateAsyncNoRenego_Succeeds(bool sendClientCertificate)
{
bool negotiateClientCertificateCalled = false;
using CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(TestConfiguration.PassingTestTimeout);

(SslStream client, SslStream server) = TestHelper.GetConnectedSslStreams();
using (client)
using (server)
using (X509Certificate2 serverCertificate = Configuration.Certificates.GetServerCertificate())
using (X509Certificate2 clientCertificate = Configuration.Certificates.GetClientCertificate())
{
SslClientAuthenticationOptions clientOptions = new SslClientAuthenticationOptions()
{
TargetHost = Guid.NewGuid().ToString("N"),
EnabledSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12,
};
clientOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
clientOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) =>
{
return sendClientCertificate ? clientCertificate : null;
};

SslServerAuthenticationOptions serverOptions = new SslServerAuthenticationOptions() { ServerCertificate = serverCertificate,
AllowRenegotiation = false };
serverOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
if (negotiateClientCertificateCalled && sendClientCertificate)
{
Assert.Equal(clientCertificate.GetCertHash(), certificate?.GetCertHash());
}
else
{
Assert.Null(certificate);
}
return true;
};

await TestConfiguration.WhenAllOrAnyFailedWithTimeout(
client.AuthenticateAsClientAsync(clientOptions, cts.Token),
server.AuthenticateAsServerAsync(serverOptions, cts.Token));

Assert.Null(server.RemoteCertificate);

// Client needs to be reading for renegotiation to happen.
byte[] buffer = new byte[TestHelper.s_ping.Length];
ValueTask<int> t = client.ReadAsync(buffer, cts.Token);

negotiateClientCertificateCalled = true;
await server.NegotiateClientCertificateAsync(cts.Token);
if (sendClientCertificate)
{
Assert.NotNull(server.RemoteCertificate);
}
else
{
Assert.Null(server.RemoteCertificate);
}
// Finish the client's read
await server.WriteAsync(TestHelper.s_ping, cts.Token);
await t;
// verify that the session is usable with or without client's certificate
await TestHelper.PingPong(client, server, cts.Token);
await TestHelper.PingPong(server, client, cts.Token);
}
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.SupportsTls13))]
[InlineData(true)]
[InlineData(false)]
Expand Down

0 comments on commit eaa3dff

Please sign in to comment.