1 (edited by phpdev1 2018-07-07 11:19:08)

Topic: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

Hi,
I am using an API in a production environment that needs strict TLS security due to PCI requirements (seems to be stricter than regular TLSv1.2)
They have provided a list of ciphers excluding which no other ciphers will be supported - i.e. connections will be refused:
"ECDHE-ECDSA-AES128-GCM-SHA256"
"ECDHE-RSA-AES128-GCM-SHA256"    -- only this one works right now
"ECDHE-ECDSA-AES256-GCM-SHA384"
"ECDHE-RSA-AES256-GCM-SHA384"
"ECDHE-ECDSA-AES256-SHA384"
"ECDHE-RSA-AES256-SHA384"
"ECDHE-ECDSA-CHACHA20-POLY1305"
"ECDHE-RSA-CHACHA20-POLY1305"
"ECDHE-ECDSA-AES128-SHA256"
"ECDHE-RSA-AES128-SHA256"

I want some more (at least 3-4) working as well.

First, here is my detailed server configuration:
------------------------------------------------
I have php70-php* from the Remi Repo for Centos 6 (64-bit)

Some phpinfo() outputs:
----------------
PHP Version 7.0.11
Linux 2.6.32-642.1.1.el6.centos.plus.x86_64 #1 SMP Wed Jun 1 03:11:50 UTC 2016 x86_64
Loaded Configuration File : /etc/opt/remi/php70/php.ini

PHP API            : 20151012
PHP Extension    : 20151012
Zend Extension    : 320151012
Zend Extension Build : API320151012,NTS
PHP Extension Build : API20151012,NTS
Debug Build    : no
Registered Stream Socket Transports : tcp, udp, unix, udg, ssl, sslv3, sslv2, tls, tlsv1.0, tlsv1.1, tlsv1.2

curl:
------------
cURL support : enabled
cURL Information : 7.19.7
Age : 3

Features
AsynchDNS : No
CharConv : No
Debug : No
GSS-Negotiate : Yes
IDN : Yes
IPv6 : Yes
krb4 : No
Largefile : Yes
libz : Yes
NTLM : Yes
SPNEGO : No
SSL : Yes
SSPI : No
Host : x86_64-redhat-linux-gnu
SSL Version : NSS/3.27.1
ZLib Version : 1.2.3
libSSH Version : libssh2/1.4.2
----------------


From the command line:
----------------
# curl -V
curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Protocols: tftp ftp telnet dict ldap ldaps ht tp file ht tps ftps scp sftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz

# yum list installed | grep curl
curl.x86_64                       7.19.7-53.el6_9                    @base     
libcurl.x86_64                    7.19.7-53.el6_9                    @base     
python-pycurl.x86_64              7.19.0-9.el6                       @base     

# yum list installed | grep nss
nss.x86_64                        3.36.0-8.el6                       @base     
nss-softokn.x86_64                3.14.3-23.el6_7                    @CentOS6-Updates/6.7
nss-softokn-freebl.x86_64         3.14.3-23.el6_7                    @CentOS6-Updates/6.7
nss-sysinit.x86_64                3.36.0-8.el6                       @base     
nss-tools.x86_64                  3.36.0-8.el6                       @base     
nss-util.x86_64                   3.36.0-1.el6                       @base     
openssh.x86_64                    5.3p1-118.1.el6_8                  @updates   
openssh-clients.x86_64            5.3p1-118.1.el6_8                  @updates   
openssh-server.x86_64             5.3p1-118.1.el6_8                  @updates   
openssl.x86_64                    1.0.1e-57.el6                      @base     
openssl-devel.x86_64              1.0.1e-57.el6                      @base
----------------


Problem:
------------------------------------------------
From what I have figured out after a lot of googling is that:
- On Centos, php-curl uses NSS not openssl.
- In remirepo, php-curl is packaged in php70-php-common or similar.
- The curl version used by php is not necessarily the curl installed in the system available from the command line (I am not sure of this)
- The NSS used by php-curl is not the NSS installed in the system, but one built-in with php-curl
As you can see, NSS is 3.36.0-*.el6, while the NSS shown in phpinfo() output for curl is NSS/3.27.1

My php-curl+nss combination only supplies one cipher in the above list: ECDHE-RSA-AES128-GCM-SHA256
I tested this from php code and it worked:

curl_setopt($curl, CURLOPT_SSL_CIPHER_LIST, 'ecdhe_rsa_aes_128_gcm_sha_256');

