msphpsql icon indicating copy to clipboard operation
msphpsql copied to clipboard

Can't Connect to Server, TCP Provider: Error code 0x2746.

Open savecol opened this issue 1 year ago • 12 comments

PHP version
PHP 8.1

PHP SQLSRV or PDO_SQLSRV version
PHP sqlsrv 5.111

Microsoft ODBC Driver versions tested
[ODBC Driver 18 for SQL Server] libmsodbcsql-18.2.so.1.1

[ODBC Driver 17 for SQL Server] libmsodbcsql-17.10.so.2.1

SQL Server version
SQL Server 2014 SP3 - Windows Server 2012

Client operating system
Fedora 38

Problem description
I'm trying to connect to a Windows Server machine that has a SQL Server 2014 SP3 instance, but neither php driver or sqlcdm cli connect to the server because they use TLS v1 in the ssl negotiation where TLS v1.2 should be used as shown in the packet trace. The connection gets terminated by the server image

Expected behavior and actual behavior
The connection to the server should be made using TLS v1.2, as shown in this packet trace generated from a connection using DBeaver with the Microsoft JDBC SQL Server driver.

image

Tried changing the openssl.cnf file to have

[system_default_sect] MinProtocol = TLSv1.2 CipherString = DEFAULT@SECLEVEL=0 ## tried with 1 too
# CipherString = DEFAULT@SECLEVEL=1

but none of these worked, the connection is still forced to use TLS v1

savecol avatar May 18 '23 16:05 savecol

Which version of OpenSSL are you using? Also, do you know which ODBC driver PHP calls 17 or 18?

v-makouz avatar May 18 '23 23:05 v-makouz

My system uses OpenSSL 3.0.8 and PHP is calling the 18 version of the ODBC driver image

savecol avatar May 19 '23 18:05 savecol

Looks like all of those are fine. Can you look at the server event log right after a failed attempt to see what it says? Usually the log would be in something like: C:\Program Files\Microsoft SQL Server\MSSQL<Your Version>.MSSQLSERVER\MSSQL\Log\ERRORLOG

v-makouz avatar May 24 '23 23:05 v-makouz

Sadly I haven't been granted access to the server yet, I'm working on that. What feels odd is even the cli trying to make a connection through TLS v1 where my system is configured to allow a minimum of v1.2 (the default) like the JDBC dirver does. Should I attach my openssl conf?.

Also, is there a way to force the TLS version through ODBC config? I feel that could work.

savecol avatar May 27 '23 00:05 savecol

Tried opening an ODBC connection using Devart ODBC driver and connected immediately, w/o having to deal with any configuration, but using Microsoft Drivers fails every time.

This is the packet register from the Devart driver connection

image

savecol avatar May 27 '23 21:05 savecol

Can you provide contents of the Client Hello, Server Hello, Client Key Exchange, and Change Cipher Spec from the Wireshark log, for both working and non-working case? We need to see what the client and server are negotiating.

Microsoft ODBC Driver should use the system setting for TLS, maybe Devart ODBC doesn't? I'm not familiar with it, so it'll be interesting to see what they negotiate differently.

v-makouz avatar May 30 '23 16:05 v-makouz

I have similar problem on RHEL 9, it's probably caused by unexpected eof. I tried to block access to OpenSSL 3 library forcing libmsodbcsql use OpenSSL 1.1 (for compat-openssl11 package) and everything works as expected.(blocked by mounting custom /usr/lib64 in cgroup) It`s same with msodbcsql17 or 18, no configuration change(legacy, TLS version,SECLEVEL) helps, i also whent throught similiar path with tcpdump and wireshark and notice TLS 1.0...

Building OpenSSL with forced SSL_OP_IGNORE_UNEXPECTED_EOF helps to get working openssl s_client <IP>:1433 without needing -ignore_unexpected_eof but not for msodbcsql... maybe it`s not unexpected_eof after all.

Lathanderjk avatar Jun 17 '23 07:06 Lathanderjk

We have same problem with OpenSSL 3.0.8, MS ODBC Driver 17, unixODBC2.3.11, SQL Server 2014. Client keeps waiting for 'Server Hello' but server doesn't reply. Even openssl is not able to connect to sql server, not even sslcan shows the server ciphers. Everything works with OpenSSL 1.1.1. Also the client uses TLSv1 with OpenSLL 3.0.8 but it's TLSv1.2 with OpenSLL 1.1.1 !!!

@Lathanderjk Did you find a solution to it? Could you please share the steps?

utkalRP avatar Aug 03 '23 11:08 utkalRP

SQLServer could provide a library that could use by C/C++/PHP/ODBC/Ruby/Nodejs/JDBC?

ODBC is not friendly for App, can't package it directly, and it's huge.

taozuhong avatar Aug 18 '23 03:08 taozuhong

Just run this in your shell: update-crypto-policies --set DEFAULT:SHA1

ngochangngo52 avatar Sep 15 '23 14:09 ngochangngo52

Works for me on Docker Ubuntu 22.04 ODBC Driver 18 for SQL Server

In /etc/ssl/openssl.cnf file :

1/ change openssl_conf = openssl_init to openssl_conf = default_conf

2/ add those lines at the end of file

[ default_conf ]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT@SECLEVEL=0

Then test it with

isql -v -k "Driver={ODBC Driver 18 for SQL Server};Server=xx;Database=xx;UID=xx;PWD=xx;Encrypt=no"

thdaguin avatar Jan 05 '24 16:01 thdaguin

Works for me on Docker Ubuntu 22.04 ODBC Driver 18 for SQL Server

In /etc/ssl/openssl.cnf file :

1/ change openssl_conf = openssl_init to openssl_conf = default_conf

2/ add those lines at the end of file

[ default_conf ]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT@SECLEVEL=0

Then test it with

isql -v -k "Driver={ODBC Driver 18 for SQL Server};Server=xx;Database=xx;UID=xx;PWD=xx;Encrypt=no"

worked for me on same environment, thank you!

junionestor avatar Mar 18 '24 17:03 junionestor

A cleaner solution for RHEL9: https://stackoverflow.com/a/75944492/2897386

update-crypto-policies --set LEGACY

You might have to reboot afterwards.

juresaht2 avatar Jul 11 '24 13:07 juresaht2

This is not a PHP driver issue, but rather compatibility between OpenSSL and SQL Server. Starting with OpenSSL 3.0 TLSv1.0 and TLSv1.1 were deprecated and are not allowed by default, requiring at least TLSv1.2. Many older servers don't have TLSv1.2, thus the connection fails. The ideal solution is to patch or upgrade the server. If that's not possible, one can configure OpenSSL to still allow use of older protocols, but it's best to consult OpenSSL documentation or support for the most up to date instructions for how to do so.

v-makouz avatar Aug 21 '24 19:08 v-makouz