@ -1,6 +1,6 @@
#!/usr/bin/env sh
VER = 2.6.7
VER = 2.6.8
PROJECT_NAME = "acme.sh"
@ -107,7 +107,7 @@ __green() {
if [ " $__INTERACTIVE " ] ; then
printf '\033[1;31;32m'
fi
printf -- " $1 "
printf -- "%b" " $1 "
if [ " $__INTERACTIVE " ] ; then
printf '\033[0m'
fi
@ -117,7 +117,7 @@ __red() {
if [ " $__INTERACTIVE " ] ; then
printf '\033[1;31;40m'
fi
printf -- " $1 "
printf -- "%b" " $1 "
if [ " $__INTERACTIVE " ] ; then
printf '\033[0m'
fi
@ -138,8 +138,8 @@ _printargs() {
_dlg_versions( ) {
echo "Diagnosis versions: "
echo " openssl: $ACME_OPENSSL_BIN "
if _exists " $ ACME_OPENSSL_BIN" ; then
$ ACME_OPENSSL_BIN version 2>& 1
if _exists " ${ ACME_OPENSSL_BIN :- openssl } " ; then
${ ACME_OPENSSL_BIN :- openssl } version 2>& 1
else
echo " $ACME_OPENSSL_BIN doesn't exists. "
fi
@ -340,7 +340,7 @@ _hasfield() {
_sep = ","
fi
for f in $( echo " $_str " | tr ',' ' ' ) ; do
for f in $( echo " $_str " | tr " $_sep " ' ' ) ; do
if [ " $f " = " $_field " ] ; then
_debug2 " ' $_str ' contains ' $_field ' "
return 0 #contains ok
@ -790,19 +790,19 @@ _base64() {
[ "" ] #urgly
if [ " $1 " ] ; then
_debug3 " base64 multiline:' $1 ' "
$ ACME_OPENSSL_BIN base64 -e
${ ACME_OPENSSL_BIN :- openssl } base64 -e
else
_debug3 "base64 single line."
$ ACME_OPENSSL_BIN base64 -e | tr -d '\r\n'
${ ACME_OPENSSL_BIN :- openssl } base64 -e | tr -d '\r\n'
fi
}
#Usage: multiline
_dbase64( ) {
if [ " $1 " ] ; then
$ ACME_OPENSSL_BIN base64 -d -A
${ ACME_OPENSSL_BIN :- openssl } base64 -d -A
else
$ ACME_OPENSSL_BIN base64 -d
${ ACME_OPENSSL_BIN :- openssl } base64 -d
fi
}
@ -819,9 +819,9 @@ _digest() {
if [ " $alg " = "sha256" ] || [ " $alg " = "sha1" ] || [ " $alg " = "md5" ] ; then
if [ " $outputhex " ] ; then
$ ACME_OPENSSL_BIN dgst -" $alg " -hex | cut -d = -f 2 | tr -d ' '
${ ACME_OPENSSL_BIN :- openssl } dgst -" $alg " -hex | cut -d = -f 2 | tr -d ' '
else
$ ACME_OPENSSL_BIN dgst -" $alg " -binary | _base64
${ ACME_OPENSSL_BIN :- openssl } dgst -" $alg " -binary | _base64
fi
else
_err " $alg is not supported yet "
@ -844,9 +844,9 @@ _hmac() {
if [ " $alg " = "sha256" ] || [ " $alg " = "sha1" ] ; then
if [ " $outputhex " ] ; then
( $ ACME_OPENSSL_BIN dgst -" $alg " -mac HMAC -macopt " hexkey: $secret_hex " 2>/dev/null || $ ACME_OPENSSL_BIN dgst -" $alg " -hmac " $( printf "%s" " $secret_hex " | _h2b) " ) | cut -d = -f 2 | tr -d ' '
( ${ ACME_OPENSSL_BIN :- openssl } dgst -" $alg " -mac HMAC -macopt " hexkey: $secret_hex " 2>/dev/null || ${ ACME_OPENSSL_BIN :- openssl } dgst -" $alg " -hmac " $( printf "%s" " $secret_hex " | _h2b) " ) | cut -d = -f 2 | tr -d ' '
else
$ ACME_OPENSSL_BIN dgst -" $alg " -mac HMAC -macopt " hexkey: $secret_hex " -binary 2>/dev/null || $ ACME_OPENSSL_BIN dgst -" $alg " -hmac " $( printf "%s" " $secret_hex " | _h2b) " -binary
${ ACME_OPENSSL_BIN :- openssl } dgst -" $alg " -mac HMAC -macopt " hexkey: $secret_hex " -binary 2>/dev/null || ${ ACME_OPENSSL_BIN :- openssl } dgst -" $alg " -hmac " $( printf "%s" " $secret_hex " | _h2b) " -binary
fi
else
_err " $alg is not supported yet "
@ -865,7 +865,7 @@ _sign() {
return 1
fi
_sign_openssl = " $ACME_OPENSSL_BIN dgst -sign $keyfile "
_sign_openssl = " ${ ACME_OPENSSL_BIN :- openssl } dgst -sign $keyfile "
if [ " $alg " = "sha256" ] ; then
_sign_openssl = " $_sign_openssl - $alg "
else
@ -876,10 +876,10 @@ _sign() {
if grep "BEGIN RSA PRIVATE KEY" " $keyfile " >/dev/null 2>& 1; then
$_sign_openssl | _base64
elif grep "BEGIN EC PRIVATE KEY" " $keyfile " >/dev/null 2>& 1; then
if ! _signedECText = " $( $_sign_openssl | $ ACME_OPENSSL_BIN asn1parse -inform DER) " ; then
if ! _signedECText = " $( $_sign_openssl | ${ ACME_OPENSSL_BIN :- openssl } asn1parse -inform DER) " ; then
_err " Sign failed: $_sign_openssl "
_err " Key file: $keyfile "
_err " Key content: $( wc -l <" $keyfile " ) lis es "
_err " Key content: $( wc -l <" $keyfile " ) lin es "
return 1
fi
_debug3 "_signedECText" " $_signedECText "
@ -948,10 +948,10 @@ _createkey() {
if _isEccKey " $length " ; then
_debug " Using ec name: $eccname "
$ ACME_OPENSSL_BIN ecparam -name " $eccname " -genkey 2>/dev/null >" $f "
${ ACME_OPENSSL_BIN :- openssl } ecparam -name " $eccname " -genkey 2>/dev/null >" $f "
else
_debug " Using RSA: $length "
$ ACME_OPENSSL_BIN genrsa " $length " 2>/dev/null >" $f "
${ ACME_OPENSSL_BIN :- openssl } genrsa " $length " 2>/dev/null >" $f "
fi
if [ " $? " != "0" ] ; then
@ -1038,9 +1038,9 @@ _createcsr() {
_csr_cn = " $( _idn " $domain " ) "
_debug2 _csr_cn " $_csr_cn "
if _contains " $( uname -a) " "MINGW" ; then
$ ACME_OPENSSL_BIN req -new -sha256 -key " $csrkey " -subj " //CN= $_csr_cn " -config " $csrconf " -out " $csr "
${ ACME_OPENSSL_BIN :- openssl } req -new -sha256 -key " $csrkey " -subj " //CN= $_csr_cn " -config " $csrconf " -out " $csr "
else
$ ACME_OPENSSL_BIN req -new -sha256 -key " $csrkey " -subj " /CN= $_csr_cn " -config " $csrconf " -out " $csr "
${ ACME_OPENSSL_BIN :- openssl } req -new -sha256 -key " $csrkey " -subj " /CN= $_csr_cn " -config " $csrconf " -out " $csr "
fi
}
@ -1052,7 +1052,7 @@ _signcsr() {
cert = " $4 "
_debug "_signcsr"
_msg = " $( $ ACME_OPENSSL_BIN x509 -req -days 365 -in " $csr " -signkey " $key " -extensions v3_req -extfile " $conf " -out " $cert " 2>& 1) "
_msg = " $( ${ ACME_OPENSSL_BIN :- openssl } x509 -req -days 365 -in " $csr " -signkey " $key " -extensions v3_req -extfile " $conf " -out " $cert " 2>& 1) "
_ret = " $? "
_debug " $_msg "
return $_ret
@ -1065,7 +1065,7 @@ _readSubjectFromCSR() {
_usage "_readSubjectFromCSR mycsr.csr"
return 1
fi
$ ACME_OPENSSL_BIN req -noout -in " $_csrfile " -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
${ ACME_OPENSSL_BIN :- openssl } req -noout -in " $_csrfile " -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
}
#_csrfile
@ -1080,7 +1080,7 @@ _readSubjectAltNamesFromCSR() {
_csrsubj = " $( _readSubjectFromCSR " $_csrfile " ) "
_debug _csrsubj " $_csrsubj "
_dnsAltnames = " $( $ ACME_OPENSSL_BIN req -noout -text -in " $_csrfile " | grep "^ *DNS:.*" | tr -d ' \n' ) "
_dnsAltnames = " $( ${ ACME_OPENSSL_BIN :- openssl } req -noout -text -in " $_csrfile " | grep "^ *DNS:.*" | tr -d ' \n' ) "
_debug _dnsAltnames " $_dnsAltnames "
if _contains " $_dnsAltnames , " " DNS: $_csrsubj , " ; then
@ -1101,7 +1101,8 @@ _readKeyLengthFromCSR() {
return 1
fi
_outcsr = " $( $ACME_OPENSSL_BIN req -noout -text -in " $_csrfile " ) "
_outcsr = " $( ${ ACME_OPENSSL_BIN :- openssl } req -noout -text -in " $_csrfile " ) "
_debug2 _outcsr " $_outcsr "
if _contains " $_outcsr " "Public Key Algorithm: id-ecPublicKey" ; then
_debug "ECC CSR"
echo " $_outcsr " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
@ -1159,9 +1160,9 @@ toPkcs() {
_initpath " $domain " " $_isEcc "
if [ " $pfxPassword " ] ; then
$ ACME_OPENSSL_BIN pkcs12 -export -out " $CERT_PFX_PATH " -inkey " $CERT_KEY_PATH " -in " $CERT_PATH " -certfile " $CA_CERT_PATH " -password " pass: $pfxPassword "
${ ACME_OPENSSL_BIN :- openssl } pkcs12 -export -out " $CERT_PFX_PATH " -inkey " $CERT_KEY_PATH " -in " $CERT_PATH " -certfile " $CA_CERT_PATH " -password " pass: $pfxPassword "
else
$ ACME_OPENSSL_BIN pkcs12 -export -out " $CERT_PFX_PATH " -inkey " $CERT_KEY_PATH " -in " $CERT_PATH " -certfile " $CA_CERT_PATH "
${ ACME_OPENSSL_BIN :- openssl } pkcs12 -export -out " $CERT_PFX_PATH " -inkey " $CERT_KEY_PATH " -in " $CERT_PATH " -certfile " $CA_CERT_PATH "
fi
if [ " $? " = "0" ] ; then
@ -1183,7 +1184,7 @@ toPkcs8() {
_initpath " $domain " " $_isEcc "
$ ACME_OPENSSL_BIN pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in " $CERT_KEY_PATH " -out " $CERT_PKCS8_PATH "
${ ACME_OPENSSL_BIN :- openssl } pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in " $CERT_KEY_PATH " -out " $CERT_PKCS8_PATH "
if [ " $? " = "0" ] ; then
_info " Success, $CERT_PKCS8_PATH "
@ -1344,7 +1345,7 @@ _calcjwk() {
if grep "BEGIN RSA PRIVATE KEY" " $keyfile " >/dev/null 2>& 1; then
_debug "RSA key"
pub_exp = $( $ ACME_OPENSSL_BIN rsa -in " $keyfile " -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
pub_exp = $( ${ ACME_OPENSSL_BIN :- openssl } rsa -in " $keyfile " -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
if [ " ${# pub_exp } " = "5" ] ; then
pub_exp = 0$pub_exp
fi
@ -1353,7 +1354,7 @@ _calcjwk() {
e = $( echo " $pub_exp " | _h2b | _base64)
_debug3 e " $e "
modulus = $( $ ACME_OPENSSL_BIN rsa -in " $keyfile " -modulus -noout | cut -d '=' -f 2)
modulus = $( ${ ACME_OPENSSL_BIN :- openssl } rsa -in " $keyfile " -modulus -noout | cut -d '=' -f 2)
_debug3 modulus " $modulus "
n = " $( printf "%s" " $modulus " | _h2b | _base64 | _url_replace) "
_debug3 n " $n "
@ -1366,12 +1367,12 @@ _calcjwk() {
JWK_HEADERPLACE_PART2 = '", "alg": "RS256", "jwk": ' $jwk '}'
elif grep "BEGIN EC PRIVATE KEY" " $keyfile " >/dev/null 2>& 1; then
_debug "EC key"
crv = " $( $ ACME_OPENSSL_BIN ec -in " $keyfile " -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n" ) "
crv = " $( ${ ACME_OPENSSL_BIN :- openssl } ec -in " $keyfile " -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n" ) "
_debug3 crv " $crv "
if [ -z " $crv " ] ; then
_debug "Let's try ASN1 OID"
crv_oid = " $( $ ACME_OPENSSL_BIN ec -in " $keyfile " -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n" ) "
crv_oid = " $( ${ ACME_OPENSSL_BIN :- openssl } ec -in " $keyfile " -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n" ) "
_debug3 crv_oid " $crv_oid "
case " ${ crv_oid } " in
"prime256v1" )
@ -1391,15 +1392,15 @@ _calcjwk() {
_debug3 crv " $crv "
fi
pubi = " $( $ ACME_OPENSSL_BIN ec -in " $keyfile " -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1) "
pubi = " $( ${ ACME_OPENSSL_BIN :- openssl } ec -in " $keyfile " -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1) "
pubi = $( _math " $pubi " + 1)
_debug3 pubi " $pubi "
pubj = " $( $ ACME_OPENSSL_BIN ec -in " $keyfile " -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1) "
pubj = " $( ${ ACME_OPENSSL_BIN :- openssl } ec -in " $keyfile " -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1) "
pubj = $( _math " $pubj " - 1)
_debug3 pubj " $pubj "
pubtext = " $( $ ACME_OPENSSL_BIN ec -in " $keyfile " -noout -text 2>/dev/null | sed -n " $pubi , ${ pubj } p " | tr -d " \n\r" ) "
pubtext = " $( ${ ACME_OPENSSL_BIN :- openssl } ec -in " $keyfile " -noout -text 2>/dev/null | sed -n " $pubi , ${ pubj } p " | tr -d " \n\r" ) "
_debug3 pubtext " $pubtext "
xlen = " $( printf "%s" " $pubtext " | tr -d ':' | wc -c) "
@ -2017,7 +2018,7 @@ _starttlsserver() {
return 1
fi
__S_OPENSSL = " $ ACME_OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY "
__S_OPENSSL = " ${ ACME_OPENSSL_BIN :- openssl } s_server -cert $TLS_CERT -key $TLS_KEY "
if [ " $opaddr " ] ; then
__S_OPENSSL = " $__S_OPENSSL -accept $opaddr : $port "
else
@ -2258,16 +2259,16 @@ _initpath() {
fi
if [ -z " $TLS_CONF " ] ; then
TLS_CONF = " $DOMAIN_PATH /tls.valdation.conf "
TLS_CONF = " $DOMAIN_PATH /tls.vali dation.conf "
fi
if [ -z " $TLS_CERT " ] ; then
TLS_CERT = " $DOMAIN_PATH /tls.valdation.cert "
TLS_CERT = " $DOMAIN_PATH /tls.vali dation.cert "
fi
if [ -z " $TLS_KEY " ] ; then
TLS_KEY = " $DOMAIN_PATH /tls.valdation.key "
TLS_KEY = " $DOMAIN_PATH /tls.vali dation.key "
fi
if [ -z " $TLS_CSR " ] ; then
TLS_CSR = " $DOMAIN_PATH /tls.valdation.csr "
TLS_CSR = " $DOMAIN_PATH /tls.vali dation.csr "
fi
}
@ -2385,7 +2386,7 @@ _setApache() {
_debug "Backup apache config file" " $httpdconf "
if ! cp " $httpdconf " " $APACHE_CONF_BACKUP_DIR / " ; then
_err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed."
_err " This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT "
_err " This might be a bug of $PROJECT_NAME , pleas e report issue: $PROJECT "
return 1
fi
_info " JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR / $httpdconfname "
@ -2883,7 +2884,7 @@ _on_issue_err() {
uri = $( echo " $ventry " | cut -d " $sep " -f 3)
vtype = $( echo " $ventry " | cut -d " $sep " -f 4)
_currentRoot = $( echo " $ventry " | cut -d " $sep " -f 5)
__trigger_validaton " $uri " " $keyauthorization "
__trigger_validati on " $uri " " $keyauthorization "
done
)
fi
@ -3105,7 +3106,7 @@ __get_domain_new_authz() {
}
#uri keyAuthorization
__trigger_validaton( ) {
__trigger_validati on( ) {
_debug2 "tigger domain validation."
_t_url = " $1 "
_debug2 _t_url " $_t_url "
@ -3120,6 +3121,10 @@ issue() {
_usage " Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
return 1
fi
if [ -z " $1 " ] ; then
_usage "Please specify at least one validation method: '--webroot', '--standalone', '--apache', '--nginx' or '--dns' etc."
return 1
fi
_web_roots = " $1 "
_main_domain = " $2 "
_alt_domains = " $3 "
@ -3490,7 +3495,7 @@ issue() {
_exec_err >/dev/null 2>& 1
fi
else
_debug "not chaning owner/group of webroot"
_debug "not chang ing owner/group of webroot"
fi
fi
@ -3531,7 +3536,7 @@ issue() {
fi
fi
if ! __trigger_validaton " $uri " " $keyauthorization " ; then
if ! __trigger_validati on " $uri " " $keyauthorization " ; then
_err " $d :Can not get challenge: $response "
_clearupwebbroot " $_currentRoot " " $removelevel " " $token "
_clearup
@ -3635,6 +3640,7 @@ issue() {
_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
@ -3681,16 +3687,34 @@ issue() {
if ! _contains " $Le_LinkIssuer " ":" ; then
Le_LinkIssuer = " $API $Le_LinkIssuer "
fi
_debug Le_LinkIssuer " $Le_LinkIssuer "
_savedomainconf "Le_LinkIssuer" " $Le_LinkIssuer "
if [ " $Le_LinkIssuer " ] ; then
_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 "
_get " $Le_LinkIssuer " | _base64 "multiline" >>" $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 " ) "
rm -f " $CA_CERT_PATH .der "
break
fi
_link_issuer_retry = $( _math $_link_issuer_retry + 1)
_sleep " $_link_issuer_retry "
done
if [ " $_link_issuer_retry " = " $_MAX_ISSUER_RETRY " ] ; then
_err "Max retry for issuer ca cert is reached."
fi
else
_debug "No Le_LinkIssuer header found."
fi
Le_CertCreateTime = $( _time)
@ -4134,6 +4158,7 @@ _installcert() {
export CERT_KEY_PATH
export CA_CERT_PATH
export CERT_FULLCHAIN_PATH
export Le_Domain
cd " $DOMAIN_PATH " && eval " $_reload_cmd "
) ; then
_info " $( __green "Reload success" ) "
@ -4462,7 +4487,7 @@ _precheck() {
fi
fi
if ! _exists " $ ACME_OPENSSL_BIN" ; then
if ! _exists " ${ ACME_OPENSSL_BIN :- openssl } " ; then
_err " Please install openssl first. ACME_OPENSSL_BIN= $ACME_OPENSSL_BIN "
_err "We need openssl to generate keys."
return 1
@ -4704,6 +4729,7 @@ _uninstallalias() {
cron( ) {
IN_CRON = 1
_initpath
_info " $( __green "===Starting cron===" ) "
if [ " $AUTO_UPGRADE " = "1" ] ; then
export LE_WORKING_DIR
(
@ -4723,6 +4749,7 @@ cron() {
renewAll
_ret = " $? "
IN_CRON = ""
_info " $( __green "===End cron===" ) "
exit $_ret
}
@ -4806,13 +4833,13 @@ Parameters:
--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.
--insecure Do not check the server certificate, in some devices, the api server' s certificate may not be trusted.
--ca-bundle Specific es the path to the CA certificate bundle to verify api server' s certificate.
--ca-bundle Specifies the path to the CA certificate bundle to verify api server' s certificate.
--ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl.
--nocron Only valid for '--install' command, which means: do not install the default cron job. In this case , the certs will not be renewed automatically.
--ecc Specifies to use the ECC cert. Valid for '--install-cert' , '--renew' , '--revoke' , '--toPkcs' and '--createCSR'
--csr Specifies the input csr.
--pre-hook Command to be run before obtaining any certificates.
--post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed.
--post-hook Command to be run after attempting to obtain/renew certificates. No matter the obt ain/renew is success or failed.
--renew-hook Command to be run once for each successfully renewed certificate.
--deploy-hook The hook file to deploy cert
--ocsp-must-staple, --ocsp Generate ocsp must Staple extension.