Home » Php » ssl – PHP handshake fail TLS1.0

ssl – PHP handshake fail TLS1.0

Posted by: admin July 12, 2020 Leave a comment

Questions:

I try to connect via fsockopen to sendm.cert.legalmail.it on 465 port, is SMTPS service called PEC in italy.

With any version of PHP i have tried this snippet work:

<?php
fsockopen('tls://sendm.cert.legalmail.it', 465);

all it’s ok with OpenSSL 1.0.2h, if i upgrade to OpenSSL 1.0.2j this snippet fail with this error:

    PHP Warning:  fsockopen(): SSL operation failed with code 1. OpenSSL Error messages:
    error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure in ~/Development/experimental/php-handshake/connect.php on line 3
    PHP Warning:  fsockopen(): Failed to enable crypto in ~/Development/experimental/php-handshake/connect.php on line 3
    PHP Warning:  fsockopen(): unable to connect to tls://sendm.cert.legalmail.it:465 (Unknown error) in ~/Development/experimental/php-handshake/connect.php on line 3

So with OpenSSL 1.0.2j i try to connect via command line:

openssl s_client -connect sendm.cert.legalmail.it:465

It works perfectly.

I try check SSL on the server with testssl this is the dump (stripped):

SSLv2               not offered (OK)
SSLv3               not offered (OK)
TLS 1               offered
TLS 1.1             not offered
TLS 1.2             not offered
Version tolerance   downgraded to TLSv1.0 (OK)

Only TLS 1 is avaiable, i try to force the handshake to TLS1 with this uri: 'tlsv1.0:://sendm.cert.legalmail.it' but the result is the same.

I’m on Ubuntu 16.04, tested with PHP5.6 and PHP7.1.

Where is the bug? in openssl? in PHP? in the server handshake?

Update if i look at chiper always with ./testssl.sh -E sendm.cert.legalmail.it:465 with OpenSSL 1.0.2j return:

x05     RC4-SHA                           RSA        RC4       128      TLS_RSA_WITH_RC4_128_SHA                           
x04     RC4-MD5                           RSA        RC4       128      TLS_RSA_WITH_RC4_128_MD5                           
x16     EDH-RSA-DES-CBC3-SHA              DH 1024    3DES      168      TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA                  
x0a     DES-CBC3-SHA                      RSA        3DES      168      TLS_RSA_WITH_3DES_EDE_CBC_SHA                      
x15     EDH-RSA-DES-CBC-SHA               DH 1024    DES       56       TLS_DHE_RSA_WITH_DES_CBC_SHA                       
x09     DES-CBC-SHA                       RSA        DES       56       TLS_RSA_WITH_DES_CBC_SHA                           
x14     EXP-EDH-RSA-DES-CBC-SHA           DH(512)    DES       40,exp   TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA              
x08     EXP-DES-CBC-SHA                   RSA(512)   DES       40,exp   TLS_RSA_EXPORT_WITH_DES40_CBC_SHA                  
x06     EXP-RC2-CBC-MD5                   RSA(512)   RC2       40,exp   TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5                 
x03     EXP-RC4-MD5                       RSA(512)   RC4       40,exp   TLS_RSA_EXPORT_WITH_RC4_40_MD5      

With the version OpenSSL 1.0.2h

x05     RC4-SHA                           RSA        RC4       128       
x04     RC4-MD5                           RSA        RC4       128       
x16     EDH-RSA-DES-CBC3-SHA              DH 1024    3DES      168       
x0a     DES-CBC3-SHA                      RSA        3DES      168

And php const OPENSSL_DEFAULT_STREAM_CIPHERS is the same accross all versione it contains:

ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:HIGH:!SSLv2:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!RC4:!ADH
How to&Answers:

Ok, after some research i find why:

PHP has a OPENSSL_DEFAULT_STREAM_CIPHERS which contains the default query for openssl, with this command:

openssl ciphers -v `php -r 'echo OPENSSL_DEFAULT_STREAM_CIPHERS;'`

i get all ciphers PHP can handle with the current version of openssl installed.

Between 1.0.2h and 1.0.2j the same query return different ciphers list a drop support for these:

  1. EDH-RSA-DES-CBC3-SHA
  2. DES-CBC3-SHA

So by default the PHP can’t handle the connection correctly, but if i force the $context with this cipher the connection take place:

$context = stream_context_create(
    [
        'ssl' => [
            'ciphers' => 'EDH-RSA-DES-CBC3-SHA:DES-CBC3-SHA',
        ],
    ]
);

$fp = stream_socket_client(
  'tls://sendm.cert.legalmail.it:465',
  $errno,
  $errstr,
  30,
  STREAM_CLIENT_CONNECT,
  $context
);

Answer:

For everyone else experiencing the same issue: it seems that Legalmail TLS server now supports TLSv1.2, so this is not a problem anymore with them.

Answer:

Edited answer completely: look at answer here HTTPS and SSL3_GET_SERVER_CERTIFICATE:certificate verify failed, CA is OK

This is probably the cause for fsock as well as curl.
Although his question is on windows / xampp, I suppose it will help, I suppose the one who upgraded the OS did not merge the php.ini with new version(s)