|
@@ -37,6 +37,7 @@ VTYPE_HTTP="http-01"
|
|
|
VTYPE_DNS="dns-01"
|
|
|
VTYPE_TLS="tls-sni-01"
|
|
|
VTYPE_TLS2="tls-sni-02"
|
|
|
+VTYPE_ALPN="tls-alpn-01"
|
|
|
|
|
|
LOCAL_ANY_ADDRESS="0.0.0.0"
|
|
|
|
|
@@ -48,6 +49,7 @@ NO_VALUE="no"
|
|
|
|
|
|
W_TLS="tls"
|
|
|
W_DNS="dns"
|
|
|
+W_ALPN="alpn"
|
|
|
DNS_ALIAS_PREFIX="="
|
|
|
|
|
|
MODE_STATELESS="stateless"
|
|
@@ -124,23 +126,19 @@ if [ -t 1 ]; then
|
|
|
fi
|
|
|
|
|
|
__green() {
|
|
|
- if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
|
|
- printf '\033[1;31;32m'
|
|
|
+ if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
|
|
+ printf '\033[1;31;32m%b\033[0m' "$1"
|
|
|
+ return
|
|
|
fi
|
|
|
printf -- "%b" "$1"
|
|
|
- if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
|
|
- printf '\033[0m'
|
|
|
- fi
|
|
|
}
|
|
|
|
|
|
__red() {
|
|
|
- if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
|
|
- printf '\033[1;31;40m'
|
|
|
+ if [ "${__INTERACTIVE}${ACME_NO_COLOR:-0}" = "10" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
|
|
+ printf '\033[1;31;40m%b\033[0m' "$1"
|
|
|
+ return
|
|
|
fi
|
|
|
printf -- "%b" "$1"
|
|
|
- if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" -o "${ACME_FORCE_COLOR}" = "1" ]; then
|
|
|
- printf '\033[0m'
|
|
|
- fi
|
|
|
}
|
|
|
|
|
|
_printargs() {
|
|
@@ -1050,7 +1048,7 @@ _idn() {
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
-#_createcsr cn san_list keyfile csrfile conf
|
|
|
+#_createcsr cn san_list keyfile csrfile conf acmeValidationv1
|
|
|
_createcsr() {
|
|
|
_debug _createcsr
|
|
|
domain="$1"
|
|
@@ -1058,6 +1056,7 @@ _createcsr() {
|
|
|
csrkey="$3"
|
|
|
csr="$4"
|
|
|
csrconf="$5"
|
|
|
+ acmeValidationv1="$6"
|
|
|
_debug2 domain "$domain"
|
|
|
_debug2 domainlist "$domainlist"
|
|
|
_debug2 csrkey "$csrkey"
|
|
@@ -1066,7 +1065,9 @@ _createcsr() {
|
|
|
|
|
|
printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf"
|
|
|
|
|
|
- if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
|
|
|
+ if [ "$acmeValidationv1" ]; then
|
|
|
+ printf -- "\nsubjectAltName=DNS:$domainlist" >>"$csrconf"
|
|
|
+ elif [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
|
|
|
#single domain
|
|
|
_info "Single domain" "$domain"
|
|
|
printf -- "\nsubjectAltName=DNS:$domain" >>"$csrconf"
|
|
@@ -1088,6 +1089,10 @@ _createcsr() {
|
|
|
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
|
|
|
fi
|
|
|
|
|
|
+ if [ "$acmeValidationv1" ]; then
|
|
|
+ printf "\n1.3.6.1.5.5.7.1.30.1=critical,DER:04:20:${acmeValidationv1}" >>"${csrconf}"
|
|
|
+ fi
|
|
|
+
|
|
|
_csr_cn="$(_idn "$domain")"
|
|
|
_debug2 _csr_cn "$_csr_cn"
|
|
|
if _contains "$(uname -a)" "MINGW"; then
|
|
@@ -1138,12 +1143,17 @@ _readSubjectAltNamesFromCSR() {
|
|
|
|
|
|
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
|
|
|
_debug "AltNames contains subject"
|
|
|
- _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")"
|
|
|
+ _excapedAlgnames="$(echo "$_dnsAltnames" | tr '*' '#')"
|
|
|
+ _debug _excapedAlgnames "$_excapedAlgnames"
|
|
|
+ _escapedSubject="$(echo "$_csrsubj" | tr '*' '#')"
|
|
|
+ _debug _escapedSubject "$_escapedSubject"
|
|
|
+ _dnsAltnames="$(echo "$_excapedAlgnames," | sed "s/DNS:$_escapedSubject,//g" | tr '#' '*' | sed "s/,\$//g")"
|
|
|
+ _debug _dnsAltnames "$_dnsAltnames"
|
|
|
else
|
|
|
_debug "AltNames doesn't contain subject"
|
|
|
fi
|
|
|
|
|
|
- printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
|
|
|
+ echo "$_dnsAltnames" | sed "s/DNS://g"
|
|
|
}
|
|
|
|
|
|
#_csrfile
|
|
@@ -1520,7 +1530,8 @@ _calcjwk() {
|
|
|
JWK_HEADERPLACE_PART1='{"nonce": "'
|
|
|
JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'"'
|
|
|
else
|
|
|
- _err "Only RSA or EC key is supported."
|
|
|
+ _err "Only RSA or EC key is supported. keyfile=$keyfile"
|
|
|
+ _debug2 "$(cat "$keyfile")"
|
|
|
return 1
|
|
|
fi
|
|
|
|
|
@@ -2105,7 +2116,7 @@ _sleep() {
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
-# _starttlsserver san_a san_b port content _ncaddr
|
|
|
+# _starttlsserver san_a san_b port content _ncaddr acmeValidationv1
|
|
|
_starttlsserver() {
|
|
|
_info "Starting tls server."
|
|
|
san_a="$1"
|
|
@@ -2113,10 +2124,12 @@ _starttlsserver() {
|
|
|
port="$3"
|
|
|
content="$4"
|
|
|
opaddr="$5"
|
|
|
+ acmeValidationv1="$6"
|
|
|
|
|
|
_debug san_a "$san_a"
|
|
|
_debug san_b "$san_b"
|
|
|
_debug port "$port"
|
|
|
+ _debug acmeValidationv1 "$acmeValidationv1"
|
|
|
|
|
|
#create key TLS_KEY
|
|
|
if ! _createkey "2048" "$TLS_KEY"; then
|
|
@@ -2129,7 +2142,7 @@ _starttlsserver() {
|
|
|
if [ "$san_b" ]; then
|
|
|
alt="$alt,$san_b"
|
|
|
fi
|
|
|
- if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then
|
|
|
+ if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$acmeValidationv1"; then
|
|
|
_err "Create tls validation csr error."
|
|
|
return 1
|
|
|
fi
|
|
@@ -2155,6 +2168,10 @@ _starttlsserver() {
|
|
|
__S_OPENSSL="$__S_OPENSSL -6"
|
|
|
fi
|
|
|
|
|
|
+ if [ "$acmeValidationv1" ]; then
|
|
|
+ __S_OPENSSL="$__S_OPENSSL -alpn acme-tls/1"
|
|
|
+ fi
|
|
|
+
|
|
|
_debug "$__S_OPENSSL"
|
|
|
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
|
|
|
$__S_OPENSSL -tlsextdebug &
|
|
@@ -2843,7 +2860,7 @@ _isRealNginxConf() {
|
|
|
_skip_ssl=1
|
|
|
for _listen_i in $(echo "$_seg_n" | tr "\t" ' ' | grep "^ *listen" | tr -d " "); do
|
|
|
if [ "$_listen_i" ]; then
|
|
|
- if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl[ |;]")" ]; then
|
|
|
+ if [ "$(echo "$_listen_i" | _egrep_o "listen.*ssl")" ]; then
|
|
|
_debug2 "$_listen_i is ssl"
|
|
|
else
|
|
|
_debug2 "$_listen_i is plain text"
|
|
@@ -2925,6 +2942,7 @@ _clearupdns() {
|
|
|
_debug txt "$txt"
|
|
|
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
|
|
|
_debug "$d is already verified, skip $vtype."
|
|
|
+ _alias_index="$(_math "$_alias_index" + 1)"
|
|
|
continue
|
|
|
fi
|
|
|
|
|
@@ -3064,8 +3082,8 @@ _on_before_issue() {
|
|
|
_savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
|
|
|
fi
|
|
|
_checkport="$Le_HTTPPort"
|
|
|
- elif [ "$_currentRoot" = "$W_TLS" ]; then
|
|
|
- _info "Standalone tls mode."
|
|
|
+ elif [ "$_currentRoot" = "$W_TLS" ] || [ "$_currentRoot" = "$W_ALPN" ]; then
|
|
|
+ _info "Standalone tls/alpn mode."
|
|
|
if [ -z "$Le_TLSPort" ]; then
|
|
|
Le_TLSPort=443
|
|
|
else
|
|
@@ -3691,6 +3709,10 @@ $_authorizations_map"
|
|
|
fi
|
|
|
fi
|
|
|
|
|
|
+ if [ "$_currentRoot" = "$W_ALPN" ]; then
|
|
|
+ vtype="$VTYPE_ALPN"
|
|
|
+ fi
|
|
|
+
|
|
|
if [ "$ACME_VERSION" = "2" ]; then
|
|
|
response="$(echo "$_authorizations_map" | grep "^$d," | sed "s/$d,//")"
|
|
|
_debug2 "response" "$response"
|
|
@@ -3775,6 +3797,7 @@ $_authorizations_map"
|
|
|
_debug d "$d"
|
|
|
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
|
|
|
_debug "$d is already verified, skip $vtype."
|
|
|
+ _alias_index="$(_math "$_alias_index" + 1)"
|
|
|
continue
|
|
|
fi
|
|
|
|
|
@@ -4003,6 +4026,16 @@ $_authorizations_map"
|
|
|
_on_issue_err "$_post_hook" "$vlist"
|
|
|
return 1
|
|
|
fi
|
|
|
+ elif [ "$vtype" = "$VTYPE_ALPN" ]; then
|
|
|
+ acmevalidationv1="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
|
|
|
+ _debug acmevalidationv1 "$acmevalidationv1"
|
|
|
+ if ! _starttlsserver "$d" "" "$Le_TLSPort" "$keyauthorization" "$_ncaddr" "$acmevalidationv1"; then
|
|
|
+ _err "Start tls server error."
|
|
|
+ _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
|
|
|
+ _clearup
|
|
|
+ _on_issue_err "$_post_hook" "$vlist"
|
|
|
+ return 1
|
|
|
+ fi
|
|
|
fi
|
|
|
|
|
|
if ! __trigger_validation "$uri" "$keyauthorization"; then
|
|
@@ -4602,7 +4635,8 @@ deploy() {
|
|
|
|
|
|
_initpath "$_d" "$_isEcc"
|
|
|
if [ ! -d "$DOMAIN_PATH" ]; then
|
|
|
- _err "Domain is not valid:'$_d'"
|
|
|
+ _err "The domain '$_d' is not a cert name. You must use the cert name to specify the cert to install."
|
|
|
+ _err "Can not find path:'$DOMAIN_PATH'"
|
|
|
return 1
|
|
|
fi
|
|
|
|
|
@@ -4629,7 +4663,8 @@ installcert() {
|
|
|
|
|
|
_initpath "$_main_domain" "$_isEcc"
|
|
|
if [ ! -d "$DOMAIN_PATH" ]; then
|
|
|
- _err "Domain is not valid:'$_main_domain'"
|
|
|
+ _err "The domain '$_main_domain' is not a cert name. You must use the cert name to specify the cert to install."
|
|
|
+ _err "Can not find path:'$DOMAIN_PATH'"
|
|
|
return 1
|
|
|
fi
|
|
|
|
|
@@ -5463,6 +5498,7 @@ Parameters:
|
|
|
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure.
|
|
|
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
|
|
|
--standalone Use standalone mode.
|
|
|
+ --alpn Use standalone alpn mode.
|
|
|
--stateless Use stateless mode, see: $_STATELESS_WIKI
|
|
|
--apache Use apache mode.
|
|
|
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
|
|
@@ -5474,7 +5510,7 @@ Parameters:
|
|
|
--log-level 1|2 Specifies the log level, default is 1.
|
|
|
--syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
|
|
|
|
|
|
- These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
|
|
|
+ These parameters are to install the cert to nginx/apache or any other server after issue/renew a cert:
|
|
|
|
|
|
--cert-file After issue/renew, the cert will be copied to this path.
|
|
|
--key-file After issue/renew, the key will be copied to this path.
|
|
@@ -5485,7 +5521,7 @@ Parameters:
|
|
|
|
|
|
--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 .
|
|
|
+ --home Specifies the home dir for $PROJECT_NAME.
|
|
|
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
|
|
|
--config-home Specifies the home dir to save all the configurations.
|
|
|
--useragent Specifies the user agent string. it will be saved for future use too.
|
|
@@ -5493,6 +5529,7 @@ Parameters:
|
|
|
--accountkey Specifies the account key path, only valid for the '--install' command.
|
|
|
--days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
|
|
|
--httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
|
|
|
+ --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
|
|
|
--local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
|
|
|
--listraw Only used for '--list' command, list the certs in raw format.
|
|
|
--stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
|
|
@@ -5817,6 +5854,14 @@ _process() {
|
|
|
_webroot="$_webroot,$wvalue"
|
|
|
fi
|
|
|
;;
|
|
|
+ --alpn)
|
|
|
+ wvalue="$W_ALPN"
|
|
|
+ if [ -z "$_webroot" ]; then
|
|
|
+ _webroot="$wvalue"
|
|
|
+ else
|
|
|
+ _webroot="$_webroot,$wvalue"
|
|
|
+ fi
|
|
|
+ ;;
|
|
|
--stateless)
|
|
|
wvalue="$MODE_STATELESS"
|
|
|
if [ -z "$_webroot" ]; then
|
|
@@ -5941,6 +5986,11 @@ _process() {
|
|
|
Le_HTTPPort="$_httpport"
|
|
|
shift
|
|
|
;;
|
|
|
+ --tlsport)
|
|
|
+ _tlsport="$2"
|
|
|
+ Le_TLSPort="$_tlsport"
|
|
|
+ shift
|
|
|
+ ;;
|
|
|
--listraw)
|
|
|
_listraw="raw"
|
|
|
;;
|