mirror of
				https://github.com/hiskang/acme.sh
				synced 2025-10-31 18:37:30 +00:00 
			
		
		
		
	support tls (#215)
* support tls-sni-01 '--tls' and '--tlsport' * fix tls doc
This commit is contained in:
		
							parent
							
								
									869578ce4a
								
							
						
					
					
						commit
						e22bcf7cb4
					
				
							
								
								
									
										14
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								README.md
									
									
									
									
									
								
							| @ -170,6 +170,20 @@ acme.sh --issue --standalone -d aa.com -d www.aa.com -d cp.aa.com | ||||
| 
 | ||||
| More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert | ||||
| 
 | ||||
| # Use Standalone tls server to issue cert | ||||
| 
 | ||||
| **(requires you be root/sudoer, or you have permission to listen tcp 443 port)** | ||||
| 
 | ||||
| acme.sh supports `tls-sni-01` validation. | ||||
| 
 | ||||
| The tcp `443` port **MUST** be free to listen, otherwise you will be prompted to free the `443` port and try again. | ||||
| 
 | ||||
| ```bash | ||||
| acme.sh --issue --tls -d aa.com -d www.aa.com -d cp.aa.com | ||||
| ``` | ||||
| 
 | ||||
| More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert | ||||
| 
 | ||||
| # Use Apache mode | ||||
| 
 | ||||
| **(requires you be root/sudoer, since it is required to interact with apache server)** | ||||
|  | ||||
							
								
								
									
										293
									
								
								acme.sh
									
									
									
									
									
								
							
							
						
						
									
										293
									
								
								acme.sh
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| #!/usr/bin/env sh | ||||
| 
 | ||||
| VER=2.2.6 | ||||
| VER=2.2.7 | ||||
| 
 | ||||
| PROJECT_NAME="acme.sh" | ||||
| 
 | ||||
| @ -17,6 +17,10 @@ STAGE_CA="https://acme-staging.api.letsencrypt.org" | ||||
| 
 | ||||
| VTYPE_HTTP="http-01" | ||||
| VTYPE_DNS="dns-01" | ||||
| VTYPE_TLS="tls-sni-01" | ||||
| VTYPE_TLS2="tls-sni-02" | ||||
| 
 | ||||
| W_TLS="tls" | ||||
| 
 | ||||
| BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----" | ||||
| END_CSR="-----END CERTIFICATE REQUEST-----" | ||||
| @ -251,7 +255,7 @@ _dbase64() { | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
| #Usage: hashalg | ||||
| #Usage: hashalg  [outputhex] | ||||
| #Output Base64-encoded digest | ||||
| _digest() { | ||||
|   alg="$1" | ||||
| @ -260,8 +264,14 @@ _digest() { | ||||
|     return 1 | ||||
|   fi | ||||
|    | ||||
|   outputhex="$2" | ||||
|    | ||||
|   if [ "$alg" = "sha256" ] ; then | ||||
|     openssl dgst -sha256 -binary | _base64 | ||||
|     if [ "$outputhex" ] ; then | ||||
|       echo $(openssl dgst -sha256 -hex | cut -d = -f 2) | ||||
|     else | ||||
|       openssl dgst -sha256 -binary | _base64 | ||||
|     fi | ||||
|   else | ||||
|     _err "$alg is not supported yet" | ||||
|     return 1 | ||||
| @ -288,6 +298,86 @@ _sign() { | ||||
|    | ||||
| } | ||||
| 
 | ||||
| # _createkey  2048|ec-256   file | ||||
| _createkey() { | ||||
|   length="$1" | ||||
|   f="$2" | ||||
|   isec="" | ||||
|   if _startswith "$length" "ec-" ; then | ||||
|     isec="1" | ||||
|     length=$(printf $length | cut -d '-' -f 2-100) | ||||
|     eccname="$length" | ||||
|   fi | ||||
| 
 | ||||
|   if [ -z "$length" ] ; then | ||||
|     if [ "$isec" ] ; then | ||||
|       length=256 | ||||
|     else | ||||
|       length=2048 | ||||
|     fi | ||||
|   fi | ||||
|   _info "Use length $length" | ||||
| 
 | ||||
|   if [ "$isec" ] ; then | ||||
|     if [ "$length" = "256" ] ; then | ||||
|       eccname="prime256v1" | ||||
|     fi | ||||
|     if [ "$length" = "384" ] ; then | ||||
|       eccname="secp384r1" | ||||
|     fi | ||||
|     if [ "$length" = "521" ] ; then | ||||
|       eccname="secp521r1" | ||||
|     fi | ||||
|     _info "Using ec name: $eccname" | ||||
|   fi | ||||
| 
 | ||||
|   #generate account key | ||||
|   if [ "$isec" ] ; then | ||||
|     openssl ecparam  -name $eccname -genkey 2>/dev/null > "$f" | ||||
|   else | ||||
|     openssl genrsa $length 2>/dev/null > "$f" | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
| #_createcsr  cn  san_list  keyfile csrfile conf | ||||
| _createcsr() { | ||||
|   _debug _createcsr | ||||
|   domain="$1" | ||||
|   domainlist="$2" | ||||
|   key="$3" | ||||
|   csr="$4" | ||||
|   csrconf="$5" | ||||
|   _debug2 domain "$domain" | ||||
|   _debug2 domainlist "$domainlist" | ||||
|   if [ -z "$domainlist" ] || [ "$domainlist" = "no" ]; then | ||||
|     #single domain | ||||
|     _info "Single domain" "$domain" | ||||
|     printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$csrconf" | ||||
|     openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr" | ||||
|   else | ||||
|     if _contains "$domainlist" "," ; then | ||||
|       alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" | ||||
|     else | ||||
|       alt="DNS:$domainlist" | ||||
|     fi | ||||
|     #multi  | ||||
|     _info "Multi domain" "$alt" | ||||
|     printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment\nsubjectAltName=$alt" > "$csrconf" | ||||
|     openssl req -new -sha256 -key "$key" -subj "/CN=$domain" -config "$csrconf" -out "$csr" | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
| #_signcsr key  csr  conf cert | ||||
| _signcsr() { | ||||
|   key="$1" | ||||
|   csr="$2" | ||||
|   conf="$3" | ||||
|   cert="$4" | ||||
|    | ||||
|   openssl x509 -req -days 365  -in "$csr"  -signkey "$key"  -extensions v3_req -extfile "$conf" -out "$cert" | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| _ss() { | ||||
|   _port="$1" | ||||
|    | ||||
| @ -364,7 +454,7 @@ createAccountKey() { | ||||
|     return | ||||
|   else | ||||
|     #generate account key | ||||
|     openssl genrsa $length 2>/dev/null > "$ACCOUNT_KEY_PATH" | ||||
|     _createkey $length "$ACCOUNT_KEY_PATH" | ||||
|   fi | ||||
| 
 | ||||
| } | ||||
| @ -378,45 +468,12 @@ createDomainKey() { | ||||
|   fi | ||||
|    | ||||
|   domain=$1 | ||||
|   length=$2 | ||||
|   isec="" | ||||
|   if _startswith "$length" "ec-" ; then | ||||
|     isec="1" | ||||
|     length=$(printf $length | cut -d '-' -f 2-100) | ||||
|     eccname="$length" | ||||
|   fi | ||||
| 
 | ||||
|   if [ -z "$length" ] ; then | ||||
|     if [ "$isec" ] ; then | ||||
|       length=256 | ||||
|     else | ||||
|       length=2048 | ||||
|     fi | ||||
|   fi | ||||
|   _info "Use length $length" | ||||
| 
 | ||||
|   if [ "$isec" ] ; then | ||||
|     if [ "$length" = "256" ] ; then | ||||
|       eccname="prime256v1" | ||||
|     fi | ||||
|     if [ "$length" = "384" ] ; then | ||||
|       eccname="secp384r1" | ||||
|     fi | ||||
|     if [ "$length" = "521" ] ; then | ||||
|       eccname="secp521r1" | ||||
|     fi | ||||
|     _info "Using ec name: $eccname" | ||||
|   fi | ||||
|    | ||||
|   _initpath $domain | ||||
|    | ||||
|   length=$2 | ||||
| 
 | ||||
|   if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then  | ||||
|     #generate account key | ||||
|     if [ "$isec" ] ; then | ||||
|       openssl ecparam  -name $eccname -genkey 2>/dev/null > "$CERT_KEY_PATH" | ||||
|     else | ||||
|       openssl genrsa $length 2>/dev/null > "$CERT_KEY_PATH" | ||||
|     fi | ||||
|     _createkey "$length" "$CERT_KEY_PATH" | ||||
|   else | ||||
|     if [ "$IS_RENEW" ] ; then | ||||
|       _info "Domain key exists, skip" | ||||
| @ -447,19 +504,8 @@ createCSR() { | ||||
|     return | ||||
|   fi | ||||
|    | ||||
|   if [ -z "$domainlist" ] || [ "$domainlist" = "no" ]; then | ||||
|     #single domain | ||||
|     _info "Single domain" "$domain" | ||||
|     printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n" > "$DOMAIN_SSL_CONF" | ||||
|     openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" | ||||
|   else | ||||
|     alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")" | ||||
|     #multi  | ||||
|     _info "Multi domain" "$alt" | ||||
|     printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\n[SAN]\nsubjectAltName=$alt" > "$DOMAIN_SSL_CONF" | ||||
|     openssl req -new -sha256 -key "$CERT_KEY_PATH" -subj "/CN=$domain" -reqexts SAN -config "$DOMAIN_SSL_CONF" -out "$CSR_PATH" | ||||
|   fi | ||||
| 
 | ||||
|   _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" | ||||
|    | ||||
| } | ||||
| 
 | ||||
| _urlencode() { | ||||
| @ -819,9 +865,52 @@ _stopserver(){ | ||||
|   if [ -z "$pid" ] ; then | ||||
|     return | ||||
|   fi | ||||
|    | ||||
|   _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 | ||||
| 
 | ||||
|   _get "http://localhost:$Le_HTTPPort" >/dev/null 2>&1 | ||||
|   _get "http://localhost:$Le_TLSPort" >/dev/null 2>&1 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| # _starttlsserver  san_a  san_b port content | ||||
| _starttlsserver() { | ||||
|   _info "Starting tls server." | ||||
|   san_a="$1" | ||||
|   san_b="$2" | ||||
|   port="$3" | ||||
|   content="$4" | ||||
|    | ||||
|   _debug san_a "$san_a" | ||||
|   _debug san_b "$san_b" | ||||
|   _debug port "$port" | ||||
|    | ||||
|   #create key TLS_KEY | ||||
|   if ! _createkey "2048" "$TLS_KEY" ; then | ||||
|     _err "Create tls validation key error." | ||||
|     return 1 | ||||
|   fi | ||||
|    | ||||
|   #create csr | ||||
|   alt="$san_a" | ||||
|   if [ "$san_b" ] ; then | ||||
|     alt="$alt,$san_b" | ||||
|   fi | ||||
|   if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"  ; then | ||||
|     _err "Create tls validation csr error." | ||||
|     return 1 | ||||
|   fi | ||||
|    | ||||
|   #self signed | ||||
|   if ! _signcsr "$TLS_KEY"  "$TLS_CSR"  "$TLS_CONF" "$TLS_CERT" ; then | ||||
|     _err "Create tls validation cert error." | ||||
|     return 1 | ||||
|   fi | ||||
|    | ||||
|   #start openssl | ||||
|   (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT"  -key "$TLS_KEY" -accept $port >/dev/null 2>&1) & | ||||
|   serverproc="$!" | ||||
|   sleep 2 | ||||
|   _debug serverproc $serverproc | ||||
| } | ||||
| 
 | ||||
| _initpath() { | ||||
| @ -935,6 +1024,20 @@ _initpath() { | ||||
|   if [ -z "$CERT_PFX_PATH" ] ; then | ||||
|     CERT_PFX_PATH="$domainhome/$domain.pfx" | ||||
|   fi | ||||
|    | ||||
|   if [ -z "$TLS_CONF" ] ; then | ||||
|     TLS_CONF="$domainhome/tls.valdation.conf" | ||||
|   fi | ||||
|   if [ -z "$TLS_CERT" ] ; then | ||||
|     TLS_CERT="$domainhome/tls.valdation.cert" | ||||
|   fi | ||||
|   if [ -z "$TLS_KEY" ] ; then | ||||
|     TLS_KEY="$domainhome/tls.valdation.key" | ||||
|   fi | ||||
|   if [ -z "$TLS_CSR" ] ; then | ||||
|     TLS_CSR="$domainhome/tls.valdation.csr" | ||||
|   fi | ||||
|    | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -1073,6 +1176,12 @@ _clearup() { | ||||
|   _stopserver $serverproc | ||||
|   serverproc="" | ||||
|   _restoreApache | ||||
|   if [ -z "$DEBUG" ] ; then | ||||
|     rm -f "$TLS_CONF" | ||||
|     rm -f "$TLS_CERT" | ||||
|     rm -f "$TLS_KEY" | ||||
|     rm -f "$TLS_CSR" | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
| # webroot  removelevel tokenfile | ||||
| @ -1171,6 +1280,24 @@ issue() { | ||||
|     fi | ||||
|   fi | ||||
|    | ||||
|   if _hasfield "$Le_Webroot" "$W_TLS" ; then | ||||
|     _info "Standalone tls mode." | ||||
|      | ||||
|     if [ -z "$Le_TLSPort" ] ; then | ||||
|       Le_TLSPort=443 | ||||
|     else | ||||
|       _savedomainconf "Le_TLSPort"  "$Le_TLSPort" | ||||
|     fi     | ||||
|      | ||||
|     netprc="$(_ss "$Le_TLSPort" | grep "$Le_TLSPort")" | ||||
|     if [ "$netprc" ] ; then | ||||
|       _err "$netprc" | ||||
|       _err "tcp port $Le_TLSPort is already used by $(echo "$netprc" | cut -d :  -f 4)" | ||||
|       _err "Please stop it first" | ||||
|       return 1 | ||||
|     fi | ||||
|   fi | ||||
|    | ||||
|   if _hasfield "$Le_Webroot" "apache" ; then | ||||
|     if ! _setApache ; then | ||||
|       _err "set up apache error. Report error to me." | ||||
| @ -1263,6 +1390,11 @@ issue() { | ||||
|       if _startswith "$_currentRoot" "dns" ; then | ||||
|         vtype="$VTYPE_DNS" | ||||
|       fi | ||||
|        | ||||
|       if [ "$_currentRoot" = "$W_TLS" ] ; then | ||||
|         vtype="$VTYPE_TLS" | ||||
|       fi | ||||
|        | ||||
|       _info "Getting token for domain" $d | ||||
| 
 | ||||
|       if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" ; then | ||||
| @ -1406,7 +1538,7 @@ issue() { | ||||
|     _debug "keyauthorization" "$keyauthorization" | ||||
|     _debug "uri" "$uri" | ||||
|     removelevel="" | ||||
|     token="" | ||||
|     token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)" | ||||
| 
 | ||||
|     _debug "_currentRoot" "$_currentRoot" | ||||
| 
 | ||||
| @ -1439,7 +1571,6 @@ issue() { | ||||
| 
 | ||||
|         _debug wellknown_path "$wellknown_path" | ||||
| 
 | ||||
|         token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)" | ||||
|         _debug "writing token:$token to $wellknown_path/$token" | ||||
| 
 | ||||
|         mkdir -p "$wellknown_path" | ||||
| @ -1451,6 +1582,37 @@ issue() { | ||||
|         fi | ||||
|          | ||||
|       fi | ||||
|        | ||||
|     elif [ "$vtype" = "$VTYPE_TLS" ] ; then | ||||
|       #create A | ||||
|       #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )" | ||||
|       #_debug2 _hash_A "$_hash_A" | ||||
|       #_x="$(echo $_hash_A | cut -c 1-32)" | ||||
|       #_debug2 _x "$_x" | ||||
|       #_y="$(echo $_hash_A | cut -c 33-64)" | ||||
|       #_debug2 _y "$_y" | ||||
|       #_SAN_A="$_x.$_y.token.acme.invalid" | ||||
|       #_debug2 _SAN_A "$_SAN_A" | ||||
|        | ||||
|       #create B | ||||
|       _hash_B="$(printf "%s" $keyauthorization | _digest "sha256" "hex" )" | ||||
|       _debug2 _hash_B "$_hash_B" | ||||
|       _x="$(echo $_hash_B | cut -c 1-32)" | ||||
|       _debug2 _x "$_x" | ||||
|       _y="$(echo $_hash_B | cut -c 33-64)" | ||||
|       _debug2 _y "$_y" | ||||
|        | ||||
|       #_SAN_B="$_x.$_y.ka.acme.invalid" | ||||
|        | ||||
|       _SAN_B="$_x.$_y.acme.invalid" | ||||
|       _debug2 _SAN_B "$_SAN_B" | ||||
|        | ||||
|       if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" ; then | ||||
|         _err "Start tls server error." | ||||
|         _clearupwebbroot "$_currentRoot" "$removelevel" "$token" | ||||
|         _clearup | ||||
|         return 1 | ||||
|       fi | ||||
|     fi | ||||
|      | ||||
|     if ! _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" ; then | ||||
| @ -2203,6 +2365,7 @@ Parameters: | ||||
|      | ||||
|   --webroot, -w  /path/to/webroot   Specifies the web root folder for web root mode. | ||||
|   --standalone                      Use standalone mode. | ||||
|   --tls                             Use standalone tls mode. | ||||
|   --apache                          Use apache mode. | ||||
|   --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file]   Use dns mode or dns api. | ||||
|   --dnssleep  [60]                  The time in seconds to wait for all the txt records to take effect in dns api mode. Default 60 seconds. | ||||
| @ -2227,6 +2390,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 80 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. | ||||
|   --listraw                         Only used for '--list' command, list the certs in raw format. | ||||
|   " | ||||
| } | ||||
| @ -2277,6 +2441,7 @@ _process() { | ||||
|   _accountkey="" | ||||
|   _certhome="" | ||||
|   _httpport="" | ||||
|   _tlsport="" | ||||
|   _dnssleep="" | ||||
|   _listraw="" | ||||
|   while [ ${#} -gt 0 ] ; do | ||||
| @ -2399,6 +2564,14 @@ _process() { | ||||
|           _webroot="$_webroot,$wvalue" | ||||
|         fi | ||||
|         ;; | ||||
|     --tls) | ||||
|         wvalue="$W_TLS" | ||||
|         if [ -z "$_webroot" ] ; then | ||||
|           _webroot="$wvalue" | ||||
|         else | ||||
|           _webroot="$_webroot,$wvalue" | ||||
|         fi | ||||
|         ;; | ||||
|     --dns) | ||||
|         wvalue="dns" | ||||
|         if ! _startswith "$2" "-" ; then | ||||
| @ -2490,6 +2663,12 @@ _process() { | ||||
|         Le_HTTPPort="$_httpport" | ||||
|         shift | ||||
|         ;; | ||||
|     --tlsport ) | ||||
|         _tlsport="$2" | ||||
|         Le_TLSPort="$_tlsport" | ||||
|         shift | ||||
|         ;; | ||||
|          | ||||
|     --listraw ) | ||||
|         _listraw="raw" | ||||
|         ;;         | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user