ca

ca.git
git clone git://git.lenczewski.org/ca.git
Log | Files | Refs | README

commit 12df907bebff4029abf2bacd32ac0cb6924f44d1
Author: MikoĊ‚aj Lenczewski <mikolaj@lenczewski.org>
Date:   Tue,  5 May 2026 01:06:56 +0100

Initial commit

Diffstat:
A.gitignore | 4++++
AREADME | 7+++++++
Aca.country.txt | 1+
Aca.organization.txt | 1+
Aca.state.txt | 1+
Acrl.uri.txt | 1+
Afrag.cnf | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainit-ca.sh | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amake-ca-crl.sh | 8++++++++
Amake-cert.sh | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amake-intermediate-ca.sh | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aocsp.uri.txt | 1+
Arevoke-cert.sh | 21+++++++++++++++++++++
Arevoke-intermediate-ca.sh | 8++++++++
14 files changed, 513 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,4 @@ +ca/ +certs/ + +**/.*.swp diff --git a/README b/README @@ -0,0 +1,7 @@ +ca +============================================================================== +A set of shell scripts for generating a small self-signed certificate authority, +and generating signed certificates for use with email and other services. + +Taken from the excellent website: + https://jamielinux.com/docs/openssl-certificate-authority/index.html diff --git a/ca.country.txt b/ca.country.txt @@ -0,0 +1 @@ +PLACEHOLDER diff --git a/ca.organization.txt b/ca.organization.txt @@ -0,0 +1 @@ +PLACEHOLDER diff --git a/ca.state.txt b/ca.state.txt @@ -0,0 +1 @@ +PLACEHOLDER diff --git a/crl.uri.txt b/crl.uri.txt @@ -0,0 +1 @@ +PLACEHOLDER diff --git a/frag.cnf b/frag.cnf @@ -0,0 +1,66 @@ +# strict policy for signing intermediate certificates +# see policy format for `man ca` +[ CA_policy_strict ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# loose policy for signing generic certificates (signed by intermediate certs) +# see policy format for `man ca` +[ CA_policy_loose ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# extensions for the root ca certificate (`man x509v3_config`) +[ v3_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true +keyUsage = critical, digitalSignature, cRLSign, keyCertSign + +# extensions for intermediate ca certificates (`man x509v3_config`) +[ v3_intermediate_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true, pathlen:0 +keyUsage = critical, digitalSignature, cRLSign, keyCertSign + +# extensions for client certificates (`man x509v3_config`) +[ client_cert ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +basicConstraints = CA:false +keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = clientAuth, emailProtection +nsCertType = client, email +nsComment = "Generated Client Certificate" + +# extensions for server certificates (`man x509v3_config`) +[ server_cert ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +basicConstraints = CA:false +keyUsage = critical, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth +nsCertType = server +nsComment = "Generated Server Certificate" + +# extensions for the revocation list (`man x509v3_config`) +[ crl_ext ] +authorityKeyIdentifier = keyid:always + +# extensions for OSCP signing certificates (`man ocsp`) +[ ocsp ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +basicConstraints = CA:false +keyUsage = critical, digitalSignature +extendedKeyUsage = critical, OCSPSigning diff --git a/init-ca.sh b/init-ca.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +set -ex + +# initial directory structure + +mkdir -p ca \ + ca/cert \ + ca/crl \ + ca/new \ + ca/priv + +chmod 700 ca/priv + +touch ca/index.txt +touch ca/serial + +SERIAL=$(date '+%Y%m%d') +echo $SERIAL > ca/serial + +echo 1000 > ca/crlnumber + +# create openssl ca config + +C=$(cat ca.country.txt) +ST=$(cat ca.state.txt) +O=$(cat ca.organization.txt) + +[ "${C:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.country.txt!" && exit 1 + +[ "${ST:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.state.txt!" && exit 1 + +[ "${O:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.organization.txt!" && exit 1 + +CRL_URI="$(cat crl.uri.txt)" + +[ "${CRL_URI:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in crl.uri.txt!" && exit 1 + +cat >ca/openssl.cnf <<EOF +# root ca configuration + +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = $(dirname $0)/ca +certs = \$dir/cert +crl_dir = \$dir/crl +new_certs_dir = \$dir/new +database = \$dir/index.txt +serial = \$dir/serial +RANDFILE = \$dir/priv/.rand + +# root key and certificate +private_key = \$dir/priv/ca.key.pem +certificate = \$dir/cert/ca.crt.pem + +# certificate revocation list config +crlnumber = \$dir/crlnumber +crl = \$dir/crl/ca.crl.pem +crl_extensions = crl_ext +default_crl_days = 31 + +# use a strong digest +default_md = sha512 + +# misc config +name_opt = ca_default +cert_opt = ca_default +default_days = 365 +preserve = no +policy = CA_policy_strict + +# default fields when making certificate requests +[ req ] +default_bits = 4096 + +string_mask = utf8only + +default_md = sha512 + +x509_extensions = v3_ca + +[ v3_intermediate_ca ] +crlDistributionPoints = URI:http://${CRL_URI} + +EOF + +cat >>ca/openssl.cnf < frag.cnf + +# create the root certificate + +# generate the key +openssl genrsa -aes256 -out ca/priv/ca.key.pem 4096 +chmod 400 ca/priv/ca.key.pem + +# generate the certificate +openssl req -config ca/openssl.cnf \ + -new -x509 -days 36500 -extensions v3_ca \ + -subj "/C=$C/ST=$ST/O=$O/CN=$O Root CA" \ + -key ca/priv/ca.key.pem \ + -out ca/cert/ca.crt.pem + +chmod 444 ca/cert/ca.crt.pem + +# verify the certificate +openssl x509 -noout -text -in ca/cert/ca.crt.pem + +echo "NOTE: Install the root certificate on all devices" +echo "NOTE: Root certificate is found in 'ca/cert/ca.crt.pem'" +echo "NOTE: Please run 'make-intermediate-ca.sh' at least once" diff --git a/make-ca-crl.sh b/make-ca-crl.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +set -ex + +# generate the crl + +openssl ca -config ca/openssl.cnf \ + -gencrl -out ca/intermediate/crl/intermediate.crl.pem diff --git a/make-cert.sh b/make-cert.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +TYPE="$1" +DOMAIN="$2" +shift 2 + +EXTRA="$(echo $@ | xargs printf '%s\n' | paste -s -d '/' -)" + +PCKSPASS="${PCKSPASS:-password}" +DAYS="${DAYS:-730}" + +case "$TYPE" in + client|server) + ;; + + *) + echo "Usage: $0 <server|client> <fqdn> <x509-subj-extra>..." + exit 1 + ;; +esac + +if [ -z "$DOMAIN" ]; then + echo "Usage: $0 <server|client> <fqdn> <x509-subj-extra>..." + exit 1 +fi + +set -ex + +mkdir -p certs certs/$TYPE "certs/$TYPE/$DOMAIN" + +# generate the key +openssl genrsa \ + -out "certs/$TYPE/$DOMAIN/$DOMAIN.key.pem" 4096 + +chmod 600 "certs/$TYPE/$DOMAIN/$DOMAIN.key.pem" + +# generate the certificate + +C=$(cat ca.country.txt) +ST=$(cat ca.state.txt) +O=$(cat ca.organization.txt) + +[ "${C:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.country.txt!" && exit 1 + +[ "${ST:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.state.txt!" && exit 1 + +[ "${O:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.organization.txt!" && exit 1 + +openssl req -config ca/intermediate/current/openssl_usr.cnf \ + -key "certs/$TYPE/$DOMAIN/$DOMAIN.key.pem" \ + -new -subj "/C=$C/ST=$ST/O=$O/CN=${DOMAIN}/${EXTRA}" \ + -out "certs/$TYPE/$DOMAIN/$DOMAIN.csr.pem" + +openssl ca -config ca/intermediate/current/openssl_usr.cnf \ + -days $DAYS -notext -extensions ${TYPE}_cert \ + -in "certs/$TYPE/$DOMAIN/$DOMAIN.csr.pem" \ + -out "certs/$TYPE/$DOMAIN/$DOMAIN.crt.pem" + +chmod 644 "certs/$TYPE/$DOMAIN/$DOMAIN.crt.pem" + +# verify the certificate +openssl x509 -noout -text -in "certs/$TYPE/$DOMAIN/$DOMAIN.crt.pem" +openssl verify -CAfile ca/intermediate/current/cert/ca-chain.pem \ + "certs/$TYPE/$DOMAIN/$DOMAIN.crt.pem" + +# publish certificate +echo "NOTE: Certificate key is found in 'certs/$TYPE/$DOMAIN/$DOMAIN.key.pem'" +echo "NOTE: Certificate is found in 'certs/$TYPE/$DOMAIN/$DOMAIN.crt.pem'" diff --git a/make-intermediate-ca.sh b/make-intermediate-ca.sh @@ -0,0 +1,208 @@ +#!/bin/sh + +DATE="$(date '+%Y-%m-%d')" +SERIAL=$(date '+%Y%m%d') + +[ -d ca/intermediate/$DATE ] && \ + echo "Warning: Intermediate CA for serial $SERIAL already exists: ca/intermediate/$DATE" && exit 1 + +INTERMEDIATE_CA_ROOT=ca/intermediate/$DATE + +set -ex + +# initial directory structure + +mkdir -p $INTERMEDIATE_CA_ROOT \ + $INTERMEDIATE_CA_ROOT/cert \ + $INTERMEDIATE_CA_ROOT/csr \ + $INTERMEDIATE_CA_ROOT/new \ + $INTERMEDIATE_CA_ROOT/priv \ + ca/intermediate/crl + +chmod 700 $INTERMEDIATE_CA_ROOT/priv + +touch $INTERMEDIATE_CA_ROOT/index.txt $INTERMEDIATE_CA_ROOT/serial + +echo $SERIAL > $INTERMEDIATE_CA_ROOT/serial +echo 1000 > $INTERMEDIATE_CA_ROOT/crlnumber + +# create openssl ca config + +C=$(cat ca.country.txt) +ST=$(cat ca.state.txt) +O=$(cat ca.organization.txt) + +[ "${C:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.country.txt!" && exit 1 + +[ "${ST:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.state.txt!" && exit 1 + +[ "${O:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ca.organization.txt!" && exit 1 + +OCSP_URI="$(cat ocsp.uri.txt)" + +[ "${OCSP_URI:-PLACEHOLDER}" = "PLACEHOLDER" ] && \ + echo "Please fill in ocsp.uri.txt!" && exit 1 + +cat >$INTERMEDIATE_CA_ROOT/openssl.cnf <<EOF +# intermediate ca configuration + +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = $(dirname $0)/ca/intermediate/$DATE +certs = \$dir/cert +crl_dir = \$dir/crl +new_certs_dir = \$dir/new +database = \$dir/index.txt +serial = \$dir/serial +RANDFILE = \$dir/priv/.rand + +# root key and certificate +private_key = \$dir/priv/intermediate.key.pem +certificate = \$dir/cert/intermediate.crt.pem + +# certificate revocation list config +crlnumber = \$dir/crlnumber +crl = \$dir/crl/intermediate.crl.pem +crl_extensions = crl_ext +default_crl_days = 30 + +# use a strong digest +default_md = sha512 + +# misc config +name_opt = ca_default +cert_opt = ca_default +default_days = 365 +preserve = no +policy = CA_policy_loose + +# default fields when making certificate requests +[ req ] +default_bits = 4096 + +string_mask = utf8only + +default_md = sha512 + +x509_extensions = v3_ca + +EOF + +cat >>$INTERMEDIATE_CA_ROOT/openssl.cnf < frag.cnf + +cat >$INTERMEDIATE_CA_ROOT/openssl_usr.cnf <<EOF +# server and client certificate configuration + +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = $(dirname $0)/ca/intermediate/$DATE +certs = \$dir/cert +crl_dir = \$dir/crl +new_certs_dir = \$dir/new +database = \$dir/index.txt +serial = \$dir/serial +RANDFILE = \$dir/priv/.rand + +# root key and certificate +private_key = \$dir/priv/intermediate.key.pem +certificate = \$dir/cert/intermediate.crt.pem + +# certificate revocation list config +crlnumber = \$dir/crlnumber +crl = \$dir/crl/intermediate.crl.pem +crl_extensions = crl_ext +default_crl_days = 30 + +# use a strong digest +default_md = sha512 + +# misc config +name_opt = ca_default +cert_opt = ca_default +default_days = 365 +preserve = no +policy = CA_policy_loose + +# default fields when making certificate requests +[ req ] +default_bits = 4096 + +string_mask = utf8only + +default_md = sha512 + +x509_extensions = v3_ca + +[ client_cert ] +authorityInfoAccess = OCSP;URI:http://${OCSP_URI} + +[ server_cert ] +authorityInfoAccess = OCSP;URI:http://${OCSP_URI} + +EOF + +cat >>$INTERMEDIATE_CA_ROOT/openssl_usr.cnf < frag.cnf + +# create the intermediate pair + +# generate the key +openssl genrsa -aes256 -out $INTERMEDIATE_CA_ROOT/priv/intermediate.key.pem 4096 +chmod 400 $INTERMEDIATE_CA_ROOT/priv/intermediate.key.pem + +# generate the certificate +openssl req -config $INTERMEDIATE_CA_ROOT/openssl.cnf \ + -new -subj "/C=$C/ST=$ST/O=$O/CN=$O Intermediate CA" \ + -key $INTERMEDIATE_CA_ROOT/priv/intermediate.key.pem \ + -out $INTERMEDIATE_CA_ROOT/csr/intermediate.csr.pem + +openssl ca -config ca/openssl.cnf \ + -days 3650 -notext -extensions v3_intermediate_ca \ + -in $INTERMEDIATE_CA_ROOT/csr/intermediate.csr.pem \ + -out $INTERMEDIATE_CA_ROOT/cert/intermediate.crt.pem + +chmod 444 $INTERMEDIATE_CA_ROOT/cert/intermediate.crt.pem + +# verify the certificate +openssl x509 -noout -text -in $INTERMEDIATE_CA_ROOT/cert/intermediate.crt.pem +openssl verify -CAfile ca/cert/ca.crt.pem $INTERMEDIATE_CA_ROOT/cert/intermediate.crt.pem + +# create the ocsp pair + +openssl genrsa -out $INTERMEDIATE_CA_ROOT/priv/$OCSP_URI.ocsp.key.pem 4096 +chmod 400 $INTERMEDIATE_CA_ROOT/priv/$OCSP_URI.ocsp.key.pem + +openssl req -config $INTERMEDIATE_CA_ROOT/openssl.cnf \ + -new -subj="/C=$C/ST=$ST/O=$O/CN=$OCSP_URI" \ + -key "$INTERMEDIATE_CA_ROOT/priv/$OCSP_URI.ocsp.key.pem" \ + -out "$INTERMEDIATE_CA_ROOT/csr/$OCSP_URI.ocsp.csr.pem" + +openssl ca -config $INTERMEDIATE_CA_ROOT/openssl.cnf \ + -days 3650 -notext -extensions ocsp \ + -in "$INTERMEDIATE_CA_ROOT/csr/$OCSP_URI.ocsp.csr.pem" \ + -out "$INTERMEDIATE_CA_ROOT/cert/$OCSP_URI.ocsp.crt.pem" + +openssl x509 -noout -text -in "$INTERMEDIATE_CA_ROOT/cert/$OCSP_URI.ocsp.crt.pem" + +# create root ca crl + +$(dirname $0)/make-ca-crl.sh + +# create chain of trust + +cat $INTERMEDIATE_CA_ROOT/cert/intermediate.crt.pem > $INTERMEDIATE_CA_ROOT/cert/ca-chain.pem + +# create symlink +ln -sf $DATE ca/intermediate/current + +echo "NOTE: Generated CRL is found in '$INTERMEDIATE_CA_ROOT/crl/intermediate.crl.pem'" +echo "NOTE: Please run 'make-ca-crl.sh' on a regular basis (once every 30 days) to update it" +echo "NOTE: OCSP key is found in '$INTERMEDIATE_CA_ROOT/priv/*.ocsp.key.pem'" +echo "NOTE: OCSP cert is found in '$INTERMEDIATE_CA_ROOT/cert/*.ocsp.crt.pem'" +echo "NOTE: Chain of Trust is found in '$INTERMEDIATE_CA_ROOT/cert/ca-chain.pem'" diff --git a/ocsp.uri.txt b/ocsp.uri.txt @@ -0,0 +1 @@ +PLACEHOLDER diff --git a/revoke-cert.sh b/revoke-cert.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +TYPE="$1" +DOMAIN="$2" + +case "$TYPE" in + client|server) + ;; + + *) + echo "Usage: $0 <server|client> <fqdn>" + ;; +esac + +if [ -z "$DOMAIN" ]; then + echo "Usage: $0 <server|client> <fqdn>" + exit 1 +fi + +openssl ca -config ca/intermediate/current/openssl_usr.cnf \ + -revoke "certs/$TYPE/$DOMAIN/$DOMAIN.crt.pem" diff --git a/revoke-intermediate-ca.sh b/revoke-intermediate-ca.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +set -x + +openssl ca -config ca/openssl.cnf \ + -revoke $1 + +$(dirname $0)/make-ca-crl.sh