diff --git a/script_refresh-proxied-certs.sh b/script_refresh-proxied-certs.sh index f6bcaa6..76fdf10 100755 --- a/script_refresh-proxied-certs.sh +++ b/script_refresh-proxied-certs.sh @@ -6,6 +6,12 @@ # Typical arborescence is : # /etc/ssl/proxy-certs/www.foobar.com.crt # /etc/ssl/proxy-certs/www.foobar.com.key +# +# It supports RSA/ECDSA duo : +# /etc/ssl/proxy-certs/www.foobar.com.sigalg-rsa.crt +# /etc/ssl/proxy-certs/www.foobar.com.sigalg-rsa.key +# /etc/ssl/proxy-certs/www.foobar.com.sigalg-ecc.crt +# /etc/ssl/proxy-certs/www.foobar.com.sigalg-ecc.key # # note : don't forget to make the webserver reload the new certificates. @@ -15,37 +21,64 @@ set -e EXIT_STATUS=0 TMPFILE="$( mktemp )" -for i in *.crt; do - FQDN_HOSTNAME="$( echo $i | sed 's/\.crt$//' )" +for i in *.key; do + # Filename may be in the form : + # - www.foobar.com.key + # - www.foobar.com.sigalg-rsa.key + # - www.foobar.com.sigalg-ecc.key + BASENAME="$( echo "$i" | sed 's/\.key$//' )" + FQDN_HOSTNAME="$( echo "$BASENAME" | sed 's/\.sigalg-.*$//' )" + SIGALG="$( echo "$BASENAME" | sed -n 's/.*sigalg-\(.*\)$/\1/p' )" # 'rsa', 'ecc' or '' # We don't refresh when there is a certificate request: # those are locally served websites - if [ ! -f "$FQDN_HOSTNAME.csr" ] && [ "$FQDN_HOSTNAME.key" ]; then + if [ ! -f "$BASENAME.csr" ] && [ ! -f "$BASENAME.req" ]; then + # Prepare sigalg/ciphers options + case "$SIGALG" in + 'ecc') + SIGALG_OPTIONS="-tls1_2 -cipher ECDSA" + ;; + 'rsa') + SIGALG_OPTIONS="-tls1_2 -cipher RSA" + ;; + '') + SIGALG_OPTIONS="" + ;; + ?) + echo "ERROR: unknown sigalg." >&2 + EXIT_STATUS=1 + # This may not be critical. We continue, hoping for the best... + SIGALG_OPTIONS="" + ;; + esac + # Fetch the certificate from the origin server and store # in a temporary file. openssl s_client \ -showcerts \ -servername "$FQDN_HOSTNAME" \ - -connect "$FQDN_HOSTNAME:443" < /dev/null 2>/dev/null | \ + -connect "$FQDN_HOSTNAME:443" $SIGALG_OPTIONS < /dev/null 2>/dev/null | \ sed -n '/^-----BEGIN CERTIFICATE-----$/,/^-----END CERTIFICATE-----$/p' > "$TMPFILE" # Check that the new cert still match the local key # (it should also fail safely when the host wasn't reachable) - if [ "$( ( openssl x509 -noout -modulus -in "$TMPFILE"; openssl rsa -noout -modulus -in "$FQDN_HOSTNAME.key" ) | uniq | wc -l )" -ne 1 ]; then + if [ "$( openssl x509 -in "$TMPFILE" -pubkey -noout )" != "$( openssl pkey -in "$BASENAME.key" -pubout )" ]; then # Mismatch : raise an alert - echo "WARNING: retrieved certificate does not match '$FQDN_HOSTNAME.key'" >&2 + echo "WARNING: retrieved certificate does not match '$BASENAME.key'" >&2 EXIT_STATUS=1 else # Note: we try not to uselessly write and update the files' mtime, # but do it anyway if 'diff' is not available. - if ! which diff >/dev/null || ! diff -q "$FQDN_HOSTNAME.crt" "$TMPFILE" >/dev/null ; then + if [ ! -f "$BASENAME.crt" ] || ! which diff >/dev/null || ! diff -q "$BASENAME.crt" "$TMPFILE" >/dev/null ; then # Update the local certificate without changing ACL - cat "$TMPFILE" > "$FQDN_HOSTNAME.crt" + cat "$TMPFILE" > "$BASENAME.crt" fi fi fi +done - # While we are at it, let's check the expiry dates +# While we are at it, let's check the expiry dates +for i in *.crt; do if [ "$( date --date="$( openssl x509 -noout -dates -in "$i" | sed -n '/^notAfter/s/^notAfter=//p' )" +%s )" -lt "$(( $( date +%s ) + 86400 ))" ]; then echo "WARNING: certificate '$i' near or already expired." >&2 EXIT_STATUS=1