#!/usr/bin/env sh
-VER=3.0.6
+VER=3.0.7
PROJECT_NAME="acme.sh"
LOG_LEVEL_1=1
LOG_LEVEL_2=2
LOG_LEVEL_3=3
-DEFAULT_LOG_LEVEL="$LOG_LEVEL_1"
+DEFAULT_LOG_LEVEL="$LOG_LEVEL_2"
DEBUG_LEVEL_1=1
DEBUG_LEVEL_2=2
DEBUG_LEVEL_3=3
-DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1
+DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_2
DEBUG_LEVEL_NONE=0
DOH_CLOUDFLARE=1
fi
}
+if [ "$(echo abc | egrep -o b 2>/dev/null)" = "b" ]; then
+ __USE_EGREP=1
+else
+ __USE_EGREP=""
+fi
+
_egrep_o() {
- if ! egrep -o "$1" 2>/dev/null; then
+ if [ "$__USE_EGREP" ]; then
+ egrep -o -- "$1"
+ else
sed -n 's/.*\('"$1"'\).*/\1/p'
fi
}
createCSR() {
_info "Creating csr"
if [ -z "$1" ]; then
- _usage "Usage: $PROJECT_ENTRY --create-csr --domain <domain.tld> [--domain <domain2.tld> ...]"
+ _usage "Usage: $PROJECT_ENTRY --create-csr --domain <domain.tld> [--domain <domain2.tld> ...] [--ecc]"
return
fi
_ACME_CURL="$_ACME_CURL -g "
fi
-#don't use --fail-with-body
-##from curl 7.76: return fail on HTTP errors but keep the body
-#if _contains "$(curl --help http 2>&1)" "--fail-with-body"; then
-# _ACME_CURL="$_ACME_CURL --fail-with-body "
-#fi
+ #don't use --fail-with-body
+ ##from curl 7.76: return fail on HTTP errors but keep the body
+ #if _contains "$(curl --help http 2>&1)" "--fail-with-body"; then
+ # _ACME_CURL="$_ACME_CURL --fail-with-body "
+ #fi
fi
if [ -z "$_ACME_WGET" ] && _exists "wget"; then
}
_tail_n() {
- if ! tail -n "$1" 2>/dev/null; then
+ if _is_solaris; then
#fix for solaris
tail -"$1"
+ else
+ tail -n "$1"
+ fi
+}
+
+_tail_c() {
+ if _is_solaris; then
+ #fix for solaris
+ tail -"$1"c
+ else
+ tail -c "$1"
fi
}
if [ -z "$keyfile" ]; then
keyfile="$ACCOUNT_KEY_PATH"
fi
+ _debug "=======Begin Send Signed Request======="
_debug url "$url"
_debug payload "$payload"
_debug3 _body "$_body"
fi
+ _retryafter=$(echo "$responseHeaders" | grep -i "^Retry-After *: *[0-9]\+ *" | cut -d : -f 2 | tr -d ' ' | tr -d '\r')
+ if [ "$code" = '503' ]; then
+ _sleep_overload_retry_sec=$_retryafter
+ if [ -z "$_sleep_overload_retry_sec" ]; then
+ _sleep_overload_retry_sec=5
+ fi
+ if [ $_sleep_overload_retry_sec -le 600 ]; then
+ _info "It seems the CA server is currently overloaded, let's wait and retry. Sleeping $_sleep_overload_retry_sec seconds."
+ _sleep $_sleep_overload_retry_sec
+ continue
+ else
+ _info "The retryafter=$_retryafter is too large > 600, not retry anymore."
+ fi
+ fi
if _contains "$_body" "JWS has invalid anti-replay nonce" || _contains "$_body" "JWS has an invalid anti-replay nonce"; then
_info "It seems the CA server is busy now, let's wait and retry. Sleeping $_sleep_retry_sec seconds."
_CACHED_NONCE=""
if [ ! -f "$__conf" ]; then
touch "$__conf"
fi
- if [ -n "$(tail -c 1 <"$__conf")" ]; then
+ if [ -n "$(_tail_c 1 <"$__conf")" ]; then
echo >>"$__conf"
fi
return 0 # do nothing
fi
_saved="$(_readdomainconf "SAVED_$_rac_key")"
- eval $_rac_key="$_saved"
+ eval $_rac_key=\$_saved
export $_rac_key
}
if _isEccKey "$_ilength"; then
DOMAIN_PATH="$domainhomeecc"
- else
+ elif [ -z "$__SELECTED_RSA_KEY" ]; then
if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then
_info "The domain '$domain' seems to have a ECC cert already, lets use ecc cert."
DOMAIN_PATH="$domainhomeecc"
fi
fi
_debug DOMAIN_PATH "$DOMAIN_PATH"
+ export DOMAIN_PATH
fi
if [ -z "$DOMAIN_BACKUP_PATH" ]; then
}
-_exec() {
- if [ -z "$_EXEC_TEMP_ERR" ]; then
- _EXEC_TEMP_ERR="$(_mktemp)"
- fi
-
- if [ "$_EXEC_TEMP_ERR" ]; then
- eval "$@ 2>>$_EXEC_TEMP_ERR"
- else
- eval "$@"
- fi
-}
-
-_exec_err() {
- [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR"
-}
-
_apachePath() {
_APACHECTL="apachectl"
if ! _exists apachectl; then
fi
fi
- if ! _exec $_APACHECTL -V >/dev/null; then
- _exec_err
+ if ! $_APACHECTL -V >/dev/null; then
return 1
fi
cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf"
_debug "Restored: $httpdconf."
- if ! _exec $_APACHECTL -t; then
- _exec_err
+ if ! $_APACHECTL -t; then
_err "Sorry, restore apache config error, please contact me."
return 1
fi
#test the conf first
_info "Checking if there is an error in the apache config file before starting."
- if ! _exec "$_APACHECTL" -t >/dev/null; then
- _exec_err
+ if ! $_APACHECTL -t >/dev/null; then
_err "The apache config file has error, please fix it first, then try again."
_err "Don't worry, there is nothing changed to your system."
return 1
chmod 755 "$ACME_DIR"
fi
- if ! _exec "$_APACHECTL" graceful; then
- _exec_err
+ if ! $_APACHECTL graceful; then
_err "$_APACHECTL graceful error, please contact me."
_restoreApache
return 1
_err "nginx command is not found."
return 1
fi
- NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")"
+ NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "\-\-conf-path=[^ ]* " | tr -d " ")"
_debug NGINX_CONF "$NGINX_CONF"
NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)"
_debug NGINX_CONF "$NGINX_CONF"
return 1
fi
_info "Check the nginx conf before setting up."
- if ! _exec "nginx -t" >/dev/null; then
- _exec_err
+ if ! nginx -t >/dev/null; then
return 1
fi
fi
_debug3 "Modified config:$(cat $FOUND_REAL_NGINX_CONF)"
_info "nginx conf is done, let's check it again."
- if ! _exec "nginx -t" >/dev/null; then
- _exec_err
+ if ! nginx -t >/dev/null; then
_err "It seems that nginx conf was broken, let's restore."
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
return 1
fi
_info "Reload nginx"
- if ! _exec "nginx -s reload" >/dev/null; then
- _exec_err
+ if ! nginx -s reload >/dev/null; then
_err "It seems that nginx reload error, let's restore."
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
return 1
done
_info "Reload nginx"
- if ! _exec "nginx -s reload" >/dev/null; then
- _exec_err
+ if ! nginx -s reload >/dev/null; then
_err "It seems that nginx reload error, please report bug."
return 1
fi
_d="*.$_d"
fi
_debug2 _d "$_d"
- _authorizations_map="$_d,$response
+ _authorizations_map="$_d,$response#$_authz_url
$_authorizations_map"
done
+
_debug2 _authorizations_map "$_authorizations_map"
_index=0
_on_issue_err "$_post_hook"
return 1
fi
-
+ _authz_url="$(echo "$_candidates" | sed "s/$_idn_d,//" | _egrep_o "#.*" | sed "s/^#//")"
+ _debug _authz_url "$_authz_url"
if [ -z "$thumbprint" ]; then
thumbprint="$(__calc_account_thumbprint)"
fi
+ keyauthorization=""
+
+ if echo "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
+ _debug "$d is already valid."
+ keyauthorization="$STATE_VERIFIED"
+ _debug keyauthorization "$keyauthorization"
+ fi
+
entry="$(echo "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
_debug entry "$entry"
- keyauthorization=""
- if [ -z "$entry" ]; then
- if ! _startswith "$d" '*.'; then
- _debug "Not a wildcard domain, lets check whether the validation is already valid."
- if echo "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
- _debug "$d is already valid."
- keyauthorization="$STATE_VERIFIED"
- _debug keyauthorization "$keyauthorization"
- fi
- fi
- if [ -z "$keyauthorization" ]; then
- _err "Error, can not get domain token entry $d for $vtype"
- _supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')"
- if [ "$_supported_vtypes" ]; then
- _err "The supported validation types are: $_supported_vtypes, but you specified: $vtype"
- fi
- _clearup
- _on_issue_err "$_post_hook"
- return 1
+
+ if [ -z "$keyauthorization" -a -z "$entry" ]; then
+ _err "Error, can not get domain token entry $d for $vtype"
+ _supported_vtypes="$(echo "$response" | _egrep_o "\"challenges\":\[[^]]*]" | tr '{' "\n" | grep type | cut -d '"' -f 4 | tr "\n" ' ')"
+ if [ "$_supported_vtypes" ]; then
+ _err "The supported validation types are: $_supported_vtypes, but you specified: $vtype"
fi
+ _clearup
+ _on_issue_err "$_post_hook"
+ return 1
fi
if [ -z "$keyauthorization" ]; then
fi
keyauthorization="$token.$thumbprint"
_debug keyauthorization "$keyauthorization"
-
- if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
- _debug "$d is already verified."
- keyauthorization="$STATE_VERIFIED"
- _debug keyauthorization "$keyauthorization"
- fi
fi
- dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
+ dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot$sep$_authz_url"
_debug dvlist "$dvlist"
vlist="$vlist$dvlist$dvsep"
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
+ _authz_url=$(echo "$ventry" | cut -d "$sep" -f 6)
_debug d "$d"
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
_debug "$d is already verified, skip $vtype."
uri=$(echo "$ventry" | cut -d "$sep" -f 3)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
-
+ _authz_url=$(echo "$ventry" | cut -d "$sep" -f 6)
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
_info "$d is already verified, skip $vtype."
continue
_debug "d" "$d"
_debug "keyauthorization" "$keyauthorization"
_debug "uri" "$uri"
+ _debug "_authz_url" "$_authz_url"
removelevel=""
token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)"
if ! chmod a+r "$wellknown_path/$token"; then
_debug "chmod failed, but we just continue."
fi
- if [ ! "$usingApache" ]; then
- if webroot_owner=$(_stat "$_currentRoot"); then
- _debug "Changing owner/group of .well-known to $webroot_owner"
- if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then
- _debug "$(cat "$_EXEC_TEMP_ERR")"
- _exec_err >/dev/null 2>&1
- fi
- else
- _debug "not changing owner/group of webroot"
- fi
- fi
-
fi
elif [ "$vtype" = "$VTYPE_ALPN" ]; then
acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
MAX_RETRY_TIMES=30
fi
+ _debug "Lets check the status of the authz"
while true; do
waittimes=$(_math "$waittimes" + 1)
if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then
errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)"
_debug2 errordetail "$errordetail"
if [ "$errordetail" ]; then
- _err "$d:Verify error:$errordetail"
+ _err "Invalid status, $d:Verify error detail:$errordetail"
else
- _err "$d:Verify error:$error"
+ _err "Invalid status, $d:Verify error:$error"
fi
if [ "$DEBUG" ]; then
if [ "$vtype" = "$VTYPE_HTTP" ]; then
break
fi
- if [ "$status" = "pending" ]; then
+ if _contains "$status" "pending"; then
_info "Pending, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
- elif [ "$status" = "processing" ]; then
+ elif _contains "$status" "processing"; then
_info "Processing, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
else
- _err "$d:Verify error:$response"
+ _err "Unknown status: $status, $d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
_sleep 2
_debug "checking"
- _send_signed_request "$uri"
+ _send_signed_request "$_authz_url"
if [ "$?" != "0" ]; then
- _err "$d:Verify error:$response"
+ _err "Invalid code, $d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
+ _debug2 DOMAIN_CONF "$DOMAIN_CONF"
. "$DOMAIN_CONF"
_savedomainconf Le_DeployHook "$_hooks"
uri="${ACME_REVOKE_CERT}"
+ _info "Try account key first."
+ if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then
+ if [ -z "$response" ]; then
+ _info "Revoke success."
+ rm -f "$CERT_PATH"
+ cat "$CERT_KEY_PATH" >"$CERT_KEY_PATH.revoked"
+ cat "$CSR_PATH" >"$CSR_PATH.revoked"
+ return 0
+ else
+ _err "Revoke error."
+ _debug "$response"
+ fi
+ fi
+
if [ -f "$CERT_KEY_PATH" ]; then
- _info "Try domain key first."
+ _info "Try domain key."
if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then
if [ -z "$response" ]; then
_info "Revoke success."
else
_info "Domain key file doesn't exist."
fi
-
- _info "Try account key."
-
- if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then
- if [ -z "$response" ]; then
- _info "Revoke success."
- rm -f "$CERT_PATH"
- cat "$CERT_KEY_PATH" >"$CERT_KEY_PATH.revoked"
- cat "$CSR_PATH" >"$CSR_PATH.revoked"
- return 0
- else
- _err "Revoke error."
- _debug "$response"
- fi
- fi
return 1
}
-f, --force Force install, force cert renewal or override sudo restrictions.
--staging, --test Use staging server, for testing.
- --debug [0|1|2|3] Output debug info. Defaults to 1 if argument is omitted.
+ --debug [0|1|2|3] Output debug info. Defaults to $DEBUG_LEVEL_DEFAULT if argument is omitted.
--output-insecure Output all the sensitive messages.
By default all the credentials/sensitive messages are hidden from the output/debug/log for security.
-w, --webroot <directory> Specifies the web root folder for web root mode.
-k, --keylength <bits> Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384, ec-521.
-ak, --accountkeylength <bits> Specifies the account key length: 2048, 3072, 4096
--log [file] Specifies the log file. Defaults to \"$DEFAULT_LOG_FILE\" if argument is omitted.
- --log-level <1|2> Specifies the log level, default is 1.
+ --log-level <1|2> Specifies the log level, default is $DEFAULT_LOG_LEVEL.
--syslog <0|3|6|7> Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
--eab-kid <eab_key_id> Key Identifier for External Account Binding.
--eab-hmac-key <eab_hmac_key> HMAC key for External Account Binding.
These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert:
- --cert-file <file> Path to copy the cert file to after issue/renew..
+ --cert-file <file> Path to copy the cert file to after issue/renew.
--key-file <file> Path to copy the key file to after issue/renew.
--ca-file <file> Path to copy the intermediate cert file to after issue/renew.
--fullchain-file <file> Path to copy the fullchain cert file to after issue/renew.
--no-profile Only valid for '--install' command, which means: do not install aliases to user profile.
--no-color Do not output color text.
--force-color Force output of color text. Useful for non-interactive use with the aha tool for HTML E-Mails.
- --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--to-pkcs12' and '--create-csr'
+ --ecc Specifies use of the ECC cert. Only valid for '--install-cert', '--renew', '--remove ', '--revoke',
+ '--deploy', '--to-pkcs8', '--to-pkcs12' and '--create-csr'.
--csr <file> Specifies the input csr.
--pre-hook <command> Command to be run before obtaining any certificates.
--post-hook <command> Command to be run after attempting to obtain/renew certificates. Runs regardless of whether obtain/renew succeeded or failed.
--keylength | -k)
_keylength="$2"
shift
+ if [ "$_keylength" ] && ! _isEccKey "$_keylength"; then
+ export __SELECTED_RSA_KEY=1
+ fi
;;
-ak | --accountkeylength)
_accountkeylength="$2"