So you want to learn how to make a CA...
- This is a proof of concept. It should not be used as a production CA.
- All tasks are presumed to be executed by the same user, on the same manhine.
- A production CA would set up and leverage separation of duties.
- A production CA would not generate CSRs, create the cert, and sign on the same machine.
- As noted below, for user/client certs (ex: use a cert to provide authentication), vs service certs (https, smtps, etc) see the point related to
-extensions usr_cert
.
- web-auth-ssl/newcerts
- web-auth-ssl/private
- web-auth-ssl/p12
- web-auth-ssl/crl
- web-auth-ssl/certs
mkdir -p \
web-auth-ssl/newcerts \
web-auth-ssl/private \
web-auth-ssl/p12 \
web-auth-ssl/crl \
web-auth-ssl/certs
# Check your openssl distribution for the location of openssl.cnf
# For example, Homebrew locates the file here: /opt/homebrew/etc/openssl@1.1/openssl.cnf
cp /etc/pki/tls/openssl.cnf web-auth-ssl/openssl.cnf
touch web-auth-ssl/index.txt
echo 1000 > web-auth-ssl/crlnumber
echo 1000 > web-auth-ssl/serial
Things to change in web-auth-ssl/openssl.cnf
[ CA_default ]
dir = /home/myDir/web-auth-ssl
certs = $dir/certs
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/ca.cert.pem
serial = $dir/serial
crlnumber = $dir/crlnumber
crl = $dir/crl.pem
private_key = $dir/private/ca.key.pem
RANDFILE = $dir/private/.rand
crl_extensions = crl_ext
policy = policy_match
[ req_distinguished_name ]
countryName_default = US
stateOrProvinceName_default = Georgia
localityName_default = Atlanta
0.organizationName_default = Improvised Science
organizationalUnitName_default = Web Auth
[ usr_cert ]
basicConstraints=CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = CA:true
keyUsage = cRLSign, keyCertSign
Things you do to set up the CA
openssl genrsa \
-aes256 \
-out private/ca.key.pem 4096
chmod 400 private/ca.key.pem
openssl req \
-config openssl.cnf \
-new \
-x509 \
-days 3650 \
-sha256 \
-extensions v3_ca \
-key private/ca.key.pem \
-out certs/ca.cert.pem
chmod 444 certs/ca.cert.pem
CRL = Certificate Revocation List
openssl ca \
-config openssl.cnf \
-keyfile private/ca.key.pem \
-cert certs/ca.cert.pem \
-gencrl \
-out crl/crl.pem
openssl crl -in crl/crl.pem -text
Thing you would do as the cert requestor
openssl genrsa -out private/user@host.key.pem 4096
chmod 400 private/user@host.key.pem
openssl req \
-config openssl.cnf \
-sha256 \
-new \
-key private/user@host.key.pem \
-out certs/user@host.csr.pem
openssl req -text -noout -verify -in certs/user@host.csr.pem
This is not actually a requestor task... In a real PKI, the CA owner would create & cign the cert from the CSR.
- Take note, in the case of a user cert (ex: a user will import this cert into a browser to present for authentication), add the
-extensions usr_cert
option to the command below.
openssl ca \
-config openssl.cnf \
-keyfile private/ca.key.pem \
-cert certs/ca.cert.pem \
-notext \
-md sha256 \
-in certs/user@host.csr.pem \
-out certs/user@host.cert.pem
Take note of the new cert listed in index.txt
cat index.txt
openssl x509 -in certs/user@host.cert.pem -noout -text
openssl verify -CAfile certs/ca.cert.pem certs/user@host.cert.pem
For easy distribution and import into browsers, export the key to PKCS #12 format. The importer will need to know the "export" password provided in this step.
openssl pkcs12 \
-export \
-out p12/user@host.p12 \
-inkey private/user@host.key.pem \
-in certs/user@host.cert.pem \
-certfile certs/ca.cert.pem
openssl pkcs12 -in p12/user@host.p12
From time to time, user certs may need to be revoked. First, revoke the cert. Second, add the revocation to the CRL.
openssl ca \
-config openssl.cnf \
-keyfile private/ca.key.pem \
-cert certs/ca.cert.pem \
-revoke certs/user@host.cert.pem
openssl ca \
-config openssl.cnf \
-keyfile private/ca.key.pem \
-cert certs/ca.cert.pem \
-gencrl \
-out crl/crl.pem
Be sure to update/publish crl/crl.pem
to your web server and/or apps.