-
Notifications
You must be signed in to change notification settings - Fork 314
Closed
Description
Describe the bug
We're encountering an issue when trying to use ServerCertificate https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.servercertificate?view=sqlclient-dotnet-standard-5.1
When trying to establish trust with this parameter in Linux, we get an SSL handshake error (seems to reside in the validation callback).
Exception and stack trace details:
{
"errorType": "SqlException",
"errorMessage": "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)",
"stackTrace": [
"at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)",
"at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)",
"at Microsoft.Data.SqlClient.TdsParser.EnableSsl(UInt32 info, SqlConnectionEncryptOption encrypt, Boolean integratedSecurity, String serverCertificateFilename)",
"at Microsoft.Data.SqlClient.TdsParser.ConsumePreLoginHandshake(SqlConnectionEncryptOption encrypt, Boolean trustServerCert, Boolean integratedSecurity, Boolean& marsCapable, Boolean& fedAuthRequired, Boolean tlsFirst, String serverCert)",
"at Microsoft.Data.SqlClient.TdsParser.Connect(ServerInfo serverInfo, SqlInternalConnectionTds connHandler, Boolean ignoreSniOpenTimeout, Int64 timerExpire, SqlConnectionString connectionOptions, Boolean withFailover)",
"at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover)",
"at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)",
"at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)",
"at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool)",
"at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)",
"at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)",
"at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)",
"at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)",
"at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)",
"at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)",
"at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)",
"at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)",
"at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)",
"at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)",
"at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)",
"at Microsoft.Data.SqlClient.SqlConnection.Open()",
.....
],
"cause": {
"errorType": "AuthenticationException",
"errorMessage": "The remote certificate was rejected by the provided RemoteCertificateValidationCallback.",
"stackTrace": [
"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)",
"at Microsoft.Data.SqlClient.SNI.SNITCPHandle.EnableSsl(UInt32 options)"
]
}
}
To reproduce
- Use any certificate to encrypt your SQL server instance. This guide works fine: https://learn.microsoft.com/en-US/sql/database-engine/configure-windows/configure-sql-server-encryption?view=sql-server-ver16
- Establish a connection to your database via SqlConnection (C# example code below). The important bits in the connection string are TrustServerCertificate=false, Encrypt=True, ServerCertificate=\your\linux\path\cert.cer.
static void Main(string[] args)
{
public const string ConnectionString = "Data Source={...};Initial Catalog={...};Integrated Security=false;User ID={...};Password={...};Encrypt=True;TrustServerCertificate=false;ServerCertificate={your linux certificate path};";
using (SqlConnection connection = new SqlConnection(builder.ConnectionString))
{
connection.Open();
}
}
Expected behavior
Connection should establish with certificate trust.
Further technical details
Microsoft.Data.SqlClient version: 5.1.1
.NET target: .NET 6
SQL Server version: SQL Server 2019
Operating systems:
- SQL Server: Windows Server 2019
- Clients: Windows 10 (ServerCertificate works here), RHEL 9 (reproduced issue), Amazon Linux (reproduced issue), AWS .NET 6 lambda function (reproduced issue)
Additional Context
- This is not an issue in Windows - ServerCertificate works perfectly.
- Installing to the Linux trust store as described here (https://learn.microsoft.com/en-us/sql/linux/sql-server-linux-encrypted-connections?view=sql-server-ver16) also worked, after some additional tinkering.
- We're trying to establish trust in an AWS lambda function, so the Linux trust store unfortunately will not work for us in this case (there is no ability to install certificates in AWS lambda functions).
lnowak-preglife
Metadata
Metadata
Assignees
Labels
No labels
Type
Projects
Status
Closed