wolfssl-examples/certs/check-expiry.sh

101 lines
4.1 KiB
Bash
Executable File

#!/bin/sh
# Walk the committed certificates and CRLs and flag ones that are about to
# expire, so a cert dying becomes a scheduled regeneration instead of a red
# morning. Already expired ones are reported but not failed: several are legacy
# or deliberately stale fixtures (ntru-cert.pem, expired-* used for negative
# tests). Covers PEM and DER X.509 certs, PEM/DER CRLs (nextUpdate), and the
# certs inside PKCS#12 bundles (*.p12, opened with the examples' password).
# A bundle is never a fixture, so an expired one fails outright.
set -eu
DIR="${1:-certs}"
WARN_DAYS="${WARN_DAYS:-30}"
FAIL_DAYS="${FAIL_DAYS:-7}"
warn_secs=$((WARN_DAYS * 86400))
fail_secs=$((FAIL_DAYS * 86400))
now=$(date +%s)
rc=0
checked=0
# openssl prints dates like "Jun 10 12:00:00 2027 GMT"; parse with GNU then BSD.
to_epoch() {
date -d "$1" +%s 2>/dev/null || date -jf "%b %e %T %Y %Z" "$1" +%s 2>/dev/null || echo 0
}
check_cert() {
f="$1"; form="$2"
openssl x509 -inform "$form" -noout -in "$f" >/dev/null 2>&1 || return 0
checked=$((checked + 1))
if ! openssl x509 -inform "$form" -checkend 0 -noout -in "$f" >/dev/null 2>&1; then
echo "::notice::already expired (legacy/fixture, not failing): $f"
elif ! openssl x509 -inform "$form" -checkend "$fail_secs" -noout -in "$f" >/dev/null 2>&1; then
end=$(openssl x509 -inform "$form" -enddate -noout -in "$f" | cut -d= -f2)
echo "::error::$f expires within $FAIL_DAYS days ($end) -- regenerate now"
rc=1
elif ! openssl x509 -inform "$form" -checkend "$warn_secs" -noout -in "$f" >/dev/null 2>&1; then
end=$(openssl x509 -inform "$form" -enddate -noout -in "$f" | cut -d= -f2)
echo "::warning::$f expires within $WARN_DAYS days ($end) -- schedule regeneration"
fi
}
check_crl() {
f="$1"; form="$2"
nu=$(openssl crl -inform "$form" -nextupdate -noout -in "$f" 2>/dev/null | cut -d= -f2)
[ -n "$nu" ] || return 0
checked=$((checked + 1))
secs=$(to_epoch "$nu")
[ "$secs" -ne 0 ] || return 0
if [ "$secs" -le "$now" ]; then
echo "::notice::CRL past nextUpdate (fixture, not failing): $f"
elif [ "$secs" -le $((now + fail_secs)) ]; then
echo "::error::$f CRL nextUpdate within $FAIL_DAYS days ($nu) -- regenerate now"
rc=1
elif [ "$secs" -le $((now + warn_secs)) ]; then
echo "::warning::$f CRL nextUpdate within $WARN_DAYS days ($nu) -- schedule regeneration"
fi
}
P12_PASS="${P12_PASS:-wolfSSL test}"
# True if the PEM cert in $cert is still valid $1 seconds from now.
cert_ok() {
printf '%s\n' "$cert" | openssl x509 -checkend "$1" -noout >/dev/null 2>&1
}
check_p12() {
f="$1"
certs=$(openssl pkcs12 -in "$f" -nokeys -passin "pass:${P12_PASS}" \
2>/dev/null) \
|| { echo "::notice::$f does not open with P12_PASS, skipped"; return 0; }
n=$(printf '%s\n' "$certs" | grep -c -- '-----BEGIN CERTIFICATE-----')
i=0
while [ "$i" -lt "$n" ]; do
i=$((i + 1))
checked=$((checked + 1))
cert=$(printf '%s\n' "$certs" | awk -v want="$i" \
'/-----BEGIN CERTIFICATE-----/{c++} c==want')
end=$(printf '%s\n' "$cert" | openssl x509 -enddate -noout | cut -d= -f2)
if ! cert_ok 0; then
echo "::error::$f cert $i expired ($end) -- run certs/generate-client-bundle.sh"
rc=1
elif ! cert_ok "$fail_secs"; then
echo "::error::$f cert $i expires within $FAIL_DAYS days ($end)" \
"-- regenerate now"
rc=1
elif ! cert_ok "$warn_secs"; then
echo "::warning::$f cert $i expires within $WARN_DAYS days ($end)" \
"-- schedule regeneration"
fi
done
}
for f in $(find "$DIR" -name '*.pem' | sort); do check_cert "$f" PEM; done
for f in $(find "$DIR" -name '*.der' | sort); do check_cert "$f" DER; done
for f in $(find "$DIR" \( -name '*crl*.pem' -o -name '*.crl' \) | sort); do check_crl "$f" PEM; done
for f in $(find "$DIR" -name '*crl*.der' | sort); do check_crl "$f" DER; done
for f in $(find "$DIR" -name '*.p12' | sort); do check_p12 "$f"; done
echo "checked $checked cert/CRL file(s); fail threshold ${FAIL_DAYS}d, warn ${WARN_DAYS}d"
exit $rc