How should I proceed with upgrading to TLS 1.2?

AllisonC picture AllisonC · Sep 9, 2015 · Viewed 10.4k times · Source

EDIT: We have gotten a new server with updated openssl and are all set, so I'm voting to close this question.

We got this email from Authorize.NET about some technical updates. I am trying to figure out what needs to be done, but my skills are lacking in this area and I could use some help. They had four main points in their email:

  1. After the update is complete on September 21st, any website or payment solution that connects via api.authorize.net that cannot validate SHA-2 signed certificates will fail to connect to Authorize.Net's servers.

    Our server uses SHA-1, but we have a GoDaddy Certificate Installed that uses SHA-2.

  2. In October of this year, due to system updates, it will be possible to receive Authorize.Net IDs (Transaction ID, Batch ID, etc.) that are not in sequential order.

    I don't think this one will affect us.

  3. As you may already be aware, new PCI DSS requirements state that all payment systems must disable TLS 1.0 by June 30, 2016. To ensure that we are compliant ahead of that date, we will be disabling TLS 1.0 first in the sandbox environment and then in our production environments. Both dates are still to be determined, but please make sure your solutions are prepared for this change as soon as possible.

I know we will need to upgrade OpenSSL on our server. This is what we currently have...

Current     Version          Recommended       Depends On
TLS         1.0              1.2    
OpenSSL     0.9.8h           1.0.1  
PHP         5.2.6            5.6               Open SSL 1.0.1
Apache      2.2.10           2.4    
Linux OS    SUSE Enterprise  SUSE Enterprise 
             Server 11        Server 12 
Drupal      6.9              7.39              Mysql 5.0.15/PHP 5.4
MySQL       5.0.67           5.6               SUSE Enterprise Server 12 (x86_64)
phpMyAdmin  3.3.3            4.4.14.1          PHP 5.3.7/MySQL 5.5

Answer

jww picture jww · Sep 16, 2015

How should I proceed with upgrading to TLS 1.2?

To meet the technical requirements, its sufficient to use either OpenSSL 1.0.1 or 1.0.2. Both provide TLS 1.2, and both trivially provide SHA-256. (There are other hidden fulfillments, like OpenSSL 1.0.0 does not provide the full compliment of EC gear and the full compliment of TLS 1.2 cipher suites, but 1.0.1 and 1.0.2 does).

In your C-Code that uses OpenSSL, all you need to do for the SSL Context or Session:

/* Useless return value ??? */
SSL_library_init();

const SSL_METHOD* method = SSLv23_method();
if(NULL == method) handleFailure();

SSL_CTX* ctx = SSL_CTX_new(method);
if(ctx == NULL) handleFailure();

/* Cannot fail ??? */
const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | \
    SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_COMPRESSION;
SSL_CTX_set_options(ctx, flags);

For Apache-like server configurations, use something like the following (mine includes +TLSv1 +TLSv1.1):

# From my CentOS production server
SSLProtocol -all +TLSv1.2

You should probably tend to cipher suites, too. For that, in C-code:

const char CIHPHER_LIST[] = "HIGH:!aNULL:!RC4:!MD5"

/* Ensure at least one cipher suite is added, which indicates non-failure */
int rc = SSL_CTX_set_cipher_list(ctx, CIHPHER_LIST);
if(!(rc >= 1)) handleFailure();

And in an Apache-like configuration file:

# From my CentOS production server
SSLCipherSuite HIGH:!aNULL:!MD5:!RC4

If you want to avoid RSA key transport (TLS 1.3 is removing it), then:

SSLCipherSuite HIGH:!aNULL:!MD5:!RC4:!kRSA

When you remove RSA key transport, you are pretty much left with ephemeral key exchange protocols (modulo cipher suites like PSK and SRP).

If you want to explicitly use ephemeral key exchanges, then you will need something like kEECDH:kECDHE:kDHE:kEDH:!aNULL. See openssl ciphers(1) man page for more details.

I'm reading between the lines, but the TLS 1.2 requirement probably has something to do with authenticated encryption, and modes of operation like GCM. For that, use openssl ciphers(1) again:

$ openssl ciphers -v 'HIGH:!aNULL' | grep GCM
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
DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDH-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(256) Mac=AEAD
ECDH-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(256) Mac=AEAD
AES256-GCM-SHA384       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
DHE-DSS-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(128) Mac=AEAD
ECDH-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/RSA Au=ECDH Enc=AESGCM(128) Mac=AEAD
ECDH-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH/ECDSA Au=ECDH Enc=AESGCM(128) Mac=AEAD
AES128-GCM-SHA256       TLSv1.2 Kx=RSA      Au=RSA  Enc=AESGCM(128) Mac=AEAD

Or:

$ openssl ciphers -v 'HIGH:!aNULL' | grep GCM | grep -v "Kx=RSA"  | cut -d " " -f 1
ECDHE-RSA-AES256-GCM-SHA384
ECDHE-ECDSA-AES256-GCM-SHA384
DHE-DSS-AES256-GCM-SHA384
DHE-RSA-AES256-GCM-SHA384
ECDH-RSA-AES256-GCM-SHA384
ECDH-ECDSA-AES256-GCM-SHA384
ECDHE-RSA-AES128-GCM-SHA256
ECDHE-ECDSA-AES128-GCM-SHA256
DHE-DSS-AES128-GCM-SHA256
DHE-RSA-AES128-GCM-SHA256
ECDH-RSA-AES128-GCM-SHA256
ECDH-ECDSA-AES128-GCM-SHA256

Instead of specifying HIGH:!aNULL:!MD5:!RC4:!kRSA, you can do the following:

const char CIPHER_LIST[] =
    "ECDHE-RSA-AES256-GCM-SHA384:"
    "ECDHE-ECDSA-AES256-GCM-SHA384:"
    "DHE-DSS-AES256-GCM-SHA384:"
    "DHE-RSA-AES256-GCM-SHA384:"
    "ECDH-RSA-AES256-GCM-SHA384:"
    "ECDH-ECDSA-AES256-GCM-SHA384:"
    "ECDHE-RSA-AES128-GCM-SHA256:"
    "ECDHE-ECDSA-AES128-GCM-SHA256:"
    "DHE-DSS-AES128-GCM-SHA256:"
    "DHE-RSA-AES128-GCM-SHA256:"
    "ECDH-RSA-AES128-GCM-SHA256:"
    "ECDH-ECDSA-AES128-GCM-SHA256:"

/* Ensure at least one cipher suite is added, which indicates non-failure */
int rc = SSL_CTX_set_cipher_list(ctx, CIPHER_LIST);
if(!(rc >= 1)) handleFailure();

If you look at the AES256-GCM-SHA384 cipher suite, you'll see uses key transport (Kx=RSA), so you may want to avoid it even though its TLS 1.2. Hece the reason for the grep -v on it.

For completeness, Au=RSA is fine. It just means the server uses its RSA key for signing only. And in practice, Au=DSS is rarely used, so OpenSSL will remove the cipher suite if there's no DSS key.


Now, the hardship is probably getting a distro that provides the latest OpenSSL 1.0.2 and provides the long term support. My CentOS machines don't provide it, so I have to build it from sources, and then rebuild every library or program that depends upon OpenSSL while playing those stupid r-path games.

In your case, that looks like Apache, PHP, Drupal, MySQL, phpAdmin (does anyone really use that when security is a concern :) and friends.