dotnet / SqlClient

Microsoft.Data.SqlClient provides database connectivity to SQL Server for .NET applications.
MIT License
820 stars 272 forks source link

SqlConnection.Open() sends TLSv1 Client Hello when running on Linux but not on Windows #2661

Open mortenbock opened 2 weeks ago

mortenbock commented 2 weeks ago

Hi

We have a SQL 2016 server host OnPrem, and have created a Hybrid Connection in Azure, allowing us to connect to the SQL server from our applications.

However, the connection is only successful when hosted on a Windows machine.

The application is a standard .net8.0 application, with the latest Microsoft.Data.SqlClient package installed (5.2.1).

What we are seeing is, that when hosted on a Windows OS, the packets sent over the hybrid connection are:

TDS - TDS7 pre-login message
TDS - Response
TLSv1.2 - Client Hello
TLSv1.2 - Server Hello

So this results in a working connection, and we can query our data.

When hosted in a Linux OS it looks like this:

TDS - TDS7 pre-login message
TDS - Response
TLSv1 - Client Hello

So the clients sends a TLSv1 Client Hello instead of TLSv1.2, and then the communication stops, and we never get a Server Hello.

The Linux OS is the container that is generated when using the dotnet publish -t:PublishContainer on a new dotnet 8 application, which uses the mcr.microsoft.com/dotnet/aspnet:8.0 base image.

If I switch the connection string in the Linux hosted app to an Azure Sql database, then the packets look like this:

TDS - TDS7 pre-login message
TDS - Response
TDS - TDS7 pre-login message
TDS - TDS7 pre-login message (Not last buffer)
TLSv1.2 - Server Hello, Certificate, Certificate Status, Server Key Exchange, Server Hello Done

So in this scenario, there is no Client Hello being sent.

What would cause the Linux hosted application to send a TLSv1 - Client Hello instead of the TLSv1.2 - Client Hello that the Windows hosted application sends?

And is there something in the TDS - Response that can instruct the client to not send a Client Hello at all, which is what I'm seeing on the Azure DB connection?

Attaching Wireshark screenshots here for the different scenarios:

Windows app => SQL 2016: image

Linux app => SQL 2016: image

Linux app => Azure SQL: image

JRahnama commented 2 weeks ago

@mortenbock, it seems like you are using Windows 11 for your Windows testing. What is the value for Encrypt in your connection string?

On another note, the SqlClient driver does not interfere with TLS. It merely detects the supported TLS version on the client OS and negotiates it with the server. If an agreement is reached, the server will request additional information such as certificates, ciphers, etc.

In your case, I suspect you are seeing a FIN message from the server, which indicates the connection is being terminated from the server side.

Overall, this does not seem like a SqlClient issue but rather an OS setup issue concerning different TLS versions. Can you disable TLS 1.0 and 1.1? Also, can you check if TLS 1.3 is enabled on your Linux machine and disable it, allowing TLS 1.2 to be the primary active TLS version?

For additional reading you can look into this document.

mortenbock commented 2 weeks ago

@JRahnama We tried different values for the Encrypt setting.

However, it seems we had a breakthrough today. We managed to get at working connection by modifying the OpenSSL configuration. We had tried this before, but there must have been an error in the config we tried at that time.

The packet that Wireshark marks as TLSv1 seems to be a red herring, that just means that the client and server could not negotiate a common TLS protocol/cypher suite. When changing the OpenSSL config, that packet is updated to TLSv1.2 after the negotiation succeeds.

Link for others hitting this issue: https://learn.microsoft.com/en-us/dotnet/core/compatibility/cryptography/5.0/default-cipher-suites-for-tls-on-linux

I will try and update back here when we find the right modification of the OpenSSL config. Trying to not open too many options since these settings will affect outbound http traffic as well.