Secure Sockets Layer

From Organic Design
(Redirected from SSL)
Jump to: navigation, search
Procedure.svg Secure Sockets Layer
Organic Design procedure

Using LetsEncrypt to create certificates

Let's Encrypt is a new system created by the Internet Security Research Group that went public on December 3rd 2015 and allows the creation of completely free SSL certificates using a utility that runs on the server hosting the SSL sites. Their own User Guide is quite self-explanatory for dealing with usual server configurations and even supports a fully automated configuration. Simply install from their Github repo and run the letsencrypt-auto script, or on Debian systems you can simply use apt.

Their system is based on a new protocol called ACME (Automated Certificate Management Environment) which the ISRG created specifically for the LetsEncrypt project.

In our situation where we have many domains and non-standard server-blocks with regular expressions for domain name matching and other complications, we prefer to use the LetsEncrypt system to just create the certificates without it attempting to modify any of our web-server configuration at all. The certonly sub-command is used for this scenario, and this sub-command can further be used with many different domain validation methods. Our preferred syntax is as follows:

letsencrypt-auto certonly --keep-until-expiring --expand --webroot -w /var/www/domains/letsencrypt -d foo.com -d bar.com -d baz.com

Here we're using the --webroot domain validation method which allows you to specify the file-system paths in which LetsEncrypt should place the validation files for your domains so that it can find the file from an external request to each domain to verify your ownership of it.

The keep-until-expiring option is only needed when running the command automatically from the crontab to make the script automatically skip any certificates that are not close to expiry. Using this option means we can run the command on a daily basis to keep the certs for as long as they last. Another option would be to use the --renew-by-default option instead and run the command on a monthly basis.

The expand option is also only needed when running the command automatically to prevent the command from requiring the user to confirm that the command replace the existing certificate and expand the number of domains it covers.

We've used just one file-system location, DOC_ROOT/letsencrypt, for all the domains (you can put more -w options into the command if different domains require a different path to their web-root). We then added a rewrite rule into our web-server configuration so that requesting http://ANY-DOMAIN/.webroot/... will request from the same common DOC_ROOT/letsencrypt file-system location no matter what domain it is. Here's our Nginx rewrite rule that all domains use:

rewrite ^/\.well-known /letsencrypt$uri last;

Note that this method does not require root privileges, the script only needs to access the DOC_ROOT/letsencrypt directory which can be set to very restricted ownership that only LetsEncrypt and the web-server can access.

To further simplify the situation we've included this rewrite rule in our nginx.php.conf file which is a file that is included within the server blocks of any domains that need PHP functionality (i.e. all of them). This way there's no need for any configuration specific to LetsEncrypt within the sever blocks themselves, and the SSL configuration (which is also a separate file included into server blocks that need it) only needs to refer to the single LetsEncrypt certificate that applies for all the domains.

Using this method the same command can be called on a monthly cronjob to keep the certificates renewed, and we can add more domains to the command any time without having to change any configuration at all :-)

Easy peezy lemon squeezy!!!

Letsencrypt-odnz.jpg
Ssllabs likes letsencrypt cert.jpg

Automating things even further

At Organic Design we use our own letsencrypt-renew.pl script that is called daily from the crontab to keep our certificates renewed. The script is passed the path to a config file in its --domains command-line parameter which contains a list of the domains and sub-domains required by the system. To add or remove domains, simply modify this configuration file and run the command. The format of the configuration file is one domain per line, with all the required sub-domains as a comma-separated list as follows:

foo.bar : @, www, wiki, private

Note: the "@" sub-domain stands for the naked domain.

Creating a self-signed certificate

First we need to ensure that we have a valid SSL certificate for each domain that will be using SSL connections. First generate a self signed certificate for each domain. Remember that this will raise the "untrusted secure site" error in the client browser, for sites that require a proper commercial certificate, use the generate a certificate request for a commercial Certificate Authority procedure instead.

Our convention is to keep all the certificates in /var/www/ssl, so first change the current directory to that and create the certificate with the following command format. Ensure the common name (cn) is entered as a wildcard such as *.foo.com so that the certificate applies to all the sub-domains such as www.foo.com or webmail.foo.com etc. This certificate format will work for both Apache and Nginx.

First we need to create a private key. Note that this process will require a pass-phrase for the key - don't worry, we'll remove it later to make things easier,

openssl genrsa -des3 -out ssl.key 2048


Now we need to create a CSR (Certificate Signing Request):

openssl req -new -key ssl.key -out ssl.csr


Now we need to remove the pass-phrase otherwise it'll prevent the web-server from restarting without it being entered (you'll need to enter the pass-phrase to remove it though),

cp ssl.key ssl-pass.key
openssl rsa -in ssl-pass.key -out ssl.key


Now we can generate the actual certificate:

openssl x509 -req -days 3650 -in ssl.csr -signkey ssl.key -out ssl.crt


Each secure domain will require virtual-host definition in a separate file in the /var/www/ssl directory and having the same file name as the domain name it applies to, and can then be referred to by the relevant host container in the web server configuration, for example for Nginx:

ssl on;
ssl_certificate /var/www/ssl/foo.crt;
ssl_certificate_key /var/www/ssl/foo.key;


If running an older version of Nginx (pre 1.1), it's a good idea to add some extra entropy to the key for use by Diffie Hellman ciphers:

openssl dhparam -rand - 2048 >> /var/www/ssl/foo.key


