Merge branch 'dev' into master

This commit is contained in:
风扇滑翔翼
2026-01-02 14:52:10 +08:00
committed by GitHub
51 changed files with 3991 additions and 429 deletions

252
acme.sh
View File

@@ -1,6 +1,6 @@
#!/usr/bin/env sh
VER=3.1.2
VER=3.1.3
PROJECT_NAME="acme.sh"
@@ -23,9 +23,6 @@ _SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY"
CA_LETSENCRYPT_V2="https://acme-v02.api.letsencrypt.org/directory"
CA_LETSENCRYPT_V2_TEST="https://acme-staging-v02.api.letsencrypt.org/directory"
CA_BUYPASS="https://api.buypass.com/acme/directory"
CA_BUYPASS_TEST="https://api.test4.buypass.no/acme/directory"
CA_ZEROSSL="https://acme.zerossl.com/v2/DV90"
_ZERO_EAB_ENDPOINT="https://api.zerossl.com/acme/eab-credentials-email"
@@ -35,6 +32,8 @@ CA_SSLCOM_ECC="https://acme.ssl.com/sslcom-dv-ecc"
CA_GOOGLE="https://dv.acme-v02.api.pki.goog/directory"
CA_GOOGLE_TEST="https://dv.acme-v02.test-api.pki.goog/directory"
CA_ACTALIS="https://acme-api.actalis.com/acme/directory"
DEFAULT_CA=$CA_ZEROSSL
DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST
@@ -42,14 +41,13 @@ CA_NAMES="
ZeroSSL.com,zerossl
LetsEncrypt.org,letsencrypt
LetsEncrypt.org_test,letsencrypt_test,letsencrypttest
BuyPass.com,buypass
BuyPass.com_test,buypass_test,buypasstest
SSL.com,sslcom
Google.com,google
Google.com_test,googletest,google_test
Actalis.com,actalis.com,actalis
"
CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_BUYPASS,$CA_BUYPASS_TEST,$CA_SSLCOM_RSA,$CA_GOOGLE,$CA_GOOGLE_TEST"
CA_SERVERS="$CA_ZEROSSL,$CA_LETSENCRYPT_V2,$CA_LETSENCRYPT_V2_TEST,$CA_SSLCOM_RSA,$CA_GOOGLE,$CA_GOOGLE_TEST,$CA_ACTALIS"
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
@@ -67,7 +65,7 @@ ID_TYPE_IP="ip"
LOCAL_ANY_ADDRESS="0.0.0.0"
DEFAULT_RENEW=60
DEFAULT_RENEW=30
NO_VALUE="no"
@@ -180,6 +178,8 @@ _VALIDITY_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Validity"
_DNSCHECK_WIKI="https://github.com/acmesh-official/acme.sh/wiki/dnscheck"
_PROFILESELECTION_WIKI="https://github.com/acmesh-official/acme.sh/wiki/Profile-selection"
_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead."
_DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR"
@@ -436,14 +436,28 @@ _secure_debug3() {
fi
}
__USE_TR_TAG=""
if [ "$(echo "abc" | LANG=C tr a-z A-Z 2>/dev/null)" != "ABC" ]; then
__USE_TR_TAG="1"
fi
export __USE_TR_TAG
_upper_case() {
# shellcheck disable=SC2018,SC2019
tr '[a-z]' '[A-Z]'
if [ "$__USE_TR_TAG" ]; then
LANG=C tr '[:lower:]' '[:upper:]'
else
# shellcheck disable=SC2018,SC2019
LANG=C tr '[a-z]' '[A-Z]'
fi
}
_lower_case() {
# shellcheck disable=SC2018,SC2019
tr '[A-Z]' '[a-z]'
if [ "$__USE_TR_TAG" ]; then
LANG=C tr '[:upper:]' '[:lower:]'
else
# shellcheck disable=SC2018,SC2019
LANG=C tr '[A-Z]' '[a-z]'
fi
}
_startswith() {
@@ -1017,7 +1031,7 @@ _digest() {
outputhex="$2"
if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
if [ "$alg" = "sha3-256" ] || [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
if [ "$outputhex" ]; then
${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
else
@@ -1236,7 +1250,7 @@ _idn() {
fi
}
#_createcsr cn san_list keyfile csrfile conf acmeValidationv1
#_createcsr cn san_list keyfile csrfile conf acmeValidationv1 extendedUsage
_createcsr() {
_debug _createcsr
domain="$1"
@@ -1245,6 +1259,7 @@ _createcsr() {
csr="$4"
csrconf="$5"
acmeValidationv1="$6"
extusage="$7"
_debug2 domain "$domain"
_debug2 domainlist "$domainlist"
_debug2 csrkey "$csrkey"
@@ -1253,9 +1268,8 @@ _createcsr() {
printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]" >"$csrconf"
if [ "$Le_ExtKeyUse" ]; then
_savedomainconf Le_ExtKeyUse "$Le_ExtKeyUse"
printf "\nextendedKeyUsage=$Le_ExtKeyUse\n" >>"$csrconf"
if [ "$extusage" ]; then
printf "\nextendedKeyUsage=$extusage\n" >>"$csrconf"
else
printf "\nextendedKeyUsage=serverAuth,clientAuth\n" >>"$csrconf"
fi
@@ -1811,6 +1825,10 @@ _time() {
# 2022-04-01 08:10:33 to 1648800633
#or 2022-04-01T08:10:33Z to 1648800633
_date2time() {
#Mac/BSD
if date -u -j -f "%Y-%m-%d %H:%M:%S" "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return
fi
#Linux
if date -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return
@@ -1820,10 +1838,6 @@ _date2time() {
if gdate -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return
fi
#Mac/BSD
if date -u -j -f "%Y-%m-%d %H:%M:%S" "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return
fi
#Omnios
if python3 -c "import datetime; print(int(datetime.datetime.strptime(\"$1\", \"%Y-%m-%d %H:%M:%S\").replace(tzinfo=datetime.timezone.utc).timestamp()))" 2>/dev/null; then
return
@@ -1883,6 +1897,11 @@ _inithttp() {
if [ -z "$_ACME_CURL" ] && _exists "curl"; then
_ACME_CURL="curl --silent --dump-header $HTTP_HEADER "
if [ "$ACME_USE_IPV6_REQUESTS" ]; then
_ACME_CURL="$_ACME_CURL --ipv6 "
elif [ "$ACME_USE_IPV4_REQUESTS" ]; then
_ACME_CURL="$_ACME_CURL --ipv4 "
fi
if [ -z "$ACME_HTTP_NO_REDIRECTS" ]; then
_ACME_CURL="$_ACME_CURL -L "
fi
@@ -1910,6 +1929,11 @@ _inithttp() {
if [ -z "$_ACME_WGET" ] && _exists "wget"; then
_ACME_WGET="wget -q"
if [ "$ACME_USE_IPV6_REQUESTS" ]; then
_ACME_WGET="$_ACME_WGET --inet6-only "
elif [ "$ACME_USE_IPV4_REQUESTS" ]; then
_ACME_WGET="$_ACME_WGET --inet4-only "
fi
if [ "$ACME_HTTP_NO_REDIRECTS" ]; then
_ACME_WGET="$_ACME_WGET --max-redirect 0 "
fi
@@ -2538,15 +2562,19 @@ _startserver() {
_NC="socat"
if [ "$Le_Listen_V6" ]; then
_NC="$_NC -6"
else
SOCAT_OPTIONS=TCP6-LISTEN
elif [ "$Le_Listen_V4" ]; then
_NC="$_NC -4"
SOCAT_OPTIONS=TCP4-LISTEN
else
SOCAT_OPTIONS=TCP-LISTEN
fi
if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then
_NC="$_NC -d -d -v"
fi
SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork
SOCAT_OPTIONS=$SOCAT_OPTIONS:$Le_HTTPPort,crlf,reuseaddr,fork
#Adding bind to local-address
if [ "$ncaddr" ]; then
@@ -2755,6 +2783,7 @@ _clearAPI() {
ACME_REVOKE_CERT=""
ACME_NEW_NONCE=""
ACME_AGREEMENT=""
ACME_RENEWAL_INFO=""
}
#server
@@ -2799,6 +2828,9 @@ _initAPI() {
ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3)
export ACME_AGREEMENT
ACME_RENEWAL_INFO=$(echo "$response" | _egrep_o 'renewalInfo" *: *"[^"]*"' | cut -d '"' -f 3)
export ACME_RENEWAL_INFO
_debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE"
_debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ"
_debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER"
@@ -2806,6 +2838,7 @@ _initAPI() {
_debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT"
_debug "ACME_AGREEMENT" "$ACME_AGREEMENT"
_debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE"
_debug "ACME_RENEWAL_INFO" "$ACME_RENEWAL_INFO"
if [ "$ACME_NEW_ACCOUNT" ] && [ "$ACME_NEW_ORDER" ]; then
return 0
fi
@@ -4416,6 +4449,8 @@ issue() {
_preferred_chain="${15}"
_valid_from="${16}"
_valid_to="${17}"
_certificate_profile="${18}"
_extended_key_usage="${19}"
if [ -z "$_ACME_IS_RENEW" ]; then
_initpath "$_main_domain" "$_key_length"
@@ -4491,6 +4526,11 @@ issue() {
else
_cleardomainconf "Le_Preferred_Chain"
fi
if [ "$_certificate_profile" ]; then
_savedomainconf "Le_Certificate_Profile" "$_certificate_profile"
else
_cleardomainconf "Le_Certificate_Profile"
fi
Le_API="$ACME_DIRECTORY"
_savedomainconf "Le_API" "$Le_API"
@@ -4555,12 +4595,25 @@ issue() {
return 1
fi
fi
if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then
_keyusage="$_extended_key_usage"
if [ "$Le_API" = "$CA_GOOGLE" ] || [ "$Le_API" = "$CA_GOOGLE_TEST" ]; then
if [ -z "$_keyusage" ]; then
#https://github.com/acmesh-official/acme.sh/issues/6610
#google accepts serverauth only
_keyusage="serverAuth"
fi
fi
if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" "" "$_keyusage"; then
_err "Error creating CSR."
_clearup
_on_issue_err "$_post_hook"
return 1
fi
if [ "$_extended_key_usage" ]; then
_savedomainconf "Le_ExtKeyUse" "$_extended_key_usage"
else
_cleardomainconf "Le_ExtKeyUse"
fi
fi
_savedomainconf "Le_Keylength" "$_key_length"
@@ -4623,6 +4676,9 @@ issue() {
if [ "$_notAfter" ]; then
_newOrderObj="$_newOrderObj,\"notAfter\": \"$_notAfter\""
fi
if [ "$_certificate_profile" ]; then
_newOrderObj="$_newOrderObj,\"profile\": \"$_certificate_profile\""
fi
_debug "STEP 1, Ordering a Certificate"
if ! _send_signed_request "$ACME_NEW_ORDER" "$_newOrderObj}"; then
_err "Error creating new order."
@@ -5191,6 +5247,16 @@ $_authorizations_map"
return 1
fi
break
elif _contains "$response" "\"ready\""; then
_info "Order status is 'ready', let's sleep and retry."
_retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *:" | cut -d : -f 2 | tr -d ' ' | tr -d '\r')
_debug "_retryafter" "$_retryafter"
if [ "$_retryafter" ]; then
_info "Sleeping for $_retryafter seconds then retrying"
_sleep $_retryafter
else
_sleep 2
fi
elif _contains "$response" "\"processing\""; then
_info "Order status is 'processing', let's sleep and retry."
_retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *:" | cut -d : -f 2 | tr -d ' ' | tr -d '\r')
@@ -5460,10 +5526,6 @@ renew() {
_info "Switching back to $CA_LETSENCRYPT_V2"
Le_API="$CA_LETSENCRYPT_V2"
;;
"$CA_BUYPASS_TEST")
_info "Switching back to $CA_BUYPASS"
Le_API="$CA_BUYPASS"
;;
"$CA_GOOGLE_TEST")
_info "Switching back to $CA_GOOGLE"
Le_API="$CA_GOOGLE"
@@ -5505,6 +5567,7 @@ renew() {
Le_PostHook="$(_readdomainconf Le_PostHook)"
Le_RenewHook="$(_readdomainconf Le_RenewHook)"
Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)"
Le_Certificate_Profile="$(_readdomainconf Le_Certificate_Profile)"
# When renewing from an old version, the empty Le_Keylength means 2048.
# Note, do not use DEFAULT_DOMAIN_KEY_LENGTH as that value may change over
# time but an empty value implies 2048 specifically.
@@ -5519,7 +5582,7 @@ renew() {
_cleardomainconf Le_OCSP_Staple
fi
fi
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain" "$Le_Valid_From" "$Le_Valid_To"
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress" "$Le_ChallengeAlias" "$Le_Preferred_Chain" "$Le_Valid_From" "$Le_Valid_To" "$Le_Certificate_Profile" "$Le_ExtKeyUse"
res="$?"
if [ "$res" != "0" ]; then
return "$res"
@@ -5780,9 +5843,9 @@ list() {
_sep="|"
if [ "$_raw" ]; then
if [ -z "$_domain" ]; then
printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}CA${_sep}Created${_sep}Renew"
printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Profile${_sep}CA${_sep}Created${_sep}Renew"
fi
for di in "${CERT_HOME}"/*.*/; do
for di in "${CERT_HOME}"/{*.*,*:*}/; do
d=$(basename "$di")
_debug d "$d"
(
@@ -5795,7 +5858,7 @@ list() {
. "$DOMAIN_CONF"
_ca="$(_getCAShortName "$Le_API")"
if [ -z "$_domain" ]; then
printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$_ca${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr"
printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_Certificate_Profile${_sep}$_ca${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr"
else
if [ "$_domain" = "$d" ]; then
cat "$DOMAIN_CONF"
@@ -5814,6 +5877,48 @@ list() {
}
list_profiles() {
_initpath
_initAPI
_l_server_url="$ACME_DIRECTORY"
_l_server_name="$(_getCAShortName "$_l_server_url")"
_info "Fetching profiles from $_l_server_name ($_l_server_url)..."
response=$(_get "$_l_server_url" "" 10)
if [ "$?" != "0" ]; then
_err "Failed to connect to CA directory: $_l_server_url"
return 1
fi
normalized_response=$(echo "$response" | _normalizeJson)
profiles_json=$(echo "$normalized_response" | _egrep_o '"profiles" *: *\{[^\}]*\}')
if [ -z "$profiles_json" ]; then
_info "The CA '$_l_server_name' does not publish certificate profiles via its directory endpoint."
return 0
fi
# Strip the outer layer to get the key-value pairs
profiles_kv=$(echo "$profiles_json" | sed 's/"profiles" *: *{//' | sed 's/}$//' | tr ',' '\n')
printf "\n%-15s %s\n" "name" "info"
printf -- "--------------------------------------------------------------------\n"
_old_IFS="$IFS"
IFS='
'
for pair in $profiles_kv; do
# Trim quotes and whitespace
_name=$(echo "$pair" | cut -d: -f1 | tr -d '" \t')
_info_url=$(echo "$pair" | cut -d: -f2- | sed 's/^ *//' | tr -d '"')
printf "%-15s %s\n" "$_name" "$_info_url"
done
IFS="$_old_IFS"
return 0
}
_deploy() {
_d="$1"
_hooks="$2"
@@ -6437,6 +6542,36 @@ deactivate() {
done
}
#cert
_getAKI() {
_cert="$1"
openssl x509 -in "$_cert" -text -noout | grep "X509v3 Authority Key Identifier" -A 1 | _tail_n 1 | tr -d ' :'
}
#cert
_getSerial() {
_cert="$1"
openssl x509 -in "$_cert" -serial -noout | cut -d = -f 2
}
#cert
_get_ARI() {
_cert="$1"
_aki=$(_getAKI "$_cert")
_ser=$(_getSerial "$_cert")
_debug2 "_aki" "$_aki"
_debug2 "_ser" "$_ser"
_akiurl="$(echo "$_aki" | _h2b | _base64 | tr -d = | _url_encode)"
_debug2 "_akiurl" "$_akiurl"
_serurl="$(echo "$_ser" | _h2b | _base64 | tr -d = | _url_encode)"
_debug2 "_serurl" "$_serurl"
_ARI_URL="$ACME_RENEWAL_INFO/$_akiurl.$_serurl"
_get "$_ARI_URL"
}
# Detect profile file if not specified as environment variable
_detect_profile() {
if [ -n "$PROFILE" -a -f "$PROFILE" ]; then
@@ -6992,6 +7127,9 @@ Parameters:
If no match, the default offered chain will be used. (default: empty)
See: $_PREFERRED_CHAIN_WIKI
--cert-profile, --certificate-profile <profile> If the CA offers profiles, select the desired profile
See: $_PROFILESELECTION_WIKI
--valid-to <date-time> Request the NotAfter field of the cert.
See: $_VALIDITY_WIKI
--valid-from <date-time> Request the NotBefore field of the cert.
@@ -7068,6 +7206,8 @@ Parameters:
--auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. Defaults to 1 if argument is omitted.
--listen-v4 Force standalone/tls server to listen at ipv4.
--listen-v6 Force standalone/tls server to listen at ipv6.
--request-v4 Force client requests to use ipv4 to connect to the CA server.
--request-v6 Force client requests to use ipv6 to connect to the CA server.
--openssl-bin <file> Specifies a custom openssl bin location.
--use-wget Force to use wget, if you have both curl and wget installed.
--yes-I-know-dns-manual-mode-enough-go-ahead-please Force use of dns manual mode.
@@ -7186,6 +7326,24 @@ _processAccountConf() {
_saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET"
fi
if [ "$_request_v6" ]; then
_saveaccountconf "ACME_USE_IPV6_REQUESTS" "$_request_v6"
_clearaccountconf "ACME_USE_IPV4_REQUESTS"
ACME_USE_IPV4_REQUESTS=
elif [ "$_request_v4" ]; then
_saveaccountconf "ACME_USE_IPV4_REQUESTS" "$_request_v4"
_clearaccountconf "ACME_USE_IPV6_REQUESTS"
ACME_USE_IPV6_REQUESTS=
elif [ "$ACME_USE_IPV6_REQUESTS" ]; then
_saveaccountconf "ACME_USE_IPV6_REQUESTS" "$ACME_USE_IPV6_REQUESTS"
_clearaccountconf "ACME_USE_IPV4_REQUESTS"
ACME_USE_IPV4_REQUESTS=
elif [ "$ACME_USE_IPV4_REQUESTS" ]; then
_saveaccountconf "ACME_USE_IPV4_REQUESTS" "$ACME_USE_IPV4_REQUESTS"
_clearaccountconf "ACME_USE_IPV6_REQUESTS"
ACME_USE_IPV6_REQUESTS=
fi
}
_checkSudo() {
@@ -7351,6 +7509,8 @@ _process() {
_local_address=""
_log_level=""
_auto_upgrade=""
_request_v4=""
_request_v6=""
_listen_v4=""
_listen_v6=""
_openssl_bin=""
@@ -7367,6 +7527,8 @@ _process() {
_preferred_chain=""
_valid_from=""
_valid_to=""
_certificate_profile=""
_extended_key_usage=""
while [ ${#} -gt 0 ]; do
case "${1}" in
@@ -7470,6 +7632,9 @@ _process() {
--set-default-chain)
_CMD="setdefaultchain"
;;
--list-profiles)
_CMD="list_profiles"
;;
-d | --domain)
_dvalue="$2"
@@ -7685,6 +7850,10 @@ _process() {
_valid_to="$2"
shift
;;
--certificate-profile | --cert-profile)
_certificate_profile="$2"
shift
;;
--httpport)
_httpport="$2"
Le_HTTPPort="$_httpport"
@@ -7755,7 +7924,7 @@ _process() {
shift
;;
--extended-key-usage)
Le_ExtKeyUse="$2"
_extended_key_usage="$2"
shift
;;
--ocsp-must-staple | --ocsp)
@@ -7808,6 +7977,18 @@ _process() {
fi
AUTO_UPGRADE="$_auto_upgrade"
;;
--request-v4)
_request_v4="1"
ACME_USE_IPV4_REQUESTS="1"
_request_v6=""
ACME_USE_IPV6_REQUESTS=""
;;
--request-v6)
_request_v6="1"
ACME_USE_IPV6_REQUESTS="1"
_request_v4=""
ACME_USE_IPV4_REQUESTS=""
;;
--listen-v4)
_listen_v4="1"
Le_Listen_V4="$_listen_v4"
@@ -7960,7 +8141,7 @@ _process() {
uninstall) uninstall "$_nocron" ;;
upgrade) upgrade ;;
issue)
issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" "$_valid_from" "$_valid_to"
issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" "$_valid_from" "$_valid_to" "$_certificate_profile" "$_extended_key_usage"
;;
deploy)
deploy "$_domain" "$_deploy_hook" "$_ecc"
@@ -8031,6 +8212,9 @@ _process() {
setdefaultchain)
setdefaultchain "$_preferred_chain"
;;
list_profiles)
list_profiles
;;
*)
if [ "$_CMD" ]; then
_err "Invalid command: $_CMD"