9

I have been provided a certificate for a SQL Server, which has been successfully installed and activated. I can confirm this from the logs:

The certificate [Cert Hash(sha1) "xxxxxxxxxxxxxxxxxxE5C050F7D75F58E4E2F"] was successfully loaded for encryption.

Connecting to the database using SSMS is successful, simply by encrypting the connection without trusing the server certificate.

I wanted to replicate this using WSL and later on - docker.

I am testing this with a simple .net 6 console application:

var con = new SqlConnection("Server=domain.host.eu,50730;Database=databasename;User Id=user;Password='password';");
await con.OpenAsync();
var version = con.ExecuteScalar<string>("SELECT @@VERSION");
Console.WriteLine(version);

This works, if I add Trust Server Certificate=True; to the connection string. Without it, the connection fails:

Unhandled exception. Microsoft.Data.SqlClient.SqlException (0x80131904): A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: TCP Provider, error: 35 - An internal exception was caught)
 ---> System.Security.Authentication.AuthenticationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback.
   at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception)
   at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)
   at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
   at System.Net.Security.SslStream.AuthenticateAsClient(SslClientAuthenticationOptions sslClientAuthenticationOptions)
   at System.Net.Security.SslStream.AuthenticateAsClient(String targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)

I wanted to extract the certificate from the pfx:

openssl pkcs12 -in host.domain.eu.pem.pfx -clcerts -nokeys -out host.domain.eu.crt
sudo cp host.domain.eu.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

Unfortunately, this fails with the same error messages and I don't know where I went wrong. I can only assume, that my handling of the certs on Linux is wrong.

Max Lee
  • 241
  • 1
  • 5
  • 14
Marco
  • 22,856
  • 9
  • 75
  • 124
  • Have you looked at these issues: [#1535](https://github.com/dotnet/SqlClient/issues/1535) and [#1402](https://github.com/dotnet/SqlClient/issues/1402)? – Aaron Bertrand May 02 '22 at 12:58
  • @AaronBertrand I have, but unfortunately they do not offer a viable / working solution, except to trust the server certificate – Marco May 02 '22 at 13:05
  • Also the certificate must meet [some requirements to be considered valid](https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms189067(v=sql.105)?redirectedfrom=MSDN) – Cleptus May 02 '22 at 13:05
  • Cleptus, I know that it is working, by testing it from a Windows machine using SSMS and verifying from the logs, that the cert was loaded. – Marco May 02 '22 at 13:08
  • So what steps did you do to add it in to SQL Server on Linux? – Charlieface May 02 '22 at 13:19
  • The server stays the same. The connection fails from linux, steps as described above. – Marco May 02 '22 at 13:22
  • But who issues the certificate and how do you trust the issuer? – Charlieface May 02 '22 at 13:41
  • It's our internal it department. I have to draw the line somewhere. So I trust the certificates I get from them. – Marco May 02 '22 at 13:47
  • So it's not a new/different self-signed certificate then? Did you add your IT department's CA and ICA certificates to the ca-certificates store on linux? – AlwaysLearning May 02 '22 at 14:03
  • I've tried that too, yes @AlwaysLearning. Unfortunately the error stayed the same. And no, it's not a self signed certificate. – Marco May 02 '22 at 14:11

2 Answers2

19

If you're connecting to something unimportant, I was experiencing this error connecting from my dotnetcore API, to a microsoft sql server contained in a docker container (all locally) for dev work. My solution was putting encrypt=False at the end of my connection string like so (within appsettings.json):

"DefaultConnection": "server=localhost;database=newcomparer;trusted_connection=false;User Id=sa;Password=reallyStrongPwd123;Persist Security Info=False;Encrypt=False"

Eric Milliot-Martinez
  • 4,076
  • 3
  • 23
  • 28
  • 1
    Encrypt False is an utterly wrong solution, as I wouldn't be using certificates, if I wanted to not encrypt the connection. – Marco Jan 19 '23 at 14:55
  • 4
    I don't totally disagree with you, but my googling looking for a solution brought me here, I found a solution to my simple dev environment problem and decided to share the solution for others... – Eric Milliot-Martinez Jan 23 '23 at 02:06
  • FYI: It is not working for me, a nice exception was thrown by kerberos. Microsoft.Data.SqlClient.SqlException: 'Cannot authenticate using Kerberos. Ensure Kerberos has been initialized on the client with 'kinit' and a Service Principal Name has been registered for the SQL Server to allow Kerberos authentication. ErrorCode=InternalError, Exception=Interop+NetSecurityNative+GssApiException: GSSAPI operation failed with error - Unspecified GSS failure. – alexDuty Feb 07 '23 at 15:50
7

I double blindsided myself and got distracted by 2 mishaps at the same time.

After importing a certificate into the SQL Configuration Manager, you can choose from 2 nigh on identical entries. The difference beeing one having a friendly name of host.domain (FQDN), while the other has no friendly name. Naturally I have not double checked and just stayed with the one without the FQDN as the friendly name, which was pre-selected after the import and looked valid. The second mistake was to not realize, that WSL was not part of our domain and could not resolve the database name. So I used to the FQDN to reach it. This caused the mismatch between host, which the database instance expected and host.domain, which the client from inside WSL used.

After this I borrowed an Ubuntu vm inside our domain and verified, that using only the host,port schema in the connection string works.

And to make it explicit and work inside wsl I switched the certificates around to require the FQDN as the friendly namae while connecting, so connections can be made from inside the domain, as well as "outside" (from wsl).

tl;dr: One possible explanation for the exception The remote certificate was rejected by the provided RemoteCertificateValidationCallback. is, that the instance name in the connection string and the expected name from the instance do not match.

Marco
  • 22,856
  • 9
  • 75
  • 124
  • 1
    possible solution: [How to solve 'Cannot authenticate using Kerberos' issue doing EF Core database scaffolding in Linux(Ubuntu 18.04)? Are there any solutions?](https://stackoverflow.com/a/62467563/12743268) it worked for me. – alexDuty Feb 07 '23 at 16:10