|
@ -1,6 +1,6 @@ |
|
|
#!/usr/bin/env sh |
|
|
#!/usr/bin/env sh |
|
|
|
|
|
|
|
|
VER=2.7.2 |
|
|
|
|
|
|
|
|
VER=2.7.3 |
|
|
|
|
|
|
|
|
PROJECT_NAME="acme.sh" |
|
|
PROJECT_NAME="acme.sh" |
|
|
|
|
|
|
|
@ -13,7 +13,8 @@ _SCRIPT_="$0" |
|
|
|
|
|
|
|
|
_SUB_FOLDERS="dnsapi deploy" |
|
|
_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_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf" |
|
|
|
|
|
|
|
|
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" |
|
|
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)" |
|
@ -24,7 +25,8 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048 |
|
|
|
|
|
|
|
|
DEFAULT_OPENSSL_BIN="openssl" |
|
|
DEFAULT_OPENSSL_BIN="openssl" |
|
|
|
|
|
|
|
|
STAGE_CA="https://acme-staging.api.letsencrypt.org" |
|
|
|
|
|
|
|
|
STAGE_CA="https://acme-staging.api.letsencrypt.org/directory" |
|
|
|
|
|
_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org" |
|
|
|
|
|
|
|
|
VTYPE_HTTP="http-01" |
|
|
VTYPE_HTTP="http-01" |
|
|
VTYPE_DNS="dns-01" |
|
|
VTYPE_DNS="dns-01" |
|
@ -1714,9 +1716,19 @@ _send_signed_request() { |
|
|
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do |
|
|
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do |
|
|
_debug3 _request_retry_times "$_request_retry_times" |
|
|
_debug3 _request_retry_times "$_request_retry_times" |
|
|
if [ -z "$_CACHED_NONCE" ]; then |
|
|
if [ -z "$_CACHED_NONCE" ]; then |
|
|
_debug2 "Get nonce." |
|
|
|
|
|
nonceurl="$API/directory" |
|
|
|
|
|
|
|
|
_headers="" |
|
|
|
|
|
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")" |
|
|
_headers="$(_get "$nonceurl" "onlyheader")" |
|
|
|
|
|
fi |
|
|
|
|
|
|
|
|
if [ "$?" != "0" ]; then |
|
|
if [ "$?" != "0" ]; then |
|
|
_err "Can not connect to $nonceurl to get nonce." |
|
|
_err "Can not connect to $nonceurl to get nonce." |
|
@ -2169,6 +2181,62 @@ __initHome() { |
|
|
fi |
|
|
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_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_NEW_ACCOUNT" ]; 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_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_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_ORDER" "$ACME_NEW_ORDER" |
|
|
|
|
|
_debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT" |
|
|
|
|
|
_debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT" |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
#[domain] [keylength] |
|
|
#[domain] [keylength] |
|
|
_initpath() { |
|
|
_initpath() { |
|
|
|
|
|
|
|
@ -2189,17 +2257,19 @@ _initpath() { |
|
|
CA_HOME="$DEFAULT_CA_HOME" |
|
|
CA_HOME="$DEFAULT_CA_HOME" |
|
|
fi |
|
|
fi |
|
|
|
|
|
|
|
|
if [ -z "$API" ]; then |
|
|
|
|
|
|
|
|
if [ -z "$ACME_DIRECTORY" ]; then |
|
|
if [ -z "$STAGE" ]; then |
|
|
if [ -z "$STAGE" ]; then |
|
|
API="$DEFAULT_CA" |
|
|
|
|
|
|
|
|
ACME_DIRECTORY="$DEFAULT_CA" |
|
|
else |
|
|
else |
|
|
API="$STAGE_CA" |
|
|
|
|
|
_info "Using stage api:$API" |
|
|
|
|
|
|
|
|
ACME_DIRECTORY="$STAGE_CA" |
|
|
|
|
|
_info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY" |
|
|
fi |
|
|
fi |
|
|
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 -s / | cut -d / -f 2)" |
|
|
|
|
|
_debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST" |
|
|
|
|
|
|
|
|
|
|
|
CA_DIR="$CA_HOME/$_ACME_SERVER_HOST" |
|
|
|
|
|
|
|
|
_DEFAULT_CA_CONF="$CA_DIR/ca.conf" |
|
|
_DEFAULT_CA_CONF="$CA_DIR/ca.conf" |
|
|
|
|
|
|
|
@ -3020,7 +3090,7 @@ _regAccount() { |
|
|
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then |
|
|
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then |
|
|
return 1 |
|
|
return 1 |
|
|
fi |
|
|
fi |
|
|
|
|
|
|
|
|
|
|
|
_initAPI |
|
|
_updateTos="" |
|
|
_updateTos="" |
|
|
_reg_res="new-reg" |
|
|
_reg_res="new-reg" |
|
|
while true; do |
|
|
while true; do |
|
@ -3035,7 +3105,7 @@ _regAccount() { |
|
|
if [ -z "$_updateTos" ]; then |
|
|
if [ -z "$_updateTos" ]; then |
|
|
_info "Registering account" |
|
|
_info "Registering account" |
|
|
|
|
|
|
|
|
if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then |
|
|
|
|
|
|
|
|
if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then |
|
|
_err "Register account Error: $response" |
|
|
_err "Register account Error: $response" |
|
|
return 1 |
|
|
return 1 |
|
|
fi |
|
|
fi |
|
@ -3121,12 +3191,12 @@ _findHook() { |
|
|
__get_domain_new_authz() { |
|
|
__get_domain_new_authz() { |
|
|
_gdnd="$1" |
|
|
_gdnd="$1" |
|
|
_info "Getting new-authz for domain" "$_gdnd" |
|
|
_info "Getting new-authz for domain" "$_gdnd" |
|
|
|
|
|
|
|
|
|
|
|
_initAPI |
|
|
_Max_new_authz_retry_times=5 |
|
|
_Max_new_authz_retry_times=5 |
|
|
_authz_i=0 |
|
|
_authz_i=0 |
|
|
while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do |
|
|
while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do |
|
|
_debug "Try new-authz for the $_authz_i time." |
|
|
_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." |
|
|
_err "Can not get domain new authz." |
|
|
return 1 |
|
|
return 1 |
|
|
fi |
|
|
fi |
|
@ -3204,13 +3274,16 @@ issue() { |
|
|
if [ "$_web_roots" = "dns-cx" ]; then |
|
|
if [ "$_web_roots" = "dns-cx" ]; then |
|
|
_web_roots="dns_cx" |
|
|
_web_roots="dns_cx" |
|
|
fi |
|
|
fi |
|
|
_debug "Using api: $API" |
|
|
|
|
|
|
|
|
|
|
|
if [ ! "$IS_RENEW" ]; then |
|
|
if [ ! "$IS_RENEW" ]; then |
|
|
_initpath "$_main_domain" "$_key_length" |
|
|
_initpath "$_main_domain" "$_key_length" |
|
|
mkdir -p "$DOMAIN_PATH" |
|
|
mkdir -p "$DOMAIN_PATH" |
|
|
fi |
|
|
fi |
|
|
|
|
|
|
|
|
|
|
|
_debug "Using ACME_DIRECTORY: $ACME_DIRECTORY" |
|
|
|
|
|
|
|
|
|
|
|
_initAPI |
|
|
|
|
|
|
|
|
if [ -f "$DOMAIN_CONF" ]; then |
|
|
if [ -f "$DOMAIN_CONF" ]; then |
|
|
Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) |
|
|
Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime) |
|
|
_debug Le_NextRenewTime "$Le_NextRenewTime" |
|
|
_debug Le_NextRenewTime "$Le_NextRenewTime" |
|
@ -3244,7 +3317,7 @@ issue() { |
|
|
_cleardomainconf "Le_LocalAddress" |
|
|
_cleardomainconf "Le_LocalAddress" |
|
|
fi |
|
|
fi |
|
|
|
|
|
|
|
|
Le_API="$API" |
|
|
|
|
|
|
|
|
Le_API="$ACME_DIRECTORY" |
|
|
_savedomainconf "Le_API" "$Le_API" |
|
|
_savedomainconf "Le_API" "$Le_API" |
|
|
|
|
|
|
|
|
if [ "$_alt_domains" = "$NO_VALUE" ]; then |
|
|
if [ "$_alt_domains" = "$NO_VALUE" ]; then |
|
@ -3683,7 +3756,7 @@ issue() { |
|
|
_info "Verify finished, start to sign." |
|
|
_info "Verify finished, start to sign." |
|
|
der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)" |
|
|
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_ORDER}" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then |
|
|
_err "Sign failed." |
|
|
_err "Sign failed." |
|
|
_on_issue_err "$_post_hook" |
|
|
_on_issue_err "$_post_hook" |
|
|
return 1 |
|
|
return 1 |
|
@ -3736,7 +3809,8 @@ issue() { |
|
|
|
|
|
|
|
|
Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>') |
|
|
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 |
|
|
if ! _contains "$Le_LinkIssuer" ":"; then |
|
|
Le_LinkIssuer="$API$Le_LinkIssuer" |
|
|
|
|
|
|
|
|
_info "$(__red "Relative issuer link found.")" |
|
|
|
|
|
Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer" |
|
|
fi |
|
|
fi |
|
|
_debug Le_LinkIssuer "$Le_LinkIssuer" |
|
|
_debug Le_LinkIssuer "$Le_LinkIssuer" |
|
|
_savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" |
|
|
_savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer" |
|
@ -3852,7 +3926,15 @@ renew() { |
|
|
. "$DOMAIN_CONF" |
|
|
. "$DOMAIN_CONF" |
|
|
|
|
|
|
|
|
if [ "$Le_API" ]; then |
|
|
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 |
|
|
|
|
|
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 |
|
|
#reload ca configs |
|
|
ACCOUNT_KEY_PATH="" |
|
|
ACCOUNT_KEY_PATH="" |
|
|
ACCOUNT_JSON_PATH="" |
|
|
ACCOUNT_JSON_PATH="" |
|
@ -4319,8 +4401,10 @@ revoke() { |
|
|
return 1 |
|
|
return 1 |
|
|
fi |
|
|
fi |
|
|
|
|
|
|
|
|
|
|
|
_initAPI |
|
|
|
|
|
|
|
|
data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" |
|
|
data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}" |
|
|
uri="$API/acme/revoke-cert" |
|
|
|
|
|
|
|
|
uri="${ACME_REVOKE_CERT}" |
|
|
|
|
|
|
|
|
if [ -f "$CERT_KEY_PATH" ]; then |
|
|
if [ -f "$CERT_KEY_PATH" ]; then |
|
|
_info "Try domain key first." |
|
|
_info "Try domain key first." |
|
@ -4452,6 +4536,7 @@ deactivate() { |
|
|
_d_domain_list="$1" |
|
|
_d_domain_list="$1" |
|
|
_d_type="$2" |
|
|
_d_type="$2" |
|
|
_initpath |
|
|
_initpath |
|
|
|
|
|
_initAPI |
|
|
_debug _d_domain_list "$_d_domain_list" |
|
|
_debug _d_domain_list "$_d_domain_list" |
|
|
if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then |
|
|
if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then |
|
|
_usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" |
|
|
_usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]" |
|
@ -4879,6 +4964,7 @@ Parameters: |
|
|
|
|
|
|
|
|
--reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server. |
|
|
--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. |
|
|
--accountconf Specifies a customized account config file. |
|
|
--home Specifies the home dir for $PROJECT_NAME . |
|
|
--home Specifies the home dir for $PROJECT_NAME . |
|
|
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command. |
|
|
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command. |
|
@ -5039,6 +5125,7 @@ _process() { |
|
|
_openssl_bin="" |
|
|
_openssl_bin="" |
|
|
_syslog="" |
|
|
_syslog="" |
|
|
_use_wget="" |
|
|
_use_wget="" |
|
|
|
|
|
_server="" |
|
|
while [ ${#} -gt 0 ]; do |
|
|
while [ ${#} -gt 0 ]; do |
|
|
case "${1}" in |
|
|
case "${1}" in |
|
|
|
|
|
|
|
@ -5155,6 +5242,12 @@ _process() { |
|
|
--staging | --test) |
|
|
--staging | --test) |
|
|
STAGE="1" |
|
|
STAGE="1" |
|
|
;; |
|
|
;; |
|
|
|
|
|
--server) |
|
|
|
|
|
ACME_DIRECTORY="$2" |
|
|
|
|
|
_server="$ACME_DIRECTORY" |
|
|
|
|
|
export ACME_DIRECTORY |
|
|
|
|
|
shift |
|
|
|
|
|
;; |
|
|
--debug) |
|
|
--debug) |
|
|
if [ -z "$2" ] || _startswith "$2" "-"; then |
|
|
if [ -z "$2" ] || _startswith "$2" "-"; then |
|
|
DEBUG="$DEBUG_LEVEL_DEFAULT" |
|
|
DEBUG="$DEBUG_LEVEL_DEFAULT" |
|
@ -5478,6 +5571,9 @@ _process() { |
|
|
|
|
|
|
|
|
if [ "$DEBUG" ]; then |
|
|
if [ "$DEBUG" ]; then |
|
|
version |
|
|
version |
|
|
|
|
|
if [ "$_server" ]; then |
|
|
|
|
|
_debug "Using server: $_server" |
|
|
|
|
|
fi |
|
|
fi |
|
|
fi |
|
|
|
|
|
|
|
|
case "${_CMD}" in |
|
|
case "${_CMD}" in |
|
|