Skip to content

Instantly share code, notes, and snippets.

@rmrfslashbin
Last active November 21, 2022 16:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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/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

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/user@host.key.pem 4096
chmod 400 private/user@host.key.pem

Generate a CSR

openssl req \
  -config openssl.cnf \
  -sha256 \
  -new \
  -key private/user@host.key.pem \
  -out certs/user@host.csr.pem

Verify CSR

openssl req -text -noout -verify -in certs/user@host.csr.pem

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/user@host.csr.pem \
  -out certs/user@host.cert.pem

Verify the cert

Take note of the new cert listed in index.txt

cat index.txt
openssl x509 -in certs/user@host.cert.pem -noout -text

Verify user against CA

openssl verify -CAfile certs/ca.cert.pem certs/user@host.cert.pem

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/user@host.p12 \
  -inkey private/user@host.key.pem \
  -in certs/user@host.cert.pem \
  -certfile certs/ca.cert.pem

Verify pkcs12 file

openssl pkcs12 -in p12/user@host.p12

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/user@host.cert.pem

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