Skip to content

Instantly share code, notes, and snippets.

@philfry
Last active November 11, 2023 22:10
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save philfry/f288976d8e520b01c878a8693041e3ec to your computer and use it in GitHub Desktop.
Save philfry/f288976d8e520b01c878a8693041e3ec to your computer and use it in GitHub Desktop.

generating a crl with smallstep

prerequisites

configure openssl

# /etc/step/openssl.conf
[ ca ]
default_ca = step

[ step ]
dir = /var/lib/step
certificate = $dir/certs/root_ca.crt
private_key = $dir/secrets/root_ca_key
crlnumber = $dir/crlnumber
database = $dir/index.txt
default_crl_days = 44
default_md = sha512
unique_subject = no

provider password

save your provider password to /etc/step/passwd

when using bbolt

configuration of ca.json

{
  "db": {
    "type": "bbolt",
    "dataSource": "/var/lib/step/db/bolt.db"
  }
}

install required tools

dnf -y install golang jq
go go get github.com/muesli/thunder

when using mysql

configuration of ca.json

{
  "db": {
    "type": "mysql",
    "dataSource": "step:step@tcp(127.0.0.1:3306)/",
    "database": "step"
  }
}

install required tools

dnf -y install mariadb jq

generating the index.txt

when using bbolt

since the database is locked when step-ca is running, you must shut it down first

