Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set 'verify_peer_name=false' SSL context option via php.ini in PHP 5.6

Tags:

php

ssl

The case: I would like to open SSL connection to localhost while SSL certificate was issues for FQDN.

The problem: Without special handling in line (*) the program below fails with the following message:

PHP Warning: stream_socket_enable_crypto(): Peer certificate CN='myhost.com' did not match expected CN='localhost' in test.php

The test PHP program:

$fp = stream_socket_client("tcp://localhost:993", $errno, $errstr, 30);

// (*) if commented, the program fails
//stream_context_set_option($fp, 'ssl', 'verify_peer_name', false); 

if (!$fp) {
        die("Unable to connect: $errstr ($errno)");
}
if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
        die("Failed to start SSL");
}
fwrite($fp, "USER god\r\n");
fwrite($fp, "PASS secret\r\n");
while ($motd = fgets($fp)) {
        echo $motd;
}
fclose($fp);

As I have a lot of legacy code, I would love to have a solution by only applying changes to php.ini (or CLI), but unfortunately neither of below works:

php -d verify_peer_name=false test.php

php -d ssl.verify_peer_name=false test.php

Ideas?

References:

  • SSL operation failed with code 1
  • How do I verify a TLS SMTP certificate is valid?
  • SSL and PHP streams
  • SSL solution for PHP 5.6
  • OpenSSL changes in PHP 5.6.x
  • SSL context options
like image 497
dma_k Avatar asked Nov 07 '14 21:11

dma_k


1 Answers

TL; DR

When cafile and capath are at the same time runtime configuration and SSL context options, verify_peer_name and verify_peer are only SSL context options.

So those later two can not be modified via runtime configuration directives.


I can understand the confusion from the documentation reproduced here under, but those two paragraphs actually refer to two different concept in PHP.

The default CA bundle may be overridden on a global basis by setting either the openssl.cafile or openssl.capath configuration setting, or on a per request basis by using the cafile or capath context options.

While not recommended in general, it is possible to disable peer certificate verification for a request by setting the verify_peer context option to FALSE, and to disable peer name validation by setting the verify_peer_name context option to FALSE.

Link to PHP manual source

First note that the documentation itself makes a clear difference between openssl.cafile and openssl.capath being on a global basis or on a per request basis versus verify_peer and verify_peer_name being for a request only.

So that basically means that, when openssl.cafile and openssl.capath can be adapted both via php.ini or via stream_context_set_option, on the other hand verify_peer and verify_peer_name are only accessible via stream_context_set_option.

This is also confirmed by PHP source code itself, here are some lines showing that PHP underlaying C language is getting the value from php_stream_context_get_option only.

must_verify_peer_name = GET_VER_OPT("verify_peer_name")
        ? zend_is_true(val)
        : sslsock->is_client;

Link to PHP github source code

For clarity, here is the declaration of the macro GET_VER_OPT

#define GET_VER_OPT(name)               (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", name)) != NULL)

Link to PHP github source code

When cafile and capath are actually first matched against php_stream_context_get_option value, but then, if those are NULL in the context, they are then fetched in the ini configuration.

GET_VER_OPT_STRING("cafile", cafile);
GET_VER_OPT_STRING("capath", capath);

if (cafile == NULL) {
    cafile = zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0);
    cafile = strlen(cafile) ? cafile : NULL;
}

Link to PHP github source code

Then a little lower in the exact same function:

if (capath == NULL) {
    capath = zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0);
    capath = strlen(capath) ? capath : NULL;
}

Link to PHP github source code

For clarity, here is the declaration of the macro GET_VER_OPT_STRING

#define GET_VER_OPT_STRING(name, str)   if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_P(val); }

Link to PHP github source code

You can also see that, when those two value openssl.capth and openssl.cafile are defined as existing ini configuration, the later verify_peer and verify_peer_name are nowhere to be found.

So sadly the only way to go, as the documentation is prompting it, is to configure it for a request via stream_context_set_option ( $stream_or_context , 'ssl' , 'verify_peer_name' , false )


In a long gone history: this was the default value of those two SSL context options. They changed in PHP version 5.6.0, as prompted by the documentation:

5.6.0 Added peer_fingerprint and verify_peer_name. verify_peer default changed to TRUE.

Link to PHP documentation

Which means that this kind of issue can appear after upgrading PHP from PHP < 5.6.0 so, the default value of those two options could have been kept to false by sticking to a PHP version lower than 5.6.0; but since the branches 5.*.* of PHP are now totally out of support this is not a viable option anymore.

like image 196
β.εηοιτ.βε Avatar answered Oct 20 '22 14:10

β.εηοιτ.βε