From 2a188905daa83d645ddba3ec6034231e7e51941a Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:49:45 +0800 Subject: [PATCH 1/8] support `--server` --- acme.sh | 104 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/acme.sh b/acme.sh index 84de9824..70381336 100755 --- a/acme.sh +++ b/acme.sh @@ -13,7 +13,8 @@ _SCRIPT_="$0" _SUB_FOLDERS="dnsapi deploy" -DEFAULT_CA="https://acme-v01.api.letsencrypt.org" +_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org" +DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory" DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" @@ -24,7 +25,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" -STAGE_CA="https://acme-staging.api.letsencrypt.org" +STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -1714,8 +1715,8 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce." - nonceurl="$API/directory" + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" _headers="$(_get "$nonceurl" "onlyheader")" if [ "$?" != "0" ]; then @@ -2169,6 +2170,53 @@ __initHome() { fi } +#server +_initAPI() { + _api_server="${1:-$ACME_DIRECTORY}" + _debug "_init api for server: $_api_server" + + if [ "$_api_server" = "$DEFAULT_CA" ]; then + #just for performance, hardcode the default entry points + export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" + export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" + export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" + fi + + if [ -z "$ACME_KEY_CHANGE" ]; then + response=$(_get "$_api_server") + if [ "$?" != "0" ]; then + _debug2 "response" "$response" + _err "Can not init api." + return 1 + fi + _debug2 "response" "$response" + + ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_KEY_CHANGE + + ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_AUTHZ + + ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_CERT + + ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_REG + + ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_REVOKE_CERT + + fi + + _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" + _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" + _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" + _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" +} + #[domain] [keylength] _initpath() { @@ -2189,17 +2237,19 @@ _initpath() { CA_HOME="$DEFAULT_CA_HOME" fi - if [ -z "$API" ]; then + if [ -z "$ACME_DIRECTORY" ]; then if [ -z "$STAGE" ]; then - API="$DEFAULT_CA" + ACME_DIRECTORY="$DEFAULT_CA" else - API="$STAGE_CA" - _info "Using stage api:$API" + ACME_DIRECTORY="$STAGE_CA" + _info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" fi fi - _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')" - CA_DIR="$CA_HOME/$_API_HOST" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" + + CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" _DEFAULT_CA_CONF="$CA_DIR/ca.conf" @@ -3020,7 +3070,7 @@ _regAccount() { if ! _calcjwk "$ACCOUNT_KEY_PATH"; then return 1 fi - + _initAPI _updateTos="" _reg_res="new-reg" while true; do @@ -3035,7 +3085,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3126,7 +3176,7 @@ __get_domain_new_authz() { _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do _debug "Try new-authz for the $_authz_i time." - if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then + if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then _err "Can not get domain new authz." return 1 fi @@ -3204,13 +3254,16 @@ issue() { if [ "$_web_roots" = "dns-cx" ]; then _web_roots="dns_cx" fi - _debug "Using api: $API" if [ ! "$IS_RENEW" ]; then _initpath "$_main_domain" "$_key_length" mkdir -p "$DOMAIN_PATH" fi + _debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" + + _initAPI + if [ -f "$DOMAIN_CONF" ]; then Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) _debug Le_NextRenewTime "$Le_NextRenewTime" @@ -3244,7 +3297,7 @@ issue() { _cleardomainconf "Le_LocalAddress" fi - Le_API="$API" + Le_API="$ACME_DIRECTORY" _savedomainconf "Le_API" "$Le_API" if [ "$_alt_domains" = "$NO_VALUE" ]; then @@ -3683,7 +3736,7 @@ 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 "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 @@ -3736,7 +3789,8 @@ issue() { 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 - Le_LinkIssuer="$API$Le_LinkIssuer" + _info "$(__red "Relative issuer link found.")" + Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" fi _debug Le_LinkIssuer "$Le_LinkIssuer" _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" @@ -3852,7 +3906,11 @@ renew() { . "$DOMAIN_CONF" if [ "$Le_API" ]; then - API="$Le_API" + if [ "$_OLD_CA_HOST" = "$Le_API" ]; then + export Le_API="$DEFAULT_CA" + _savedomainconf Le_API "$Le_API" + fi + export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" ACCOUNT_JSON_PATH="" @@ -4315,8 +4373,10 @@ revoke() { return 1 fi + _initAPI + data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" - uri="$API/acme/revoke-cert" + uri="${ACME_REVOKE_CERT}" if [ -f "$CERT_KEY_PATH" ]; then _info "Try domain key first." @@ -4875,6 +4935,7 @@ Parameters: --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. + --server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory) --accountconf Specifies a customized account config file. --home Specifies the home dir for $PROJECT_NAME . --cert-home Specifies the home dir to save all the certs, only valid for '--install' command. @@ -5150,6 +5211,11 @@ _process() { --staging | --test) STAGE="1" ;; + --server) + ACME_DIRECTORY="$2" + export ACME_DIRECTORY + shift + ;; --debug) if [ -z "$2" ] || _startswith "$2" "-"; then DEBUG="$DEBUG_LEVEL_DEFAULT" From f8c1d97a258f8c8769facee5432a78cfc4dabefb Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 15:59:27 +0800 Subject: [PATCH 2/8] fix format --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 70381336..2c2130d5 100755 --- a/acme.sh +++ b/acme.sh @@ -2174,7 +2174,7 @@ __initHome() { _initAPI() { _api_server="${1:-$ACME_DIRECTORY}" _debug "_init api for server: $_api_server" - + if [ "$_api_server" = "$DEFAULT_CA" ]; then #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" From 287623df58d0603056e560a7c046585237dfe249 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:20:32 +0800 Subject: [PATCH 3/8] fix for deactivate function --- acme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index 2c2130d5..e1e66d85 100755 --- a/acme.sh +++ b/acme.sh @@ -3171,7 +3171,7 @@ _findHook() { __get_domain_new_authz() { _gdnd="$1" _info "Getting new-authz for domain" "$_gdnd" - + _initAPI _Max_new_authz_retry_times=5 _authz_i=0 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do From cbb74c984fa52d44137cf9f62421e4422312c991 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 16:30:04 +0800 Subject: [PATCH 4/8] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index e1e66d85..27d1cc49 100755 --- a/acme.sh +++ b/acme.sh @@ -4508,6 +4508,7 @@ deactivate() { _d_domain_list="$1" _d_type="$2" _initpath + _initAPI _debug _d_domain_list "$_d_domain_list" if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" From ce59fc6c102ec113921c1a20b81a487316e2db79 Mon Sep 17 00:00:00 2001 From: neilpang Date: Sat, 17 Jun 2017 17:15:37 +0800 Subject: [PATCH 5/8] fix renew for stage cert --- acme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/acme.sh b/acme.sh index 27d1cc49..d2c8cf24 100755 --- a/acme.sh +++ b/acme.sh @@ -26,6 +26,7 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 DEFAULT_OPENSSL_BIN="openssl" STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" +_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" VTYPE_HTTP="http-01" VTYPE_DNS="dns-01" @@ -3910,6 +3911,10 @@ renew() { export Le_API="$DEFAULT_CA" _savedomainconf Le_API "$Le_API" fi + if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then + export Le_API="$STAGE_CA" + _savedomainconf Le_API "$Le_API" + fi export ACME_DIRECTORY="$Le_API" #reload ca configs ACCOUNT_KEY_PATH="" From 8afec596aabe4795036b7387e092c7cb4cd6995b Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:05:43 +0800 Subject: [PATCH 6/8] fix https://github.com/Neilpang/acme.sh/issues/882#issuecomment-309383956 --- acme.sh | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/acme.sh b/acme.sh index d2c8cf24..c9c58074 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,9 +1716,18 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then - _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" - nonceurl="$ACME_DIRECTORY" - _headers="$(_get "$nonceurl" "onlyheader")" + if [ "$ACME_NEW_NONCE" ]; then + _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" + nonceurl="$ACME_NEW_NONCE" + if _post "" "$nonceurl" "" "HEAD"; then + _headers="$(cat "$HTTP_HEADER")" + fi + fi + if [ -z "$_headers" ]; then + _debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY" + nonceurl="$ACME_DIRECTORY" + _headers="$(_get "$nonceurl" "onlyheader")" + fi if [ "$?" != "0" ]; then _err "Can not connect to $nonceurl to get nonce." @@ -2180,12 +2189,12 @@ _initAPI() { #just for performance, hardcode the default entry points export ACME_KEY_CHANGE="https://acme-v01.api.letsencrypt.org/acme/key-change" export ACME_NEW_AUTHZ="https://acme-v01.api.letsencrypt.org/acme/new-authz" - export ACME_NEW_CERT="https://acme-v01.api.letsencrypt.org/acme/new-cert" - export ACME_NEW_REG="https://acme-v01.api.letsencrypt.org/acme/new-reg" + export ACME_NEW_ORDER="https://acme-v01.api.letsencrypt.org/acme/new-cert" + export ACME_NEW_ACCOUNT="https://acme-v01.api.letsencrypt.org/acme/new-reg" export ACME_REVOKE_CERT="https://acme-v01.api.letsencrypt.org/acme/revoke-cert" fi - if [ -z "$ACME_KEY_CHANGE" ]; then + if [ -z "$ACME_NEW_ACCOUNT" ]; then response=$(_get "$_api_server") if [ "$?" != "0" ]; then _debug2 "response" "$response" @@ -2200,21 +2209,30 @@ _initAPI() { ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_NEW_AUTHZ - ACME_NEW_CERT=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_CERT + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ORDER" ]; then + ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ORDER - ACME_NEW_REG=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) - export ACME_NEW_REG + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3) + if [ -z "$ACME_NEW_ACCOUNT" ]; then + ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3) + fi + export ACME_NEW_ACCOUNT ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3) export ACME_REVOKE_CERT + ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3) + export ACME_NEW_NONCE + fi _debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE" _debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ" - _debug "ACME_NEW_CERT" "$ACME_NEW_CERT" - _debug "ACME_NEW_REG" "$ACME_NEW_REG" + _debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER" + _debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" _debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" } @@ -3086,7 +3104,7 @@ _regAccount() { if [ -z "$_updateTos" ]; then _info "Registering account" - if ! _send_signed_request "${ACME_NEW_REG}" "$regjson"; then + if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then _err "Register account Error: $response" return 1 fi @@ -3737,7 +3755,7 @@ 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_CERT}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then + if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then _err "Sign failed." _on_issue_err "$_post_hook" return 1 From 87f3dc4558dbdb0f54a0adf6d9f2df093bbb6985 Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:19:30 +0800 Subject: [PATCH 7/8] fix server host --- acme.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/acme.sh b/acme.sh index c9c58074..18ed71a7 100755 --- a/acme.sh +++ b/acme.sh @@ -2265,7 +2265,7 @@ _initpath() { fi fi - _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -d '/')" + _ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)" _debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" @@ -5119,6 +5119,7 @@ _process() { _openssl_bin="" _syslog="" _use_wget="" + _server="" while [ ${#} -gt 0 ]; do case "${1}" in @@ -5237,6 +5238,7 @@ _process() { ;; --server) ACME_DIRECTORY="$2" + _server="$ACME_DIRECTORY" export ACME_DIRECTORY shift ;; @@ -5560,6 +5562,9 @@ _process() { if [ "$DEBUG" ]; then version + if [ "$_server" ]; then + _debug "Using server: $_server" + fi fi case "${_CMD}" in From 1d384e3192a4ace6d3ef708d43e65e0015cd2e1d Mon Sep 17 00:00:00 2001 From: neilpang Date: Mon, 19 Jun 2017 20:24:31 +0800 Subject: [PATCH 8/8] minor --- acme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/acme.sh b/acme.sh index 18ed71a7..428340d2 100755 --- a/acme.sh +++ b/acme.sh @@ -1716,6 +1716,7 @@ _send_signed_request() { while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do _debug3 _request_retry_times "$_request_retry_times" if [ -z "$_CACHED_NONCE" ]; then + _headers="" if [ "$ACME_NEW_NONCE" ]; then _debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE" nonceurl="$ACME_NEW_NONCE"