acme.sh script has been updated to v3.1.3

This commit is contained in:
2026-02-16 17:10:54 +01:00
parent 89b86d0988
commit 3963be4ce5
2 changed files with 362 additions and 78 deletions

BIN
.metadata

Binary file not shown.

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env sh #!/usr/bin/env sh
VER=3.0.8 VER=3.1.3
PROJECT_NAME="acme.sh" 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="https://acme-v02.api.letsencrypt.org/directory"
CA_LETSENCRYPT_V2_TEST="https://acme-staging-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" CA_ZEROSSL="https://acme.zerossl.com/v2/DV90"
_ZERO_EAB_ENDPOINT="https://api.zerossl.com/acme/eab-credentials-email" _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="https://dv.acme-v02.api.pki.goog/directory"
CA_GOOGLE_TEST="https://dv.acme-v02.test-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_CA=$CA_ZEROSSL
DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST DEFAULT_STAGING_CA=$CA_LETSENCRYPT_V2_TEST
@@ -42,14 +41,13 @@ CA_NAMES="
ZeroSSL.com,zerossl ZeroSSL.com,zerossl
LetsEncrypt.org,letsencrypt LetsEncrypt.org,letsencrypt
LetsEncrypt.org_test,letsencrypt_test,letsencrypttest LetsEncrypt.org_test,letsencrypt_test,letsencrypttest
BuyPass.com,buypass
BuyPass.com_test,buypass_test,buypasstest
SSL.com,sslcom SSL.com,sslcom
Google.com,google Google.com,google
Google.com_test,googletest,google_test 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)" DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
@@ -67,7 +65,7 @@ ID_TYPE_IP="ip"
LOCAL_ANY_ADDRESS="0.0.0.0" LOCAL_ANY_ADDRESS="0.0.0.0"
DEFAULT_RENEW=60 DEFAULT_RENEW=30
NO_VALUE="no" 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" _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_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" _DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR"
@@ -250,6 +250,13 @@ _dlg_versions() {
socat -V 2>&1 socat -V 2>&1
else else
_debug "socat doesn't exist." _debug "socat doesn't exist."
if _exists "python3"; then
python3 -V 2>&1
elif _exists "python2"; then
python2 -V 2>&1
elif _exists "python"; then
python -V 2>&1
fi
fi fi
} }
@@ -436,14 +443,28 @@ _secure_debug3() {
fi 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() { _upper_case() {
if [ "$__USE_TR_TAG" ]; then
LANG=C tr '[:lower:]' '[:upper:]'
else
# shellcheck disable=SC2018,SC2019 # shellcheck disable=SC2018,SC2019
tr '[a-z]' '[A-Z]' LANG=C tr '[a-z]' '[A-Z]'
fi
} }
_lower_case() { _lower_case() {
if [ "$__USE_TR_TAG" ]; then
LANG=C tr '[:upper:]' '[:lower:]'
else
# shellcheck disable=SC2018,SC2019 # shellcheck disable=SC2018,SC2019
tr '[A-Z]' '[a-z]' LANG=C tr '[A-Z]' '[a-z]'
fi
} }
_startswith() { _startswith() {
@@ -672,8 +693,10 @@ _hex_dump() {
#0 1 2 3 4 5 6 7 8 9 - _ . ~ #0 1 2 3 4 5 6 7 8 9 - _ . ~
#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e #30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e
#_url_encode [upper-hex] the encoded hex will be upper-case if the argument upper-hex is followed
#stdin stdout #stdin stdout
_url_encode() { _url_encode() {
_upper_hex=$1
_hex_str=$(_hex_dump) _hex_str=$(_hex_dump)
_debug3 "_url_encode" _debug3 "_url_encode"
_debug3 "_hex_str" "$_hex_str" _debug3 "_hex_str" "$_hex_str"
@@ -883,6 +906,9 @@ _url_encode() {
;; ;;
#other hex #other hex
*) *)
if [ "$_upper_hex" = "upper-hex" ]; then
_hex_code=$(printf "%s" "$_hex_code" | _upper_case)
fi
printf '%%%s' "$_hex_code" printf '%%%s' "$_hex_code"
;; ;;
esac esac
@@ -916,6 +942,9 @@ _sed_i() {
if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then
_debug "Using sed -i" _debug "Using sed -i"
sed -i "$options" "$filename" sed -i "$options" "$filename"
elif sed -h 2>&1 | grep "\-i extension" >/dev/null 2>&1; then
_debug "Using FreeBSD sed -i"
sed -i "" "$options" "$filename"
else else
_debug "No -i support in sed" _debug "No -i support in sed"
text="$(cat "$filename")" text="$(cat "$filename")"
@@ -1009,7 +1038,7 @@ _digest() {
outputhex="$2" outputhex="$2"
if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then if [ "$alg" = "sha3-256" ] || [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
if [ "$outputhex" ]; then if [ "$outputhex" ]; then
${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' ' ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
else else
@@ -1228,7 +1257,7 @@ _idn() {
fi fi
} }
#_createcsr cn san_list keyfile csrfile conf acmeValidationv1 #_createcsr cn san_list keyfile csrfile conf acmeValidationv1 extendedUsage
_createcsr() { _createcsr() {
_debug _createcsr _debug _createcsr
domain="$1" domain="$1"
@@ -1237,6 +1266,7 @@ _createcsr() {
csr="$4" csr="$4"
csrconf="$5" csrconf="$5"
acmeValidationv1="$6" acmeValidationv1="$6"
extusage="$7"
_debug2 domain "$domain" _debug2 domain "$domain"
_debug2 domainlist "$domainlist" _debug2 domainlist "$domainlist"
_debug2 csrkey "$csrkey" _debug2 csrkey "$csrkey"
@@ -1245,9 +1275,8 @@ _createcsr() {
printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]" >"$csrconf" printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]" >"$csrconf"
if [ "$Le_ExtKeyUse" ]; then if [ "$extusage" ]; then
_savedomainconf Le_ExtKeyUse "$Le_ExtKeyUse" printf "\nextendedKeyUsage=$extusage\n" >>"$csrconf"
printf "\nextendedKeyUsage=$Le_ExtKeyUse\n" >>"$csrconf"
else else
printf "\nextendedKeyUsage=serverAuth,clientAuth\n" >>"$csrconf" printf "\nextendedKeyUsage=serverAuth,clientAuth\n" >>"$csrconf"
fi fi
@@ -1393,6 +1422,12 @@ _ss() {
return 0 return 0
fi fi
if [ "$(uname)" = "AIX" ]; then
_debug "Using: AIX netstat"
netstat -an | grep "^tcp" | grep "LISTEN" | grep "\.$_port "
return 0
fi
if _exists "netstat"; then if _exists "netstat"; then
_debug "Using: netstat" _debug "Using: netstat"
if netstat -help 2>&1 | grep "\-p proto" >/dev/null; then if netstat -help 2>&1 | grep "\-p proto" >/dev/null; then
@@ -1437,8 +1472,8 @@ _toPkcs() {
else else
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" ${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca"
fi fi
if [ "$?" == "0" ]; then if [ "$?" = "0" ]; then
_savedomainconf "Le_PFXPassword" "$pfxPassword" _savedomainconf "Le_PFXPassword" "$pfxPassword" "base64"
fi fi
} }
@@ -1623,6 +1658,11 @@ _time2str() {
return return
fi fi
#Omnios
if date -u -r "$1" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null; then
return
fi
#Solaris #Solaris
if printf "%(%Y-%m-%dT%H:%M:%SZ)T\n" $1 2>/dev/null; then if printf "%(%Y-%m-%dT%H:%M:%SZ)T\n" $1 2>/dev/null; then
return return
@@ -1792,6 +1832,10 @@ _time() {
# 2022-04-01 08:10:33 to 1648800633 # 2022-04-01 08:10:33 to 1648800633
#or 2022-04-01T08:10:33Z to 1648800633 #or 2022-04-01T08:10:33Z to 1648800633
_date2time() { _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 #Linux
if date -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then if date -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return return
@@ -1801,12 +1845,12 @@ _date2time() {
if gdate -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then if gdate -u -d "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then
return return
fi fi
#Mac/BSD #Omnios
if date -u -j -f "%Y-%m-%d %H:%M:%S" "$(echo "$1" | tr -d "Z" | tr "T" ' ')" +"%s" 2>/dev/null; then 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 return
fi fi
#Omnios #Omnios
if da="$(echo "$1" | tr -d "Z" | tr "T" ' ')" perl -MTime::Piece -e 'print Time::Piece->strptime($ENV{da}, "%Y-%m-%d %H:%M:%S")->epoch, "\n";' 2>/dev/null; then if python3 -c "import datetime; print(int(datetime.datetime.strptime(\"$1\", \"%Y-%m-%dT%H:%M:%SZ\").replace(tzinfo=datetime.timezone.utc).timestamp()))" 2>/dev/null; then
return return
fi fi
_err "Cannot parse _date2time $1" _err "Cannot parse _date2time $1"
@@ -1860,6 +1904,11 @@ _inithttp() {
if [ -z "$_ACME_CURL" ] && _exists "curl"; then if [ -z "$_ACME_CURL" ] && _exists "curl"; then
_ACME_CURL="curl --silent --dump-header $HTTP_HEADER " _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 if [ -z "$ACME_HTTP_NO_REDIRECTS" ]; then
_ACME_CURL="$_ACME_CURL -L " _ACME_CURL="$_ACME_CURL -L "
fi fi
@@ -1887,6 +1936,11 @@ _inithttp() {
if [ -z "$_ACME_WGET" ] && _exists "wget"; then if [ -z "$_ACME_WGET" ] && _exists "wget"; then
_ACME_WGET="wget -q" _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 if [ "$ACME_HTTP_NO_REDIRECTS" ]; then
_ACME_WGET="$_ACME_WGET --max-redirect 0 " _ACME_WGET="$_ACME_WGET --max-redirect 0 "
fi fi
@@ -2188,7 +2242,6 @@ _send_signed_request() {
_debug2 _headers "$_headers" _debug2 _headers "$_headers"
_CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)" _CACHED_NONCE="$(echo "$_headers" | grep -i "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
fi fi
_debug2 _CACHED_NONCE "$_CACHED_NONCE"
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
_err "Cannot connect to $nonceurl to get nonce." _err "Cannot connect to $nonceurl to get nonce."
return 1 return 1
@@ -2305,6 +2358,7 @@ _setopt() {
fi fi
if [ ! -f "$__conf" ]; then if [ ! -f "$__conf" ]; then
touch "$__conf" touch "$__conf"
chmod 600 "$__conf"
fi fi
if [ -n "$(_tail_c 1 <"$__conf")" ]; then if [ -n "$(_tail_c 1 <"$__conf")" ]; then
echo >>"$__conf" echo >>"$__conf"
@@ -2361,7 +2415,7 @@ _clear_conf() {
_sdkey="$2" _sdkey="$2"
if [ "$_c_c_f" ]; then if [ "$_c_c_f" ]; then
_conf_data="$(cat "$_c_c_f")" _conf_data="$(cat "$_c_c_f")"
echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f" echo "$_conf_data" | sed "/^$_sdkey *=.*$/d" >"$_c_c_f"
else else
_err "Config file is empty, cannot clear" _err "Config file is empty, cannot clear"
fi fi
@@ -2513,18 +2567,23 @@ _startserver() {
_debug Le_Listen_V4 "$Le_Listen_V4" _debug Le_Listen_V4 "$Le_Listen_V4"
_debug Le_Listen_V6 "$Le_Listen_V6" _debug Le_Listen_V6 "$Le_Listen_V6"
if _exists "socat"; then
_NC="socat" _NC="socat"
if [ "$Le_Listen_V6" ]; then if [ "$Le_Listen_V6" ]; then
_NC="$_NC -6" _NC="$_NC -6"
else SOCAT_OPTIONS=TCP6-LISTEN
elif [ "$Le_Listen_V4" ]; then
_NC="$_NC -4" _NC="$_NC -4"
SOCAT_OPTIONS=TCP4-LISTEN
else
SOCAT_OPTIONS=TCP-LISTEN
fi fi
if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then if [ "$DEBUG" ] && [ "$DEBUG" -gt "1" ]; then
_NC="$_NC -d -d -v" _NC="$_NC -d -d -v"
fi fi
SOCAT_OPTIONS=TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SOCAT_OPTIONS=$SOCAT_OPTIONS:$Le_HTTPPort,crlf,reuseaddr,fork
#Adding bind to local-address #Adding bind to local-address
if [ "$ncaddr" ]; then if [ "$ncaddr" ]; then
@@ -2541,9 +2600,43 @@ echo 'Content-Length\: $_content_len'; \
echo ''; \ echo ''; \
printf '%s' '$content';" 2>"$_SOCAT_ERR" & printf '%s' '$content';" 2>"$_SOCAT_ERR" &
serverproc="$!" serverproc="$!"
else
_PYTHON=""
if _exists "python3"; then
_PYTHON="python3"
elif _exists "python2"; then
_PYTHON="python2"
elif _exists "python"; then
_PYTHON="python"
fi
if [ "$_PYTHON" ]; then
_debug "Using python: $_PYTHON"
_AF="socket.AF_INET"
_BIND_ADDR="0.0.0.0"
if [ "$Le_Listen_V6" ]; then
_AF="socket.AF_INET6"
_BIND_ADDR="::"
fi
if [ "$ncaddr" ]; then
_BIND_ADDR="$ncaddr"
fi
export _SOCAT_ERR="$(_mktemp)"
$_PYTHON -c "import socket,sys;s=socket.socket($_AF,socket.SOCK_STREAM);s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1);s.bind((sys.argv[2],int(sys.argv[1])));s.listen(5);res='HTTP/1.0 200 OK\r\nContent-Length: '+str(len(sys.argv[3]))+'\r\n\r\n'+sys.argv[3];
while True:
c,a=s.accept()
c.sendall(res.encode() if hasattr(res, 'encode') else res)
c.close()" "$Le_HTTPPort" "$_BIND_ADDR" "$content" 2>"$_SOCAT_ERR" &
serverproc="$!"
_NC="$_PYTHON"
else
_err "Please install socat or python first for standalone mode."
return 1
fi
fi
if [ -f "$_SOCAT_ERR" ]; then if [ -f "$_SOCAT_ERR" ]; then
if grep "Permission denied" "$_SOCAT_ERR" >/dev/null; then if grep "Permission denied" "$_SOCAT_ERR" >/dev/null; then
_err "socat: $(cat $_SOCAT_ERR)" _err "$_NC: $(cat $_SOCAT_ERR)"
_err "Can not listen for user: $(whoami)" _err "Can not listen for user: $(whoami)"
_err "Maybe try with root again?" _err "Maybe try with root again?"
rm -f "$_SOCAT_ERR" rm -f "$_SOCAT_ERR"
@@ -2733,6 +2826,7 @@ _clearAPI() {
ACME_REVOKE_CERT="" ACME_REVOKE_CERT=""
ACME_NEW_NONCE="" ACME_NEW_NONCE=""
ACME_AGREEMENT="" ACME_AGREEMENT=""
ACME_RENEWAL_INFO=""
} }
#server #server
@@ -2745,7 +2839,7 @@ _initAPI() {
_request_retry_times=0 _request_retry_times=0
while [ -z "$ACME_NEW_ACCOUNT" ] && [ "${_request_retry_times}" -lt "$MAX_API_RETRY_TIMES" ]; do while [ -z "$ACME_NEW_ACCOUNT" ] && [ "${_request_retry_times}" -lt "$MAX_API_RETRY_TIMES" ]; do
_request_retry_times=$(_math "$_request_retry_times" + 1) _request_retry_times=$(_math "$_request_retry_times" + 1)
response=$(_get "$_api_server") response=$(_get "$_api_server" "" 10)
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
_debug2 "response" "$response" _debug2 "response" "$response"
_info "Cannot init API for: $_api_server." _info "Cannot init API for: $_api_server."
@@ -2777,6 +2871,9 @@ _initAPI() {
ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3) ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3)
export ACME_AGREEMENT 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_KEY_CHANGE" "$ACME_KEY_CHANGE"
_debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ"
_debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER"
@@ -2784,6 +2881,7 @@ _initAPI() {
_debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT"
_debug "ACME_AGREEMENT" "$ACME_AGREEMENT" _debug "ACME_AGREEMENT" "$ACME_AGREEMENT"
_debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE" _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE"
_debug "ACME_RENEWAL_INFO" "$ACME_RENEWAL_INFO"
if [ "$ACME_NEW_ACCOUNT" ] && [ "$ACME_NEW_ORDER" ]; then if [ "$ACME_NEW_ACCOUNT" ] && [ "$ACME_NEW_ORDER" ]; then
return 0 return 0
fi fi
@@ -3491,7 +3589,7 @@ _on_before_issue() {
_debug _chk_alt_domains "$_chk_alt_domains" _debug _chk_alt_domains "$_chk_alt_domains"
#run pre hook #run pre hook
if [ "$_chk_pre_hook" ]; then if [ "$_chk_pre_hook" ]; then
_info "Runing pre hook:'$_chk_pre_hook'" _info "Running pre hook:'$_chk_pre_hook'"
if ! ( if ! (
export Le_Domain="$_chk_main_domain" export Le_Domain="$_chk_main_domain"
export Le_Alt="$_chk_alt_domains" export Le_Alt="$_chk_alt_domains"
@@ -3502,9 +3600,9 @@ _on_before_issue() {
fi fi
fi fi
if _hasfield "$_chk_web_roots" "$NO_VALUE"; then if _hasfield "$_chk_web_roots" "$NO_VALUE" && [ "$_chk_web_roots" = "$NO_VALUE" ]; then
if ! _exists "socat"; then if ! _exists "socat" && ! _exists "python" && ! _exists "python2" && ! _exists "python3"; then
_err "Please install socat tools first." _err "Please install socat or python tools first."
return 1 return 1
fi fi
fi fi
@@ -4394,6 +4492,8 @@ issue() {
_preferred_chain="${15}" _preferred_chain="${15}"
_valid_from="${16}" _valid_from="${16}"
_valid_to="${17}" _valid_to="${17}"
_certificate_profile="${18}"
_extended_key_usage="${19}"
if [ -z "$_ACME_IS_RENEW" ]; then if [ -z "$_ACME_IS_RENEW" ]; then
_initpath "$_main_domain" "$_key_length" _initpath "$_main_domain" "$_key_length"
@@ -4413,7 +4513,7 @@ issue() {
Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
_debug Le_NextRenewTime "$Le_NextRenewTime" _debug Le_NextRenewTime "$Le_NextRenewTime"
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
_valid_to_saved=$(_readdomainconf Le_Valid_to) _valid_to_saved=$(_readdomainconf Le_Valid_To)
if [ "$_valid_to_saved" ] && ! _startswith "$_valid_to_saved" "+"; then if [ "$_valid_to_saved" ] && ! _startswith "$_valid_to_saved" "+"; then
_info "The domain is set to be valid to: $_valid_to_saved" _info "The domain is set to be valid to: $_valid_to_saved"
_info "It cannot be renewed automatically" _info "It cannot be renewed automatically"
@@ -4469,6 +4569,11 @@ issue() {
else else
_cleardomainconf "Le_Preferred_Chain" _cleardomainconf "Le_Preferred_Chain"
fi fi
if [ "$_certificate_profile" ]; then
_savedomainconf "Le_Certificate_Profile" "$_certificate_profile"
else
_cleardomainconf "Le_Certificate_Profile"
fi
Le_API="$ACME_DIRECTORY" Le_API="$ACME_DIRECTORY"
_savedomainconf "Le_API" "$Le_API" _savedomainconf "Le_API" "$Le_API"
@@ -4480,6 +4585,7 @@ issue() {
if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then
_err "_on_before_issue." _err "_on_before_issue."
_on_issue_err "$_post_hook"
return 1 return 1
fi fi
@@ -4532,12 +4638,25 @@ issue() {
return 1 return 1
fi fi
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." _err "Error creating CSR."
_clearup _clearup
_on_issue_err "$_post_hook" _on_issue_err "$_post_hook"
return 1 return 1
fi fi
if [ "$_extended_key_usage" ]; then
_savedomainconf "Le_ExtKeyUse" "$_extended_key_usage"
else
_cleardomainconf "Le_ExtKeyUse"
fi
fi fi
_savedomainconf "Le_Keylength" "$_key_length" _savedomainconf "Le_Keylength" "$_key_length"
@@ -4600,6 +4719,9 @@ issue() {
if [ "$_notAfter" ]; then if [ "$_notAfter" ]; then
_newOrderObj="$_newOrderObj,\"notAfter\": \"$_notAfter\"" _newOrderObj="$_newOrderObj,\"notAfter\": \"$_notAfter\""
fi fi
if [ "$_certificate_profile" ]; then
_newOrderObj="$_newOrderObj,\"profile\": \"$_certificate_profile\""
fi
_debug "STEP 1, Ordering a Certificate" _debug "STEP 1, Ordering a Certificate"
if ! _send_signed_request "$ACME_NEW_ORDER" "$_newOrderObj}"; then if ! _send_signed_request "$ACME_NEW_ORDER" "$_newOrderObj}"; then
_err "Error creating new order." _err "Error creating new order."
@@ -4739,7 +4861,8 @@ $_authorizations_map"
_debug keyauthorization "$keyauthorization" _debug keyauthorization "$keyauthorization"
fi fi
entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" # Fix for empty error objects in response which mess up the original code, adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018
entry="$(echo "$response" | sed s/'"error":{}'/'"error":null'/ | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
_debug entry "$entry" _debug entry "$entry"
if [ -z "$keyauthorization" -a -z "$entry" ]; then if [ -z "$keyauthorization" -a -z "$entry" ]; then
@@ -4989,9 +5112,11 @@ $_authorizations_map"
_debug "Writing token: $token to $wellknown_path/$token" _debug "Writing token: $token to $wellknown_path/$token"
mkdir -p "$wellknown_path" # Ensure .well-known is visible to web server user/group
# https://github.com/Neilpang/acme.sh/pull/32
if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then if ! (umask ugo+rx &&
mkdir -p "$wellknown_path" &&
printf "%s" "$keyauthorization" >"$wellknown_path/$token"); then
_err "$d: Cannot write token to file: $wellknown_path/$token" _err "$d: Cannot write token to file: $wellknown_path/$token"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token" _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup _clearup
@@ -5111,6 +5236,19 @@ $_authorizations_map"
_on_issue_err "$_post_hook" "$vlist" _on_issue_err "$_post_hook" "$vlist"
return 1 return 1
fi fi
_retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *: *[0-9]\+ *" | cut -d : -f 2 | tr -d ' ' | tr -d '\r')
_sleep_overload_retry_sec=$_retryafter
if [ "$_sleep_overload_retry_sec" ]; then
if [ $_sleep_overload_retry_sec -le 600 ]; then
_sleep $_sleep_overload_retry_sec
else
_info "The retryafter=$_retryafter value is too large (> 600), will not retry anymore."
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
fi
done done
done done
@@ -5152,6 +5290,16 @@ $_authorizations_map"
return 1 return 1
fi fi
break 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 elif _contains "$response" "\"processing\""; then
_info "Order status is 'processing', let's sleep and retry." _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') _retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *:" | cut -d : -f 2 | tr -d ' ' | tr -d '\r')
@@ -5350,10 +5498,10 @@ $_authorizations_map"
_savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime" _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
#convert to pkcs12 #convert to pkcs12
Le_PFXPassword="$(_readdomainconf Le_PFXPassword)"
if [ "$Le_PFXPassword" ]; then if [ "$Le_PFXPassword" ]; then
_toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$Le_PFXPassword" _toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$Le_PFXPassword"
fi fi
export CERT_PFX_PATH
if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then
_savedomainconf "Le_RealCertPath" "$_real_cert" _savedomainconf "Le_RealCertPath" "$_real_cert"
@@ -5421,10 +5569,6 @@ renew() {
_info "Switching back to $CA_LETSENCRYPT_V2" _info "Switching back to $CA_LETSENCRYPT_V2"
Le_API="$CA_LETSENCRYPT_V2" Le_API="$CA_LETSENCRYPT_V2"
;; ;;
"$CA_BUYPASS_TEST")
_info "Switching back to $CA_BUYPASS"
Le_API="$CA_BUYPASS"
;;
"$CA_GOOGLE_TEST") "$CA_GOOGLE_TEST")
_info "Switching back to $CA_GOOGLE" _info "Switching back to $CA_GOOGLE"
Le_API="$CA_GOOGLE" Le_API="$CA_GOOGLE"
@@ -5466,6 +5610,11 @@ renew() {
Le_PostHook="$(_readdomainconf Le_PostHook)" Le_PostHook="$(_readdomainconf Le_PostHook)"
Le_RenewHook="$(_readdomainconf Le_RenewHook)" Le_RenewHook="$(_readdomainconf Le_RenewHook)"
Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)" Le_Preferred_Chain="$(_readdomainconf Le_Preferred_Chain)"
Le_Certificate_Profile="$(_readdomainconf Le_Certificate_Profile)"
Le_Valid_From="$(_readdomainconf Le_Valid_From)"
Le_Valid_To="$(_readdomainconf Le_Valid_To)"
Le_ExtKeyUse="$(_readdomainconf Le_ExtKeyUse)"
# When renewing from an old version, the empty Le_Keylength means 2048. # 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 # Note, do not use DEFAULT_DOMAIN_KEY_LENGTH as that value may change over
# time but an empty value implies 2048 specifically. # time but an empty value implies 2048 specifically.
@@ -5473,7 +5622,14 @@ renew() {
if [ -z "$Le_Keylength" ]; then if [ -z "$Le_Keylength" ]; then
Le_Keylength=2048 Le_Keylength=2048
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" if [ "$CA_LETSENCRYPT_V2" = "$Le_API" ]; then
#letsencrypt doesn't support ocsp anymore
if [ "$Le_OCSP_Staple" ]; then
export Le_OCSP_Staple=""
_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" "$Le_Certificate_Profile" "$Le_ExtKeyUse"
res="$?" res="$?"
if [ "$res" != "0" ]; then if [ "$res" != "0" ]; then
return "$res" return "$res"
@@ -5640,6 +5796,10 @@ signcsr() {
_local_addr="${11}" _local_addr="${11}"
_challenge_alias="${12}" _challenge_alias="${12}"
_preferred_chain="${13}" _preferred_chain="${13}"
_valid_f="${14}"
_valid_t="${15}"
_cert_prof="${16}"
_en_key_usage="${17}"
_csrsubj=$(_readSubjectFromCSR "$_csrfile") _csrsubj=$(_readSubjectFromCSR "$_csrfile")
if [ "$?" != "0" ]; then if [ "$?" != "0" ]; then
@@ -5683,7 +5843,7 @@ signcsr() {
_info "Copying CSR to: $CSR_PATH" _info "Copying CSR to: $CSR_PATH"
cp "$_csrfile" "$CSR_PATH" cp "$_csrfile" "$CSR_PATH"
issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias" "$_preferred_chain" issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength" "$_real_cert" "$_real_key" "$_real_ca" "$_reload_cmd" "$_real_fullchain" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_addr" "$_challenge_alias" "$_preferred_chain" "$_valid_f" "$_valid_t" "$_cert_prof" "$_en_key_usage"
} }
@@ -5734,9 +5894,10 @@ list() {
_sep="|" _sep="|"
if [ "$_raw" ]; then if [ "$_raw" ]; then
if [ -z "$_domain" ]; 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 fi
for di in "${CERT_HOME}"/*.*/; do for di in "${CERT_HOME}"/*.* "${CERT_HOME}"/*:*; do
[ -d "$di" ] || continue
d=$(basename "$di") d=$(basename "$di")
_debug d "$d" _debug d "$d"
( (
@@ -5749,7 +5910,7 @@ list() {
. "$DOMAIN_CONF" . "$DOMAIN_CONF"
_ca="$(_getCAShortName "$Le_API")" _ca="$(_getCAShortName "$Le_API")"
if [ -z "$_domain" ]; then 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 else
if [ "$_domain" = "$d" ]; then if [ "$_domain" = "$d" ]; then
cat "$DOMAIN_CONF" cat "$DOMAIN_CONF"
@@ -5768,6 +5929,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() { _deploy() {
_d="$1" _d="$1"
_hooks="$2" _hooks="$2"
@@ -5792,7 +5995,7 @@ _deploy() {
return 1 return 1
fi fi
if ! $d_command "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then if ! $d_command "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH" "$CERT_PFX_PATH"; then
_err "Error deploying for domain: $_d" _err "Error deploying for domain: $_d"
return 1 return 1
fi fi
@@ -5955,7 +6158,7 @@ _installcert() {
); then ); then
_info "$(__green "Reload successful")" _info "$(__green "Reload successful")"
else else
_err "Reload error for: $Le_Domain" _err "Reload error for: $_main_domain"
fi fi
fi fi
@@ -6035,7 +6238,7 @@ installcronjob() {
_script="$(_readlink "$_SCRIPT_")" _script="$(_readlink "$_SCRIPT_")"
_debug _script "$_script" _debug _script "$_script"
if [ -f "$_script" ]; then if [ -f "$_script" ]; then
_info "Usinging the current script from: $_script" _info "Using the current script from: $_script"
lesh="$_script" lesh="$_script"
else else
_err "Cannot install cronjob, $PROJECT_ENTRY not found." _err "Cannot install cronjob, $PROJECT_ENTRY not found."
@@ -6306,7 +6509,8 @@ _deactivate() {
fi fi
_debug "Trigger validation." _debug "Trigger validation."
vtype="$(_getIdType "$_d_domain")" vtype="$(_getIdType "$_d_domain")"
entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')" # Fix for empty error objects in response which mess up the original code, adapted from fix suggested here: https://github.com/acmesh-official/acme.sh/issues/4933#issuecomment-1870499018
entry="$(echo "$response" | sed s/'"error":{}'/'"error":null'/ | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
_debug entry "$entry" _debug entry "$entry"
if [ -z "$entry" ]; then if [ -z "$entry" ]; then
_err "$d: Cannot get domain token" _err "$d: Cannot get domain token"
@@ -6390,6 +6594,36 @@ deactivate() {
done 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 file if not specified as environment variable
_detect_profile() { _detect_profile() {
if [ -n "$PROFILE" -a -f "$PROFILE" ]; then if [ -n "$PROFILE" -a -f "$PROFILE" ]; then
@@ -6438,6 +6672,7 @@ _initconf() {
#NO_TIMESTAMP=1 #NO_TIMESTAMP=1
" >"$ACCOUNT_CONF_PATH" " >"$ACCOUNT_CONF_PATH"
chmod 600 "$ACCOUNT_CONF_PATH"
fi fi
} }
@@ -6473,9 +6708,9 @@ _precheck() {
return 1 return 1
fi fi
if ! _exists "socat"; then if ! _exists "socat" && ! _exists "python" && ! _exists "python2" && ! _exists "python3"; then
_err "It is recommended to install socat first." _err "It is recommended to install socat or python first."
_err "We use socat for the standalone server, which is used for standalone mode." _err "We use socat or python for the standalone server, which is used for standalone mode."
_err "If you don't want to use standalone mode, you may ignore this warning." _err "If you don't want to use standalone mode, you may ignore this warning."
fi fi
@@ -6787,7 +7022,7 @@ _send_notify() {
_nsource="$NOTIFY_SOURCE" _nsource="$NOTIFY_SOURCE"
if [ -z "$_nsource" ]; then if [ -z "$_nsource" ]; then
_nsource="$(hostname)" _nsource="$(uname -n)"
fi fi
_nsubject="$_nsubject by $_nsource" _nsubject="$_nsubject by $_nsource"
@@ -6945,6 +7180,9 @@ Parameters:
If no match, the default offered chain will be used. (default: empty) If no match, the default offered chain will be used. (default: empty)
See: $_PREFERRED_CHAIN_WIKI 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. --valid-to <date-time> Request the NotAfter field of the cert.
See: $_VALIDITY_WIKI See: $_VALIDITY_WIKI
--valid-from <date-time> Request the NotBefore field of the cert. --valid-from <date-time> Request the NotBefore field of the cert.
@@ -6989,7 +7227,7 @@ Parameters:
--accountconf <file> Specifies a customized account config file. --accountconf <file> Specifies a customized account config file.
--home <directory> Specifies the home dir for $PROJECT_NAME. --home <directory> Specifies the home dir for $PROJECT_NAME.
--cert-home <directory> Specifies the home dir to save all the certs, only valid for '--install' command. --cert-home <directory> Specifies the home dir to save all the certs.
--config-home <directory> Specifies the home dir to save all the configurations. --config-home <directory> Specifies the home dir to save all the configurations.
--useragent <string> Specifies the user agent string. it will be saved for future use too. --useragent <string> Specifies the user agent string. it will be saved for future use too.
-m, --email <email> Specifies the account email, only valid for the '--install' and '--update-account' command. -m, --email <email> Specifies the account email, only valid for the '--install' and '--update-account' command.
@@ -7021,6 +7259,8 @@ Parameters:
--auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future. Defaults to 1 if argument is omitted. --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-v4 Force standalone/tls server to listen at ipv4.
--listen-v6 Force standalone/tls server to listen at ipv6. --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. --openssl-bin <file> Specifies a custom openssl bin location.
--use-wget Force to use wget, if you have both curl and wget installed. --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. --yes-I-know-dns-manual-mode-enough-go-ahead-please Force use of dns manual mode.
@@ -7139,6 +7379,24 @@ _processAccountConf() {
_saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET" _saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET"
fi 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() { _checkSudo() {
@@ -7304,6 +7562,8 @@ _process() {
_local_address="" _local_address=""
_log_level="" _log_level=""
_auto_upgrade="" _auto_upgrade=""
_request_v4=""
_request_v6=""
_listen_v4="" _listen_v4=""
_listen_v6="" _listen_v6=""
_openssl_bin="" _openssl_bin=""
@@ -7320,6 +7580,8 @@ _process() {
_preferred_chain="" _preferred_chain=""
_valid_from="" _valid_from=""
_valid_to="" _valid_to=""
_certificate_profile=""
_extended_key_usage=""
while [ ${#} -gt 0 ]; do while [ ${#} -gt 0 ]; do
case "${1}" in case "${1}" in
@@ -7423,6 +7685,9 @@ _process() {
--set-default-chain) --set-default-chain)
_CMD="setdefaultchain" _CMD="setdefaultchain"
;; ;;
--list-profiles)
_CMD="list_profiles"
;;
-d | --domain) -d | --domain)
_dvalue="$2" _dvalue="$2"
@@ -7638,6 +7903,10 @@ _process() {
_valid_to="$2" _valid_to="$2"
shift shift
;; ;;
--certificate-profile | --cert-profile)
_certificate_profile="$2"
shift
;;
--httpport) --httpport)
_httpport="$2" _httpport="$2"
Le_HTTPPort="$_httpport" Le_HTTPPort="$_httpport"
@@ -7708,7 +7977,7 @@ _process() {
shift shift
;; ;;
--extended-key-usage) --extended-key-usage)
Le_ExtKeyUse="$2" _extended_key_usage="$2"
shift shift
;; ;;
--ocsp-must-staple | --ocsp) --ocsp-must-staple | --ocsp)
@@ -7761,6 +8030,18 @@ _process() {
fi fi
AUTO_UPGRADE="$_auto_upgrade" 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)
_listen_v4="1" _listen_v4="1"
Le_Listen_V4="$_listen_v4" Le_Listen_V4="$_listen_v4"
@@ -7913,13 +8194,13 @@ _process() {
uninstall) uninstall "$_nocron" ;; uninstall) uninstall "$_nocron" ;;
upgrade) upgrade ;; upgrade) upgrade ;;
issue) 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)
deploy "$_domain" "$_deploy_hook" "$_ecc" deploy "$_domain" "$_deploy_hook" "$_ecc"
;; ;;
signcsr) signcsr)
signcsr "$_csr" "$_webroot" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address" "$_challenge_alias" "$_preferred_chain" signcsr "$_csr" "$_webroot" "$_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"
;; ;;
showcsr) showcsr)
showcsr "$_csr" "$_domain" showcsr "$_csr" "$_domain"
@@ -7984,6 +8265,9 @@ _process() {
setdefaultchain) setdefaultchain)
setdefaultchain "$_preferred_chain" setdefaultchain "$_preferred_chain"
;; ;;
list_profiles)
list_profiles
;;
*) *)
if [ "$_CMD" ]; then if [ "$_CMD" ]; then
_err "Invalid command: $_CMD" _err "Invalid command: $_CMD"