- 2018/05/05

I was usually copy ssl_ciphers values from somewhere on Internet and paste it on my Nginx config when deploying SSL certificate. After some experiment with those ssl_ciphers, now I note it based on certificate type, TLS version, and make sure every cipher is explicitly defined (handpicked, not just blindly using group and not knowing what’s inside).

RSA Certificate

Most common certificate type, all CA provide RSA certificate, with recommended size 2048-bit to 4096-bit.

TLSv1.2 ONLY
### /etc/nginx/snippets/tls12-rsa.conf
ssl                         on;
ssl_protocols               TLSv1.2;
ssl_ciphers                 ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256;
ssl_ecdh_curve              prime256v1;
ssl_prefer_server_ciphers   on;
ssl_buffer_size             4k;
ssl_session_timeout         1h;
ssl_session_cache           shared:SSL:64m;
ssl_session_tickets         off;

Nginx >=1.13 build with OpenSSL 1.1.0:

ssl_ciphers                 ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256;
ssl_ecdh_curve              X25519:prime256v1;

AES128 ciphers only:

ssl_ciphers                 ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256;

TLSv1.2, TLSv1.1, TLSv1.0

### /etc/nginx/snippets/tlsall-rsa.conf
ssl                         on;
ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers                 ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
ssl_dhparam                 /etc/ssl/dhparam.pem; # openssl dhparam -dsaparam -out /etc/ssl/dhparam.pem 4096
ssl_ecdh_curve              prime256v1;
ssl_prefer_server_ciphers   on;
ssl_buffer_size             4k;
ssl_session_timeout         1h;
ssl_session_cache           shared:SSL:64m;
ssl_session_tickets         off;

Nginx >=1.13 build with OpenSSL 1.1.0:

ssl_ciphers                 ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA;
ssl_ecdh_curve              X25519:prime256v1;

AES128 ciphers only:

ssl_ciphers                 ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA;

ECC Certificate

Newer certificate type, not all CA provide ECC certificate, and only have compatilibity with modern client. ECC key have same strength with larger RSA key. For example, 256-bit ECC key equivalent to 3072-bit RSA key, and 384-bit ECC key equivalent to 7680-bit RSA key.

TLSv1.2 ONLY

### /etc/nginx/snippets/tls12-ecc.conf
ssl                         on;
ssl_protocols               TLSv1.2;
ssl_ciphers                 ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256;
ssl_ecdh_curve              prime256v1;
ssl_prefer_server_ciphers   on;
ssl_buffer_size             4k;
ssl_session_timeout         1h;
ssl_session_cache           shared:SSL:64m;
ssl_session_tickets         off;

Nginx >=1.13 build with OpenSSL 1.1.0:

ssl_ciphers                 ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256;
ssl_ecdh_curve              X25519:prime256v1;

AES128 ciphers only:

ssl_ciphers                 ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256;

TLSv1.2, TLSv1.1, TLSv1.0

### /etc/nginx/snippets/tlsall-ecc.conf
ssl                         on;
ssl_protocols               TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers                ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:DHE-ECDSA-AES256-SHA:DHE-ECDSA-AES128-SHA;
ssl_dhparam                 /etc/ssl/dhparam.pem; # openssl dhparam -dsaparam -out /etc/ssl/dhparam.pem 4096
ssl_ecdh_curve              prime256v1;
ssl_prefer_server_ciphers   on;
ssl_buffer_size             4k;
ssl_session_timeout         1h;
ssl_session_cache           shared:SSL:64m;
ssl_session_tickets         off;

Nginx >=1.13 build with OpenSSL 1.1.0:

ssl_ciphers                 ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:DHE-ECDSA-AES256-SHA:DHE-ECDSA-AES128-SHA;
ssl_ecdh_curve              X25519:prime256v1;

AES128 ciphers only:

ssl_ciphers                 ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:DHE-ECDSA-AES128-SHA;

Dual Certificate

If you have ECC and RSA certificate, on Nginx >= 1.13 you can use dual setup for ssl, for example:

### /etc/nginx/snippets/tlsall-dual.conf
ssl                         on;
ssl_protocols               TLSv1.2;
ssl_ciphers                 ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

For certificate path, use it as following:

### /etc/nginx/snippets/yourdomain.com.cert.conf
# ECDSA
ssl_certificate             /etc/ssl/acme/yourdomain.com.ec256.full.pem;
ssl_certificate_key         /etc/ssl/acme/yourdomain.com.ec256.key.pem;
# RSA
ssl_certificate             /etc/ssl/acme/yourdomain.com.rsa2048.full.pem;
ssl_certificate_key         /etc/ssl/acme/yourdomain.com.rsa2048.key.pem;
# TRUSTED CA FOR OCSP
ssl_trusted_certificate     /etc/ssl/acme/yourdomain.com.trusted_ca.pem;
# OCSP
ssl_stapling                on;
ssl_stapling_verify         on;
resolver                    1.1.1.1 1.0.0.1 valid=300s;
resolver_timeout            5s;

Testing

When we are done with SSL/TLS setup, we can test using following service/tools:

To get info about cipher we use, we can use openssl ciphers -V [CIPHER], for example:

# by group
$ openssl ciphers -V CHACHA20
0xCC,0xA9 - ECDHE-ECDSA-CHACHA20-POLY1305   TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
0xCC,0xA8 - ECDHE-RSA-CHACHA20-POLY1305     TLSv1.2 Kx=ECDH     Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
0xCC,0xAA - DHE-RSA-CHACHA20-POLY1305       TLSv1.2 Kx=DH       Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
0xCC,0xAE - RSA-PSK-CHACHA20-POLY1305       TLSv1.2 Kx=RSAPSK   Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
0xCC,0xAD - DHE-PSK-CHACHA20-POLY1305       TLSv1.2 Kx=DHEPSK   Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD
0xCC,0xAC - ECDHE-PSK-CHACHA20-POLY1305     TLSv1.2 Kx=ECDHEPSK Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD
0xCC,0xAB - PSK-CHACHA20-POLY1305           TLSv1.2 Kx=PSK      Au=PSK  Enc=CHACHA20/POLY1305(256) Mac=AEAD

# by name/namelist
$ openssl ciphers -V ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256
0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256   TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
0xC0,0x23 - ECDHE-ECDSA-AES128-SHA256       TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)   Mac=SHA256

Conclusion

Choosing what SSL ciphers we want to use, here is some of consideration:

  • Security

    Encryption using AES256(/GCM) or AES128(/GCM) is sufficient, or maybe CHACHA20/POLY1305. Cipher ordering is important.

  • Compatibility

    TLSv1.2 for modern client only, or need to support all TLS version and wider compatibility including old android, Java and IE.

For infrastructure perspective, TLS for data transit is only one of many aspect for our application security. We may need Web Application Firewall if we require more strict security. It’s all depends on what is your requirements.