Skip to content

Commit 8398be5

Browse files
Fall back to TLSv1.2 when System.Security.Authentication.SslProtocols.None is disabled/unavailable
See #764 for background. In some environments we cannot assume that SslProtocols.None will behave as expected: * It can be disabled via app context and other means * Its effective behavior is different between .NET versions according to .NET community blog posts and GitHub issues So we borrow from [1] and special case this exception to retry with an explicitly defined version (TLSv1.2, same as modern .NET default). The discussion in [2] should also be mentioned as they have lead us to understanding of many aspects of this intricate setting. 1. mysql-net/MySqlConnector@715c3b5 2. robinrodricks/FluentFTP#452 (comment)
1 parent 3379195 commit 8398be5

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

projects/client/RabbitMQ.Client/src/client/api/SslHelper.cs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
using System;
4242
using System.IO;
4343
using System.Net.Security;
44+
using System.Security.Authentication;
4445
using System.Security.Cryptography.X509Certificates;
4546

4647
namespace RabbitMQ.Client
@@ -59,21 +60,32 @@ private SslHelper(SslOption sslOption)
5960
}
6061

6162
/// <summary>
62-
/// Upgrade a Tcp stream to an Ssl stream using the SSL options provided.
63+
/// Upgrade a Tcp stream to an Ssl stream using the TLS options provided.
6364
/// </summary>
64-
public static Stream TcpUpgrade(Stream tcpStream, SslOption sslOption)
65+
public static Stream TcpUpgrade(Stream tcpStream, SslOption options)
6566
{
66-
var helper = new SslHelper(sslOption);
67+
var helper = new SslHelper(options);
6768

6869
RemoteCertificateValidationCallback remoteCertValidator =
69-
sslOption.CertificateValidationCallback ?? helper.CertificateValidationCallback;
70+
options.CertificateValidationCallback ?? helper.CertificateValidationCallback;
7071
LocalCertificateSelectionCallback localCertSelector =
71-
sslOption.CertificateSelectionCallback ?? helper.CertificateSelectionCallback;
72+
options.CertificateSelectionCallback ?? helper.CertificateSelectionCallback;
7273

7374
var sslStream = new SslStream(tcpStream, false, remoteCertValidator, localCertSelector);
7475

75-
sslStream.AuthenticateAsClientAsync(sslOption.ServerName, sslOption.Certs, sslOption.Version,
76-
sslOption.CheckCertificateRevocation).GetAwaiter().GetResult();
76+
Action<SslOption> TryAuthenticating = (SslOption opts) => {
77+
sslStream.AuthenticateAsClientAsync(opts.ServerName, opts.Certs, opts.Version,
78+
opts.CheckCertificateRevocation).GetAwaiter().GetResult();
79+
};
80+
try {
81+
TryAuthenticating(options);
82+
} catch(ArgumentException e) when (e.ParamName == "sslProtocolType" && options.Version == SslProtocols.None) {
83+
// SslProtocols.None is dysfunctional in this environment, possibly due to TLS version restrictions
84+
// in the app context, system or .NET version-specific behavior. See rabbitmq/rabbitmq-dotnet-client#764
85+
// for background.
86+
options.UseFallbackTlsVersions();
87+
TryAuthenticating(options);
88+
}
7789

7890
return sslStream;
7991
}

projects/client/RabbitMQ.Client/src/client/api/SslOption.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,5 +149,16 @@ public X509CertificateCollection Certs
149149
/// Retrieve or set the Ssl protocol version.
150150
/// </summary>
151151
public SslProtocols Version { get; set; }
152+
153+
/// <summary>
154+
/// Reconfigures the instance to enable/use TLSv1.2.
155+
/// Only used in environments where System.Security.Authentication.SslProtocols.None
156+
/// is unavailable or effectively disabled, as reported by System.Net.ServicePointManager.
157+
/// </summary>
158+
public SslProtocols UseFallbackTlsVersions()
159+
{
160+
this.Version = SslProtocols.Tls12;
161+
return Version;
162+
}
152163
}
153164
}

0 commit comments

Comments
 (0)