#!/bin/bash declare -rg CERT_KEY_FILE="/etc/lighttpd/server.pem" declare -rg PUB_CERT_FILE="/etc/lighttpd/pub-cert.pem" declare -rg CHAIN_FILE="/etc/lighttpd/chain.pem" declare -rg REDIR_FLAG="/etc/lighttpd/redirect.flag" declare -rg RELOAD_FLAG="/home/taskmanager/acme-reload" declare -rg ACME_KEY="/home/taskmanager/certs/key.pem" declare -rg ACME_FULLCHAIN="/home/taskmanager/certs/fullchain.pem" declare -rg WWW="/srv/openslx/www" declare -rga acme_common=( -w "$WWW" --key-file "$ACME_KEY" --fullchain-file "$ACME_FULLCHAIN" --reloadcmd "touch '$RELOAD_FLAG'" ) declare -a tmpfiles= trap 'rm -rf -- "${tmpfiles[@]}"' EXIT is_readable () { [ -r "$1" ] && [ -f "$1" ] && return 0 echo "Not a file, or not readable: $1" return 1 } op_disable () { [ -e "$CERT_KEY_FILE" ] || exit 0 rm -f -- "$CERT_KEY_FILE" || exit 1 rm -f -- "$CHAIN_FILE" "$PUB_CERT_FILE" } op_test () { [ $# -eq 2 ] || exit 1 local K=$1 local C=$2 is_readable "$K" || exit 2 is_readable "$C" || exit 3 # Encrypt something, then decrypt again and compare local TEST_IN=$(mktemp --tmpdir bwlp-XXXXXXXX) [ -z "$TEST_IN" ] && exit 4 tmpfiles+=( "$TEST_IN" ) date > "$TEST_IN" # Try to sign something - output doesn't matter, this is only to check if cert and key match openssl smime -sign -in "$TEST_IN" -out /dev/null -signer "$C" -inkey "$K" || exit 7 exit 0 # No restart either way } op_import () { [ $# -lt 2 ] && exit 1 local K=$1 local C=$2 local CHAIN=$3 is_readable "$K" || exit 2 is_readable "$C" || exit 3 rm -f -- "$CHAIN_FILE" # Create server.pem { cat "$C" # If we have a chainfile, try to use it aswell if [ -s "$CHAIN" ] && openssl x509 -noout -hash -in "$CHAIN" &> /dev/null \ && [ "$( grep -c '^-----END' "$CHAIN" )" = "$( grep -c '^-----BEGIN' "$CHAIN" )" ]; then echo cat "$CHAIN" fi echo cat "$K" } > "$CERT_KEY_FILE" chmod 0600 "$CERT_KEY_FILE" || exit 4 post_setup_hook return 0 } op_acme_issue () { [ $# -lt 3 ] && exit 1 local i local provider="$1" local mail="$2" shift 2 declare -a domains=() set -x for i; do domains+=( -d "$i" ) done rm -f -- "$RELOAD_FLAG" if [ -n "$ACME_WIPE" ]; then rm -rf -- /home/taskmanager/.acme.sh/* rm -rf -- /home/taskmanager/certs/* touch /home/taskmanager/.acme.sh/account.conf chown taskmanager:taskmanager /home/taskmanager/.acme.sh/account.conf else rm -rf -- /home/taskmanager/.acme.sh/???*.* rm -rf -- /home/taskmanager/certs/* fi mkdir -p "$WWW/.well-known/acme-challenge" chown taskmanager:taskmanager "$WWW/.well-known/acme-challenge" chmod 0700 /home/taskmanager/certs if [ -n "$ACME_KEY_ID" ] && [ -n "$ACME_HMAC_KEY" ]; then sudo -u taskmanager -n ACCOUNT_EMAIL="$mail" \ /opt/openslx/acme.sh --register-account --server "$provider" --eab-kid "$ACME_KEY_ID" --eab-hmac-key "$ACME_HMAC_KEY" fi tmpfiles+=( "$RELOAD_FLAG" ) sudo -u taskmanager -n ACCOUNT_EMAIL="$mail" \ /opt/openslx/acme.sh --server "$provider" --issue "${domains[@]}" "${acme_common[@]}" i=$? if [ -e "$RELOAD_FLAG" ]; then # Renew must have happened op_import "$ACME_KEY" "$ACME_FULLCHAIN" return 0 fi # No reload in other case, exit exit "$i" } op_acme_renew () { mkdir -p "$WWW/.well-known/acme-challenge" chown taskmanager:taskmanager "$WWW/.well-known/acme-challenge" rm -f -- "$RELOAD_FLAG" tmpfiles+=( "$RELOAD_FLAG" ) sudo -u taskmanager -n /opt/openslx/acme.sh --renew --domain "$1" "${acme_common[@]}" i=$? (( i == 2 )) && i=0 if (( i != 0 )) || ! [ -e "$ACME_FULLCHAIN" ] || ! [ -e "$ACME_KEY" ] \ || ! openssl x509 -checkend 600 -in "$ACME_FULLCHAIN"; then sudo -u taskmanager -n /opt/openslx/acme.sh --renew --force --domain "$1" "${acme_common[@]}" i=$? fi if [ -e "$RELOAD_FLAG" ]; then # Renew must have happened op_import "$ACME_KEY" "$ACME_FULLCHAIN" return 0 fi # No reload in other case, exit exit "$i" } op_acme_try_enable () { [ -s "$ACME_KEY" ] || exit 1 [ -s "$ACME_FULLCHAIN" ] || exit 2 openssl x509 -checkend 600 -noout -in "$ACME_FULLCHAIN" || exit 3 ( op_test "$ACME_KEY" "$ACME_FULLCHAIN" ) || exit 4 op_import "$ACME_KEY" "$ACME_FULLCHAIN" } op_random () { [ -z "$1" ] && exit 1 rm -f -- "$CHAIN_FILE" openssl req -x509 -new -newkey rsa:4096 -keyout "$CERT_KEY_FILE" -out "$CERT_KEY_FILE" -days 5000 -nodes -subj "/C=DE/ST=Nowhere/L=Springfield/O=bwLehrpool/CN=$1" || exit 2 chmod 0600 "$CERT_KEY_FILE" || exit 3 post_setup_hook return 0 } post_setup_hook () { rm -f -- "$PUB_CERT_FILE" openssl x509 -outform pem -in "$CERT_KEY_FILE" -out "$PUB_CERT_FILE" } setup_redirect () { if [ -n "$REDIR" ]; then touch "$REDIR_FLAG" else rm -f -- "$REDIR_FLAG" fi } ACME_KEY_ID= ACME_HMAC_KEY= ACME_WIPE= RE_ONLY= REDIR= while true; do case "$1" in --redirect-only) RE_ONLY=tru ;; --redirect) REDIR=truh ;; --acme-wipe) ACME_WIPE=1 ;; --acme-key-id) ACME_KEY_ID="$2" shift ;; --acme-hmac-key) ACME_HMAC_KEY="$2" shift ;; *) break ;; esac shift done setup_redirect if [ -z "$RE_ONLY" ]; then OP=$1 shift case "$OP" in --random) op_random "$@" ;; --test) op_test "$@" ;; --import) tmpfiles+=( "$@" ) op_import "$@" ;; --disable) op_disable ;; --acme-issue) op_acme_issue "$@" ;; --acme-renew) op_acme_renew "$@" ;; --acme-try-enable) op_acme_try_enable ;; *) echo "Invalid operation: $1" exit 1 ;; esac fi ( sleep .5 systemctl restart lighttpd ) & exit 0