Skip to content

Commit 803d807

Browse files
committed
Use reflection instead of catching exception. Fixes #475
This avoids a first-chance exception always being thrown on .NET Framework (in order to determine if SslProtocols.None is valid).
1 parent 1c920e4 commit 803d807

File tree

1 file changed

+20
-16
lines changed

1 file changed

+20
-16
lines changed

src/MySqlConnector/Utilities/Utility.cs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@
22
using System.Globalization;
33
using System.IO;
44
using System.Linq;
5-
using System.Net.Security;
5+
using System.Net;
6+
#if NETSTANDARD1_3 || NETSTANDARD2_0
67
using System.Runtime.InteropServices;
8+
#endif
9+
#if NET45 || NET46
10+
using System.Reflection;
11+
#endif
712
using System.Security.Authentication;
813
using System.Security.Cryptography;
914
using System.Text;
@@ -262,27 +267,26 @@ public static SslProtocols GetDefaultSslProtocols()
262267
{
263268
if (!s_defaultSslProtocols.HasValue)
264269
{
270+
// Prior to .NET Framework 4.7, SslProtocols.None is not a valid argument to SslStream.AuthenticateAsClientAsync.
271+
// If the NET46 build is loaded by an application that targets. NET 4.7 (or later), or if app.config has set
272+
// Switch.System.Net.DontEnableSystemDefaultTlsVersions to false, then SslProtocols.None will work; otherwise,
273+
// if the application targets .NET 4.6.2 or earlier and hasn't changed the AppContext switch, then it will
274+
// fail at runtime. We attempt to determine if it will fail by accessing the internal static
275+
// ServicePointManager.DisableSystemDefaultTlsVersions property, which controls whether SslProtocols.None is
276+
// an acceptable value.
277+
bool disableSystemDefaultTlsVersions;
265278
try
266279
{
267-
using (var memoryStream = new MemoryStream())
268-
using (var sslStream = new SslStream(memoryStream))
269-
{
270-
sslStream.AuthenticateAsClient("localhost", null, SslProtocols.None, false);
271-
}
272-
}
273-
catch (ArgumentException ex) when (ex.ParamName == "sslProtocolType")
274-
{
275-
// Prior to .NET Framework 4.7, SslProtocols.None is not a valid argument to AuthenticateAsClientAsync.
276-
// If the NET46 build is loaded by an application that targets. NET 4.7 (or later), or if app.config has set
277-
// Switch.System.Net.DontEnableSystemDefaultTlsVersions to false, then SslProtocols.None will work; otherwise,
278-
// if the application targets .NET 4.6.2 or earlier and hasn't changed the AppContext switch, then it will
279-
// fail at runtime; we catch the exception and explicitly specify the protocols to use.
280-
s_defaultSslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
280+
var property = typeof(ServicePointManager).GetProperty("DisableSystemDefaultTlsVersions", BindingFlags.NonPublic | BindingFlags.Static);
281+
disableSystemDefaultTlsVersions = property == null || (property.GetValue(null) is bool b && b);
281282
}
282283
catch (Exception)
283284
{
284-
s_defaultSslProtocols = SslProtocols.None;
285+
// couldn't access the property; assume the safer default of 'true'
286+
disableSystemDefaultTlsVersions = true;
285287
}
288+
289+
s_defaultSslProtocols = disableSystemDefaultTlsVersions ? (SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12) : SslProtocols.None;
286290
}
287291

288292
return s_defaultSslProtocols.Value;

0 commit comments

Comments
 (0)