I had to refer to the curl source file nss.c on the curl github repo to get the correct cipher name format to use in the php curl call.

My problem is that the other ciphers do not work. I want to know what to do to get them to work.

It seems I have to upgrade php-curl, because upgrading curl itself using yum did not seem to help.
I tried to hit the API with curl on the command line and I got the error "Unknown cipher in list"

Although the curl version in yum is 7.19.7-53.el6_9, it seems that CentOS team does a lot of backporting to ensure that TLSv1.2 is available in CentOS 6 as mentioned here:
https://serverfault.com/questions/80026 … 270#800270

I also want to know whether php-curl uses the libcurl in the system (installed using yum) or whether it is built-in.
It seems to be built-in but I am not sure.
If it uses the system libcurl, maybe I can get the ciphers to work by installing curl+nss of higher version from somewhere?

From another topic (3659) on this forum as well as many other places, it seems building curl from source is not advised.

This means the only option I have left is to upgrade php from php70 to php71 or php72 to whichever version I find supports the ECDHE ciphers mentioned above, hoping that the NSS built-in with php-curl will support those (eg. *-SHA384-*, *-CHACHA20-POLY1305-*)

I considered upgrading Centos itself from 6.8/9 to 7.x latest, but since the php7*-common package has its own curl+nss combination, independent of the system curl and system NSS, I don't know which version might have these ciphers (eg. *-SHA384-*, *-CHACHA20-POLY1305-*)

Maybe someone can point me to a place where I can get a list of the ciphers that php-curl provides, listed by version?

Of course the last resort will be to try all combinations:
php70 + Centos 6 - this is not working
php71 + Centos 6
php72 + Centos 6
php70 + Centos 7
php71 + Centos 7
php72 + Centos 7

I would prefer not upgrade to Centos 7 because that means recreating our entire production environment from scratch.

Many thanks in advance for any help you can offer.

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

To be clear, PHP is build using system libcurl, which is build using system libnss.


Definitively, using C7 should help.

Laptop:  Fedora 38 + rpmfusion + remi (SCL only)
x86_64 builder: Fedora 39 + rpmfusion + remi-test
aarch64 builder: RHEL 9 with EPEL
Hosting Server: CentOS 8 Stream with EPEL, rpmfusion, remi

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

Using some cipher names from https://curl.haxx.se/docs/ssl-ciphers.html

On Centos 6.10

+ rsa_aes_128_cbc_sha_256       : *OK* ()
+ ecdhe_rsa_aes_128_cbc_sha_256 : *OK* ()
+ rsa_aes_128_gcm_sha_256       : *OK* ()
+ ecdhe_rsa_aes_128_gcm_sha_256 : *OK* ()

On CentOS 7.5

+ rsa_aes_128_cbc_sha_256       : *OK* ()
+ ecdhe_rsa_aes_128_cbc_sha_256 : *OK* ()
+ rsa_aes_128_gcm_sha_256       : *OK* ()
+ ecdhe_rsa_aes_128_gcm_sha_256 : *OK* ()
+ rsa_aes_256_gcm_sha_384       : *OK* ()
+ ecdhe_rsa_aes_256_gcm_sha_384 : *OK* ()
+ ecdhe_rsa_chacha20_poly1305_sha_256: *OK* ()

BTW, I really think the cipher have not to be selected in app sources, but rather should be a system configuration task.
1/ mostly on the server to only accept secure clients
2/ on the client

We even have a Fedora policy to enforce this
https://fedoraproject.org/wiki/Packaging:CryptoPolicies

Indeed, it is much more simpler to fix a server configuration, than having to change all the sources of all the connected applications.

Especially as cipher names differs with used backend (NSS used in EL <= 7;  OpenSSL used in Fedora and very probably in EL-8,;...)

Laptop:  Fedora 38 + rpmfusion + remi (SCL only)
x86_64 builder: Fedora 39 + rpmfusion + remi-test
aarch64 builder: RHEL 9 with EPEL
Hosting Server: CentOS 8 Stream with EPEL, rpmfusion, remi

4 (edited by phpdev1 2018-07-09 14:23:54)

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

Firstly, thank you very much for quick and precise replies smile

Regarding C7, I agree that it is the best way and I will be testing that shortly.

The main reason for all this effort is that the API provider has suddenly enforced this restriction and changing production servers is a challenging task due to all the other things like monitoring, config settings, tweaks and feature sets depending on specific versions.