Check the config before restarting with apachectl -t or nginx -t, and if everything is fine, start or restart the web server from /etc/init.d as usual. After starting, follow the web server error log as you start the server and as you make SSL requests and see if problems show up.

tail -f /var/log/[apache2|nginx]/error.log

Selecting a good set of ciphers

With revelations about mass surveillance in the news everywhere, such as this article, an obscure feature of SSL/TLS called perfect forward secrecy has suddenly become a very important feature to enable.

You'll need at least OpenSSL version 1.0 and Apache version 2.3.3 (or Nginx which has supported it for quite some time now). First check that your version of OpenSSL supports elliptic curve Diffie-Hellman protocols.

openssl ciphers ECDH

If you have support for it, you'll get a long list of output like the following example, or if not you'll get an "Error in cipher list: result.

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:AECDH-AES256-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:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AECDH-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-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:AECDH-AES128-
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:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AECDH-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:ECDHE-RSA-NULL-SHA:ECDHE-ECDSA-NULL-SHA:AECDH-NULL-SHA:ECDH-
RSA-NULL-SHA:ECDH-ECDSA-NULL-SHA


You can then set the protocols in your cypher suite to an optimal list and prioritisation. You can use Qualys SSL labs test. I'm not sure if it's possible to get a combination of ciphers that satisfy everything. The best I've come up with is a value that allows perfect forward secrecy and mitigates the BEAST attack, but it allows RC4 which vulnerabilities have been found in, but haven't yet been exploited in any way. Here's a screenshot of the best result I've managed to obtain (and the best I've seen from the top results in their chart).

SSL Labs result.jpg

The cipher suite used to obtain this result is the set recommended by SSLlabs and is as follows. It's put in the SSLCipherSuite setting in /etc/apache2/mods-available/ssl.conf, or in the ssl_ciphers value in the site's SSL server container of the Nginx configuration. Our Nginx configuration is as follows:

ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EDH+aRSA:EECDH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
ssl_prefer_server_ciphers on;


It's a good idea to also change the default logging format so that you can see what cipher clients are connecting with - especially to ensure that your own browser is using a ECDHE cipher.

log_format organicdesign '$remote_addr - [$time_local] '
                         '"$request" $status $body_bytes_sent '
                         '"$http_referer" "$http_user_agent" $ssl_cipher';
access_log /var/log/nginx/access.log organicdesign;

Mozilla has a good page on cipher sets for different levels of security versus backward compatibility here.

Strong Diffie-Hellman parameters

SSL labs was giving a This server supports weak Diffie-Hellman (DH) key exchange parameters. Grade capped to B warning. To get round this you can make a 2048 bit param file as follows:

openssl dhparam -out /var/www/ssl/dhparams.pem 2048

And then refer to that file from the web-server configuration:

ssl_dhparam /var/www/ssl/dhparams.pem;

Other SSL certificates in our system

We also run a number of other SSL certificates in the system which may need rebuilding from time to time. See the appropriate procedure for each one for the details on building the certificates.

Critical bug named "Heartbleed" found in OpenSSL

On April 7, 2014, it was announced that all versions of OpenSSL in the 1.0.1 series up to and including 1.0.1f had a severe memory handling error in their implementation of the TLS Heartbeat Extension. This error could be used to reveal up to 64 kilobytes of the application's memory. The vulnerability had existed since December 31, 2011, and had been adopted to widespread use since the release of the OpenSSL version 1.0.1 on March 14, 2012. By reading the memory of the SSL server, attackers could access sensitive data, compromising the security of the server and its users. Potentially vulnerable secure data include the server's private master key, which enables attackers to break the encryption of the server's earlier eavesdropped communications and impersonate as the server. The vulnerability might also reveal unencrypted parts of other user's sensitive requests and responses, including session cookies and passwords, which might allow attackers to hijack the identity of another user of the service. At its disclosure, some 17% or half a million of the Internet's secure web servers certified by trusted authorities were believed to have been vulnerable to the attack. [more...].

The warning about the bug in OpenSSL coincided with the release of version 1.0.1g of the open-source program, which is the default cryptographic library used in the Apache and nginx Web server applications, as well as a wide variety of operating systems and e-mail and instant-messaging clients. The bug, which has resided in production versions of OpenSSL for more than two years, could make it possible for people to recover the private encryption key at the heart of the digital certificates used to authenticate Internet servers and to encrypt data traveling between them and end users. Attacks leave no traces in server logs, so there's no way of knowing if the bug has been actively exploited. Still, the risk is extraordinary, given the ability to disclose keys, passwords, and other credentials that could be used in future compromises. [more...] [Debian patch info...]

Critical vulnerability named "Poodle" renders SSL v3.0 useless

After more than a week of persistent rumours, yesterday (Oct 14) we finally learned about the new SSL 3 vulnerability everyone was afraid of. The so-called POODLE attack is a problem in the CBC encryption scheme as implemented in the SSL 3 protocol. (Other protocols are not vulnerable because this area had been strengthened in TLS 1.0.) Conceptually, the vulnerability is very similar to the 2011 BEAST exploit. In order to successfully exploit POODLE the attacker must be able to inject malicious JavaScript into the victim's browser and also be able to observe and manipulate encrypted network traffic on the wire. As far as MITM attacks go, this one is complicated, but easier to execute than BEAST because it doesn't require any special browser plugins. If you care to learn the details, you can find them in the short paper or in Adam Langley's blog post.

See also