Skip to content

Instantly share code, notes, and snippets.

@brimston3
Created August 16, 2017 18:28
Show Gist options
  • Save brimston3/ea4c7fc4a616fef6ffef937293409ab5 to your computer and use it in GitHub Desktop.
Save brimston3/ea4c7fc4a616fef6ffef937293409ab5 to your computer and use it in GitHub Desktop.
Some examples for extracting certificate information and tests for checking if a HTTPD reload is needed
#!/bin/sh
:<<"EOF"
openssl_acme_cert_script_examples.sh
CodeLibrary, server management
Inspecting acmetool generated certificates.
===========================================
This file contains some handy script examples for checking various details in
a remote tls server's certificate and comparing it to the current on-disk
version that acmetool (or similar) has stored.
No temporary files are used, only pipes. Most operations can be piped as
a one-liner, though safety checking is adviseable.
Copyright 2017-08-16 Andrew Domaszek.
All rights reserved.
Licensed under BSD-new
Dependency:
openssl (tested with 1.0.1t)
Todos:
1. Currently does not cache x509 parsing. Posix shell does not have arrays
and I find myself doing these checks with busybox often. This makes it
more difficult to handle K-V storage objects in a pipeline (indirection
has awkward syntax).
EOF
DEBUG=1
ACME_LIVE_DIR=/var/lib/acme/live
ACME_DOMAIN=YOUR.DOMAIN
DEBUGPRINT() {
if [ "x$DEBUG" != "x" ]; then
ANSI_GREEN='\033[0;32m'
ANSI_RESET='\033[0m'
echo $ANSI_GREEN"$@"$ANSI_RESET
fi
}
##
# Simple single-domain certificate file modified time newer than 1 day.
if [ "$(find "$ACME_LIVE_DIR/$ACME_DOMAIN/cert" -mtime -1 2>/dev/null | wc -l)" -gt 0 ]; then
DEBUGPRINT "Certificate on disk for $ACME_DOMAIN is newer than 1 day"
# Rehash znc
# reload nginx
fi
##
# Simple single-domain validity check against the default root certificate store.
# May need -CAfile rootcerts.pem or -CApath /etc/ssl/certs for alternate root cert stores.
if ! openssl verify "$ACME_LIVE_DIR/$ACME_DOMAIN/chain"; then
DEBUGPRINT "$ACME_DOMAIN chain validation failed."
# send alert email to admin here, this is bad.
else
DEBUGPRINT "Local certificate chain for $ACME_DOMAIN verifies okay."
fi
##
# More general reload catching that I use on my project instance:
if [ "$(find "$ACME_LIVE_DIR/" -name cert -mtime -1 2>/dev/null | wc -l)" -gt 0 ]; then
DEBUGPRINT "$ACME_LIVE_DIR has at least one certificate newer than one day"
# reload nginx
fi
##
# Extract remote certificate:
DEBUGPRINT "Remote server https certificate for $ACME_DOMAIN:"
echo "" | openssl s_client -showcerts -servername "$ACME_DOMAIN" -connect "$ACME_DOMAIN:443" 2>/dev/null | openssl x509 -inform pem -noout -text
##
# Some pipeable "filter" functions to extract the desired field.
get_cert_min_date_filter() {
openssl x509 -inform pem -noout -text | grep -iF "Not Before:" | sed -e 's@^.*: @@'
}
get_cert_serial_filter() {
# attributes are not case sensitive, so force to lowercase.
openssl x509 -inform pem -noout -text | awk 'f{print;f=0} /^[ ]*Serial Number:/{f=1}' | tr -d ' ' | tr '[A-Z]' '[a-z]'
}
get_cert_subject_filter() {
# attributes are not case sensitive, so force to lowercase.
openssl x509 -inform pem -noout -text | grep -iF "Subject:" | sed -e 's@^.*: @@' | tr '[A-Z]' '[a-z]'
}
# Demonstrate using above filter to do a timestamp comparison:
TLS_REMOTE_MIN_DATE="$(echo | openssl s_client -showcerts -servername "$ACME_DOMAIN" -connect "$ACME_DOMAIN:443" 2>/dev/null | get_cert_min_date_filter)"
TLS_LOCAL_MIN_DATE="$(cat "$ACME_LIVE_DIR/$ACME_DOMAIN/cert" | get_cert_min_date_filter)"
if [ "x$TLS_REMOTE_MIN_DATE" != "x" -a "x$TLS_LOCAL_MIN_DATE" != "x" ]; then
TLS_REMOTE_ZTIME="$(date --date="$TLS_REMOTE_MIN_DATE" +"%s" 2>/dev/null)"
TLS_LOCAL_ZTIME="$(date --date="$TLS_LOCAL_MIN_DATE" +"%s" 2>/dev/null)"
if [ "$TLS_REMOTE_ZTIME" -ne "$TLS_LOCAL_ZTIME" ]; then
DEBUGPRINT "Not-Before times differ between on-disk certificate ($TLS_LOCAL_MIN_DATE) and remote server certificate ($TLS_REMOTE_MIN_DATE)."
# times are different, maybe reload nginx?
# could be that the subjects are different, should probably check.
# cert serial is not suitable for this check because it will always be different if any field is different.
else
DEBUGPRINT "Not-Before times match for on-disk ($TLS_LOCAL_MIN_DATE) and remote server ($TLS_REMOTE_MIN_DATE) certificates."
fi
else
DEBUGPRINT "An error occurred getting the Not-Before date from either the on-disk ($TLS_LOCAL_MIN_DATE) or remote server ($TLS_REMOTE_MIN_DATE) certificate."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment