Skip to content

Instantly share code, notes, and snippets.

@rmrfslashbin
Last active November 21, 2022 16:19
Show Gist options
  • Save rmrfslashbin/34ae2d4d56991b4613b302486778c0cd to your computer and use it in GitHub Desktop.
Save rmrfslashbin/34ae2d4d56991b4613b302486778c0cd to your computer and use it in GitHub Desktop.
Roll-your-own CA

Roll-your-own CA

So you want to learn how to make a CA...

Use-Case

  • 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.

Dir Struct

  • web-auth-ssl/newcerts
  • web-auth-ssl/private
  • web-auth-ssl/p12
  • web-auth-ssl/crl
  • web-auth-ssl/certs

Create Dir Struct

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/[email protected]/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

openssl.cnf

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

CA Tasks

Things you do to set up the CA

Generate the root CA key

openssl genrsa \
  -aes256 \
  -out private/ca.key.pem 4096
chmod 400 private/ca.key.pem

Generate the root CA cert

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

Generate the CRL

CRL = Certificate Revocation List

openssl ca \
  -config openssl.cnf \
  -keyfile private/ca.key.pem \
  -cert certs/ca.cert.pem \
  -gencrl \
  -out crl/crl.pem

Verify CRL

openssl crl -in crl/crl.pem -text

User Tasks

Thing you would do as the cert requestor

Generate a key

openssl genrsa -out private/[email protected] 4096
chmod 400 private/[email protected]

Generate a CSR

openssl req \
  -config openssl.cnf \
  -sha256 \
  -new \
  -key private/[email protected] \
  -out certs/[email protected]

Verify CSR

openssl req -text -noout -verify -in certs/[email protected]

Sign the CSR/create a cert

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/[email protected] \
  -out certs/[email protected]

Verify the cert

Take note of the new cert listed in index.txt

cat index.txt
openssl x509 -in certs/[email protected] -noout -text

Verify user against CA

openssl verify -CAfile certs/ca.cert.pem certs/[email protected]

Export cert/key to pkcs12 format

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/[email protected] \
  -inkey private/[email protected] \
  -in certs/[email protected] \
  -certfile certs/ca.cert.pem

Verify pkcs12 file

openssl pkcs12 -in p12/[email protected]

User Cert Revocation

From time to time, user certs may need to be revoked. First, revoke the cert. Second, add the revocation to the CRL.

Revoke user cert

openssl ca \
  -config openssl.cnf \
  -keyfile private/ca.key.pem \
  -cert certs/ca.cert.pem \
  -revoke certs/[email protected]

Update CA the CRL

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment