#!/bin/sh # Wrapper for uacme to work on openwrt. set -u ACME=/usr/sbin/uacme HPROGRAM=/usr/share/uacme/uacme.sh LOG_TAG=acme-uacme NOTIFY=/usr/lib/acme/notify HOOKDIR=/usr/lib/acme # shellcheck source=net/acme/files/functions.sh . /usr/lib/acme/functions.sh link_certs() { local main_domain local domain_dir domain_dir="$1" main_domain="$2" #uacme saves only fullchain as cert.pem ( umask 077 cat "$domain_dir/cert.pem" "$state_dir/private/$main_domain/key.pem" >"$domain_dir/combined.cer" sed -n '1,/-----END CERTIFICATE-----/p' "$domain_dir/cert.pem" >"$domain_dir/leaf_cert.pem" sed '1,/-----END CERTIFICATE-----/d' "$domain_dir/cert.pem" >"$domain_dir/chain.crt" ) if [ ! -e "$CERT_DIR/$main_domain.crt" ]; then ln -s "$domain_dir/leaf_cert.pem" "$CERT_DIR/$main_domain.crt" fi #uacme doesn't rotate key, and it saves ../private/$main_domain dir if [ ! -e "$CERT_DIR/$main_domain.key" ]; then ln -s "$state_dir/private/$main_domain/key.pem" "$CERT_DIR/$main_domain.key" fi if [ ! -e "$CERT_DIR/$main_domain.fullchain.crt" ]; then ln -s "$domain_dir/cert.pem" "$CERT_DIR/$main_domain.fullchain.crt" fi if [ ! -e "$CERT_DIR/$main_domain.combined.crt" ]; then ln -s "$domain_dir/combined.cer" "$CERT_DIR/$main_domain.combined.crt" fi if [ ! -e "$CERT_DIR/$main_domain.chain.crt" ]; then ln -s "$domain_dir/chain.crt" "$CERT_DIR/$main_domain.chain.crt" fi } #expand acme server short alias case $acme_server in letsencrypt) unset acme_server ;; letsencrypt_test) acme_server=https://acme-staging-v02.api.letsencrypt.org/directory ;; zerossl) acme_server=https://acme.zerossl.com/v2/DV90 ;; google) acme_server=https://dv.acme-v02.api.pki.goog/directory ;; actalis) acme_server=https://acme-api.actalis.com/acme/directory ;; *) ;; esac case $1 in get) #uacme doesn't save account per ca nor it make new account when not registered #while server doesn't care, we record which CAs we have account to reduce noise #using staging var for default letsencrypts. if grep -q "^${acme_server:-$staging}$" $state_dir/accounts; then : else #not found if [ "$acme_server" ]; then $ACME new $account_email -t EC -y --confdir "$state_dir" -a $acme_server echo $acme_server >> $state_dir/accounts elif [ "$staging" = 1 ]; then $ACME new $account_email -t EC -y --confdir "$state_dir" -s echo $staging >> $state_dir/accounts else $ACME new $account_email -t EC -y --confdir "$state_dir" echo $staging >> $state_dir/accounts fi fi set -- [ "$debug" = 1 ] && set -- "$@" -v case $key_type in ec*) keylength=${key_type#ec} domain_dir="$state_dir/$main_domain" set -- "$@" -t EC ;; rsa*) keylength=${key_type#rsa} domain_dir="$state_dir/$main_domain" ;; esac set -- "$@" --bits "$keylength" if [ "$acme_server" ]; then set -- "$@" --acme-url "$acme_server" elif [ "$staging" = 1 ]; then set -- "$@" --staging else set -- "$@" fi log info "Running ACME for $main_domain with validation_method $validation_method" staging_moved=0 is_renew=0 if [ -e "$domain_dir" ]; then if [ "$staging" = 0 ] && [ -e $domain_dir/this_is_staging ]; then mv "$domain_dir" "$domain_dir.staging" mv "$state_dir/private/$main_domain" "$state_dir/private/$main_domain.staging" log info "Certificates are previously issued from a staging server, but staging option is disabled, moved to $domain_dir.staging." staging_moved=1 else #this is renewal is_renew=1 fi else log info no prv certificate remembered fi if [ "$days" ]; then set -- "$@" --days "$days" fi if [ "$cert_profile" ]; then set -- "$@" --profile "$cert_profile" fi # uacme handles challange select by hook script case "$validation_method" in "alpn") log info "using already running ualpn, it's user's duty to config ualpn server deamon" set -- "$@" -h "$HOOKDIR/client/ualpn.sh" ;; "dns") export dns set -- "$@" -h "$HOOKDIR/client/dnschalhook.sh" if [ "$dalias" ]; then export dalias if [ "$calias" ]; then log err "Both domain and challenge aliases are defined. Ignoring the challenge alias." fi elif [ "$calias" ]; then export calias fi if [ "$dns_wait" ]; then export dns_wait fi ;; "dns-persist") set -- "$@" -h "$HOOKDIR/client/dns_persist.sh" ;; "standalone") set -- "$@" --standalone --listen-v6 log err "standalone server is not implmented for uacme" exit 1 ;; "webroot") mkdir -p "$CHALLENGE_DIR" export CHALLENGE_DIR set -- "$@" -h "$HOOKDIR/client/httpchalhook.sh" ;; *) log err "Unsupported validation_method $validation_method" ;; esac set -- "$@" --confdir "$state_dir" issue for d in $domains; do set -- "$@" "$d" done log info "$ACME $*" trap '$NOTIFY issue-failed;exit 1' INT "$ACME" "$@" -k 2>&1 status=$? trap - INT case $status in 0) link_certs "$domain_dir" "$main_domain" if [ "$is_renew" = 1 ]; then $NOTIFY renewed else $NOTIFY issued if [ "$staging" = 1 ]; then touch $domain_dir/this_is_staging fi fi ;; 1) #cert is not due to renewl so don't do anything if [ "$staging_moved" = 1 ]; then log err "Staging certificate '$domain_dir' restored" mv "$domain_dir.staging" "$domain_dir" fi log debug "not due to renewal" ;; *) if [ "$is_renew" = 1 ]; then $NOTIFY renew-failed exit 1; fi if [ "$staging_moved" = 1 ]; then log err "Staging certificate '$domain_dir' restored" mv "$domain_dir.staging" "$domain_dir" mv "$state_dir/private/$main_domain.staging" "$state_dir/private/$main_domain" elif [ -d "$domain_dir" ]; then failed_dir="$domain_dir.failed-$(date +%s)" mv "$domain_dir" "$failed_dir" log err "State moved to $failed_dir" fi $NOTIFY issue-failed ;; esac ;; esac