From 0ea33100592cf669e73e912c67275a3fa144a2be Mon Sep 17 00:00:00 2001 From: Enrique Alejandro Allegretta Date: Thu, 2 Mar 2023 14:57:39 -0300 Subject: [PATCH] .NET 7 made AllowRenegotiation on SslStream false by default to avoid the following potential vulnerability https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3555, I've added a setting to make it true in the event someone wants to set it, this only applies to .NET STANDARD 2.1, support for netstandard2.1 target framework has also been added --- Src/SmtpServer/EndpointDefinitionBuilder.cs | 23 +++++++++++++++++++++ Src/SmtpServer/IEndpointDefinition.cs | 8 +++++++ Src/SmtpServer/IO/SecurableDuplexPipe.cs | 16 +++++++++++++- Src/SmtpServer/Net/EndpointListener.cs | 13 +++++++++++- Src/SmtpServer/SmtpServer.csproj | 2 +- 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/Src/SmtpServer/EndpointDefinitionBuilder.cs b/Src/SmtpServer/EndpointDefinitionBuilder.cs index 95332bc..87a0df3 100644 --- a/Src/SmtpServer/EndpointDefinitionBuilder.cs +++ b/Src/SmtpServer/EndpointDefinitionBuilder.cs @@ -99,6 +99,21 @@ public EndpointDefinitionBuilder AllowUnsecureAuthentication(bool value = true) return this; } +#if NETSTANDARD2_1_OR_GREATER + /// + /// Sets a value indicating wheter client ssl renegotiation should be allowed, this is not recommended + /// since it might allow for the following vulnerability https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3555 + /// .NET 7.0 has made renagotiation false by default https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/7.0/allowrenegotiation-default + /// + /// + /// + public EndpointDefinitionBuilder AllowClientSslRenegotiation(bool value = true) + { + _setters.Add(options => options.AllowClientSslRenegotiation = value); + return this; + } +#endif + /// /// Sets the read timeout to apply to stream operations. /// @@ -154,6 +169,7 @@ internal sealed class EndpointDefinition : IEndpointDefinition /// public bool AuthenticationRequired { get; set; } + /// /// Gets a value indicating whether authentication should be allowed on an unsecure session. /// @@ -173,6 +189,13 @@ internal sealed class EndpointDefinition : IEndpointDefinition /// The supported SSL protocols. /// public SslProtocols SupportedSslProtocols { get; set; } + +#if NETSTANDARD2_1_OR_GREATER + /// + /// Gets a value indicating if during an SSL connection a client ssl renegotiation is allowed + /// + public bool AllowClientSslRenegotiation { get; set; } +#endif } #endregion diff --git a/Src/SmtpServer/IEndpointDefinition.cs b/Src/SmtpServer/IEndpointDefinition.cs index 7489dc1..e5b8079 100644 --- a/Src/SmtpServer/IEndpointDefinition.cs +++ b/Src/SmtpServer/IEndpointDefinition.cs @@ -27,6 +27,14 @@ public interface IEndpointDefinition /// bool AllowUnsecureAuthentication { get; } + +#if NETSTANDARD2_1_OR_GREATER + /// + /// Gets a value indicating if during an SSL connection a client ssl renegotiation is allowed + /// + bool AllowClientSslRenegotiation { get; } +#endif + /// /// The timeout on each individual buffer read. /// diff --git a/Src/SmtpServer/IO/SecurableDuplexPipe.cs b/Src/SmtpServer/IO/SecurableDuplexPipe.cs index 32f2c5b..02548d3 100644 --- a/Src/SmtpServer/IO/SecurableDuplexPipe.cs +++ b/Src/SmtpServer/IO/SecurableDuplexPipe.cs @@ -29,6 +29,10 @@ internal SecurableDuplexPipe(Stream stream, Action disposeAction) Output = PipeWriter.Create(_stream); } +#if NETSTANDARD2_1_OR_GREATER + public bool AllowRenegotiation { get; set; } = false; +#endif + /// /// Upgrade to a secure pipeline. /// @@ -40,8 +44,18 @@ public async Task UpgradeAsync(X509Certificate certificate, SslProtocols protoco { var stream = new SslStream(_stream, true); +#if NETSTANDARD2_1_OR_GREATER + await stream.AuthenticateAsServerAsync(new SslServerAuthenticationOptions + { + AllowRenegotiation = AllowRenegotiation, + ServerCertificate = certificate, + CertificateRevocationCheckMode = X509RevocationMode.Online, + ClientCertificateRequired = false, + EnabledSslProtocols = protocols, + }, cancellationToken); +#else await stream.AuthenticateAsServerAsync(certificate, false, protocols, true).ConfigureAwait(false); - +#endif _stream = stream; Input = PipeReader.Create(_stream); diff --git a/Src/SmtpServer/Net/EndpointListener.cs b/Src/SmtpServer/Net/EndpointListener.cs index 55523dd..4158929 100644 --- a/Src/SmtpServer/Net/EndpointListener.cs +++ b/Src/SmtpServer/Net/EndpointListener.cs @@ -29,6 +29,12 @@ internal EndpointListener(IEndpointDefinition endpointDefinition, TcpListener tc _disposeAction = disposeAction; } + /// + /// During ssl connections allows the client to drop the connection and reconnect while renegotiation for a different TLS version + /// .NET 7.0 has set this to false to prevent the following vulnerability https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-3555 + /// + public bool AllowSslClientRenegotiation { get; set; } = false; + /// /// Returns a securable pipe to the endpoint. /// @@ -50,7 +56,12 @@ public async Task GetPipeAsync(ISessionContext context, Ca { tcpClient.Close(); tcpClient.Dispose(); - }); + }) + { +#if NETSTANDARD2_1_OR_GREATER + AllowRenegotiation = AllowSslClientRenegotiation +#endif + }; } /// diff --git a/Src/SmtpServer/SmtpServer.csproj b/Src/SmtpServer/SmtpServer.csproj index d940c8c..3fc0531 100644 --- a/Src/SmtpServer/SmtpServer.csproj +++ b/Src/SmtpServer/SmtpServer.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard2.0;netstandard2.1 8.0 SmtpServer SmtpServer