]> git.proxmox.com Git - mirror_acme.sh.git/blobdiff - acme.sh
Merge pull request #3734 from acmesh-official/dev
[mirror_acme.sh.git] / acme.sh
diff --git a/acme.sh b/acme.sh
index 0dd8b678625af80f5e39dada3277afccae056fb1..a5ac9e47bc54882cb0b1b87266655630ed186407 100755 (executable)
--- a/acme.sh
+++ b/acme.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env sh
 
-VER=3.0.0
+VER=3.0.1
 
 PROJECT_NAME="acme.sh"
 
@@ -20,6 +20,8 @@ _SUB_FOLDER_DEPLOY="deploy"
 
 _SUB_FOLDERS="$_SUB_FOLDER_DNSAPI $_SUB_FOLDER_DEPLOY $_SUB_FOLDER_NOTIFY"
 
+CA_LETSENCRYPT_V1="https://acme-v01.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"
 
@@ -1768,7 +1770,7 @@ _inithttp() {
     if [ -z "$ACME_HTTP_NO_REDIRECTS" ]; then
       _ACME_CURL="$_ACME_CURL -L "
     fi
-    if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
+    if [ "$DEBUG" ] && [ "$DEBUG" -ge 2 ]; then
       _CURL_DUMP="$(_mktemp)"
       _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP "
     fi
@@ -1808,6 +1810,8 @@ _inithttp() {
 
 }
 
+_HTTP_MAX_RETRY=8
+
 # body  url [needbase64] [POST|PUT|DELETE] [ContentType]
 _post() {
   body="$1"
@@ -1815,6 +1819,33 @@ _post() {
   needbase64="$3"
   httpmethod="$4"
   _postContentType="$5"
+  _sleep_retry_sec=1
+  _http_retry_times=0
+  _hcode=0
+  while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do
+    [ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ]
+    _lastHCode="$?"
+    _debug "Retrying post"
+    _post_impl "$body" "$_post_url" "$needbase64" "$httpmethod" "$_postContentType" "$_lastHCode"
+    _hcode="$?"
+    _debug _hcode "$_hcode"
+    if [ "$_hcode" = "0" ]; then
+      break
+    fi
+    _http_retry_times=$(_math $_http_retry_times + 1)
+    _sleep $_sleep_retry_sec
+  done
+  return $_hcode
+}
+
+# body  url [needbase64] [POST|PUT|DELETE] [ContentType] [displayError]
+_post_impl() {
+  body="$1"
+  _post_url="$2"
+  needbase64="$3"
+  httpmethod="$4"
+  _postContentType="$5"
+  displayError="$6"
 
   if [ -z "$httpmethod" ]; then
     httpmethod="POST"
@@ -1866,7 +1897,9 @@ _post() {
     fi
     _ret="$?"
     if [ "$_ret" != "0" ]; then
-      _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
+      if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
+        _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
+      fi
       if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
         _err "Here is the curl dump log:"
         _err "$(cat "$_CURL_DUMP")"
@@ -1922,7 +1955,9 @@ _post() {
       _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
     fi
     if [ "$_ret" != "0" ]; then
-      _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
+      if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
+        _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
+      fi
     fi
     _sed_i "s/^ *//g" "$HTTP_HEADER"
   else
@@ -1936,13 +1971,38 @@ _post() {
 
 # url getheader timeout
 _get() {
+  url="$1"
+  onlyheader="$2"
+  t="$3"
+  _sleep_retry_sec=1
+  _http_retry_times=0
+  _hcode=0
+  while [ "${_http_retry_times}" -le "$_HTTP_MAX_RETRY" ]; do
+    [ "$_http_retry_times" = "$_HTTP_MAX_RETRY" ]
+    _lastHCode="$?"
+    _debug "Retrying GET"
+    _get_impl "$url" "$onlyheader" "$t" "$_lastHCode"
+    _hcode="$?"
+    _debug _hcode "$_hcode"
+    if [ "$_hcode" = "0" ]; then
+      break
+    fi
+    _http_retry_times=$(_math $_http_retry_times + 1)
+    _sleep $_sleep_retry_sec
+  done
+  return $_hcode
+}
+
+# url getheader timeout displayError
+_get_impl() {
   _debug GET
   url="$1"
   onlyheader="$2"
   t="$3"
+  displayError="$4"
   _debug url "$url"
   _debug "timeout=$t"
-
+  _debug "displayError" "$displayError"
   _inithttp
 
   if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
@@ -1961,7 +2021,9 @@ _get() {
     fi
     ret=$?
     if [ "$ret" != "0" ]; then
-      _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
+      if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
+        _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
+      fi
       if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
         _err "Here is the curl dump log:"
         _err "$(cat "$_CURL_DUMP")"
@@ -1987,7 +2049,9 @@ _get() {
       _debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
     fi
     if [ "$ret" != "0" ]; then
-      _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
+      if [ -z "$displayError" ] || [ "$displayError" = "0" ]; then
+        _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
+      fi
     fi
   else
     ret=$?
@@ -2535,6 +2599,16 @@ __initHome() {
   fi
 }
 
+_clearAPI() {
+  ACME_NEW_ACCOUNT=""
+  ACME_KEY_CHANGE=""
+  ACME_NEW_AUTHZ=""
+  ACME_NEW_ORDER=""
+  ACME_REVOKE_CERT=""
+  ACME_NEW_NONCE=""
+  ACME_AGREEMENT=""
+}
+
 #server
 _initAPI() {
   _api_server="${1:-$ACME_DIRECTORY}"
@@ -2590,6 +2664,9 @@ _initAPI() {
     _info "Sleep $_sleep_retry_sec and retry."
     _sleep "$_sleep_retry_sec"
   done
+  if [ "$ACME_NEW_ACCOUNT" ] && [ "$ACME_NEW_ORDER" ]; then
+    return 0
+  fi
   _err "Can not init api, for $_api_server"
   return 1
 }
@@ -3093,7 +3170,7 @@ _checkConf() {
         if ! _startswith "$included" "/" && _exists dirname; then
           _relpath="$(dirname "$_c_file")"
           _debug "_relpath" "$_relpath"
-          included="$_relpath/included"
+          included="$_relpath/$included"
         fi
         if _checkConf "$1" "$included"; then
           return 0
@@ -3305,6 +3382,8 @@ _on_before_issue() {
   if [ "$_chk_pre_hook" ]; then
     _info "Run pre hook:'$_chk_pre_hook'"
     if ! (
+      export Le_Domain="$_chk_main_domain"
+      export Le_Alt="$_chk_alt_domains"
       cd "$DOMAIN_PATH" && eval "$_chk_pre_hook"
     ); then
       _err "Error when run pre hook."
@@ -3366,7 +3445,7 @@ _on_before_issue() {
       _netprc="$(_ss "$_checkport" | grep "$_checkport")"
       netprc="$(echo "$_netprc" | grep "$_checkaddr")"
       if [ -z "$netprc" ]; then
-        netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")"
+        netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS:$_checkport")"
       fi
       if [ "$netprc" ]; then
         _err "$netprc"
@@ -3564,7 +3643,7 @@ _regAccount() {
         return 1
       fi
       _secure_debug2 _eabresp "$_eabresp"
-      _eab_id="$(echo "$_eabresp" | tr ',}' '\n' | grep '"eab_kid"' | cut -d : -f 2 | tr -d '"')"
+      _eab_id="$(echo "$_eabresp" | tr ',}' '\n\n' | grep '"eab_kid"' | cut -d : -f 2 | tr -d '"')"
       _secure_debug2 _eab_id "$_eab_id"
       if [ -z "$_eab_id" ]; then
         _err "Can not resolve _eab_id"
@@ -3912,7 +3991,7 @@ _ns_lookup_ali() {
 }
 
 _ns_is_available_dp() {
-  if _get "https://dns.alidns.com" "" 1 >/dev/null 2>&1; then
+  if _get "https://doh.pub" "" 1 >/dev/null 2>&1; then
     return 0
   else
     return 1
@@ -4132,6 +4211,10 @@ issue() {
   if [ -z "$_ACME_IS_RENEW" ]; then
     _initpath "$_main_domain" "$_key_length"
     mkdir -p "$DOMAIN_PATH"
+  elif ! _hasfield "$_web_roots" "$W_DNS"; then
+    Le_OrderFinalize=""
+    Le_LinkOrder=""
+    Le_LinkCert=""
   fi
 
   if _hasfield "$_web_roots" "$W_DNS" && [ -z "$FORCE_DNS_MANUAL" ]; then
@@ -4699,26 +4782,13 @@ $_authorizations_map"
         return 1
       fi
 
-      _debug "sleep 2 secs to verify"
-      sleep 2
-      _debug "checking"
-
-      _send_signed_request "$uri"
-
-      if [ "$?" != "0" ]; then
-        _err "$d:Verify error:$response"
-        _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
-        _clearup
-        _on_issue_err "$_post_hook" "$vlist"
-        return 1
-      fi
       _debug2 original "$response"
 
       response="$(echo "$response" | _normalizeJson)"
       _debug2 response "$response"
 
       status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
-
+      _debug2 status "$status"
       if _contains "$status" "invalid"; then
         error="$(echo "$response" | _egrep_o '"error":\{[^\}]*')"
         _debug2 error "$error"
@@ -4750,9 +4820,9 @@ $_authorizations_map"
       fi
 
       if [ "$status" = "pending" ]; then
-        _info "Pending"
+        _info "Pending, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
       elif [ "$status" = "processing" ]; then
-        _info "Processing"
+        _info "Processing, The CA is processing your order, please just wait. ($waittimes/$MAX_RETRY_TIMES)"
       else
         _err "$d:Verify error:$response"
         _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
@@ -4760,7 +4830,19 @@ $_authorizations_map"
         _on_issue_err "$_post_hook" "$vlist"
         return 1
       fi
+      _debug "sleep 2 secs to verify again"
+      sleep 2
+      _debug "checking"
+
+      _send_signed_request "$uri"
 
+      if [ "$?" != "0" ]; then
+        _err "$d:Verify error:$response"
+        _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
+        _clearup
+        _on_issue_err "$_post_hook" "$vlist"
+        return 1
+      fi
     done
 
   done
@@ -4852,7 +4934,9 @@ $_authorizations_map"
 
   echo "$response" >"$CERT_PATH"
   _split_cert_chain "$CERT_PATH" "$CERT_FULLCHAIN_PATH" "$CA_CERT_PATH"
-
+  if [ -z "$_preferred_chain" ]; then
+    _preferred_chain=$(_readcaconf DEFAULT_PREFERRED_CHAIN)
+  fi
   if [ "$_preferred_chain" ] && [ -f "$CERT_FULLCHAIN_PATH" ]; then
     if [ "$DEBUG" ]; then
       _debug "default chain issuers: " "$(_get_chain_issuers "$CERT_FULLCHAIN_PATH")"
@@ -4906,10 +4990,10 @@ $_authorizations_map"
     _info "$(__green "Cert success.")"
     cat "$CERT_PATH"
 
-    _info "Your cert is in $(__green " $CERT_PATH ")"
+    _info "Your cert is in: $(__green "$CERT_PATH")"
 
     if [ -f "$CERT_KEY_PATH" ]; then
-      _info "Your cert key is in $(__green " $CERT_KEY_PATH ")"
+      _info "Your cert key is in: $(__green "$CERT_KEY_PATH")"
     fi
 
     if [ ! "$USER_PATH" ] || [ ! "$_ACME_IN_CRON" ]; then
@@ -4918,8 +5002,8 @@ $_authorizations_map"
     fi
   fi
 
-  [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")"
-  [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")"
+  [ -f "$CA_CERT_PATH" ] && _info "The intermediate CA cert is in: $(__green "$CA_CERT_PATH")"
+  [ -f "$CERT_FULLCHAIN_PATH" ] && _info "And the full chain certs is there: $(__green "$CERT_FULLCHAIN_PATH")"
 
   Le_CertCreateTime=$(_time)
   _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
@@ -5030,8 +5114,16 @@ renew() {
 
   . "$DOMAIN_CONF"
   _debug Le_API "$Le_API"
+  if [ -z "$Le_API" ] || [ "$CA_LETSENCRYPT_V1" = "$Le_API" ]; then
+    #if this is from an old version, Le_API is empty,
+    #so, we force to use letsencrypt server
+    Le_API="$CA_LETSENCRYPT_V2"
+  fi
 
   if [ "$Le_API" ]; then
+    if [ "$Le_API" != "$ACME_DIRECTORY" ]; then
+      _clearAPI
+    fi
     export ACME_DIRECTORY="$Le_API"
     #reload ca configs
     ACCOUNT_KEY_PATH=""
@@ -5039,6 +5131,7 @@ renew() {
     CA_CONF=""
     _debug3 "initpath again."
     _initpath "$Le_Domain" "$_isEcc"
+    _initAPI
   fi
 
   if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
@@ -5454,7 +5547,7 @@ _installcert() {
   mkdir -p "$_backup_path"
 
   if [ "$_real_cert" ]; then
-    _info "Installing cert to:$_real_cert"
+    _info "Installing cert to: $_real_cert"
     if [ -f "$_real_cert" ] && [ ! "$_ACME_IS_RENEW" ]; then
       cp "$_real_cert" "$_backup_path/cert.bak"
     fi
@@ -5462,7 +5555,7 @@ _installcert() {
   fi
 
   if [ "$_real_ca" ]; then
-    _info "Installing CA to:$_real_ca"
+    _info "Installing CA to: $_real_ca"
     if [ "$_real_ca" = "$_real_cert" ]; then
       echo "" >>"$_real_ca"
       cat "$CA_CERT_PATH" >>"$_real_ca" || return 1
@@ -5475,7 +5568,7 @@ _installcert() {
   fi
 
   if [ "$_real_key" ]; then
-    _info "Installing key to:$_real_key"
+    _info "Installing key to: $_real_key"
     if [ -f "$_real_key" ] && [ ! "$_ACME_IS_RENEW" ]; then
       cp "$_real_key" "$_backup_path/key.bak"
     fi
@@ -5488,7 +5581,7 @@ _installcert() {
   fi
 
   if [ "$_real_fullchain" ]; then
-    _info "Installing full chain to:$_real_fullchain"
+    _info "Installing full chain to: $_real_fullchain"
     if [ -f "$_real_fullchain" ] && [ ! "$_ACME_IS_RENEW" ]; then
       cp "$_real_fullchain" "$_backup_path/fullchain.bak"
     fi
@@ -5656,7 +5749,7 @@ uninstallcronjob() {
   _info "Removing cron job"
   cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")"
   if [ "$cr" ]; then
-    if _exists uname && uname -a | grep solaris >/dev/null; then
+    if _exists uname && uname -a | grep SunOS >/dev/null; then
       $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB --
     else
       $_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -
@@ -5696,6 +5789,23 @@ revoke() {
     return 1
   fi
 
+  . "$DOMAIN_CONF"
+  _debug Le_API "$Le_API"
+
+  if [ "$Le_API" ]; then
+    if [ "$Le_API" != "$ACME_DIRECTORY" ]; then
+      _clearAPI
+    fi
+    export ACME_DIRECTORY="$Le_API"
+    #reload ca configs
+    ACCOUNT_KEY_PATH=""
+    ACCOUNT_JSON_PATH=""
+    CA_CONF=""
+    _debug3 "initpath again."
+    _initpath "$Le_Domain" "$_isEcc"
+    _initAPI
+  fi
+
   cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)"
 
   if [ -z "$cert" ]; then
@@ -5775,7 +5885,24 @@ remove() {
 _deactivate() {
   _d_domain="$1"
   _d_type="$2"
-  _initpath
+  _initpath "$_d_domain" "$_d_type"
+
+  . "$DOMAIN_CONF"
+  _debug Le_API "$Le_API"
+
+  if [ "$Le_API" ]; then
+    if [ "$Le_API" != "$ACME_DIRECTORY" ]; then
+      _clearAPI
+    fi
+    export ACME_DIRECTORY="$Le_API"
+    #reload ca configs
+    ACCOUNT_KEY_PATH=""
+    ACCOUNT_JSON_PATH=""
+    CA_CONF=""
+    _debug3 "initpath again."
+    _initpath "$Le_Domain" "$_d_type"
+    _initAPI
+  fi
 
   _identifiers="{\"type\":\"dns\",\"value\":\"$_d_domain\"}"
   if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
@@ -5806,7 +5933,7 @@ _deactivate() {
   _debug2 response "$response"
   _URL_NAME="url"
 
-  entries="$(echo "$response" | tr '][' '==' | _egrep_o "challenges\": *=[^=]*=" | tr '}{' '\n' | grep "\"status\": *\"valid\"")"
+  entries="$(echo "$response" | tr '][' '==' | _egrep_o "challenges\": *=[^=]*=" | tr '}{' '\n\n' | grep "\"status\": *\"valid\"")"
   if [ -z "$entries" ]; then
     _info "No valid entries found."
     if [ -z "$thumbprint" ]; then
@@ -6422,6 +6549,8 @@ Commands:
   --deactivate             Deactivate the domain authz, professional use.
   --set-default-ca         Used with '--server', Set the default CA to use.
                            See: $_SERVER_WIKI
+  --set-default-chain      Set the default preferred chain for a CA.
+                           See: $_PREFERRED_CHAIN_WIKI
 
 
 Parameters:
@@ -6570,7 +6699,7 @@ _getRepoHash() {
   _hash_path=$1
   shift
   _hash_url="https://api.github.com/repos/acmesh-official/$PROJECT_NAME/git/refs/$_hash_path"
-  _get $_hash_url | tr -d "\r\n" | tr '{},' '\n' | grep '"sha":' | cut -d '"' -f 4
+  _get $_hash_url | tr -d "\r\n" | tr '{},' '\n\n\n' | grep '"sha":' | cut -d '"' -f 4
 }
 
 _getUpgradeHash() {
@@ -6708,6 +6837,18 @@ setdefaultca() {
   _info "Changed default CA to: $(__green "$ACME_DIRECTORY")"
 }
 
+#preferred-chain
+setdefaultchain() {
+  _initpath
+  _preferred_chain="$1"
+  if [ -z "$_preferred_chain" ]; then
+    _err "Please give a '--preferred-chain value' value."
+    return 1
+  fi
+  mkdir -p "$CA_DIR"
+  _savecaconf "DEFAULT_PREFERRED_CHAIN" "$_preferred_chain"
+}
+
 _process() {
   _CMD=""
   _domain=""
@@ -6859,6 +7000,9 @@ _process() {
     --set-default-ca)
       _CMD="setdefaultca"
       ;;
+    --set-default-chain)
+      _CMD="setdefaultchain"
+      ;;
     -d | --domain)
       _dvalue="$2"
 
@@ -7389,6 +7533,9 @@ _process() {
   setdefaultca)
     setdefaultca
     ;;
+  setdefaultchain)
+    setdefaultchain "$_preferred_chain"
+    ;;
   *)
     if [ "$_CMD" ]; then
       _err "Invalid command: $_CMD"