Creating certificates with openssl
This is a tutorial on the steps for creating a certificate using openssl
. It
is based on my learnings of all the components and steps involved. I know there
are more concise ways of generating the needed keys and certs (see section
Quick version below), but I was interested in a comprehensive full system
on creating a certificate usable by a internet server.
Create a certificate authority key and cert
I will start this guide by going through the steps of making a certificate authority (CA) to issue the certs. For the purposes of this tutorial, we are going to assume we are creating a certificate authority for a fake company called "Zebes"
Step 1: Create private key
First generate a private key using the genrsa
subcommand of openssl.
$ openssl genrsa -aes256 -out ca-zebes.key 2048
This will generate a new key and prompt for a pass phrase (need to enter it twice):
Generating RSA private key, 2048 bit long modulus (2 primes)
..........+++++
........................+++++
e is 65537 (0x010001)
Enter pass phrase for ca-zebes.key:
Verifying - Enter pass phrase for ca-zebes.key:
This will write your private key into a file called ca-zebes.key
Step 2: Create CA certificate
Now create a certificate for the CA using the private key you just generated.
Use the req
subcommand of openssl
openssl req -new -x509 -key ca-zebes.key -sha256 -days 365 -out ca-zebes.cert.pem
This will prompt you for the pass phrase for the private key file you are referencing.
Enter pass phrase for ca-zebes.key:
Then it will prompt you for the fields that will be added into the distinguised name (DN). You can enter with the values that are most appropriate for your use case.
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]: /US
State or Province Name (full name) [Some-State]: /Florida
Locality Name (eg, city) []:Orlando
Organization Name (eg, company) [Internet Widgits Pty Ltd]: /Zebes Inc
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:ZebesCA
Email Address []:user@zebes.cc
Now you could theoretically install that certificate as a trusted CA on devices that with which you intend to use certificates issued from that CA.
The point of a certificate authority is to issue signed PKI certificates, which we will do next.
Make a new PKI certificate
Now we will make a certificate for use on a TLS server. In our example, we will
use the example domain brinstar.net and alternate brinstar.lvh.me (this makes
it easy to test because *.lvh.me
points to 127.0.0.1).
Step 1: Generate a new private key
openssl genrsa -aes256 -out brinstar.key 2048
Again, this will ask you to enter and confirm a pass phrase for this key.
It is sometimes undesirable to have a server key with a passphrase on an apache server for example, because the pass phrase will need to be entered every time you restart the server, so if you want to recreate a key without a pass phrase, then run this command to generate a new key from your first key:
openssl rsa -in brinstar.key -out brinstar.nodes.key
Note that nodes
means "no DES" which will not protect the key with a pass phrase and will not encrypt it in the file.
Step 2: Prepare config file
If you will need to create a subjectAlternativeName (SAN) section for your
cert, to specify multiple DNS entries, create a config file similar to the
following and save it to a file called server.cfg
:
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (eg, city)
organizationName = Organization Name (eg, company)
commonName = Common Name (e.g. server FQDN or YOUR name)
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = brinstar.net
DNS.2 = www.brinstar.net
DNS.3 = brinstar.lvh.me
In the section alt_names
include any number of DNS entries to provide more
domains for which this certificate is to be used.
Step 3: Generate a certificate signing request
openssl req -new -key brinstar.nodes.key -config server.cfg -out brinstar.csr
This outputs a CSR file which is a certificate signing request: A request for a certificate to be signed by the CA (certificate authority). It will prompt you for some DN information.
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]: /US
State or Province Name (full name) [Some-State]: /Florida
Locality Name (eg, city) []:Orlando
Organization Name (eg, company) [Internet Widgits Pty Ltd]: /Brinstar Inc
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:brinstar.net
Email Address []:user@brinstar.cc
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Alternative step 3:
Another option for generating the CSR using the config to include all the
values to embed within the certificate without the prompts. Create a file
server.cfg
with the following contents:
FQDN = brinstar.net
COUNTRY = US
STATE = Florida
CITY = Orlando
ORGANIZATION = Brinstar, Inc
EMAIL = user@zebes.cc
[ req ]
default_bits = 2048
distinguished_name = req_dn
prompt = no
req_extensions = req_ext
[ req_dn ]
C = $COUNTRY
ST = $STATE
L = $CITY
O = $ORGANIZATION
CN = $FQDN
emailAddress = $EMAIL
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1 = brinstar.net
DNS.2 = www.brinstar.net
DNS.3 = brinstar.lvh.me
In this file you can include all the details that you would have been prompted
to enter automatically, instead of being prompted. (Notice the prompt = no
line in the file).
openssl req -new -key brinstar.nodes.key -config server.cfg -out brinstar.csr
Step 4: Verify CSR information
To verify the information is correctly embedded within the CSR file, run the following command and look for the section about Subject Alternative Name
openssl req -in brinstar.csr -text -noout | less -FX
Step 5. Make a certificate extension config file
If you have alternate subjects (multiple domains to support), you need to create an extension file, this will be used to configure the cert with the correct details.
Create a new file, called server.ext.cfg
and put the following into it
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
subjectAltName=@alt_names
[ alt_names ]
DNS.1=www.brinstar.net
DNS.2=brinstar.net
DNS.3=brinstar.lvh.me
Step 6. Create the x509 certificate
Now you are ready to use the CA, the private key and the extension config file
to generate the server's certificate using the openssl subcommand x509
:
openssl x509 -req -in brinstar.csr -CA ca-zebes.cert.pem -CAkey ca-zebes.key -CAcreateserial -extfile server.ext.cfg -out brinstar.cert.pem
This will output the new signed certificate into the file brinstar.cert.pem
.
Quick version
You can skip the Certificate Authority and the separate commands and create a self-signed cert really quickly with one command if it suits your needs.
This will create a new private key and certificate file with the settings from server.cfg and note the SAN options are specified in the -addext
parameter.
openssl req -x509 -newkey rsa:4096 -nodes\
-days 365\
-config server.cfg\
-addext "subjectAltName=DNS:brinstar.net,DNS:www.brinstar.net,DNS:brinstar.lvh.me"
-keyout "certs/brinstar.key.pem"\
-out "certs/brinstar.cert.pem"\
Attach cert/key to server config
For Nginx you will use something like this in your configuration to utilize the cert and key for the website.
server {
listen 443 ssl;
server_name brinstar.net;
ssl_certificate brinstar.cert.pem;
ssl_certificate_key brinstar.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
...
}
See The Nginx documentation for more information.
For Apache web server, you will use something like this:
LoadModule ssl_module modules/mod_ssl.so
Listen 443
<VirtualHost *:443>
ServerName brinstar.net
SSLEngine on
SSLCertificateFile "/path/to/brinstar.cert.pem"
SSLCertificateKeyFile "/path/to/brinstar.key"
</VirtualHost>