The other day, I was trying to generate a self-signed ECC certificate for a web server. This turned out to be trickier than I thought.
First of all, almost all guides use RSA, while I was trying to use Elliptic Curve cryptography (“ECC”). ECC is considered better than RSA because it offers comparable security with much smaller key sizes, resulting in faster computations.
Secondly, it turns out that instead of self-signing the certificate, I needed to generate a Certificate Authority (“CA”) certificate, and sign the server certificate with the CA’s private key. This is necessary to be able to use the certificate in Firefox (more information about this). Besides, it also makes it easier to generate more certificates later on because as long as the CA is trusted, all certificates signed by the CA are trusted.
Lastly, I wanted to be able to automate the entire process, so none of the commands should ask for user input.
First, let’s pick a curve. For a list of supported curves by OpenSSL, run the following command:
openssl ecparam -list_curves
I am going to be using secp384r1
as it has great support.
Certificate authority
Generate a private key:
openssl ecparam -out ca.key -name secp384r1 -genkey
Create a Certificate Signing Request, with “Example CA” as the Common Name (“CN”):
openssl req -new -key ca.key -out ca.csr -addext "basicConstraints=CA:TRUE" -subj "/CN=Example CA"
Generate the CA certificate:
openssl x509 -req -days 36500 -in ca.csr -signkey ca.key -out ca.crt -copy_extensions copy
To change the expiration of the CA, change the -days 36500
parameter.
The CA is now ready to go. You can add the ca.crt
file to the trusted authority store of your operating system/browser.
Server certificate
Generate a private key:
openssl ecparam -out server.key -name secp384r1 -genkey
Create a Certificate Signing Request:
openssl req -new -key server.key -out server.csr \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,DNS:\*.localhost,IP:127.0.0.1"
The CN can be anything. This certificate will be valid for localhost
, *.localhost
, and 127.0.0.1
.
Generate the server certificate signed with the CA’s private key:
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -out server.crt -days 36500 -copy_extensions copy
Your server certificate is now ready to go. Your server will need the server.crt
and the server.key
files.
You can inspect certificates using the following command:
openssl x509 -in ca.crt -text -noout
Trusting the CA
Debian-based systems:
cp ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates
Windows: Double-click the certificate file -> Install Certificate… -> Next -> Place all certificates in the following store -> Browse… -> Trusted Root Certification Authorities -> OK -> Next -> Finish
Firefox: Settings -> Privacy & Security -> View Certificates… -> Authorities -> Import…
I really don’t need a CA
Here is how you generate a self-signed certificate:
Generate a private key:
openssl ecparam -out server.key -name secp384r1 -genkey
Create a Certificate Signing Request:
openssl req -new -key server.key -out server.csr \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,DNS:\*.localhost,IP:127.0.0.1"
Generate certificate signed with the private key:
openssl x509 -req -days 36500 -in server.csr -signkey server.key -out server.crt -copy_extensions copy