Creating certificates for TLS testing
In some cases, it is needed to create your chain of certificates - CA and server (for example TLS testing). There are many descriptions out there on how to do it, nevertheless, I couldn’t find any copy-paste examples which would give me an RSA, ECDSA and EdDSA certificates. Hence, here below, one can find some instructions on how to use openssl
to quickly create your certs which, then can then be used during TLS verification.
This post doesn’t explain meaning of configuration used. If such explenation is needed I would suggest reading “Network Security with OpenSSL: Cryptography for Secure Communications”, by J. Viega or looking for required information at this blog.
Configuration file
OpenSSL uses configuration file in order to store information required during certificate creation. Configuraiton file contains things like organization name, address, location, internet address, default hash algorithm used to produce signatures, etc.
Name of both - my example CA and an organization for which server certificate will be created - is called “Cert Testing Organization” with an address www.cert_testing.com
.
Here below configuration file used in this example. Copy & paste it to file openssl.cnf
:
[ ca ]
# `man ca`
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = .
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand
# The root key and root certificate.
private_key = $dir/root.key
certificate = $dir/root.pem
# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/intermediate.crl.pem
crl_extensions = crl_ext
default_crl_days = 30
# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 9999
preserve = no
policy = policy_loose
[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the `req` tool (`man req`).
default_bits = 4096
distinguished_name = req_distinguished_name
string_mask = utf8only
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name (full name)
localityName = Locality Name (eg, city)
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name
stateOrProvinceName_default = PACA
countryName_default = FR
localityName_default = Cagnes sur Mer
organizationalUnitName_default = Cert Testing Organization
commonName_default = Cert Testing Organization
commonName_max = 64
[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ usr_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = 'Cert Testing Intermediate - Client'
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ server_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = server
nsComment = 'Cert Testing Intermediate - Server'
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[ client_cert ]
# Extensions for server certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = 'Cert Testing EE - Client'
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection
[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier = keyid:always
[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning
[alt_names]
DNS.1 = *.cert_testing.com
IP.1 = 127.0.0.1
Preparation
We will need some directories where output of cert generation will be stored:
mkdir -p private
mkdir -p certs
mkdir -p csr
CA cert creation
CA private key
First step is to create private key of CA cert. Root cert will use RSA keypair with key length of 4096 bits.
OpenSSL will ask for pasword - provide
test123
.
openssl genrsa -aes256 -out private/ca.key 4096
or in case of ECDSA certificates:
openssl ecparam -name prime256v1 -genkey -noout -out private/ca.key
openssl ec -in private/ca.key -out private/ca.key -aes256
Here second line (encrypting ca.key) is needed only for rest of the article to be copy-paste'able.
Create CA cert
This command will use a key created above and create self-signed CA certificate. Certificate will be valid for 9999 days.
Provide password
test123
and hit enter on everything else.openssl
will use values defined inopenssl.cnf
.
openssl req -config openssl.cnf \
-extensions v3_ca -new -x509 -days 9999 \
-key private/ca.key \
-out certs/ca.cert
One interesting option to notice is ``-extensions v3_ca`` - it is reference to the section with the same name in ``openssl.cnf``. This section tells the ``openssl`` that created certificate must be a CA cert (``CA:true``).
Server cert creation
In this example, certificate signing is done in 3 steps.
- Create server certificate private key
- Create certificate singing request
- Sign the request with CA private key
So let’s do it.
Server’s private key (I skip intermediate certs creation for the brevity).
- RSA/2048 with e=3, for fast verification
openssl genpkey -algorithm RSA \
-pkeyopt rsa_keygen_bits:2048 \
-pkeyopt rsa_keygen_pubexp:3 \
-out private/rsa_2048.key
* ECDSA/P-256
openssl genpkey -algorithm EC \
-pkeyopt ec_paramgen_curve:P-256 \
-pkeyopt ec_param_enc:named_curve \
-out private/ecdsa_p256.key
* EdDSA/25519 (supported by newer version of ``openssl`` and in TLS 1.3 only)
openssl genpkey -algorithm Ed25519 \
-out private/ed25519.key
Create certificate signing request - intermediary step
- RSA
openssl req -config openssl.cnf -new \ -sha256 \ -passin pass:test123 \ -key private/rsa_2048.key \ -out csr/rsa_2048.csr \ -days 9999
- ECDSA
openssl req -config openssl.cnf -new \ -sha256 \ -passin pass:test123 \ -key private/ecdsa_p256.key \ -out csr/ecdsa_p256.csr \ -days 9999
- EdDSA
openssl req -config openssl.cnf -new \ -passin pass:test123 \ -key private/ed25519.key \ -out csr/ed25519.csr \ -days 9999
Create server cert
Finally we can create set of server certificates.
- RSA
openssl x509 \ -extfile openssl.cnf \ -extensions server_cert -sha256 -req \ -CA certs/ca.cert -CAkey private/ca.key -CAcreateserial \ -passin pass:test123 \ -in csr/rsa_2048.csr \ -out certs/rsa_2048.cert \ -days 9999
- ECDSA
openssl x509 \ -extfile openssl.cnf \ -extensions server_cert -sha256 -req \ -CA certs/ca.cert -CAkey private/ca.key -CAcreateserial \ -passin pass:test123 \ -in csr/ecdsa_p256.csr \ -out certs/ecdsa_256.cert \ -days 9999
- EdDSA
openssl x509 \ -extfile openssl.cnf \ -extensions server_cert -req \ -passin pass:test123 \ -CA certs/ca.cert -CAkey private/ca.key -CAcreateserial \ -passin pass:test123 \ -in csr/ed25519.csr \ -out certs/ed25519.cert \ -days 9999
It is currently believed that all private keys created above provide similar attack resistance, which is comparable to 128-bit symmetric cipher. Nevertheless, it’s worth to notice that byte size of those keys are much different.
Client cert creation
Commands below will create client private key and certificate that can be used for mutual TLS (client authentication). Procedure is similar to creating server certificate, so I’ll do it only for ECDSA.
- Client’s private key
openssl genpkey -algorithm EC \
-pkeyopt ec_paramgen_curve:P-256 \
-pkeyopt ec_param_enc:named_curve \
-out private/cli_ecdsa_p256.key
- Create certificate signing request - intermediary step
openssl req -config openssl.cnf -new \
-sha256 \
-passin pass:test123 \
-key private/cli_ecdsa_p256.key \
-out csr/cli_ecdsa_p256.csr \
-subj "/O=Cert Testing ORG/CN=Client Cert"
- Create client cert
openssl x509 \
-extfile openssl.cnf \
-extensions client_cert \
-req \
-CA certs/ca.cert \
-CAkey private/ca.key \
-CAcreateserial \
-in csr/cli_ecdsa_p256.csr \
-passin pass:test123 \
-out certs/cli_ecdsa_p256.cert \
-days 9999
Verification
In order to verify server certificate against CA following command can be used.
> openssl verify -CAfile certs/ca.cert certs/ecdsa_256.cert
certs/ecdsa_256.cert: OK
That’s it, I hope it helps, but most of all I hope I won’t have to look for this stuff ever again.
Also
Thank you to @mattcaswell from OpenSSL team, for helping to figure out how to create EdDSA certs.