Create self-signed X.509 SSL/TLS certificates with the "subjectAltName" extension.
The security of the web's Public Key Infrastructure is being heavily criticised. Some even claim that OpenSSH is written by monkeys. But until something better comes along you'll just have to swallow it and pay money to the big boys to be protected.
In any case, it's better to have a self-signed certificate than no certificate at all. Once your browser has a legit copy of the self-signed certificate, you can securely access the website over an encrypted TLS connection. With governments controlling root certificate authorities, it can be argued that a securely distributed self-signed certificate is more secure than a paid certificate. At a mininum, a self-signed certificate successfully avoids sending passwords in clear text.
The standard tool to create certificates is the openssl
command line utility. First, you need a public/private keypair, which you can create with openssl genpkey
or openssl genrsa
. Then, you use this key to create a certificate request with openssl req
. Finally, you sign the request with either openssl x509
or openssl ca
. As you can see, there isn't one single way to create a certificate with openssl. More information about these commands can be found in their respective man pages: man genpkey
, man req
, man x509
, etc.
Fortunately, openssl offers a possibility to do all the previous steps at once. I found this out by carefully reading the man pages, because the information on the internet about generating certificates is generally contradictory, outdated and sometimes even dangerous. To create a private key and a self-signed certificate at once, issue the following command:
openssl req -x509 -new -nodes -keyout myserver.key -out myserver.crt
This command will ask you to input a few things like an "Organization Name" and most importantly a "Common Name", where you should enter the domain name of the website this certificate will be used for. You can safely leave the other fields empty, because client software never checks them anyway. You can inspect the resulting certificate with the command openssl x509 -in myserver.crt -noout -text
.
The certificate that is generated by the above command has a major downside for use in a typical webserver configuration: It is only valid for a single domain name (the name you supply when asked for the Common Name).
However, the typical webserver setup serves at least two domain names. The first name, for instance www.example.com
, simply redirects all traffic to example.com
. Requests for the second name, example.com
, are then answered with actual web pages. It's important to have one canonical domain name, because otherwise the Google might (rightfully) accuse you of hosting the same content on multiple domain names. In nginx, this behavior can be implemented with two separate server
directives. Here is an example:
server {
server_name www.example.com;
listen 80;
listen 443 ssl;
ssl_certificate myserver.crt;
ssl_certificate_key myserver.key;
return 301 $scheme://example.com$request_uri;
}
server {
server_name example.com;
listen 80;
listen 443 ssl;
ssl_certificate myserver.crt;
ssl_certificate_key myserver.key;
location / {
root /var/www/;
}
}
This setup will redirect all traffic for www.example.com
to example.com
.
There is a problem however is that the certificate myserver.crt
can only contain one domain name in the Common Name field. When that name is example.com
, the first server
block wil serve an invalid certificate. When that name is www.example.com
, the second server
block will serve an invalid certificate. To solve this, you will have to generate two separate certificates, one with www.example.com
as the Common Name, and one with example.com
as the Common Name.
SubjectAltName to the rescue! The SubjectAltName extension has been standardized in 2002 by RFC 3280. The extensions allows for multiple DNS domain names to be included in a certificate. By defining both example.com
and www.example.com
as the alternative names, you can use the same certificate for both domains. Creating a certificate with the subjectAltName extension is a little tricky, and the many tutorials on the internet all instruct you to edit the openssl.cnf file manually for each certificate that you create.
This is, finally, where Certify comes into play! It's a dead-simple command-line utility to create self-signed certificates for multiple domains without touching any config files. You use it as follows:
./certify example.com [www.example.com] [mail.example.com] [...]
Simply pass the alle the domain names as arguments to the certify
command. After answering the few questions that openssl asks you, you will find a self-signed certificate and the accompanying private key in the current directory. The certificate will be valid for 10 years and uses 2048 bit encryption. Both these values can easily be changed in the source code of the certify
script.
You can also use Certify to create wildcard certificates. By default, the certify
command uses the first argument to determine the file name for the new certificate, so you will have to pass the wildcard as the second (or higher) argument. Here is an example that generates a wildcard certificate:
./certify example.com *.example.com'
You can use the resulting certificate on example.com and on any subdomain of example.com.
Everything in this repository is freely available under a version of the GPL of your choosing.