first version to support ACME v2
							parent
							
								
									45e21d5000
								
							
						
					
					
						commit
						c1151b0d45
					
				
							
								
								
									
										308
									
								
								acme.sh
								
								
								
								
							
							
						
						
									
										308
									
								
								acme.sh
								
								
								
								
							| 
						 | 
				
			
			@ -13,8 +13,15 @@ _SCRIPT_="$0"
 | 
			
		|||
 | 
			
		||||
_SUB_FOLDERS="dnsapi deploy"
 | 
			
		||||
 | 
			
		||||
_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org"
 | 
			
		||||
DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory"
 | 
			
		||||
LETSENCRYPT_CA_V1="https://acme-v01.api.letsencrypt.org/directory"
 | 
			
		||||
LETSENCRYPT_STAGING_CA_V1="https://acme-staging.api.letsencrypt.org/directory"
 | 
			
		||||
 | 
			
		||||
LETSENCRYPT_CA_V2="https://acme-v02.api.letsencrypt.org/directory"
 | 
			
		||||
LETSENCRYPT_STAGING_CA_V2="https://acme-staging-v02.api.letsencrypt.org/directory"
 | 
			
		||||
 | 
			
		||||
DEFAULT_CA=$LETSENCRYPT_CA_V1
 | 
			
		||||
DEFAULT_STAGING_CA=$LETSENCRYPT_STAGING_CA_V1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
 | 
			
		||||
DEFAULT_ACCOUNT_EMAIL=""
 | 
			
		||||
| 
						 | 
				
			
			@ -24,13 +31,13 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048
 | 
			
		|||
 | 
			
		||||
DEFAULT_OPENSSL_BIN="openssl"
 | 
			
		||||
 | 
			
		||||
STAGE_CA="https://acme-staging.api.letsencrypt.org/directory"
 | 
			
		||||
_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org"
 | 
			
		||||
_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org"
 | 
			
		||||
 | 
			
		||||
VTYPE_HTTP="http-01"
 | 
			
		||||
VTYPE_DNS="dns-01"
 | 
			
		||||
VTYPE_TLS="tls-sni-01"
 | 
			
		||||
#VTYPE_TLS2="tls-sni-02"
 | 
			
		||||
VTYPE_TLS2="tls-sni-02"
 | 
			
		||||
 | 
			
		||||
LOCAL_ANY_ADDRESS="0.0.0.0"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1044,13 +1051,14 @@ _createcsr() {
 | 
			
		|||
  if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
 | 
			
		||||
    #single domain
 | 
			
		||||
    _info "Single domain" "$domain"
 | 
			
		||||
    printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
 | 
			
		||||
  else
 | 
			
		||||
    domainlist="$(_idn "$domainlist")"
 | 
			
		||||
    _debug2 domainlist "$domainlist"
 | 
			
		||||
    if _contains "$domainlist" ","; then
 | 
			
		||||
      alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")"
 | 
			
		||||
      alt="DNS:$domain,DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")"
 | 
			
		||||
    else
 | 
			
		||||
      alt="DNS:$domainlist"
 | 
			
		||||
      alt="DNS:$domain,DNS:$domainlist"
 | 
			
		||||
    fi
 | 
			
		||||
    #multi
 | 
			
		||||
    _info "Multi domain" "$alt"
 | 
			
		||||
| 
						 | 
				
			
			@ -1421,7 +1429,7 @@ _calcjwk() {
 | 
			
		|||
 | 
			
		||||
    JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}'
 | 
			
		||||
    JWK_HEADERPLACE_PART1='{"nonce": "'
 | 
			
		||||
    JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}'
 | 
			
		||||
    JWK_HEADERPLACE_PART2='", "alg": "RS256"'
 | 
			
		||||
  elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
 | 
			
		||||
    _debug "EC key"
 | 
			
		||||
    crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
 | 
			
		||||
| 
						 | 
				
			
			@ -1490,7 +1498,7 @@ _calcjwk() {
 | 
			
		|||
 | 
			
		||||
    JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}'
 | 
			
		||||
    JWK_HEADERPLACE_PART1='{"nonce": "'
 | 
			
		||||
    JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}'
 | 
			
		||||
    JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
 | 
			
		||||
  else
 | 
			
		||||
    _err "Only RSA or EC key is supported."
 | 
			
		||||
    return 1
 | 
			
		||||