To be clear, PHP is build using system libcurl, which is build using system libnss.

By this, I understand that it is static linking - i.e. whatever *was* used to build the package on the *build server* is what works, and not dynamic linking (i.e. php-curl picking up whatever current libcurl is present on my server at any given time).

Am I right?

I'm asking again because this means that upgrading only curl from http://www.city-fan.org/ftp/contrib/yum-repo/, even as a temporary measure, will not work.

Especially as cipher names differs with used backend (NSS used in EL <= 7;  OpenSSL used in Fedora and very probably in EL-8,;...)

I totally agree about the Crypto policy too. But since we use Centos/EL we have to use what we are given.
Even Ubuntu uses the same OpenSSL for curl and Apache so we are considering that too.
Since nobody in my organisation has used Fedora for some time, we cannot use it in production.

Thanks again.

And of course, thank you for a great repo.

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

> By this, I understand that it is static linking

No, dynamic linking

$ ldd /usr/lib64/php/modules/curl.so
    libcurl.so.4 => /usr/lib64/libcurl.so.4 (0x00007fb3da79c000)
...
$ ldd /usr/lib64/libcurl.so.4
    libnss3.so => /usr/lib64/libnss3.so (0x0000003c66600000)
...
Laptop:  Fedora 38 + rpmfusion + remi (SCL only)
x86_64 builder: Fedora 39 + rpmfusion + remi-test
aarch64 builder: RHEL 9 with EPEL
Hosting Server: CentOS 8 Stream with EPEL, rpmfusion, remi

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

Thanks again for the super quick reply!

Dynamic linking means that I could install a curl from city-fan.org repo and hope to get php-curl to talk using more ciphers.

For the sake of completeness, this verifies what you said:

 
# ldd /opt/remi/php70/root/usr/lib64/php/modules/curl.so
        libcurl.so.4 => /usr/lib64/libcurl.so.4 (0x00007f78ab1bd000)
        libssl3.so => /usr/lib64/libssl3.so (0x00007f78a99d7000)
        libnss3.so => /usr/lib64/libnss3.so (0x00007f78a9461000)
        libnssutil3.so => /usr/lib64/libnssutil3.so (0x00007f78a9232000)
        libnspr4.so => /lib64/libnspr4.so (0x00007f78a8be9000)

# ldd /usr/bin/curl 
        libcurl.so.4 => /usr/lib64/libcurl.so.4 (0x00007f23172cb000)
        libssl3.so => /usr/lib64/libssl3.so (0x00007f231608f000)
        libnss3.so => /usr/lib64/libnss3.so (0x00007f2315b1a000)
        libnssutil3.so => /usr/lib64/libnssutil3.so (0x00007f23158ea000)
        libnspr4.so => /lib64/libnspr4.so (0x00007f23152a1000)

They use the same, which is also from the nss repo package:

# repoquery -l nss                                                                                                                                                     
/etc/pki/nss-legacy
...
/usr/lib/libnss3.so
...
/usr/lib/libssl3.so
...
/usr/lib64/libnss3.so       <----- same
...
/usr/lib64/libssl3.so       <----- same
...

I also tried to check why my curl NSS version shows 3.27.1 whereas the NSS package version in yum shows nss-3.36.0-8.el6.x86_64 and I found that version numbering is more complex than I thought:

# rpm -q --whatprovides /usr/lib64/libnss3.so
nss-3.36.0-8.el6.x86_64

# ldd -r -v /usr/lib64/libnss3.so
...
        Version information:
        /usr/lib64/libnss3.so:
                libc.so.6 (GLIBC_2.4) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.3) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.3.4) => /lib64/libc.so.6
                libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
                libnssutil3.so (NSSUTIL_3.21) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.13) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.17.1) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.33) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.12.3) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.12.5) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.31) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.24) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.14) => /usr/lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.12) => /usr/lib64/libnssutil3.so
...

The mismatch between the numbers 3.27.1 and 3.36 was confusing me - I thought I had 2 NSS versions - one in the system and one in php-curl
This is not the case.

So finally,

I am going to try both ways:
1. city-fan's curl - this might help my production stay on Centos 6 for some time while I switch to Centos 7
2. Centos 7 - eventually, of course I will need to move so earlier the better.

Thank you very much for your help.

Very much appreciated.

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