export PATH=${PATH}:${HOME}/go/bin
step="/var/lib/step"
db="${step}/db/bolt.db"
revokedcerts=$(echo "ls revoked_x509_certs/" | thunder "${db}" | sed '1,3d;$d')
for cert in ${revokedcerts}; do
  echo "get revoked_x509_certs/${cert}" | thunder "${db}" | sed '1,3d' | \
  eval $(
    jq -Mr '{enddate: .RevokedAt, serial: .Serial}|to_entries|map("export \(.key)=\(.value)")|.[]'
  )
  serial=${serial^^}
  printf "R\t%s\t%s\t%s\tunknown\tdummy\n" \
	$(TZ=Z date -d "${enddate}" +%Y%m%d%H%M%SZ) \
	$(TZ=Z date -d "${enddate}" +%g%m%d%H%M%SZ) \
	${serial//:}
done > ${step}/index.txt

when using mysql

step="/var/lib/step"
mysql -Ne 'select nvalue from revoked_x509_certs' step | while read cert; do
  eval $(
    jq -Mr '{enddate: .RevokedAt, serial: .Serial}|to_entries|map("export \(.key)=\(.value)")|.[]' \
    <<<"${cert}"
  )
  serial=${serial^^}
  printf "R\t%s\t%s\t%s\tunknown\tdummy\n" \
    $(TZ=Z date -d "${enddate}" +%Y%m%d%H%M%SZ) \
    $(TZ=Z date -d "${enddate}" +%g%m%d%H%M%SZ) \
    ${serial//:}
done > ${step}/index.txt

generating the crl.pem

openssl ca -config /etc/step/openssl.conf -gencrl -passin file:/etc/step/passwd -out /path/to/crl.pem

running an ocsp responder

Add a certificate for ocsp and use it to sign the responses. See man 1 ocsp for details.

openssl ocsp -rmd sha256 -port 8080 -nmin 360 \
  -index /var/lib/step/index.txt \
  -CA /var/lib/step/certs/root_ca.crt \
  -rsigner /path/to/ocsp.pem \
  -rkey /path/to/ocsp.key
#!/bin/bash
#
# generate index.txt and crl from step database
#
# Copyright 2022, Philippe Kueck <projects at unixadm dot org>
#
# This software may be freely redistributed under the terms of the GNU
# general public license version 2.
step="{{step_data_dir}}"
conf="{{step_conf_dir}}"
db="${step}/db/bolt.db"
tmp=$(mktemp -d)
trap "rm -rf ${tmp}" 0 1 2 15
export TZ=Z
now=$(date +%s)
prep_revoked() {
eval $(
thunder "${db}" <<<"get revoked_x509_certs/${cert}" | sed '1,3d' | \
jq -Mr '{revokedAt: .RevokedAt, serial: .Serial}|to_entries|map("\(.key)=\(.value)")|.[]'
)
date -d "${revokedAt}" +%g%m%d%H%M%SZ > ${tmp}/${serial}.revoked
}
proc_cert() {
thunder "${db}" <<<"get x509_certs/${cert}" | \
dd bs=1 skip=57 of="${tmp}/${cert}.der" status=none
eval $(
openssl x509 -inform DER -in "${tmp}/${cert}.der" -noout -subject -nameopt compat | \
sed 's/=/="/;s/$/"/'
openssl x509 -inform DER -in "${tmp}/${cert}.der" -noout -serial
openssl x509 -inform DER -in "${tmp}/${cert}.der" -noout -enddate | \
sed 's/=/="/;s/$/"/'
)
enddate=$(date -d "${notAfter}" +%Y%m%d%H%M%SZ)
revoked=
state="V"
if [[ -e "${tmp}/${serial}.revoked" ]]; then
state="R"
read revoked < "${tmp}/${serial}.revoked"
elif [[ $(date -d "${notAfter}" +%s) -le ${now} ]]; then
state="E"
fi
printf "%s\t%s\t%s\t%s\tunknown\t%s\n" \
"${state}" \
"${enddate}" \
"${revoked}" \
"${serial}" \
"${subject}"
}
#################################################
systemctl stop step-ca
revoked_certs=$(thunder "${db}" <<<"ls revoked_x509_certs/" | sed '1,3d;$d')
for cert in ${revoked_certs}; do
prep_revoked "${cert}"
done
all_certs=$(thunder "${db}" <<<"ls x509_certs" | sed '1,3d;$d')
for cert in ${all_certs}; do
proc_cert "${cert}"
done > "${step}/index.txt"
systemctl start step-ca
for cert in root_ca intermediate_ca; do
eval $(
openssl x509 -in "${step}/certs/${cert}.crt" -noout -subject -nameopt compat | \
sed 's/=/="/;s/$/"/'
openssl x509 -in "${step}/certs/${cert}.crt" -noout -serial
openssl x509 -in "${step}/certs/${cert}.crt" -noout -enddate | \
sed 's/=/="/;s/$/"/'
)
enddate=$(date -d "${notAfter}" +%Y%m%d%H%M%SZ)
printf "V\t%s\t\t%s\tunknown\t%s\n" \
"${enddate}" \
"${serial}" \
"${subject}"
done >> "${step}/index.txt"
chown step: "${step}/index.txt"
chmod 600 "${step}/index.txt"
mkdir -p "${step}/crls/" 2>/dev/null
openssl ca -config "${conf}/openssl-crl.conf" -gencrl \
-passin "file:${conf}/passwd" -out "${step}/crls/crl.pem"
openssl crl -inform PEM -outform DER \
-in "${step}/crls/crl.pem" -out "${step}/crls/crl.der"
chown -R step: "${step}/crls"
@DonOtuseGH
Copy link

how do you decode such a nvalue blob?

0x7B2253657269616C223A2233373933343433393130373738313132333639333530363637353830373331323639313637222C2250726F766973696F6E65724944223A227765627365727665723A36564B4A504F5A4E7736505352376E7757624D506C694B6F4D754B485759424871674B4A793746716A4438222C22526561736F6E436F6465223A302C22526561736F6E223A22222C225265766F6B65644174223A22323032322D30342D30315432303A34333A34392E3033343937393832355A222C22546F6B656E4944223A2264376531663966313964383934393637356137613763656637383062313663666136356663343763613966613266616136366266376334373061376166643164222C224D544C53223A66616C73652C2241434D45223A66616C73657D

| xxd -r -p 😁

@philfry
Copy link
Author

philfry commented Apr 5, 2022

aye.

I just added a script to this gist I've been using for over a year now to generate a "full featured" index.txt which contains valid, expired and revoked certificates. All three types are needed to run an ocsp responder.

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