IISCrypto breaking RDP on Windows 10/Server 2019 and SQL Server 2022/2019 when disabling insecure TLS version

My company recently had a penetration test and part of the findings was the fact we had insecure cipher suites. I was the lucky one tasked with removing old cipher suites and TLS versions.

I fired up IISCrypto on my secondary Windows Server 2022 Domain Controller, built out a IISCrypto plan, applied, tested it and exported it as a reg file. Then I powered up Group Policy Manager and created a GPO to disable the old cipher suites. I was nervous doing this, but I knew we only used Server 2016, 2019, 2022, and Windows 10/11, so I didn’t expect many issues since they are all mostly new. And if I did have an issue, all I would have to do is open IISCrypto and revert the changes on things that broke.

First, I applied to the GPO to workstations. All of which are Windows 10 and Windows 11. As I’m sure you know, these changes don’t take effect until after a reboot, so it was a quiet few days. But after the weekend updates applied, that’s when things heated up.

The first report was SQL Server 2019 AND SQL Server 2022 was unable to log in, even locally. When they attempted to login, they got the simple sounding error “Internal connection fatal error. Error state: 15, Token : 23 (System.Data)”

The next report was the fact that a basic Remote Desktop (RDP) would fail when connecting into a device that the GPO has been applied to. It would display the error “An internal error has occurred”.

None of these error messages was helpful. The thing that really blew my mind was that Windows Server 2016 did not have an issue at all. Windows Server 2022/Windows 11 didn’t either. But Server 2019 and Windows 10 did. Why would Server 2016 be fine but 2019 fail when telling it to use more modern cipher suites?

As soon as a developer complained that their local SQL instance didn’t work, I thought don’t worry, I got this. I powered up IISCrypto on their PC and hit server defaults and rebooted. And… It did not fix it. I tried selecting EVERYTHING! Nothing would work.

After MANY MANY hours trying to figure out why developers with Windows 10 kept getting errors, I still could not find the cause. It wasn’t until I started going line by line in the registry file wondering why the changes wasn’t reverting with IISCrypto.

Then it CLICKED! Windows 10 and Server 2019 does NOT support TLS 1.3. Not at all. IISCrypto KNEW that. So when I told IISCrypto to revert changes, it knew Server 2019/2016 didn’t support TLS 1.3, so it didn’t attempt to revert that. It left the reg key for TLS 1.3 in place. So now Windows 10/Server 2019 thinks it supported TLS 1.3, when in reality it doesn’t. When it tried to negotiate the encryption, it said “I support TLS 1.3″ and so did the other side. So they tried to speak in TLS 1.3, but the RDP/SQL server couldn’t walk the walk. Instead, it failed with ‘Internal error”.

After removing the TLS 1.3 registry change, rebooted, everything worked perfectly.

Long story short, DO NOT use a server 2022/Windows 11 IISCrpyto Reg file on Windows Server 2019 or Windows 10. If you did, REVERT THAT REGISTRY CHANGE NOW!!

The real question I have – why does Server 2019 break down, while 2016 does not? Its like Server 2019 is only partially aware of TLS 1.3 while Server 2016 just ignores it. Sounds like a bug to me!

I hope this saves you the many hours I spent trying to find the answer! I saw where several other people asked and there never was an answer. Let me know if this helps you! Below is the error messages we were getting:

===================================

Cannot connect to localhost.

===================================

Internal connection fatal error. Error state: 15, Token : 23 (System.Data)

------------------------------
Program Location:

   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlInternalConnectionTds.CompleteLogin(Boolean enlistOK)
   at System.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean ignoreSniOpenTimeout, TimeoutTimer timeout, Boolean withFailover, Boolean isFirstTransparentAttempt, Boolean disableTnir)
   at System.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
   at System.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
   at System.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, DbConnectionPool pool, String accessToken, Boolean applyTransientFaultHandling, SqlAuthenticationProviderManager sqlAuthProviderManager)
   at System.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionFactory.CreateNonPooledConnection(DbConnection owningConnection, DbConnectionPoolGroup poolGroup, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.Open()
   at Microsoft.SqlServer.Management.SqlStudio.Explorer.ObjectExplorerService.ValidateConnection(UIConnectionInfo ci, IServerType server)
   at Microsoft.SqlServer.Management.UI.ConnectionDlg.Connector.ConnectionThreadUser()

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.