> I also tried to check why my curl NSS version shows 3.27.1 whereas the NSS package version in yum shows nss-3.36.0-8.el6.x86_64

Probably curl display version used at buildtime, which indeed may be confusing

The reason one, I usually try to make PHP extension to report both

example

$ php --ri zip
Libzip headers version => 1.5.1
Libzip library version => 1.5.1
...
Laptop:  Fedora 38 + rpmfusion + remi (SCL only)
x86_64 builder: Fedora 39 + rpmfusion + remi-test
aarch64 builder: RHEL 9 with EPEL
Hosting Server: CentOS 8 Stream with EPEL, rpmfusion, remi

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

This is just for information, for anyone else who comes looking for this specific issue:

I tested the API with Centos 7 and it seems to provide 2 more ciphers from my original list in addition to the one in Centos 6 (in my first post):

ecdhe_rsa_aes_128_gcm_sha_256 --- also works in CentOS 6
ecdhe_rsa_aes_256_gcm_sha_384
ecdhe_rsa_aes_256_sha_384

None of ecdhe_ecdsa* work
None of chacha20_poly1305* work
I did a "yum update nss" and it shows that NSS is up-to-date. (see version info below)

# openssl ciphers
ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DH-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DH-RSA-AES256-SHA256:DH-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DH-RSA-AES256-SHA:DH-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:DH-RSA-CAMELLIA256-SHA:DH-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:PSK-AES256-CBC-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DH-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DH-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DH-RSA-AES128-SHA256:DH-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DH-RSA-AES128-SHA:DH-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DH-RSA-SEED-SHA:DH-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:DH-RSA-CAMELLIA128-SHA:DH-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:PSK-AES128-CBC-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DH-RSA-DES-CBC3-SHA:DH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:IDEA-CBC-SHA:PSK-3DES-EDE-CBC-SHA:KRB5-IDEA-CBC-SHA:KRB5-DES-CBC3-SHA:KRB5-IDEA-CBC-MD5:KRB5-DES-CBC3-MD5:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:PSK-RC4-SHA:KRB5-RC4-SHA:KRB5-RC4-MD5

But curl does not use OpenSSL on CentOS, so this is actually irrelevant.

# curl -V
curl 7.29.0 (x86_64-redhat-linux-gnu) libcurl/7.29.0 NSS/3.34 zlib/1.2.7 libidn/1.28 libssh2/1.4.3
Protocols: dict file ftp ftps gopher ht tp ht tps imap imaps ldap ldaps pop3 pop3s rtsp scp sftp smtp smtps telnet tftp
Features: AsynchDNS GSS-Negotiate IDN IPv6 Largefile NTLM NTLM_WB SSL libz unix-sockets

# rpm -q --whatprovides /usr/lib64/libnss3.so
nss-3.36.0-5.el7_5.x86_64

# ldd -r -v /usr/lib64/libnss3.so
        Version information:
        /usr/lib64/libnss3.so:
                libnssutil3.so (NSSUTIL_3.12.5) => /lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.21) => /lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.12.3) => /lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.13) => /lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.17.1) => /lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.31) => /lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.24) => /lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.14) => /lib64/libnssutil3.so
                libnssutil3.so (NSSUTIL_3.12) => /lib64/libnssutil3.so

# cat /etc/redhat-release
CentOS Linux release 7.5.1804 (Core)

# uname -a
Linux ip-172-31-9-200.us-west-2.compute.internal 3.10.0-862.6.3.el7.x86_64 #1 SMP Tue Jun 26 16:32:21 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Note that in Centos 7, nss-3.36 provides NSS/3.34 as against NSS/3.27.1 in Centos 6, hence probably the 2 more ciphers.

Hope this helps someone.

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

> None of chacha20_poly1305* work

According to my tests, ecdhe_rsa_chacha20_poly1305_sha_256 is available

Laptop:  Fedora 38 + rpmfusion + remi (SCL only)
x86_64 builder: Fedora 39 + rpmfusion + remi-test
aarch64 builder: RHEL 9 with EPEL
Hosting Server: CentOS 8 Stream with EPEL, rpmfusion, remi

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

The main reason for all this effort is that the API provider has suddenly enforced this restriction and changing production servers is a challenging task due to all the other things like monitoring, config settings, tweaks and feature sets depending on specific versions.

Re: php-curl specific ciphers for TLSv1.2 (SHA384, CHACHA20-POLY1305)

Thank you very much for your help.