How to add ciphers to curl in php?

Benubird picture Benubird · Jun 5, 2015 · Viewed 13.8k times · Source

I am trying to use php curl to connect to a site, but get the error "no common encryption algorithm". Further investigation, and I think this has something to do with NSS? I've discovered that from the command line, I can reproduce the error (so the problem is definitely in curl and not with the php wrapper), but that if I set --ciphers ecdhe_ecdsa_aes_128_sha then it works:

[ec2-user@ip-10-181-165-22 current]$ curl -I https://sslspdy.com
curl: (35) Cannot communicate securely with peer: no common encryption algorithm(s).

[ec2-user@ip-10-181-165-22 current]$ curl -I --ciphers ecdhe_ecdsa_aes_128_sha https://sslspdy.com
HTTP/1.1 200 OK
Server: nginx centminmod
Content-Type: text/html; charset=utf-8
Connection: close
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000; includeSubdomains
Date: Sat, 07 Feb 1970 22:34:32 GMT
X-Page-Speed: ngx_pagespeed
Cache-Control: max-age=0, no-cache

So my questions are,

  1. Why is this happening? I have not been able to find an explanation online as to how the ssl ciphers work in curl; it seems that every page is written with the assumption that the reader is already an expert in the field - unfortunately, a sentence like "you're probably using NSS, so try switching the PKCS for FIPS" is utterly incomprehensible to me, and googling will only explain the individual components (usually by reference to 20-year old standards), and not how they relate to each other.

  2. Is there any way I can make curl tell me which ciphers it is trying and which ciphers the server will accept? I've tried looking up the server on ssllabs, but it seems to be saying the server accepts all ciphers, which it obviously doesn't.

  3. What options do I need to pass to curl_setopt so that my php script is able to connect to this server?

  4. If I set the cipher to this, will that break other sites? Is there something I can do so that curl is able to connect to all secure sites, or do I have to manually iterate over different ciphers trying each of them to find out which one works?

Answer

jww picture jww · Jun 5, 2015
  1. Why is this happening? I have not been able to find an explanation online as to how the ssl ciphers work in curl

It depends on a few things. The client and server libraries, the client and server configurations, etc. You'd need to provide more details.


  1. Is there any way I can make curl tell me which ciphers

Use the right tool for the job. In this case, its an updated sslscan.


  1. What options do I need to pass to curl_setopt so that my php script is able to connect to this server?

CURLOPT_SSL_CIPHER_LIST.


  1. If I set the cipher to this, will that break other sites?

Maybe. It depends on that particular site's configuration.

Ideally, you pick 12 or 16 cipher suites you approve of, and then you use them instead of one. The 12 or 16 covers most sites you encounter on the internet.

Here's the list I usually use. Its from Which Cipher Suites to enable for SSL Socket?:

  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
  • TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
  • TLS_DHE_RSA_WITH_AES_128_CBC_SHA
  • TLS_DHE_DSS_WITH_AES_128_CBC_SHA
  • TLS_RSA_WITH_AES_256_CBC_SHA256
  • TLS_RSA_WITH_AES_256_CBC_SHA
  • TLS_RSA_WITH_AES_128_CBC_SHA256
  • TLS_RSA_WITH_AES_128_CBC_SHA

I would like to ditch the TLS_RSA_* cipher suites because they are key transport, but I need them for those older IIS servers I encounter.

As you can see from the scan results below, this list intersects with the server's list.


Note that you don't specify, say TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384. Rather, in OpenSSL, you specify the OpenSSL's name ECDHE-ECDSA-AES256-SHA384 for the suite. You can find the OpenSSL names at the documentation for openssl ciphers.

With OpenSSL, you can also use the string "HIGH:!aNULL:!MD5:!RC4:!PSK:!SRP". That will get you about 40 or 50 that are reasonably good choices.

You can run the OpenSSL ciphers command to see what the list is:

$ openssl ciphers -v 'HIGH:!aNULL:!MD5:!RC4:!PSK:!SRP'
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
ECDHE-RSA-AES256-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA1
ECDHE-ECDSA-AES256-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA1
...

You can use an updated version of sslscan to determine what cipher suites are available:

$ sslscan --no-failed sslspdy.com
...
Testing SSL server sslspdy.com on port 443

  Supported Server Cipher(s):
    Accepted  TLSv1  256 bits  ECDHE-ECDSA-AES256-SHA
    Accepted  TLSv1  128 bits  ECDHE-ECDSA-AES128-SHA
    Accepted  TLSv1.1  256 bits  ECDHE-ECDSA-AES256-SHA
    Accepted  TLSv1.1  128 bits  ECDHE-ECDSA-AES128-SHA
    Accepted  TLSv1.2  256 bits  ECDHE-ECDSA-AES256-GCM-SHA384
    Accepted  TLSv1.2  256 bits  ECDHE-ECDSA-AES256-SHA384
    Accepted  TLSv1.2  256 bits  ECDHE-ECDSA-AES256-SHA
    Accepted  TLSv1.2  128 bits  ECDHE-ECDSA-AES128-GCM-SHA256
    Accepted  TLSv1.2  128 bits  ECDHE-ECDSA-AES128-SHA256
    Accepted  TLSv1.2  128 bits  ECDHE-ECDSA-AES128-SHA

  Prefered Server Cipher(s):
    TLSv1  128 bits  ECDHE-ECDSA-AES128-SHA
    TLSv1.1  128 bits  ECDHE-ECDSA-AES128-SHA
    TLSv1.2  128 bits  ECDHE-ECDSA-AES128-GCM-SHA256