microsoft / msphpsql

Microsoft Drivers for PHP for SQL Server
MIT License
1.78k stars 371 forks source link

Error OpenSSL Shutdown while in init - cURL - MSSQL #1512

Closed AdrienHt closed 2 weeks ago

AdrienHt commented 1 month ago

Environment

Php version: 8.2.19 PDO_SQLSRV: pdo_sqlsrv-5.12.0 Microsoft ODBC Driver version: 18.3.2.1-1
MS SQL Server version: 2022 lastest (docker image mcr.microsoft.com/mssql/server:2022-latest) Ubuntu via Docker for Mac: Ubuntu 22.04.4 LTS (Jammy Jellyfish) OpenSSL version: OpenSSL 1.1.1f 31 Mar 2020

Problem description

The following code:

<?php

$pdo = new \PDO('sqlsrv:server=tcp:' . getenv('SQL_HOST') . ',1433 ; Database = ' . getenv('SQL_DATABASE') . ';TrustServerCertificate=yes;', getenv('SQL_USERNAME'), getenv('SQL_PASSWORD'));

$pdo->beginTransaction();

$curlResource = curl_init();

$curlOptions = [
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_CAPATH => '/data/ca',
    CURLOPT_CAINFO => '/data/ca/serverCa.pem',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_URL => getenv('API_URL'),
];

foreach ($curlOptions as $option => $value) {
    curl_setopt($curlResource, $option, $value);
}

$responseContent = curl_exec($curlResource);
$errorNumber = curl_errno($curlResource);
$errorMessage = curl_error($curlResource);

curl_close($curlResource);

if ($errorNumber > 0) {
    echo 'Curl error: ' . $errorNumber . ' - ' . $errorMessage. "\n" ;
    $pdo->rollBack();
}

echo $responseContent;

Resulted in this output:

Curl error: 60 - SSL certificate problem: unable to get local issuer certificate

PHP Fatal error:  Uncaught PDOException: SQLSTATE[08S01]: [Microsoft][ODBC Driver 18 for SQL Server]SSL Provider: [error:140E0197:SSL routines:SSL_shutdown:shutdown while in init] in /data/test.php:30
Stack trace:
0 /data/test.php(30): PDO->rollBack()
1 {main}
  thrown in /data/test.php on line 30

But I expected no SQL error, only the cURL error :

Curl error: 60 - SSL certificate problem: unable to get local issuer certificate // no SQL error

The error only happens when the curl CA verification reports a certificate not allowed. The error does not happen when I remove TrustServerCertificate=yes in the dsn. The error does not happen when CURLOPT_SSL_VERIFYPEER is set to false.

It's seems that the Mssql driver call openssl function SSL_shutdown() while SSL_in_init() send true.

The SSL_in_init() seems to return true only when the curl CA verification reports a certificate not allowed.

I don't know if php curl implementation does not close the connection correctly or if the MSSQL driver should check if SSL_in_init() returns true before calling SSL_shutdown(), but there is something wrong here. I opened an issue on PHP, but they suggested that I open an issue here (https://github.com/php/php-src/issues/14230).

v-makouz commented 1 month ago

It seems likely that curl also loads OpenSSL, just like the ODBC Driver and there is probably some interference there. I'm having a bit of trouble getting php-curl to work to verify, but the fact that error goes away when CURLOPT_SSL_VERIFYPEER is set to false, strongly suggests that curl's use of OpenSSL is involved. I will investigate further.

By the way, do you know which version of OpenSSL is used there?

AdrienHt commented 1 month ago

thanks ! Yes we used OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)

v-makouz commented 1 month ago

Can you strace a successful run and the one with the error? Something like strace -o output.txt -f php file.php if it's run directly.

I can now run the repro code, but I don't get the same error, since I don't have the API URL setup that would return "certificate not allowed", if I understand the setup correctly.

AdrienHt commented 1 month ago

The error is triggered before the API call. I got the error even when https://www.google.fr is set as the API URL. Are you sure you are using the same set up ?

v-makouz commented 1 month ago

Great, thanks. I'll see what I can find in those

absci commented 2 weeks ago

Hi, turns out this is a bug in libcurl. More details here. They have fixed it for curl>=8.3.0. After upgrade the driver no longer throw an error.