| 
						 | 
				
			
			@ -1580,7 +1588,7 @@ _inithttp() {
 | 
			
		|||
# body  url [needbase64] [POST|PUT]
 | 
			
		||||
_post() {
 | 
			
		||||
  body="$1"
 | 
			
		||||
  url="$2"
 | 
			
		||||
  _post_url="$2"
 | 
			
		||||
  needbase64="$3"
 | 
			
		||||
  httpmethod="$4"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1588,7 +1596,7 @@ _post() {
 | 
			
		|||
    httpmethod="POST"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug $httpmethod
 | 
			
		||||
  _debug "url" "$url"
 | 
			
		||||
  _debug "_post_url" "$_post_url"
 | 
			
		||||
  _debug2 "body" "$body"
 | 
			
		||||
 | 
			
		||||
  _inithttp
 | 
			
		||||
| 
						 | 
				
			
			@ -1600,9 +1608,9 @@ _post() {
 | 
			
		|||
    fi
 | 
			
		||||
    _debug "_CURL" "$_CURL"
 | 
			
		||||
    if [ "$needbase64" ]; then
 | 
			
		||||
      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)"
 | 
			
		||||
      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url" | _base64)"
 | 
			
		||||
    else
 | 
			
		||||
      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")"
 | 
			
		||||
      response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$_post_url")"
 | 
			
		||||
    fi
 | 
			
		||||
    _ret="$?"
 | 
			
		||||
    if [ "$_ret" != "0" ]; then
 | 
			
		||||
| 
						 | 
				
			
			@ -1620,15 +1628,15 @@ _post() {
 | 
			
		|||
    _debug "_WGET" "$_WGET"
 | 
			
		||||
    if [ "$needbase64" ]; then
 | 
			
		||||
      if [ "$httpmethod" = "POST" ]; then
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
 | 
			
		||||
      else
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER" | _base64)"
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      if [ "$httpmethod" = "POST" ]; then
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")"
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
 | 
			
		||||
      else
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")"
 | 
			
		||||
        response="$($_WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$_post_url" 2>"$HTTP_HEADER")"
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    _ret="$?"
 | 
			
		||||
| 
						 | 
				
			
			@ -1776,7 +1784,15 @@ _send_signed_request() {
 | 
			
		|||
    nonce="$_CACHED_NONCE"
 | 
			
		||||
    _debug2 nonce "$nonce"
 | 
			
		||||
 | 
			
		||||
    protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2"
 | 
			
		||||
    if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
      if [ "$url" = "$ACME_NEW_ACCOUNT" ]; then
 | 
			
		||||
        protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
 | 
			
		||||
      else
 | 
			
		||||
        protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"kid\": \"$ACCOUNT_URL\""'}'
 | 
			
		||||
      fi
 | 
			
		||||
    else
 | 
			
		||||
      protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2, \"jwk\": $jwk"'}'
 | 
			
		||||
    fi
 | 
			
		||||
    _debug3 protected "$protected"
 | 
			
		||||
 | 
			
		||||
    protected64="$(printf "%s" "$protected" | _base64 | _url_replace)"
 | 
			
		||||
| 
						 | 
				
			
			@ -1791,7 +1807,11 @@ _send_signed_request() {
 | 
			
		|||
    sig="$(printf "%s" "$_sig_t" | _url_replace)"
 | 
			
		||||
    _debug3 sig "$sig"
 | 
			
		||||
 | 
			
		||||
    body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
 | 
			
		||||
    if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
      body="{\"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
 | 
			
		||||
    else
 | 
			
		||||
      body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
 | 
			
		||||
    fi
 | 
			
		||||
    _debug3 body "$body"
 | 
			
		||||
 | 
			
		||||
    response="$(_post "$body" "$url" "$needbase64")"
 | 
			
		||||
| 
						 | 
				
			
			@ -2170,9 +2190,15 @@ _initAPI() {
 | 
			
		|||
    _debug2 "response" "$response"
 | 
			
		||||
 | 
			
		||||
    ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_KEY_CHANGE" ]; then
 | 
			
		||||
      ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'keyChange" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_KEY_CHANGE
 | 
			
		||||
 | 
			
		||||
    ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_NEW_AUTHZ" ]; then
 | 
			
		||||
      ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'newAuthz" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_NEW_AUTHZ
 | 
			
		||||
 | 
			
		||||
    ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
| 
						 | 
				
			
			@ -2180,6 +2206,9 @@ _initAPI() {
 | 
			
		|||
    if [ -z "$ACME_NEW_ORDER" ]; then
 | 
			
		||||
      ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
      ACME_NEW_ORDER_RES="new-order"
 | 
			
		||||
      if [ -z "$ACME_NEW_ORDER" ]; then
 | 
			
		||||
        ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'newOrder" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_NEW_ORDER
 | 
			
		||||
    export ACME_NEW_ORDER_RES
 | 
			
		||||
| 
						 | 
				
			
			@ -2189,17 +2218,32 @@ _initAPI() {
 | 
			
		|||
    if [ -z "$ACME_NEW_ACCOUNT" ]; then
 | 
			
		||||
      ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
      ACME_NEW_ACCOUNT_RES="new-account"
 | 
			
		||||
      if [ -z "$ACME_NEW_ACCOUNT" ]; then
 | 
			
		||||
        ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'newAccount" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
        if [ "$ACME_NEW_ACCOUNT" ]; then
 | 
			
		||||
          export ACME_VERSION=2
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_NEW_ACCOUNT
 | 
			
		||||
    export ACME_NEW_ACCOUNT_RES
 | 
			
		||||
 | 
			
		||||
    ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_REVOKE_CERT" ]; then
 | 
			
		||||
      ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revokeCert" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_REVOKE_CERT
 | 
			
		||||
 | 
			
		||||
    ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_NEW_NONCE" ]; then
 | 
			
		||||
      ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'newNonce" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_NEW_NONCE
 | 
			
		||||
 | 
			
		||||
    ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    if [ -z "$ACME_AGREEMENT" ]; then
 | 
			
		||||
      ACME_AGREEMENT=$(echo "$response" | _egrep_o 'termsOfService" *: *"[^"]*"' | cut -d '"' -f 3)
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_AGREEMENT
 | 
			
		||||
 | 
			
		||||
    _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE"
 | 
			
		||||
| 
						 | 
				
			
			@ -2208,6 +2252,8 @@ _initAPI() {
 | 
			
		|||
    _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT"
 | 
			
		||||
    _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT"
 | 
			
		||||
    _debug "ACME_AGREEMENT" "$ACME_AGREEMENT"
 | 
			
		||||
    _debug "ACME_NEW_NONCE" "$ACME_NEW_NONCE"
 | 
			
		||||
    _debug "ACME_VERSION" "$ACME_VERSION"
 | 
			
		||||
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2236,7 +2282,7 @@ _initpath() {
 | 
			
		|||
    if [ -z "$STAGE" ]; then
 | 
			
		||||
      ACME_DIRECTORY="$DEFAULT_CA"
 | 
			
		||||
    else
 | 
			
		||||
      ACME_DIRECTORY="$STAGE_CA"
 | 
			
		||||
      ACME_DIRECTORY="$DEFAULT_STAGING_CA"
 | 
			
		||||
      _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY"
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
| 
						 | 
				
			
			@ -2951,6 +2997,7 @@ _on_issue_err() {
 | 
			
		|||
  _chk_post_hook="$1"
 | 
			
		||||
  _chk_vlist="$2"
 | 
			
		||||
  _debug _on_issue_err
 | 
			
		||||
  _cleardomainconf "ORDER_FINALIZE"
 | 
			
		||||
  if [ "$LOG_FILE" ]; then
 | 
			
		||||
    _err "Please check log file for more details: $LOG_FILE"
 | 
			
		||||
  else
 | 
			
		||||
| 
						 | 
				
			
			@ -3052,6 +3099,8 @@ _regAccount() {
 | 
			
		|||
  _initpath
 | 
			
		||||
  _reg_length="$1"
 | 
			
		||||
  _debug3 _regAccount "$_regAccount"
 | 
			
		||||
  _initAPI
 | 
			
		||||
 | 
			
		||||
  mkdir -p "$CA_DIR"
 | 
			
		||||
  if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
 | 
			
		||||
    _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
 | 
			
		||||
| 
						 | 
				
			
			@ -3073,11 +3122,18 @@ _regAccount() {
 | 
			
		|||
  if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  _initAPI
 | 
			
		||||
  _reg_res="$ACME_NEW_ACCOUNT_RES"
 | 
			
		||||
  regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
 | 
			
		||||
  if [ "$ACCOUNT_EMAIL" ]; then
 | 
			
		||||
    regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
 | 
			
		||||
  
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    regjson='{"termsOfServiceAgreed": true}'
 | 
			
		||||
    if [ "$ACCOUNT_EMAIL" ]; then
 | 
			
		||||
      regjson='{"contact": ["mailto: '$ACCOUNT_EMAIL'"], "termsOfServiceAgreed": true}'
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    _reg_res="$ACME_NEW_ACCOUNT_RES"
 | 
			
		||||
    regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
 | 
			
		||||
    if [ "$ACCOUNT_EMAIL" ]; then
 | 
			
		||||
      regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
 | 
			
		||||
    fi
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _info "Registering account"
 | 
			
		||||
| 
						 | 
				
			
			@ -3100,8 +3156,8 @@ _regAccount() {
 | 
			
		|||
  _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
 | 
			
		||||
  _debug "_accUri" "$_accUri"
 | 
			
		||||
  _savecaconf "ACCOUNT_URL" "$_accUri"
 | 
			
		||||
  export ACCOUNT_URL="$ACCOUNT_URL"
 | 
			
		||||
 | 
			
		||||
  echo "$response" >"$ACCOUNT_JSON_PATH"
 | 
			
		||||
  CA_KEY_HASH="$(__calcAccountKeyHash)"
 | 
			
		||||
  _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
 | 
			
		||||
  _savecaconf CA_KEY_HASH "$CA_KEY_HASH"
 | 
			
		||||
| 
						 | 
				
			
			@ -3113,7 +3169,6 @@ _regAccount() {
 | 
			
		|||
 | 
			
		||||
  ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)"
 | 
			
		||||
  _info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT"
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#Implement deactivate account
 | 
			
		||||
| 
						 | 
				
			
			@ -3251,7 +3306,11 @@ __trigger_validation() {
 | 
			
		|||
  _debug2 _t_url "$_t_url"
 | 
			
		||||
  _t_key_authz="$2"
 | 
			
		||||
  _debug2 _t_key_authz "$_t_key_authz"
 | 
			
		||||
  _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    _send_signed_request "$_t_url" "{\"keyAuthorization\": \"$_t_key_authz\"}"
 | 
			
		||||
  else
 | 
			
		||||
    _send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
 | 
			
		||||
  fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#webroot, domain domainlist  keylength
 | 
			
		||||
| 
						 | 
				
			
			@ -3393,32 +3452,107 @@ issue() {
 | 
			
		|||
  sep='#'
 | 
			
		||||
  dvsep=','
 | 
			
		||||
  if [ -z "$vlist" ]; then
 | 
			
		||||
    if [ "$ACME_VERSION" = "2" ] && [ -z "$ORDER_FINALIZE" ]; then
 | 
			
		||||
      #make new order request
 | 
			
		||||
      _identifiers="{\"type\":\"dns\",\"value\":\"$_main_domain\"}"
 | 
			
		||||
      for d in $(echo "$_alt_domains" | tr ',' ' '); do
 | 
			
		||||
        #todo: check wildcard ?
 | 
			
		||||
        if [ "$d" ]; then
 | 
			
		||||
          _identifiers="$_identifiers,{\"type\":\"dns\",\"value\":\"$d\"}"
 | 
			
		||||
        fi
 | 
			
		||||
      done
 | 
			
		||||
      _debug2 _identifiers "$_identifiers"
 | 
			
		||||
      if ! _send_signed_request "$ACME_NEW_ORDER" "{\"identifiers\": [$_identifiers]}"; then
 | 
			
		||||
        _err "Create new order error."
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      ORDER_FINALIZE="$(echo "$response"| tr -d '\r\n' | _egrep_o '"finalize" *: *"[^"]*"' | cut -d '"' -f 4)"
 | 
			
		||||
      _debug ORDER_FINALIZE "$ORDER_FINALIZE"
 | 
			
		||||
      if [ -z "$ORDER_FINALIZE" ]; then
 | 
			
		||||
        _err "ORDER_FINALIZE not found."
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      #for dns manual mode
 | 
			
		||||
      _savedomainconf "ORDER_FINALIZE" "$ORDER_FINALIZE"
 | 
			
		||||
 | 
			
		||||
      _authorizations_seg="$(echo "$response"| tr -d '\r\n' | _egrep_o '"authorizations" *: *\[[^\]*\]' | cut -d '[' -f 2 | tr -d ']' | tr -d '"')"
 | 
			
		||||
      _debug2 _authorizations_seg "$_authorizations_seg"
 | 
			
		||||
      if [ -z "$_authorizations_seg" ]; then
 | 
			
		||||
        _err "_authorizations_seg not found."
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      #domain and authz map
 | 
			
		||||
      _authorizations_map=""
 | 
			
		||||
      for _authz_url in $(echo "$_authorizations_seg" | tr ',' ' ' ); do
 | 
			
		||||
        _debug2 "_authz_url" "$_authz_url"
 | 
			
		||||
        if ! response="$(_get "$_authz_url")"; then
 | 
			
		||||
          _err "get to authz error."
 | 
			
		||||
          _clearup
 | 
			
		||||
          _on_issue_err "$_post_hook"
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
        response="$(echo "$response" | _normalizeJson)"
 | 
			
		||||
        _debug2 response "$response"
 | 
			
		||||
        _d="$(echo "$response" | _egrep_o '"value" *: *"[^"]*"' | cut -d : -f 2 | tr -d ' "')"
 | 
			
		||||
        _debug2 _d "$_d"
 | 
			
		||||
        _authorizations_map="$_d,$response
 | 
			
		||||
$_authorizations_map"
 | 
			
		||||
      done
 | 
			
		||||
      _debug2 _authorizations_map "$_authorizations_map"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ')
 | 
			
		||||
    _index=1
 | 
			
		||||
    _index=0
 | 
			
		||||
    _currentRoot=""
 | 
			
		||||
    for d in $alldomains; do
 | 
			
		||||
      _info "Getting webroot for domain" "$d"
 | 
			
		||||
      _index=$(_math $_index + 1)
 | 
			
		||||
      _w="$(echo $_web_roots | cut -d , -f $_index)"
 | 
			
		||||
      _debug _w "$_w"
 | 
			
		||||
      if [ "$_w" ]; then
 | 
			
		||||
        _currentRoot="$_w"
 | 
			
		||||
      fi
 | 
			
		||||
      _debug "_currentRoot" "$_currentRoot"
 | 
			
		||||
      _index=$(_math $_index + 1)
 | 
			
		||||
 | 
			
		||||
      vtype="$VTYPE_HTTP"
 | 
			
		||||
      #todo, v2 wildcard force to use dns
 | 
			
		||||
      if _startswith "$_currentRoot" "dns"; then
 | 
			
		||||
        vtype="$VTYPE_DNS"
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      if [ "$_currentRoot" = "$W_TLS" ]; then
 | 
			
		||||
        vtype="$VTYPE_TLS"
 | 
			
		||||
        if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
          vtype="$VTYPE_TLS2"
 | 
			
		||||
        else
 | 
			
		||||
          vtype="$VTYPE_TLS"
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      if ! __get_domain_new_authz "$d"; then
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook"
 | 
			
		||||
        return 1
 | 
			
		||||
      if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
        response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")"
 | 
			
		||||
        _debug2 "response" "$response"
 | 
			
		||||
        if [ -z "$response" ]; then
 | 
			
		||||
          _err "get to authz error."
 | 
			
		||||
          _clearup
 | 
			
		||||
          _on_issue_err "$_post_hook"
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        if ! __get_domain_new_authz "$d"; then
 | 
			
		||||
          _clearup
 | 
			
		||||
          _on_issue_err "$_post_hook"
 | 
			
		||||
          return 1
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
 | 
			
		||||
      if [ -z "$thumbprint" ]; then
 | 
			
		||||
| 
						 | 
				
			
			@ -3436,14 +3570,18 @@ issue() {
 | 
			
		|||
      token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
 | 
			
		||||
      _debug token "$token"
 | 
			
		||||
 | 
			
		||||
      uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
 | 
			
		||||
      if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
        uri="$(printf "%s\n" "$entry" | _egrep_o '"url":"[^"]*' | cut -d '"' -f 4 | _head_n 1)"
 | 
			
		||||
      else
 | 
			
		||||
        uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
 | 
			
		||||
      fi
 | 
			
		||||
      _debug uri "$uri"
 | 
			
		||||
 | 
			
		||||
      keyauthorization="$token.$thumbprint"
 | 
			
		||||
      _debug keyauthorization "$keyauthorization"
 | 
			
		||||
 | 
			
		||||
      if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
 | 
			
		||||
        _debug "$d is already verified, skip."
 | 
			
		||||
        _debug "$d is already verified."
 | 
			
		||||
        keyauthorization="$STATE_VERIFIED"
 | 
			
		||||
        _debug keyauthorization "$keyauthorization"
 | 
			
		||||
      fi
 | 
			
		||||
| 
						 | 
				
			
			@ -3685,12 +3823,16 @@ issue() {
 | 
			
		|||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then
 | 
			
		||||
      _err "$d:Challenge error: $response"
 | 
			
		||||
      _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
 | 
			
		||||
      _clearup
 | 
			
		||||
      _on_issue_err "$_post_hook" "$vlist"
 | 
			
		||||
      return 1
 | 
			
		||||
    if [ "$code" ] && [ "$code" != '202' ]; then
 | 
			
		||||
      if [ "$ACME_VERSION" = "2" ] && [ "$code" = '200' ]; then
 | 
			
		||||
        _debug "trigger validation code: $code"
 | 
			
		||||
      else
 | 
			
		||||
        _err "$d:Challenge error: $response"
 | 
			
		||||
        _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
 | 
			
		||||
        _clearup
 | 
			
		||||
        _on_issue_err "$_post_hook" "$vlist"
 | 
			
		||||
        return 1
 | 
			
		||||
      fi
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    waittimes=0
 | 
			
		||||
| 
						 | 
				
			
			@ -3773,18 +3915,32 @@ issue() {
 | 
			
		|||
  _info "Verify finished, start to sign."
 | 
			
		||||
  der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)"
 | 
			
		||||
 | 
			
		||||
  if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
 | 
			
		||||
    _err "Sign failed."
 | 
			
		||||
    _on_issue_err "$_post_hook"
 | 
			
		||||
    return 1
 | 
			
		||||
  fi
 | 
			
		||||
  if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
    if ! _send_signed_request "${ORDER_FINALIZE}" "{\"csr\": \"$der\"}"; then
 | 
			
		||||
      _err "Sign failed."
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$code" != "200" ]; then
 | 
			
		||||
      _err "Sign failed, code is not 200."
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    Le_LinkCert="$(echo "$response"| tr -d '\r\n' | _egrep_o '"certificate" *: *"[^"]*"' | cut -d '"' -f 4)"
 | 
			
		||||
 | 
			
		||||
  _rcert="$response"
 | 
			
		||||
  Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
 | 
			
		||||
  _debug "Le_LinkCert" "$Le_LinkCert"
 | 
			
		||||
  _savedomainconf "Le_LinkCert" "$Le_LinkCert"
 | 
			
		||||
 | 
			
		||||
  if [ "$Le_LinkCert" ]; then
 | 
			
		||||
    if ! _get "$Le_LinkCert" > "$CERT_PATH"; then
 | 
			
		||||
      _err "Sign failed, code is not 200."
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
  else
 | 
			
		||||
    if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
 | 
			
		||||
      _err "Sign failed."
 | 
			
		||||
      _on_issue_err "$_post_hook"
 | 
			
		||||
      return 1
 | 
			
		||||
    fi
 | 
			
		||||
    _rcert="$response"
 | 
			
		||||
    Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
 | 
			
		||||
    echo "$BEGIN_CERT" >"$CERT_PATH"
 | 
			
		||||
 | 
			
		||||
    #if ! _get "$Le_LinkCert" | _base64 "multiline"  >> "$CERT_PATH" ; then
 | 
			
		||||
| 
						 | 
				
			
			@ -3798,6 +3954,12 @@ issue() {
 | 
			
		|||
    fi
 | 
			
		||||
 | 
			
		||||
    echo "$END_CERT" >>"$CERT_PATH"
 | 
			
		||||
  fi
 | 
			
		||||
 | 
			
		||||
  _debug "Le_LinkCert" "$Le_LinkCert"
 | 
			
		||||
  _savedomainconf "Le_LinkCert" "$Le_LinkCert"
 | 
			
		||||
 | 
			
		||||
  if [ "$Le_LinkCert" ]; then
 | 
			
		||||
    _info "$(__green "Cert success.")"
 | 
			
		||||
    cat "$CERT_PATH"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -3825,29 +3987,37 @@ issue() {
 | 
			
		|||
  _cleardomainconf "Le_Vlist"
 | 
			
		||||
 | 
			
		||||
  Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>')
 | 
			
		||||
  if ! _contains "$Le_LinkIssuer" ":"; then
 | 
			
		||||
    _info "$(__red "Relative issuer link found.")"
 | 
			
		||||
    Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer"
 | 
			
		||||
  fi
 | 
			
		||||
  _debug Le_LinkIssuer "$Le_LinkIssuer"
 | 
			
		||||
  _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
 | 
			
		||||
 | 
			
		||||
  if [ "$Le_LinkIssuer" ]; then
 | 
			
		||||
    if ! _contains "$Le_LinkIssuer" ":"; then
 | 
			
		||||
      _info "$(__red "Relative issuer link found.")"
 | 
			
		||||
      Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer"
 | 
			
		||||
    fi
 | 
			
		||||
    _debug Le_LinkIssuer "$Le_LinkIssuer"
 | 
			
		||||
    _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
 | 
			
		||||
 | 
			
		||||
    _link_issuer_retry=0
 | 
			
		||||
    _MAX_ISSUER_RETRY=5
 | 
			
		||||
    while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do
 | 
			
		||||
      _debug _link_issuer_retry "$_link_issuer_retry"
 | 
			
		||||
      if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then
 | 
			
		||||
        echo "$BEGIN_CERT" >"$CA_CERT_PATH"
 | 
			
		||||
        _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH"
 | 
			
		||||
        echo "$END_CERT" >>"$CA_CERT_PATH"
 | 
			
		||||
      
 | 
			
		||||
      if [ "$ACME_VERSION" = "2" ]; then
 | 
			
		||||
        if _get "$Le_LinkIssuer" >"$CA_CERT_PATH"; then
 | 
			
		||||
          break
 | 
			
		||||
        fi
 | 
			
		||||
      else
 | 
			
		||||
        if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then
 | 
			
		||||
          echo "$BEGIN_CERT" >"$CA_CERT_PATH"
 | 
			
		||||
          _base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH"
 | 
			
		||||
          echo "$END_CERT" >>"$CA_CERT_PATH"
 | 
			
		||||
 | 
			
		||||
        _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")"
 | 
			
		||||
        cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH"
 | 
			
		||||
        _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")"
 | 
			
		||||
          _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")"
 | 
			
		||||
          cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH"
 | 
			
		||||
          _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")"
 | 
			
		||||
 | 
			
		||||
        rm -f "$CA_CERT_PATH.der"
 | 
			
		||||
        break
 | 
			
		||||
          rm -f "$CA_CERT_PATH.der"
 | 
			
		||||
          break
 | 
			
		||||
        fi
 | 
			
		||||
      fi
 | 
			
		||||
      _link_issuer_retry=$(_math $_link_issuer_retry + 1)
 | 
			
		||||
      _sleep "$_link_issuer_retry"
 | 
			
		||||
| 
						 | 
				
			
			@ -3957,7 +4127,7 @@ renew() {
 | 
			
		|||
      _savedomainconf Le_API "$Le_API"
 | 
			
		||||
    fi
 | 
			
		||||
    if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then
 | 
			
		||||
      export Le_API="$STAGE_CA"
 | 
			
		||||
      export Le_API="$DEFAULT_STAGING_CA"
 | 
			
		||||
      _savedomainconf Le_API "$Le_API"
 | 
			
		||||
    fi
 | 
			
		||||
    export ACME_DIRECTORY="$Le_API"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue