This project contains a set of helper scripts for maintaining a Certificate Authority (CA).
- OpenSSL v1.1.1+
Most of the configuration values in openssl.cnf
are ok as defaults. However,
you may want to change some values, such as the defaults under the
req_distinguished_name
section.
To create a self-signed CA, we need to first create a certificate signing
request (CSR). Here, we will create a CSR and a private ECDSA key with the
openssl req
command.
$ openssl req -config config/openssl.cnf \
> -newkey ec:config/ecparams -nodes -keyout private/cakey.pem \
> -out private/ca.csr
You can inspect the contents of the request using the following command,
$ openssl req -in private/ca.csr -noout -text
Once the CSR is created, we sign it with the openssl ca
command. We pass in
-extensions v3_ca
to force it to add the extensions required to generate a CA
certificate.
$ openssl ca -config config/openssl.cnf -selfsign -extensions v3_ca \
> -enddate 99991231235959Z -create_serial -in private/ca.csr -out cacert.pem
Say yes
to all prompts that proceed. The -enddate 99991231235959Z
option is
a value specified in RFC 5280 for generating a certificate that never expires.
It is not advised that you do this, but we'll let it pass for a CA.
You can inspect the details of the certificate with the following command,
$ openssl x509 -in cacert.pem -noout -text
As with every certificate, you need to create a private key and generate a
certificate signing request for the CA to sign. Servers also require a
subjectAltName
extension for specifying its fully-qualified domain name
(FQDN). Without out, browsers will refuse to accept the server certificate. On
newer versions of OpenSSL, you can do this with the -addext
option when
constructing the CSR.
$ openssl req -config config/openssl.cnf \
> -newkey ec:config/ecparams -nodes -keyout private/server-example.key \
> -out private/server-example.csr \
> -addext 'subjectAltName=DNS:example.com'
$ openssl ca -config config/openssl.cnf -extensions server_cert \
> -in private/server-example.csr -out certs/server-example.pem
For older OpenSSL versions, you have to construct a configuration file
containing the subjectAltName
.
Create a file, req.cnf
, containing the following contents.
[ req ]
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[ req_distinguished_name ]
C = US
ST = Texas
L = Dallas
O = AldeCorp
CN = example.com
[ req_ext ]
subjectAltName = DNS:example.com
Then create the private key and CSR.
$ openssl req -config req.cnf \
> -newkey ec:config/ecparams -nodes -keyout private/server-example.key \
> -out private/server-example.csr
Client certificates can be created in a similar fashion, except we do not have
to give them a subjectAltName
and we pass in client_cert
instead of
server_cert
. In most case, the common name (CN) attribute will define the
user's username.
$ openssl req -config config/openssl.cnf \
> -newkey ec:config/ecparams -nodes -keyout private/client-username.key \
> -out private/client-username.csr
$ openssl ca -config/openssl.cnf -extensions client_cert \
> -in private/client-username.csr -out certs/client-username.pem
The openssl verify
command allows us to verify if our certificates are valid.
$ openssl verify -CAfile ./cacert.pem certs/server-example.pem certs/client-username.pem
certs/server-example.pem: OK
certs/client-username.pem: OK
To go one step further, you can verify if a certificate is valid as a client or as a server.
$ openssl verify -CAfile ./cacert.pem -purpose sslserver certs/server-example.pem
certs/server-example.pem: OK
$ openssl verify -CAfile ./cacert.pem -purpose sslclient certs/client-username.pem
certs/server-example.pem: OK
If you wish to go even one step further, you can experiment with the s_server
and s_client
commands in OpenSSL to run an actual server/client with the
certificates.