Search code examples
sql-serversslconnection-stringoledb

SSL / certificate validation error in spite of TrustServerCertificate=true in connection string


At first, please note that I am aware that this question has already been asked several times. However, the accepted (and non-accepted) solutions given so far did not work in my case, so something substantial must have changed since then, which hopefully justifies asking again.

Having said this:

I am currently trying to upgrade an Access 2010 .adp application to Access 2019 .accdb. The application includes a lot of VBA code which uses ADO objects to connect with and operate on Microsoft SQL server (currently: 2008 R2, but will be upgraded soon).

I'd like to keep the most part of the code, which means to stick with ADO, so the way to go is the new OleDB SQL server driver (which has been undeprecated / newly released in 2018). The SQL server runs on another machine than my client application.

I am not able to establish a connection to SQL server from VBA. When executing the following code snippet

Dim cnTemp As Connection
Set cnTemp = New Connection
cnTemp.CursorLocation = adUseServer
cntemp.Open "Provider=MSOLEDBSQL;Server=dbserver.example.com;Initial Catalog=MyDB;Authentication=SqlPassword;User ID=sa;Password=secret;DataTypeCompatibility=80;"

I get the following error when the last line is executed:

SSL Provider: The certificate chain was issued by an authority which is not trusted.

OK, no problem, after all we have found all the other questions dealing with the same issue, all suggesting the same solution: Add Trust Server Certificate=True; to the connection string.

Well, tried that, but -to my surprise- still the same situation. Then I tried some other variants like TrustServerCertificate=True; or using true instead of True, but to no avail. I also tried adding Use Encryption for Data=True; which didn't help either (that could be expected). Furthermore, I tried some of the snippets I had found when researching the problem, but which are not documented by Microsoft as being valid in ADO connection strings (like Encrypt=true or Trusted_Connection=true;); of course, that made the situation worse, raising other error messages.

I have understood that I could solve that problem by putting the SQL server certificate into the client's trusted root certificate store, or by having SQL server use a certificate which has been issued by a known, trusted CA (e.g. Let's Encrypt).

However, I'd strongly like to know why adding Trust Server Certificate=true; to my connection string does not make the error go away and what I have to put in there to disable certificate validation (and by the way, I would be grateful if we wouldn't start a discussion about why this would be bad; this is just development and testing in a trusted, closed network, and I am aware of possible risks).


Solution

  • The reason TrustServerCertificate=True in the connection string is not honored is twofold. One is that it isn't a valid ADO classic (ADODB) connection string keyword. According to the ActiveX Data Objects (ADO) Connection String Keywords documentation, the keyword/value pair should be Trust Server Certificate=True (note spaces). The keyword is ignored entirely without the spaces and not trusted as a result.

    However, this change alone will not trust the certificate because of the Authentication-SqlPassword specification. When the Authentication keyword is specified, the documentation footnote calls out:

    To improve security, encryption and certificate validation behavior is modified when using Authentication/Access Token initialization properties or their corresponding connection string keywords. For details, see Encryption and certificate validation link.

    The referenced link includes this important note:

    Certificate validation can also be controlled through the Value field of the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\SNI18.0\GeneralFlags\Flag2 registry entry. Valid values are 0 or 1. The OLE DB driver chooses the most secure option between the registry and the connection property/keyword settings. That is, the driver will validate the server certificate as long as at least one of the registry/connection settings enables server certificate validation.

    So even with Trust Server Certificate=True, the cert will be validated when this registry value is set to 0.

    One solution is to simply remove the Authentication=SqlPassword specification as long as you don't need the improved security provided by not trusting the server certificate:

    cntemp.Open "Provider=MSOLEDBSQL;Server=dbserver.example.com;Initial Catalog=MyDB;User ID=sa;Password=secret;Trust Server Certificate=True;DataTypeCompatibility=80;"