]> git.proxmox.com Git - mirror_acme.sh.git/blame - acme.sh
fix auto upgrade
[mirror_acme.sh.git] / acme.sh
CommitLineData
0a7c9364 1#!/usr/bin/env sh
bfdf1f48 2
028e1747 3VER=2.5.5
a7b7355d 4
6cc11ffb 5PROJECT_NAME="acme.sh"
a7b7355d 6
6cc11ffb 7PROJECT_ENTRY="acme.sh"
8
9PROJECT="https://github.com/Neilpang/$PROJECT_NAME"
4c3b3608 10
f3e4cea3 11DEFAULT_INSTALL_HOME="$HOME/.$PROJECT_NAME"
12_SCRIPT_="$0"
13
14
4c3b3608 15DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
c93ec933 16DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
4c3b3608 17
08928b48 18DEFAULT_USER_AGENT="$PROJECT_ENTRY client v$VER : $PROJECT"
d0871bda 19DEFAULT_ACCOUNT_EMAIL=""
bbbdcb09 20
4c3b3608 21STAGE_CA="https://acme-staging.api.letsencrypt.org"
22
23VTYPE_HTTP="http-01"
24VTYPE_DNS="dns-01"
e22bcf7c 25VTYPE_TLS="tls-sni-01"
26VTYPE_TLS2="tls-sni-02"
27
523c7682 28MAX_RENEW=80
29
4a4dacb5 30DEFAULT_DNS_SLEEP=120
31
e22bcf7c 32W_TLS="tls"
4c3b3608 33
ec603bee 34STATE_VERIFIED="verified_ok"
35
88fab7d6 36BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----"
37END_CSR="-----END CERTIFICATE REQUEST-----"
38
39BEGIN_CERT="-----BEGIN CERTIFICATE-----"
40END_CERT="-----END CERTIFICATE-----"
41
cc179731 42RENEW_SKIP=2
43
43822d37 44ECC_SEP="_"
45ECC_SUFFIX="${ECC_SEP}ecc"
46
8663fb7e 47if [ -z "$AGREEMENT" ] ; then
4c3b3608 48 AGREEMENT="$DEFAULT_AGREEMENT"
49fi
50
08ee072f 51__INTERACTIVE=""
52if [ -t 1 ] ; then
53 __INTERACTIVE="1"
54fi
00a50605 55
43822d37 56__green() {
08ee072f 57 if [ "$__INTERACTIVE" ] ; then
2d12b689 58 printf '\033[1;31;32m'
59 fi
43822d37 60 printf -- "$1"
08ee072f 61 if [ "$__INTERACTIVE" ] ; then
2d12b689 62 printf '\033[0m'
63 fi
43822d37 64}
65
66__red() {
08ee072f 67 if [ "$__INTERACTIVE" ] ; then
2d12b689 68 printf '\033[1;31;40m'
69 fi
43822d37 70 printf -- "$1"
08ee072f 71 if [ "$__INTERACTIVE" ] ; then
2d12b689 72 printf '\033[0m'
73 fi
43822d37 74}
00a50605 75
5ea6e9c9 76__mytee() {
77 tee -a $1
78}
79
4c3b3608 80_info() {
8663fb7e 81 if [ -z "$2" ] ; then
5ea6e9c9 82 printf -- "[$(date)] $1" | __mytee $LOG_FILE
43822d37 83 else
5ea6e9c9 84 printf -- "[$(date)] $1='$2'" | __mytee $LOG_FILE
43822d37 85 fi
5ea6e9c9 86 printf "\n" | __mytee $LOG_FILE
43822d37 87}
88
89
43822d37 90_err_e() {
91 if [ -z "$2" ] ; then
5ea6e9c9 92 __red "$1" | __mytee $LOG_FILE >&2
4c3b3608 93 else
5ea6e9c9 94 __red "$1='$2'" | __mytee $LOG_FILE >&2
4c3b3608 95 fi
5ea6e9c9 96 printf "\n" | __mytee $LOG_FILE >&2
4c3b3608 97}
98
99_err() {
5ea6e9c9 100 printf -- "[$(date)] " | __mytee $LOG_FILE >&2
fac1e367 101 _err_e "$@"
4c3b3608 102 return 1
103}
104
43822d37 105_usage() {
43822d37 106 _err_e "$@"
43822d37 107}
108
c60883ef 109_debug() {
8663fb7e 110 if [ -z "$DEBUG" ] ; then
c60883ef 111 return
112 fi
43822d37 113
114 if [ -z "$2" ] ; then
5ea6e9c9 115 printf -- "[$(date)] $1" | __mytee $LOG_FILE >&2
43822d37 116 else
5ea6e9c9 117 printf -- "[$(date)] $1='$2'" | __mytee $LOG_FILE >&2
43822d37 118 fi
119
5ea6e9c9 120 printf "\n" | __mytee $LOG_FILE >&2
c60883ef 121 return 0
122}
123
a63b05a9 124_debug2() {
8663fb7e 125 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
a63b05a9 126 _debug "$@"
127 fi
128 return
129}
130
22ea4004 131_debug3() {
132 if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ] ; then
133 _debug "$@"
134 fi
135 return
136}
137
dceb3aca 138_startswith(){
139 _str="$1"
140 _sub="$2"
19539575 141 echo "$_str" | grep "^$_sub" >/dev/null 2>&1
dceb3aca 142}
143
43822d37 144_endswith(){
145 _str="$1"
146 _sub="$2"
147 echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1
148}
149
dceb3aca 150_contains(){
151 _str="$1"
152 _sub="$2"
43822d37 153 echo "$_str" | grep -- "$_sub" >/dev/null 2>&1
dceb3aca 154}
155
c53da1ef 156_hasfield() {
157 _str="$1"
158 _field="$2"
159 _sep="$3"
160 if [ -z "$_field" ] ; then
43822d37 161 _usage "Usage: str field [sep]"
c53da1ef 162 return 1
163 fi
164
165 if [ -z "$_sep" ] ; then
166 _sep=","
167 fi
168
169 for f in $(echo "$_str" | tr ',' ' ') ; do
170 if [ "$f" = "$_field" ] ; then
0c9546cc 171 _debug2 "'$_str' contains '$_field'"
c53da1ef 172 return 0 #contains ok
173 fi
174 done
0c9546cc 175 _debug2 "'$_str' does not contain '$_field'"
c53da1ef 176 return 1 #not contains
177}
178
dceb3aca 179_exists(){
c60883ef 180 cmd="$1"
8663fb7e 181 if [ -z "$cmd" ] ; then
43822d37 182 _usage "Usage: _exists cmd"
c60883ef 183 return 1
184 fi
eac18b1c 185 if type command >/dev/null 2>&1 ; then
19539575 186 command -v "$cmd" >/dev/null 2>&1
eac18b1c 187 else
19539575 188 type "$cmd" >/dev/null 2>&1
eac18b1c 189 fi
c60883ef 190 ret="$?"
690a5e20 191 _debug3 "$cmd exists=$ret"
c60883ef 192 return $ret
193}
194
00a50605 195#a + b
196_math(){
197 expr "$@"
198}
199
200_h_char_2_dec() {
201 _ch=$1
202 case "${_ch}" in
203 a|A)
19539575 204 printf "10"
00a50605 205 ;;
206 b|B)
19539575 207 printf "11"
00a50605 208 ;;
209 c|C)
19539575 210 printf "12"
00a50605 211 ;;
212 d|D)
19539575 213 printf "13"
00a50605 214 ;;
215 e|E)
19539575 216 printf "14"
00a50605 217 ;;
218 f|F)
19539575 219 printf "15"
00a50605 220 ;;
221 *)
19539575 222 printf "%s" "$_ch"
00a50605 223 ;;
19539575 224 esac
00a50605 225
226}
227
fac1e367 228
229_URGLY_PRINTF=""
230if [ "$(printf '\x41')" != 'A' ] ; then
231 _URGLY_PRINTF=1
232fi
233
4c3b3608 234_h2b() {
235 hex=$(cat)
236 i=1
237 j=2
00a50605 238 if _exists let ; then
239 uselet="1"
240 fi
690a5e20 241 _debug3 uselet "$uselet"
242 _debug3 _URGLY_PRINTF "$_URGLY_PRINTF"
19539575 243 while true ; do
00a50605 244 if [ -z "$_URGLY_PRINTF" ] ; then
19539575 245 h="$(printf $hex | cut -c $i-$j)"
00a50605 246 if [ -z "$h" ] ; then
247 break;
248 fi
249 printf "\x$h"
250 else
19539575 251 ic="$(printf $hex | cut -c $i)"
252 jc="$(printf $hex | cut -c $j)"
00a50605 253 if [ -z "$ic$jc" ] ; then
254 break;
255 fi
19539575 256 ic="$(_h_char_2_dec "$ic")"
257 jc="$(_h_char_2_dec "$jc")"
00a50605 258 printf '\'"$(printf %o "$(_math $ic \* 16 + $jc)")"
4c3b3608 259 fi
00a50605 260 if [ "$uselet" ] ; then
f4312b44 261 let "i+=2" >/dev/null
262 let "j+=2" >/dev/null
00a50605 263 else
264 i="$(_math $i + 2)"
265 j="$(_math $j + 2)"
266 fi
4c3b3608 267 done
268}
269
c60883ef 270#options file
271_sed_i() {
272 options="$1"
273 filename="$2"
8663fb7e 274 if [ -z "$filename" ] ; then
43822d37 275 _usage "Usage:_sed_i options filename"
c60883ef 276 return 1
277 fi
14f3dbb7 278 _debug2 options "$options"
279 if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then
c60883ef 280 _debug "Using sed -i"
14f3dbb7 281 sed -i "$options" "$filename"
c60883ef 282 else
283 _debug "No -i support in sed"
19539575 284 text="$(cat "$filename")"
c60883ef 285 echo "$text" | sed "$options" > "$filename"
286 fi
287}
288
22ea4004 289_egrep_o() {
290 if _contains "$(egrep -o 2>&1)" "egrep: illegal option -- o" ; then
291 sed -n 's/.*\('"$1"'\).*/\1/p'
292 else
293 egrep -o "$1"
294 fi
295}
296
88fab7d6 297#Usage: file startline endline
298_getfile() {
299 filename="$1"
300 startline="$2"
301 endline="$3"
8663fb7e 302 if [ -z "$endline" ] ; then
43822d37 303 _usage "Usage: file startline endline"
88fab7d6 304 return 1
305 fi
306
19539575 307 i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)"
8663fb7e 308 if [ -z "$i" ] ; then
88fab7d6 309 _err "Can not find start line: $startline"
310 return 1
311 fi
19539575 312 i="$(_math "$i" + 1)"
313 _debug i "$i"
88fab7d6 314
19539575 315 j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)"
8663fb7e 316 if [ -z "$j" ] ; then
88fab7d6 317 _err "Can not find end line: $endline"
318 return 1
319 fi
19539575 320 j="$(_math "$j" - 1)"
321 _debug j "$j"
88fab7d6 322
19539575 323 sed -n "$i,${j}p" "$filename"
88fab7d6 324
325}
326
327#Usage: multiline
4c3b3608 328_base64() {
8663fb7e 329 if [ "$1" ] ; then
88fab7d6 330 openssl base64 -e
331 else
332 openssl base64 -e | tr -d '\r\n'
333 fi
334}
335
336#Usage: multiline
337_dbase64() {
8663fb7e 338 if [ "$1" ] ; then
88fab7d6 339 openssl base64 -d -A
340 else
341 openssl base64 -d
342 fi
343}
344
e22bcf7c 345#Usage: hashalg [outputhex]
88fab7d6 346#Output Base64-encoded digest
347_digest() {
348 alg="$1"
8663fb7e 349 if [ -z "$alg" ] ; then
43822d37 350 _usage "Usage: _digest hashalg"
88fab7d6 351 return 1
352 fi
353
e22bcf7c 354 outputhex="$2"
355
a6014bf0 356 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
e22bcf7c 357 if [ "$outputhex" ] ; then
690a5e20 358 openssl dgst -$alg -hex | cut -d = -f 2 | tr -d ' '
e22bcf7c 359 else
a6014bf0 360 openssl dgst -$alg -binary | _base64
e22bcf7c 361 fi
88fab7d6 362 else
363 _err "$alg is not supported yet"
364 return 1
365 fi
366
367}
368
369#Usage: keyfile hashalg
370#Output: Base64-encoded signature value
371_sign() {
372 keyfile="$1"
373 alg="$2"
8663fb7e 374 if [ -z "$alg" ] ; then
43822d37 375 _usage "Usage: _sign keyfile hashalg"
88fab7d6 376 return 1
377 fi
378
8663fb7e 379 if [ "$alg" = "sha256" ] ; then
88fab7d6 380 openssl dgst -sha256 -sign "$keyfile" | _base64
381 else
382 _err "$alg is not supported yet"
383 return 1
fac1e367 384 fi
88fab7d6 385
4c3b3608 386}
387
43822d37 388#keylength
389_isEccKey() {
390 _length="$1"
391
392 if [ -z "$_length" ] ;then
393 return 1
394 fi
395
396 [ "$_length" != "1024" ] \
397 && [ "$_length" != "2048" ] \
5fbc47eb 398 && [ "$_length" != "3072" ] \
43822d37 399 && [ "$_length" != "4096" ] \
400 && [ "$_length" != "8192" ]
401}
402
e22bcf7c 403# _createkey 2048|ec-256 file
404_createkey() {
405 length="$1"
406 f="$2"
43822d37 407 eccname="$length"
e22bcf7c 408 if _startswith "$length" "ec-" ; then
e22bcf7c 409 length=$(printf $length | cut -d '-' -f 2-100)
e22bcf7c 410
e22bcf7c 411 if [ "$length" = "256" ] ; then
412 eccname="prime256v1"
413 fi
414 if [ "$length" = "384" ] ; then
415 eccname="secp384r1"
416 fi
417 if [ "$length" = "521" ] ; then
418 eccname="secp521r1"
419 fi
43822d37 420
e22bcf7c 421 fi
422
43822d37 423 if [ -z "$length" ] ; then
424 length=2048
425 fi
426
cbcd7e0f 427 _debug "Use length $length"
43822d37 428
429 if _isEccKey "$length" ; then
cbcd7e0f 430 _debug "Using ec name: $eccname"
e22bcf7c 431 openssl ecparam -name $eccname -genkey 2>/dev/null > "$f"
432 else
cbcd7e0f 433 _debug "Using RSA: $length"
e22bcf7c 434 openssl genrsa $length 2>/dev/null > "$f"
435 fi
43822d37 436
437 if [ "$?" != "0" ] ; then
438 _err "Create key error."
439 return 1
440 fi
e22bcf7c 441}
442
443#_createcsr cn san_list keyfile csrfile conf
444_createcsr() {
445 _debug _createcsr
446 domain="$1"
447 domainlist="$2"
0c9546cc 448 csrkey="$3"
e22bcf7c 449 csr="$4"
450 csrconf="$5"
451 _debug2 domain "$domain"
452 _debug2 domainlist "$domainlist"
0c9546cc 453 _debug2 csrkey "$csrkey"
454 _debug2 csr "$csr"
455 _debug2 csrconf "$csrconf"
456
457 printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" > "$csrconf"
458
e22bcf7c 459 if [ -z "$domainlist" ] || [ "$domainlist" = "no" ]; then
460 #single domain
461 _info "Single domain" "$domain"
e22bcf7c 462 else
463 if _contains "$domainlist" "," ; then
464 alt="DNS:$(echo $domainlist | sed "s/,/,DNS:/g")"
465 else
466 alt="DNS:$domainlist"
467 fi
468 #multi
469 _info "Multi domain" "$alt"
0c9546cc 470 printf -- "\nsubjectAltName=$alt" >> "$csrconf"
471 fi
472 if [ "$Le_OCSP_Stable" ] ; then
473 _savedomainconf Le_OCSP_Stable "$Le_OCSP_Stable"
474 printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >> "$csrconf"
e22bcf7c 475 fi
0c9546cc 476 openssl req -new -sha256 -key "$csrkey" -subj "/CN=$domain" -config "$csrconf" -out "$csr"
e22bcf7c 477}
478
479#_signcsr key csr conf cert
480_signcsr() {
481 key="$1"
482 csr="$2"
483 conf="$3"
484 cert="$4"
5aa146a5 485 _debug "_signcsr"
e22bcf7c 486
5aa146a5 487 _msg="$(openssl x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
488 _ret="$?"
489 _debug "$_msg"
490 return $_ret
e22bcf7c 491}
492
10afcaca 493#_csrfile
494_readSubjectFromCSR() {
495 _csrfile="$1"
496 if [ -z "$_csrfile" ] ; then
497 _usage "_readSubjectFromCSR mycsr.csr"
498 return 1
499 fi
1643b476 500 openssl req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
10afcaca 501}
502
503#_csrfile
504#echo comma separated domain list
505_readSubjectAltNamesFromCSR() {
506 _csrfile="$1"
507 if [ -z "$_csrfile" ] ; then
508 _usage "_readSubjectAltNamesFromCSR mycsr.csr"
509 return 1
510 fi
511
512 _csrsubj="$(_readSubjectFromCSR "$_csrfile")"
513 _debug _csrsubj "$_csrsubj"
514
1643b476 515 _dnsAltnames="$(openssl req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')"
10afcaca 516 _debug _dnsAltnames "$_dnsAltnames"
517
518 if _contains "$_dnsAltnames," "DNS:$_csrsubj," ; then
519 _debug "AltNames contains subject"
1643b476 520 _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")"
10afcaca 521 else
522 _debug "AltNames doesn't contain subject"
523 fi
524
1643b476 525 printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
10afcaca 526}
527
528#_csrfile
529_readKeyLengthFromCSR() {
530 _csrfile="$1"
531 if [ -z "$_csrfile" ] ; then
1643b476 532 _usage "_readKeyLengthFromCSR mycsr.csr"
10afcaca 533 return 1
534 fi
535
536 _outcsr="$(openssl req -noout -text -in "$_csrfile")"
537 if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey" ; then
538 _debug "ECC CSR"
539 echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
540 else
541 _debug "RSA CSR"
542 echo "$_outcsr" | _egrep_o "^ *Public-Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
543 fi
544}
545
546
34c27e09 547_ss() {
548 _port="$1"
edf08da6 549
550 if _exists "ss" ; then
551 _debug "Using: ss"
19539575 552 ss -ntpl | grep ":$_port "
edf08da6 553 return 0
554 fi
555
556 if _exists "netstat" ; then
251fc37c 557 _debug "Using: netstat"
ccb96535 558 if netstat -h 2>&1 | grep "\-p proto" >/dev/null ; then
559 #for windows version netstat tool
19539575 560 netstat -anb -p tcp | grep "LISTENING" | grep ":$_port "
ccb96535 561 else
14165e5a 562 if netstat -help 2>&1 | grep "\-p protocol" >/dev/null ; then
19539575 563 netstat -an -p tcp | grep LISTEN | grep ":$_port "
22ea4004 564 elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null ; then
565 #for solaris
e3c66532 566 netstat -an -P tcp | grep "\.$_port " | grep "LISTEN"
edf08da6 567 else
19539575 568 netstat -ntpl | grep ":$_port "
edf08da6 569 fi
ccb96535 570 fi
34c27e09 571 return 0
572 fi
edf08da6 573
34c27e09 574 return 1
575}
576
43822d37 577#domain [password] [isEcc]
ac2d5123 578toPkcs() {
579 domain="$1"
580 pfxPassword="$2"
8663fb7e 581 if [ -z "$domain" ] ; then
43822d37 582 _usage "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]"
ac2d5123 583 return 1
584 fi
585
43822d37 586 _isEcc="$3"
ac2d5123 587
43822d37 588 _initpath "$domain" "$_isEcc"
589
8663fb7e 590 if [ "$pfxPassword" ] ; then
ac2d5123 591 openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
592 else
593 openssl pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
594 fi
595
8663fb7e 596 if [ "$?" = "0" ] ; then
ac2d5123 597 _info "Success, Pfx is exported to: $CERT_PFX_PATH"
598 fi
599
600}
601
5fbc47eb 602#[2048]
4c3b3608 603createAccountKey() {
604 _info "Creating account key"
8663fb7e 605 if [ -z "$1" ] ; then
5fbc47eb 606 _usage "Usage: $PROJECT_ENTRY --createAccountKey --accountkeylength 2048"
4c3b3608 607 return
608 fi
609
5fbc47eb 610 length=$1
1643b476 611 if _isEccKey "$length" ; then
4c3b3608 612 length=2048
613 fi
614
5fbc47eb 615 if [ -z "$length" ] || [ "$length" = "no" ] ; then
cbcd7e0f 616 _debug "Use default length 2048"
4c3b3608 617 length=2048
618 fi
5fbc47eb 619 _debug length "$length"
4c3b3608 620 _initpath
5fbc47eb 621
8663fb7e 622 if [ -f "$ACCOUNT_KEY_PATH" ] ; then
4c3b3608 623 _info "Account key exists, skip"
624 return
625 else
626 #generate account key
31a5487c 627 _createkey "$length" "$ACCOUNT_KEY_PATH"
4c3b3608 628 fi
629
630}
631
43822d37 632#domain [length]
4c3b3608 633createDomainKey() {
634 _info "Creating domain key"
8663fb7e 635 if [ -z "$1" ] ; then
43822d37 636 _usage "Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ]"
4c3b3608 637 return
638 fi
639
640 domain=$1
e22bcf7c 641 length=$2
43822d37 642
643 _initpath $domain "$length"
e22bcf7c 644
8663fb7e 645 if [ ! -f "$CERT_KEY_PATH" ] || ( [ "$FORCE" ] && ! [ "$IS_RENEW" ] ); then
e22bcf7c 646 _createkey "$length" "$CERT_KEY_PATH"
4c3b3608 647 else
8663fb7e 648 if [ "$IS_RENEW" ] ; then
4c3b3608 649 _info "Domain key exists, skip"
650 return 0
651 else
652 _err "Domain key exists, do you want to overwrite the key?"
41e3eafa 653 _err "Add '--force', and try again."
4c3b3608 654 return 1
655 fi
656 fi
657
658}
659
43822d37 660# domain domainlist isEcc
4c3b3608 661createCSR() {
662 _info "Creating csr"
8663fb7e 663 if [ -z "$1" ] ; then
43822d37 664 _usage "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]"
4c3b3608 665 return
666 fi
4c3b3608 667
43822d37 668 domain="$1"
669 domainlist="$2"
670 _isEcc="$3"
671
672 _initpath "$domain" "$_isEcc"
4c3b3608 673
8663fb7e 674 if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then
4c3b3608 675 _info "CSR exists, skip"
676 return
677 fi
678
43822d37 679 if [ ! -f "$CERT_KEY_PATH" ] ; then
680 _err "The key file is not found: $CERT_KEY_PATH"
681 _err "Please create the key file first."
682 return 1
683 fi
e22bcf7c 684 _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"
685
4c3b3608 686}
687
166096dc 688_urlencode() {
4c3b3608 689 __n=$(cat)
690 echo $__n | tr '/+' '_-' | tr -d '= '
691}
692
693_time2str() {
694 #BSD
695 if date -u -d@$1 2>/dev/null ; then
696 return
697 fi
698
699 #Linux
700 if date -u -r $1 2>/dev/null ; then
701 return
702 fi
703
22ea4004 704 #Soaris
705 if _exists adb ; then
706 echo $(echo "0t${1}=Y" | adb)
707 fi
708
4c3b3608 709}
710
eae29099 711_normalizeJson() {
712 sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
713}
714
44df2967 715_stat() {
716 #Linux
717 if stat -c '%U:%G' "$1" 2>/dev/null ; then
718 return
719 fi
720
721 #BSD
722 if stat -f '%Su:%Sg' "$1" 2>/dev/null ; then
723 return
724 fi
3ad08e95
TB
725
726 return 1; #error, 'stat' not found
44df2967 727}
728
166096dc 729#keyfile
730_calcjwk() {
731 keyfile="$1"
8663fb7e 732 if [ -z "$keyfile" ] ; then
43822d37 733 _usage "Usage: _calcjwk keyfile"
166096dc 734 return 1
735 fi
736 EC_SIGN=""
737 if grep "BEGIN RSA PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then
738 _debug "RSA key"
739 pub_exp=$(openssl rsa -in $keyfile -noout -text | grep "^publicExponent:"| cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
8663fb7e 740 if [ "${#pub_exp}" = "5" ] ; then
166096dc 741 pub_exp=0$pub_exp
742 fi
22ea4004 743 _debug3 pub_exp "$pub_exp"
166096dc 744
745 e=$(echo $pub_exp | _h2b | _base64)
22ea4004 746 _debug3 e "$e"
166096dc 747
748 modulus=$(openssl rsa -in $keyfile -modulus -noout | cut -d '=' -f 2 )
22ea4004 749 _debug3 modulus "$modulus"
19539575 750 n="$(printf "%s" "$modulus"| _h2b | _base64 | _urlencode )"
166096dc 751 jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
22ea4004 752 _debug3 jwk "$jwk"
166096dc 753
754 HEADER='{"alg": "RS256", "jwk": '$jwk'}'
22ea4004 755 HEADERPLACE_PART1='{"nonce": "'
756 HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}'
166096dc 757 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" > /dev/null 2>&1 ; then
758 _debug "EC key"
759 EC_SIGN="1"
760 crv="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
22ea4004 761 _debug3 crv "$crv"
166096dc 762
763 pubi="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
00a50605 764 pubi=$(_math $pubi + 1)
22ea4004 765 _debug3 pubi "$pubi"
166096dc 766
767 pubj="$(openssl ec -in $keyfile -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
00a50605 768 pubj=$(_math $pubj + 1)
22ea4004 769 _debug3 pubj "$pubj"
166096dc 770
771 pubtext="$(openssl ec -in $keyfile -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
22ea4004 772 _debug3 pubtext "$pubtext"
166096dc 773
774 xlen="$(printf "$pubtext" | tr -d ':' | wc -c)"
00a50605 775 xlen=$(_math $xlen / 4)
22ea4004 776 _debug3 xlen "$xlen"
00a50605 777
19539575 778 xend=$(_math "$xend" + 1)
166096dc 779 x="$(printf $pubtext | cut -d : -f 2-$xend)"
22ea4004 780 _debug3 x "$x"
166096dc 781
782 x64="$(printf $x | tr -d : | _h2b | _base64 | _urlencode)"
22ea4004 783 _debug3 x64 "$x64"
00a50605 784
19539575 785 xend=$(_math "$xend" + 1)
166096dc 786 y="$(printf $pubtext | cut -d : -f $xend-10000)"
22ea4004 787 _debug3 y "$y"
166096dc 788
789 y64="$(printf $y | tr -d : | _h2b | _base64 | _urlencode)"
22ea4004 790 _debug3 y64 "$y64"
166096dc 791
792 jwk='{"kty": "EC", "crv": "'$crv'", "x": "'$x64'", "y": "'$y64'"}'
22ea4004 793 _debug3 jwk "$jwk"
166096dc 794
795 HEADER='{"alg": "ES256", "jwk": '$jwk'}'
22ea4004 796 HEADERPLACE_PART1='{"nonce": "'
797 HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}'
166096dc 798 else
799 _err "Only RSA or EC key is supported."
800 return 1
801 fi
802
22ea4004 803 _debug3 HEADER "$HEADER"
166096dc 804}
fac1e367 805
3aae1ae3 806_time() {
807 date -u "+%s"
808}
fac1e367 809
810_mktemp() {
811 if _exists mktemp ; then
812 mktemp
7b164426 813 return
fac1e367 814 fi
3aae1ae3 815 if [ -d "/tmp" ] ; then
816 echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp"
817 return 0
818 fi
819 _err "Can not create temp file."
fac1e367 820}
821
822_inithttp() {
823
dfdc402f 824 if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER" ; then
fac1e367 825 HTTP_HEADER="$(_mktemp)"
826 _debug2 HTTP_HEADER "$HTTP_HEADER"
827 fi
828
829 if [ -z "$CURL" ] ; then
830 CURL="curl -L --silent --dump-header $HTTP_HEADER "
831 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
832 _CURL_DUMP="$(_mktemp)"
833 CURL="$CURL --trace-ascii $_CURL_DUMP "
834 fi
835
78009539
PS
836 if [ "$CA_BUNDLE" ] ; then
837 CURL="$CURL --cacert $CA_BUNDLE "
838 fi
839
fac1e367 840 if [ "$HTTPS_INSECURE" ] ; then
841 CURL="$CURL --insecure "
842 fi
843 fi
844
845 if [ -z "$WGET" ] ; then
846 WGET="wget -q"
847 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
848 WGET="$WGET -d "
849 fi
78009539
PS
850 if [ "$CA_BUNDLE" ] ; then
851 WGET="$WGET --ca-certificate $CA_BUNDLE "
852 fi
fac1e367 853 if [ "$HTTPS_INSECURE" ] ; then
854 WGET="$WGET --no-check-certificate "
855 fi
856 fi
857
858}
859
860
c839b2b0 861# body url [needbase64] [POST|PUT]
c60883ef 862_post() {
863 body="$1"
864 url="$2"
865 needbase64="$3"
a4270efa 866 httpmethod="$4"
c60883ef 867
a4270efa 868 if [ -z "$httpmethod" ] ; then
869 httpmethod="POST"
870 fi
871 _debug $httpmethod
484d9d2a 872 _debug "url" "$url"
30de13b4 873 _debug2 "body" "$body"
fac1e367 874
875 _inithttp
876
c60883ef 877 if _exists "curl" ; then
fac1e367 878 _CURL="$CURL"
ec9fc8cb 879 _debug "_CURL" "$_CURL"
8663fb7e 880 if [ "$needbase64" ] ; then
690a5e20 881 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)"
c60883ef 882 else
690a5e20 883 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" )"
c60883ef 884 fi
16679b57 885 _ret="$?"
687cfcc2 886 if [ "$_ret" != "0" ] ; then
87ab2d90 887 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
888 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
889 _err "Here is the curl dump log:"
890 _err "$(cat "$_CURL_DUMP")"
891 fi
687cfcc2 892 fi
d0b748a4 893 elif _exists "wget" ; then
ec9fc8cb 894 _debug "WGET" "$WGET"
8663fb7e 895 if [ "$needbase64" ] ; then
8fb9a709 896 if [ "$httpmethod"="POST" ] ; then
690a5e20 897 response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
8fb9a709 898 else
690a5e20 899 response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER" | _base64)"
8fb9a709 900 fi
c60883ef 901 else
8fb9a709 902 if [ "$httpmethod"="POST" ] ; then
690a5e20 903 response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --post-data="$body" "$url" 2>"$HTTP_HEADER")"
8fb9a709 904 else
690a5e20 905 response="$($WGET -S -O - --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" --method $httpmethod --body-data="$body" "$url" 2>"$HTTP_HEADER")"
8fb9a709 906 fi
c60883ef 907 fi
16679b57 908 _ret="$?"
687cfcc2 909 if [ "$_ret" != "0" ] ; then
910 _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
911 fi
c60883ef 912 _sed_i "s/^ *//g" "$HTTP_HEADER"
d0b748a4 913 else
914 _ret="$?"
915 _err "Neither curl nor wget is found, can not do $httpmethod."
c60883ef 916 fi
16679b57 917 _debug "_ret" "$_ret"
19539575 918 printf "%s" "$response"
16679b57 919 return $_ret
c60883ef 920}
921
d529eb6d 922
75da0713 923# url getheader timeout
c60883ef 924_get() {
a4270efa 925 _debug GET
c60883ef 926 url="$1"
927 onlyheader="$2"
75da0713 928 t="$3"
c60883ef 929 _debug url $url
75da0713 930 _debug "timeout" "$t"
fac1e367 931
932 _inithttp
933
c60883ef 934 if _exists "curl" ; then
75da0713 935 _CURL="$CURL"
936 if [ "$t" ] ; then
937 _CURL="$_CURL --connect-timeout $t"
938 fi
939 _debug "_CURL" "$_CURL"
8663fb7e 940 if [ "$onlyheader" ] ; then
690a5e20 941 $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url
c60883ef 942 else
690a5e20 943 $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" $url
c60883ef 944 fi
9aaf36cd 945 ret=$?
fac1e367 946 if [ "$ret" != "0" ] ; then
d529eb6d 947 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
fac1e367 948 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
949 _err "Here is the curl dump log:"
950 _err "$(cat "$_CURL_DUMP")"
951 fi
952 fi
d0b748a4 953 elif _exists "wget" ; then
75da0713 954 _WGET="$WGET"
955 if [ "$t" ] ; then
956 _WGET="$_WGET --timeout=$t"
957 fi
958 _debug "_WGET" "$_WGET"
8663fb7e 959 if [ "$onlyheader" ] ; then
690a5e20 960 $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -S -O /dev/null $url 2>&1 | sed 's/^[ ]*//g'
c60883ef 961 else
690a5e20 962 $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - $url
c60883ef 963 fi
9aaf36cd 964 ret=$?
fac1e367 965 if [ "$ret" != "0" ] ; then
d529eb6d 966 _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
fac1e367 967 fi
d0b748a4 968 else
969 ret=$?
970 _err "Neither curl nor wget is found, can not do GET."
9aaf36cd 971 fi
ec9fc8cb 972 _debug "ret" "$ret"
c60883ef 973 return $ret
974}
166096dc 975
fac1e367 976
166096dc 977# url payload needbase64 keyfile
4c3b3608 978_send_signed_request() {
979 url=$1
980 payload=$2
981 needbase64=$3
166096dc 982 keyfile=$4
8663fb7e 983 if [ -z "$keyfile" ] ; then
166096dc 984 keyfile="$ACCOUNT_KEY_PATH"
985 fi
4c3b3608 986 _debug url $url
987 _debug payload "$payload"
988
166096dc 989 if ! _calcjwk "$keyfile" ; then
990 return 1
991 fi
c60883ef 992
22ea4004 993 payload64=$(printf "%s" "$payload" | _base64 | _urlencode)
994 _debug3 payload64 $payload64
4c3b3608 995
996 nonceurl="$API/directory"
a272ee4f 997 _headers="$(_get $nonceurl "onlyheader")"
998
7012b91f 999 if [ "$?" != "0" ] ; then
1000 _err "Can not connect to $nonceurl to get nonce."
1001 return 1
1002 fi
a272ee4f 1003
22ea4004 1004 _debug3 _headers "$_headers"
a272ee4f 1005
1006 nonce="$( echo "$_headers" | grep "Replay-Nonce:" | head -1 | tr -d "\r\n " | cut -d ':' -f 2)"
1007
22ea4004 1008 _debug3 nonce "$nonce"
4c3b3608 1009
22ea4004 1010 protected="$HEADERPLACE_PART1$nonce$HEADERPLACE_PART2"
1011 _debug3 protected "$protected"
4c3b3608 1012
166096dc 1013 protected64="$(printf "$protected" | _base64 | _urlencode)"
22ea4004 1014 _debug3 protected64 "$protected64"
166096dc 1015
22ea4004 1016 sig=$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256" | _urlencode)
1017 _debug3 sig "$sig"
4c3b3608 1018
1019 body="{\"header\": $HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
22ea4004 1020 _debug3 body "$body"
4c3b3608 1021
bbbdcb09 1022
eae29099 1023 response="$(_post "$body" $url "$needbase64")"
7012b91f 1024 if [ "$?" != "0" ] ; then
1025 _err "Can not post to $url."
1026 return 1
1027 fi
eae29099 1028 _debug2 original "$response"
1029
1030 response="$( echo "$response" | _normalizeJson )"
4c3b3608 1031
c60883ef 1032 responseHeaders="$(cat $HTTP_HEADER)"
4c3b3608 1033
a63b05a9 1034 _debug2 responseHeaders "$responseHeaders"
1035 _debug2 response "$response"
c60883ef 1036 code="$(grep "^HTTP" $HTTP_HEADER | tail -1 | cut -d " " -f 2 | tr -d "\r\n" )"
4c3b3608 1037 _debug code $code
1038
1039}
1040
4c3b3608 1041
1042#setopt "file" "opt" "=" "value" [";"]
1043_setopt() {
1044 __conf="$1"
1045 __opt="$2"
1046 __sep="$3"
1047 __val="$4"
1048 __end="$5"
8663fb7e 1049 if [ -z "$__opt" ] ; then
43822d37 1050 _usage usage: _setopt '"file" "opt" "=" "value" [";"]'
4c3b3608 1051 return
1052 fi
8663fb7e 1053 if [ ! -f "$__conf" ] ; then
4c3b3608 1054 touch "$__conf"
1055 fi
1056
22ea4004 1057 if grep -n "^$__opt$__sep" "$__conf" > /dev/null ; then
1058 _debug3 OK
dceb3aca 1059 if _contains "$__val" "&" ; then
4c3b3608 1060 __val="$(echo $__val | sed 's/&/\\&/g')"
1061 fi
1062 text="$(cat $__conf)"
6dfaaa70 1063 echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf"
4c3b3608 1064
22ea4004 1065 elif grep -n "^#$__opt$__sep" "$__conf" > /dev/null ; then
dceb3aca 1066 if _contains "$__val" "&" ; then
4c3b3608 1067 __val="$(echo $__val | sed 's/&/\\&/g')"
1068 fi
1069 text="$(cat $__conf)"
6dfaaa70 1070 echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" > "$__conf"
4c3b3608 1071
1072 else
22ea4004 1073 _debug3 APP
4c3b3608 1074 echo "$__opt$__sep$__val$__end" >> "$__conf"
1075 fi
22ea4004 1076 _debug2 "$(grep -n "^$__opt$__sep" $__conf)"
4c3b3608 1077}
1078
1079#_savedomainconf key value
1080#save to domain.conf
1081_savedomainconf() {
0c9546cc 1082 _sdkey="$1"
1083 _sdvalue="$2"
8663fb7e 1084 if [ "$DOMAIN_CONF" ] ; then
0c9546cc 1085 _setopt "$DOMAIN_CONF" "$_sdkey" "=" "\"$_sdvalue\""
4d2f38b0 1086 else
0c9546cc 1087 _err "DOMAIN_CONF is empty, can not save $_sdkey=$_sdvalue"
4d2f38b0 1088 fi
1089}
1090
1091#_cleardomainconf key
1092_cleardomainconf() {
0c9546cc 1093 _sdkey="$1"
4d2f38b0 1094 if [ "$DOMAIN_CONF" ] ; then
0c9546cc 1095 _sed_i "s/^$_sdkey.*$//" "$DOMAIN_CONF"
4c3b3608 1096 else
0c9546cc 1097 _err "DOMAIN_CONF is empty, can not save $_sdkey=$value"
4c3b3608 1098 fi
1099}
1100
61623d22 1101#_readdomainconf key
1102_readdomainconf() {
0c9546cc 1103 _sdkey="$1"
61623d22 1104 if [ "$DOMAIN_CONF" ] ; then
1105 (
0c9546cc 1106 eval $(grep "^$_sdkey *=" "$DOMAIN_CONF")
1107 eval "printf \"%s\" \"\$$_sdkey\""
61623d22 1108 )
1109 else
0c9546cc 1110 _err "DOMAIN_CONF is empty, can not read $_sdkey"
61623d22 1111 fi
1112}
1113
4c3b3608 1114#_saveaccountconf key value
1115_saveaccountconf() {
0c9546cc 1116 _sckey="$1"
1117 _scvalue="$2"
8663fb7e 1118 if [ "$ACCOUNT_CONF_PATH" ] ; then
0c9546cc 1119 _setopt "$ACCOUNT_CONF_PATH" "$_sckey" "=" "\"$_scvalue\""
4c3b3608 1120 else
0c9546cc 1121 _err "ACCOUNT_CONF_PATH is empty, can not save $_sckey=$_scvalue"
4c3b3608 1122 fi
1123}
1124
fac1e367 1125#_clearaccountconf key
1126_clearaccountconf() {
0c9546cc 1127 _scvalue="$1"
fac1e367 1128 if [ "$ACCOUNT_CONF_PATH" ] ; then
0c9546cc 1129 _sed_i "s/^$_scvalue.*$//" "$ACCOUNT_CONF_PATH"
fac1e367 1130 else
0c9546cc 1131 _err "ACCOUNT_CONF_PATH is empty, can not clear $_scvalue"
fac1e367 1132 fi
1133}
1134
4c3b3608 1135_startserver() {
1136 content="$1"
6fc1447f 1137 _debug "startserver: $$"
1b2e940d 1138 nchelp="$(nc -h 2>&1)"
850c1128 1139
399306a1 1140 if echo "$nchelp" | grep "\-q[ ,]" >/dev/null ; then
850c1128 1141 _NC="nc -q 1 -l"
1142 else
f76eb452 1143 if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null ; then
1144 _NC="nc -c -l"
6d60f288 1145 elif echo "$nchelp" | grep "\-N" |grep "Shutdown the network socket after EOF on stdin" >/dev/null ; then
1146 _NC="nc -N -l"
f76eb452 1147 else
1148 _NC="nc -l"
1149 fi
4c3b3608 1150 fi
1b2e940d 1151
f76eb452 1152 _debug "_NC" "$_NC"
39c8f79f 1153 _debug Le_HTTPPort "$Le_HTTPPort"
4c3b3608 1154# while true ; do
8663fb7e 1155 if [ "$DEBUG" ] ; then
2c554a4b 1156 if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort ; then
1157 printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort ;
3aff11f6 1158 fi
4c3b3608 1159 else
2c554a4b 1160 if ! printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC -p $Le_HTTPPort > /dev/null 2>&1; then
1161 printf "HTTP/1.1 200 OK\r\n\r\n$content" | $_NC $Le_HTTPPort > /dev/null 2>&1
3aff11f6 1162 fi
4c3b3608 1163 fi
8663fb7e 1164 if [ "$?" != "0" ] ; then
051c706d 1165 _err "nc listen error."
6fc1447f 1166 exit 1
051c706d 1167 fi
4c3b3608 1168# done
1169}
1170
6fc1447f 1171_stopserver(){
4c3b3608 1172 pid="$1"
6fc1447f 1173 _debug "pid" "$pid"
8663fb7e 1174 if [ -z "$pid" ] ; then
6fc1447f 1175 return
1176 fi
e22bcf7c 1177
dcf9cb58 1178 _debug2 "Le_HTTPPort" "$Le_HTTPPort"
1179 if [ "$Le_HTTPPort" ] ; then
276b51d9 1180 if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ] ; then
22ea4004 1181 _get "http://localhost:$Le_HTTPPort" "" 1
dcf9cb58 1182 else
22ea4004 1183 _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1
dcf9cb58 1184 fi
1185 fi
1186
1187 _debug2 "Le_TLSPort" "$Le_TLSPort"
1188 if [ "$Le_TLSPort" ] ; then
276b51d9 1189 if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ] ; then
75da0713 1190 _get "https://localhost:$Le_TLSPort" "" 1
1191 _get "https://localhost:$Le_TLSPort" "" 1
dcf9cb58 1192 else
75da0713 1193 _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
1194 _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
dcf9cb58 1195 fi
1196 fi
4c3b3608 1197}
1198
e22bcf7c 1199
1200# _starttlsserver san_a san_b port content
1201_starttlsserver() {
1202 _info "Starting tls server."
1203 san_a="$1"
1204 san_b="$2"
1205 port="$3"
1206 content="$4"
1207
1208 _debug san_a "$san_a"
1209 _debug san_b "$san_b"
1210 _debug port "$port"
1211
1212 #create key TLS_KEY
1213 if ! _createkey "2048" "$TLS_KEY" ; then
1214 _err "Create tls validation key error."
1215 return 1
1216 fi
1217
1218 #create csr
1219 alt="$san_a"
1220 if [ "$san_b" ] ; then
1221 alt="$alt,$san_b"
1222 fi
1223 if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" ; then
1224 _err "Create tls validation csr error."
1225 return 1
1226 fi
1227
1228 #self signed
1229 if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT" ; then
1230 _err "Create tls validation cert error."
1231 return 1
1232 fi
1233
1234 #start openssl
bdbf323f 1235 _debug "openssl s_server -cert \"$TLS_CERT\" -key \"$TLS_KEY\" -accept $port -naccept 1 -tlsextdebug"
fbad6a39 1236 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ] ; then
75da0713 1237 (printf "HTTP/1.1 200 OK\r\n\r\n$content" | openssl s_server -cert "$TLS_CERT" -key "$TLS_KEY" -accept $port -tlsextdebug ) &
331c4bb6 1238 else
75da0713 1239 (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) &
331c4bb6 1240 fi
1241
e22bcf7c 1242 serverproc="$!"
1243 sleep 2
1244 _debug serverproc $serverproc
1245}
1246
5ea6e9c9 1247__initHome() {
f3e4cea3 1248 if [ -z "$_SCRIPT_HOME" ] ; then
1249 if _exists readlink && _exists dirname ; then
1250 _debug "Lets guess script dir."
1251 _debug "_SCRIPT_" "$_SCRIPT_"
1252 _script="$(readlink -f "$_SCRIPT_")"
1253 _debug "_script" "$_script"
1254 _script_home="$(dirname "$_script")"
1255 _debug "_script_home" "$_script_home"
1256 if [ -d "$_script_home" ] ; then
1257 _SCRIPT_HOME="$_script_home"
1258 else
1259 _err "It seems the script home is not correct:$_script_home"
1260 fi
1261 fi
1262 fi
1263
1264
8663fb7e 1265 if [ -z "$LE_WORKING_DIR" ] ; then
f3e4cea3 1266 if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ] ; then
1267 _debug "It seems tha $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME"
1268 LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
1269 else
1270 LE_WORKING_DIR="$_SCRIPT_HOME"
1271 fi
4c3b3608 1272 fi
1273
f3e4cea3 1274 if [ -z "$LE_WORKING_DIR" ] ; then
1275 _debug "Using default home:$DEFAULT_INSTALL_HOME"
1276 LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
1277 fi
1278
d53289d7 1279 _DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf"
1280
8663fb7e 1281 if [ -z "$ACCOUNT_CONF_PATH" ] ; then
1282 if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ] ; then
1283 . "$_DEFAULT_ACCOUNT_CONF_PATH"
635695ec 1284 fi
d53289d7 1285 fi
1286
8663fb7e 1287 if [ -z "$ACCOUNT_CONF_PATH" ] ; then
d53289d7 1288 ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH"
4c3b3608 1289 fi
d0871bda 1290
1291 DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log"
5ea6e9c9 1292}
1293
1294#[domain] [keylength]
1295_initpath() {
1296
1297 __initHome
1298
8663fb7e 1299 if [ -f "$ACCOUNT_CONF_PATH" ] ; then
1300 . "$ACCOUNT_CONF_PATH"
4c3b3608 1301 fi
1302
8663fb7e 1303 if [ "$IN_CRON" ] ; then
1304 if [ ! "$_USER_PATH_EXPORTED" ] ; then
281aa349 1305 _USER_PATH_EXPORTED=1
1306 export PATH="$USER_PATH:$PATH"
1307 fi
1308 fi
1309
8663fb7e 1310 if [ -z "$API" ] ; then
1311 if [ -z "$STAGE" ] ; then
4c3b3608 1312 API="$DEFAULT_CA"
1313 else
1314 API="$STAGE_CA"
1315 _info "Using stage api:$API"
1316 fi
1317 fi
1318
8663fb7e 1319 if [ -z "$ACME_DIR" ] ; then
4c3b3608 1320 ACME_DIR="/home/.acme"
1321 fi
1322
8663fb7e 1323 if [ -z "$APACHE_CONF_BACKUP_DIR" ] ; then
8a144f4d 1324 APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR"
4c3b3608 1325 fi
1326
8663fb7e 1327 if [ -z "$USER_AGENT" ] ; then
bbbdcb09 1328 USER_AGENT="$DEFAULT_USER_AGENT"
1329 fi
1330
933c169d 1331 if [ -z "$HTTP_HEADER" ] ; then
1332 HTTP_HEADER="$LE_WORKING_DIR/http.header"
1333 fi
b2817897 1334
1335 _DEFAULT_ACCOUNT_KEY_PATH="$LE_WORKING_DIR/account.key"
8663fb7e 1336 if [ -z "$ACCOUNT_KEY_PATH" ] ; then
b2817897 1337 ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH"
4c3b3608 1338 fi
b2817897 1339
a79b26af
RD
1340 _DEFAULT_CERT_HOME="$LE_WORKING_DIR"
1341 if [ -z "$CERT_HOME" ] ; then
1342 CERT_HOME="$_DEFAULT_CERT_HOME"
1343 fi
1344
5fbc47eb 1345 if [ -z "$1" ] ; then
4c3b3608 1346 return 0
1347 fi
5fbc47eb 1348 domain="$1"
1349 _ilength="$2"
4c3b3608 1350
8663fb7e 1351 if [ -z "$DOMAIN_PATH" ] ; then
43822d37 1352 domainhome="$CERT_HOME/$domain"
1353 domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX"
1354
4c3b3608 1355 DOMAIN_PATH="$domainhome"
43822d37 1356
5fbc47eb 1357 if _isEccKey "$_ilength" ; then
43822d37 1358 DOMAIN_PATH="$domainhomeecc"
1359 else
1360 if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ] ; then
6d4e903b 1361 _info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert."
43822d37 1362 fi
1363 fi
1364 _debug DOMAIN_PATH "$DOMAIN_PATH"
4c3b3608 1365 fi
43822d37 1366
933c169d 1367 if [ ! -d "$DOMAIN_PATH" ] ; then
1368 if ! mkdir -p "$DOMAIN_PATH" ; then
1369 _err "Can not create domain path: $DOMAIN_PATH"
1370 return 1
1371 fi
1372 fi
1373
8663fb7e 1374 if [ -z "$DOMAIN_CONF" ] ; then
43822d37 1375 DOMAIN_CONF="$DOMAIN_PATH/$domain.conf"
4c3b3608 1376 fi
1377
8663fb7e 1378 if [ -z "$DOMAIN_SSL_CONF" ] ; then
0c9546cc 1379 DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf"
4c3b3608 1380 fi
1381
8663fb7e 1382 if [ -z "$CSR_PATH" ] ; then
43822d37 1383 CSR_PATH="$DOMAIN_PATH/$domain.csr"
4c3b3608 1384 fi
8663fb7e 1385 if [ -z "$CERT_KEY_PATH" ] ; then
43822d37 1386 CERT_KEY_PATH="$DOMAIN_PATH/$domain.key"
4c3b3608 1387 fi
8663fb7e 1388 if [ -z "$CERT_PATH" ] ; then
43822d37 1389 CERT_PATH="$DOMAIN_PATH/$domain.cer"
4c3b3608 1390 fi
8663fb7e 1391 if [ -z "$CA_CERT_PATH" ] ; then
43822d37 1392 CA_CERT_PATH="$DOMAIN_PATH/ca.cer"
4c3b3608 1393 fi
8663fb7e 1394 if [ -z "$CERT_FULLCHAIN_PATH" ] ; then
43822d37 1395 CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer"
caf1fc10 1396 fi
8663fb7e 1397 if [ -z "$CERT_PFX_PATH" ] ; then
43822d37 1398 CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx"
ac2d5123 1399 fi
e22bcf7c 1400
1401 if [ -z "$TLS_CONF" ] ; then
43822d37 1402 TLS_CONF="$DOMAIN_PATH/tls.valdation.conf"
e22bcf7c 1403 fi
1404 if [ -z "$TLS_CERT" ] ; then
43822d37 1405 TLS_CERT="$DOMAIN_PATH/tls.valdation.cert"
e22bcf7c 1406 fi
1407 if [ -z "$TLS_KEY" ] ; then
43822d37 1408 TLS_KEY="$DOMAIN_PATH/tls.valdation.key"
e22bcf7c 1409 fi
1410 if [ -z "$TLS_CSR" ] ; then
43822d37 1411 TLS_CSR="$DOMAIN_PATH/tls.valdation.csr"
e22bcf7c 1412 fi
1413
4c3b3608 1414}
1415
1416
1417_apachePath() {
c3dd3ef0 1418 _APACHECTL="apachectl"
80a0a7b5 1419 if ! _exists apachectl ; then
e4a19585 1420 if _exists apache2ctl ; then
c3dd3ef0 1421 _APACHECTL="apache2ctl"
e4a19585 1422 else
bc96082f 1423 _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'"
e4a19585 1424 _err "Please use webroot mode to try again."
1425 return 1
1426 fi
80a0a7b5 1427 fi
c3dd3ef0 1428 httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"' )"
78768e98 1429 _debug httpdconfname "$httpdconfname"
dceb3aca 1430 if _startswith "$httpdconfname" '/' ; then
d62ee940 1431 httpdconf="$httpdconfname"
c456d954 1432 httpdconfname="$(basename $httpdconfname)"
d62ee940 1433 else
c3dd3ef0 1434 httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"' )"
78768e98 1435 _debug httpdroot "$httpdroot"
d62ee940 1436 httpdconf="$httpdroot/$httpdconfname"
8f63baf7 1437 httpdconfname="$(basename $httpdconfname)"
d62ee940 1438 fi
78768e98 1439 _debug httpdconf "$httpdconf"
8f63baf7 1440 _debug httpdconfname "$httpdconfname"
78768e98 1441 if [ ! -f "$httpdconf" ] ; then
1442 _err "Apache Config file not found" "$httpdconf"
4c3b3608 1443 return 1
1444 fi
1445 return 0
1446}
1447
1448_restoreApache() {
8663fb7e 1449 if [ -z "$usingApache" ] ; then
4c3b3608 1450 return 0
1451 fi
1452 _initpath
1453 if ! _apachePath ; then
1454 return 1
1455 fi
1456
8663fb7e 1457 if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ] ; then
4c3b3608 1458 _debug "No config file to restore."
1459 return 0
1460 fi
1461
ff3bce32 1462 cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" > "$httpdconf"
5ef501c5 1463 _debug "Restored: $httpdconf."
c3dd3ef0 1464 if ! $_APACHECTL -t >/dev/null 2>&1 ; then
4c3b3608 1465 _err "Sorry, restore apache config error, please contact me."
1466 return 1;
1467 fi
5ef501c5 1468 _debug "Restored successfully."
4c3b3608 1469 rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname"
1470 return 0
1471}
1472
1473_setApache() {
1474 _initpath
1475 if ! _apachePath ; then
1476 return 1
1477 fi
1478
5fc5016d 1479 #test the conf first
869578ce 1480 _info "Checking if there is an error in the apache config file before starting."
c3dd3ef0 1481 _msg="$($_APACHECTL -t 2>&1 )"
5fc5016d 1482 if [ "$?" != "0" ] ; then
869578ce 1483 _err "Sorry, apache config file has error, please fix it first, then try again."
1484 _err "Don't worry, there is nothing changed to your system."
5fc5016d 1485 _err "$_msg"
1486 return 1;
1487 else
1488 _info "OK"
1489 fi
1490
4c3b3608 1491 #backup the conf
5778811a 1492 _debug "Backup apache config file" "$httpdconf"
8f63baf7 1493 if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/" ; then
869578ce 1494 _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed."
8f63baf7 1495 _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT"
1496 return 1
1497 fi
4c3b3608 1498 _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname"
1499 _info "In case there is an error that can not be restored automatically, you may try restore it yourself."
1500 _info "The backup file will be deleted on sucess, just forget it."
1501
1502 #add alias
b09d597c 1503
c3dd3ef0 1504 apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2 )"
b09d597c 1505 _debug "apacheVer" "$apacheVer"
1506 apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)"
1507 apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)"
1508
5778811a 1509 if [ "$apacheVer" ] && [ "$apacheMajer$apacheMinor" -ge "24" ] ; then
b09d597c 1510 echo "
4c3b3608 1511Alias /.well-known/acme-challenge $ACME_DIR
1512
1513<Directory $ACME_DIR >
1514Require all granted
b09d597c 1515</Directory>
5778811a 1516 " >> "$httpdconf"
b09d597c 1517 else
1518 echo "
1519Alias /.well-known/acme-challenge $ACME_DIR
1520
1521<Directory $ACME_DIR >
1522Order allow,deny
1523Allow from all
4c3b3608 1524</Directory>
5778811a 1525 " >> "$httpdconf"
b09d597c 1526 fi
1527
c3dd3ef0 1528 _msg="$($_APACHECTL -t 2>&1 )"
5fc5016d 1529 if [ "$?" != "0" ] ; then
1530 _err "Sorry, apache config error"
1531 if _restoreApache ; then
869578ce 1532 _err "The apache config file is restored."
5fc5016d 1533 else
869578ce 1534 _err "Sorry, The apache config file can not be restored, please report bug."
5fc5016d 1535 fi
4c3b3608 1536 return 1;
1537 fi
1538
8663fb7e 1539 if [ ! -d "$ACME_DIR" ] ; then
4c3b3608 1540 mkdir -p "$ACME_DIR"
1541 chmod 755 "$ACME_DIR"
1542 fi
1543
c3dd3ef0 1544 if ! $_APACHECTL graceful ; then
1545 _err "Sorry, $_APACHECTL graceful error, please contact me."
4c3b3608 1546 _restoreApache
1547 return 1;
1548 fi
1549 usingApache="1"
1550 return 0
1551}
1552
5ef501c5 1553_clearup() {
4c3b3608 1554 _stopserver $serverproc
1555 serverproc=""
1556 _restoreApache
e22bcf7c 1557 if [ -z "$DEBUG" ] ; then
1558 rm -f "$TLS_CONF"
1559 rm -f "$TLS_CERT"
1560 rm -f "$TLS_KEY"
1561 rm -f "$TLS_CSR"
1562 fi
4c3b3608 1563}
1564
1565# webroot removelevel tokenfile
1566_clearupwebbroot() {
1567 __webroot="$1"
8663fb7e 1568 if [ -z "$__webroot" ] ; then
4c3b3608 1569 _debug "no webroot specified, skip"
1570 return 0
1571 fi
1572
dcf9cb58 1573 _rmpath=""
8663fb7e 1574 if [ "$2" = '1' ] ; then
dcf9cb58 1575 _rmpath="$__webroot/.well-known"
8663fb7e 1576 elif [ "$2" = '2' ] ; then
dcf9cb58 1577 _rmpath="$__webroot/.well-known/acme-challenge"
8663fb7e 1578 elif [ "$2" = '3' ] ; then
dcf9cb58 1579 _rmpath="$__webroot/.well-known/acme-challenge/$3"
4c3b3608 1580 else
cc179731 1581 _debug "Skip for removelevel:$2"
4c3b3608 1582 fi
1583
dcf9cb58 1584 if [ "$_rmpath" ] ; then
1585 if [ "$DEBUG" ] ; then
1586 _debug "Debugging, skip removing: $_rmpath"
1587 else
1588 rm -rf "$_rmpath"
1589 fi
1590 fi
1591
4c3b3608 1592 return 0
1593
1594}
1595
b0070f03 1596_on_before_issue() {
1597 #run pre hook
1598 if [ "$Le_PreHook" ] ; then
1599 _info "Run pre hook:'$Le_PreHook'"
1600 if ! (
1601 cd "$DOMAIN_PATH" && eval "$Le_PreHook"
1602 ) ; then
1603 _err "Error when run pre hook."
1604 return 1
1605 fi
1606 fi
1607}
1608
1609_on_issue_err() {
1610 #run the post hook
1611 if [ "$Le_PostHook" ] ; then
1612 _info "Run post hook:'$Le_PostHook'"
1613 if ! (
1614 cd "$DOMAIN_PATH" && eval "$Le_PostHook"
1615 ) ; then
1616 _err "Error when run post hook."
1617 return 1
1618 fi
1619 fi
1620}
1621
1622_on_issue_success() {
1623 #run the post hook
1624 if [ "$Le_PostHook" ] ; then
1625 _info "Run post hook:'$Le_PostHook'"
1626 if ! (
1627 cd "$DOMAIN_PATH" && eval "$Le_PostHook"
1628 ) ; then
1629 _err "Error when run post hook."
1630 return 1
1631 fi
1632 fi
1633
1634 #run renew hook
1635 if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ] ; then
1636 _info "Run renew hook:'$Le_RenewHook'"
1637 if ! (
1638 cd "$DOMAIN_PATH" && eval "$Le_RenewHook"
1639 ) ; then
1640 _err "Error when run renew hook."
1641 return 1
1642 fi
1643 fi
1644
1645}
1646
1647
10afcaca 1648#webroot, domain domainlist keylength
4c3b3608 1649issue() {
8663fb7e 1650 if [ -z "$2" ] ; then
43822d37 1651 _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
4c3b3608 1652 return 1
1653 fi
1654 Le_Webroot="$1"
1655 Le_Domain="$2"
1656 Le_Alt="$3"
1657 Le_Keylength="$4"
1658 Le_RealCertPath="$5"
1659 Le_RealKeyPath="$6"
1660 Le_RealCACertPath="$7"
1661 Le_ReloadCmd="$8"
a63b05a9 1662 Le_RealFullChainPath="$9"
b0070f03 1663 Le_PreHook="${10}"
1664 Le_PostHook="${11}"
1665 Le_RenewHook="${12}"
4c3b3608 1666
eccec5f6 1667 #remove these later.
8663fb7e 1668 if [ "$Le_Webroot" = "dns-cf" ] ; then
eccec5f6 1669 Le_Webroot="dns_cf"
1670 fi
8663fb7e 1671 if [ "$Le_Webroot" = "dns-dp" ] ; then
eccec5f6 1672 Le_Webroot="dns_dp"
1673 fi
8663fb7e 1674 if [ "$Le_Webroot" = "dns-cx" ] ; then
eccec5f6 1675 Le_Webroot="dns_cx"
1676 fi
4c3b3608 1677
43822d37 1678 if [ ! "$IS_RENEW" ] ; then
1679 _initpath $Le_Domain "$Le_Keylength"
1680 mkdir -p "$DOMAIN_PATH"
1681 fi
eccec5f6 1682
8663fb7e 1683 if [ -f "$DOMAIN_CONF" ] ; then
61623d22 1684 Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
a4270efa 1685 _debug Le_NextRenewTime "$Le_NextRenewTime"
3aae1ae3 1686 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ $(_time) -lt $Le_NextRenewTime ] ; then
e2053b22 1687 _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")"
1688 _info "Add '$(__red '--force')' to force to renew."
cc179731 1689 return $RENEW_SKIP
4c3b3608 1690 fi
1691 fi
96a46cfc 1692
4d2f38b0 1693 _savedomainconf "Le_Domain" "$Le_Domain"
1694 _savedomainconf "Le_Alt" "$Le_Alt"
1695 _savedomainconf "Le_Webroot" "$Le_Webroot"
4c3b3608 1696
b0070f03 1697 _savedomainconf "Le_PreHook" "$Le_PreHook"
1698 _savedomainconf "Le_PostHook" "$Le_PostHook"
1699 _savedomainconf "Le_RenewHook" "$Le_RenewHook"
1700
1701 if ! _on_before_issue ; then
1702 _err "_on_before_issue."
1703 return 1
1704 fi
61623d22 1705
8663fb7e 1706 if [ "$Le_Alt" = "no" ] ; then
4c3b3608 1707 Le_Alt=""
1708 fi
61623d22 1709
c53da1ef 1710 if _hasfield "$Le_Webroot" "no" ; then
4c3b3608 1711 _info "Standalone mode."
5ef501c5 1712 if ! _exists "nc" ; then
4c3b3608 1713 _err "Please install netcat(nc) tools first."
b0070f03 1714 _on_issue_err
4c3b3608 1715 return 1
1716 fi
1717
8663fb7e 1718 if [ -z "$Le_HTTPPort" ] ; then
4c3b3608 1719 Le_HTTPPort=80
054cb72e 1720 else
1721 _savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
1722 fi
4c3b3608 1723
251fc37c 1724 netprc="$(_ss "$Le_HTTPPort" | grep "$Le_HTTPPort")"
8663fb7e 1725 if [ "$netprc" ] ; then
4c3b3608 1726 _err "$netprc"
1727 _err "tcp port $Le_HTTPPort is already used by $(echo "$netprc" | cut -d : -f 4)"
1728 _err "Please stop it first"
b0070f03 1729 _on_issue_err
4c3b3608 1730 return 1
1731 fi
1732 fi
1733
e22bcf7c 1734 if _hasfield "$Le_Webroot" "$W_TLS" ; then
1735 _info "Standalone tls mode."
1736
1737 if [ -z "$Le_TLSPort" ] ; then
1738 Le_TLSPort=443
1739 else
1740 _savedomainconf "Le_TLSPort" "$Le_TLSPort"
1741 fi
1742
1743 netprc="$(_ss "$Le_TLSPort" | grep "$Le_TLSPort")"
1744 if [ "$netprc" ] ; then
1745 _err "$netprc"
1746 _err "tcp port $Le_TLSPort is already used by $(echo "$netprc" | cut -d : -f 4)"
1747 _err "Please stop it first"
b0070f03 1748 _on_issue_err
e22bcf7c 1749 return 1
1750 fi
1751 fi
1752
c53da1ef 1753 if _hasfield "$Le_Webroot" "apache" ; then
4c3b3608 1754 if ! _setApache ; then
1755 _err "set up apache error. Report error to me."
b0070f03 1756 _on_issue_err
4c3b3608 1757 return 1
1758 fi
4c3b3608 1759 else
1760 usingApache=""
1761 fi
1762
8663fb7e 1763 if [ ! -f "$ACCOUNT_KEY_PATH" ] ; then
5fbc47eb 1764 _acck="no"
1765 if [ "$Le_Keylength" ] ; then
1766 _acck="$Le_Keylength"
1767 fi
1768 if ! createAccountKey "$_acck" ; then
41e3eafa 1769 _err "Create account key error."
8663fb7e 1770 if [ "$usingApache" ] ; then
5ef501c5 1771 _restoreApache
1772 fi
b0070f03 1773 _on_issue_err
41e3eafa 1774 return 1
1775 fi
1776 fi
1777
166096dc 1778 if ! _calcjwk "$ACCOUNT_KEY_PATH" ; then
8663fb7e 1779 if [ "$usingApache" ] ; then
5ef501c5 1780 _restoreApache
1781 fi
b0070f03 1782 _on_issue_err
166096dc 1783 return 1
1784 fi
1785
22ea4004 1786 accountkey_json=$(printf "%s" "$jwk" | tr -d ' ' )
1787 thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode)
4c3b3608 1788
f574e581 1789 regjson='{"resource": "new-reg", "agreement": "'$AGREEMENT'"}'
1790 if [ "$ACCOUNT_EMAIL" ] ; then
1791 regjson='{"resource": "new-reg", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}'
1792 fi
1793
88fab7d6 1794 accountkeyhash="$(cat "$ACCOUNT_KEY_PATH" | _digest "sha256" )"
f574e581 1795 accountkeyhash="$(echo $accountkeyhash$API$regjson | _digest "sha256" )"
8663fb7e 1796 if [ "$accountkeyhash" != "$ACCOUNT_KEY_HASH" ] ; then
f574e581 1797 _info "Registering account"
1798 _send_signed_request "$API/acme/new-reg" "$regjson"
8663fb7e 1799 if [ "$code" = "" ] || [ "$code" = '201' ] ; then
166096dc 1800 _info "Registered"
f574e581 1801 echo "$response" > $LE_WORKING_DIR/account.json
8663fb7e 1802 elif [ "$code" = '409' ] ; then
166096dc 1803 _info "Already registered"
1804 else
1805 _err "Register account Error: $response"
1806 _clearup
b0070f03 1807 _on_issue_err
166096dc 1808 return 1
1809 fi
1810 ACCOUNT_KEY_HASH="$accountkeyhash"
1811 _saveaccountconf "ACCOUNT_KEY_HASH" "$ACCOUNT_KEY_HASH"
1812 else
1813 _info "Skip register account key"
1814 fi
1815
58f41a19 1816 if [ "$Le_Keylength" = "no" ] ; then
1817 Le_Keylength=""
1818 fi
1819
10afcaca 1820
1821 if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ] ; then
1822 _info "Signing from existing CSR."
1823 else
1824 _key=$(_readdomainconf Le_Keylength)
1825 _debug "Read key length:$_key"
1826 if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ] ; then
1827 if ! createDomainKey $Le_Domain $Le_Keylength ; then
1828 _err "Create domain key error."
1829 _clearup
b0070f03 1830 _on_issue_err
10afcaca 1831 return 1
1832 fi
1833 fi
1834
1835 if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF" ; then
1836 _err "Create CSR error."
5ef501c5 1837 _clearup
b0070f03 1838 _on_issue_err
41e3eafa 1839 return 1
1840 fi
4c3b3608 1841 fi
10afcaca 1842
61623d22 1843 _savedomainconf "Le_Keylength" "$Le_Keylength"
58f41a19 1844
4c3b3608 1845 vlist="$Le_Vlist"
1846 # verify each domain
1847 _info "Verify each domain"
1848 sep='#'
8663fb7e 1849 if [ -z "$vlist" ] ; then
4c3b3608 1850 alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ' )
a63b05a9 1851 _index=1
1852 _currentRoot=""
4c3b3608 1853 for d in $alldomains
a63b05a9 1854 do
1855 _info "Getting webroot for domain" $d
1856 _w="$(echo $Le_Webroot | cut -d , -f $_index)"
1857 _debug _w "$_w"
8663fb7e 1858 if [ "$_w" ] ; then
a63b05a9 1859 _currentRoot="$_w"
1860 fi
1861 _debug "_currentRoot" "$_currentRoot"
00a50605 1862 _index=$(_math $_index + 1)
a63b05a9 1863
1864 vtype="$VTYPE_HTTP"
dceb3aca 1865 if _startswith "$_currentRoot" "dns" ; then
a63b05a9 1866 vtype="$VTYPE_DNS"
1867 fi
e22bcf7c 1868
1869 if [ "$_currentRoot" = "$W_TLS" ] ; then
1870 vtype="$VTYPE_TLS"
1871 fi
1872
4c3b3608 1873 _info "Getting token for domain" $d
c4d8fd83 1874
1875 if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$d\"}}" ; then
1876 _err "Can not get domain token."
1877 _clearup
b0070f03 1878 _on_issue_err
c4d8fd83 1879 return 1
1880 fi
1881
8663fb7e 1882 if [ ! -z "$code" ] && [ ! "$code" = '201' ] ; then
4c3b3608 1883 _err "new-authz error: $response"
1884 _clearup
b0070f03 1885 _on_issue_err
4c3b3608 1886 return 1
1887 fi
1888
22ea4004 1889 entry="$(printf "%s\n" "$response" | _egrep_o '[^{]*"type":"'$vtype'"[^}]*')"
4c3b3608 1890 _debug entry "$entry"
19539575 1891 if [ -z "$entry" ] ; then
1892 _err "Error, can not get domain token $d"
1893 _clearup
b0070f03 1894 _on_issue_err
19539575 1895 return 1
1896 fi
22ea4004 1897 token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
4c3b3608 1898 _debug token $token
1899
22ea4004 1900 uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*'| cut -d : -f 2,3 | tr -d '"' )"
4c3b3608 1901 _debug uri $uri
1902
1903 keyauthorization="$token.$thumbprint"
1904 _debug keyauthorization "$keyauthorization"
1905
d35bf517 1906
1907 if printf "$response" | grep '"status":"valid"' >/dev/null 2>&1 ; then
1908 _info "$d is already verified, skip."
1909 keyauthorization=$STATE_VERIFIED
1910 _debug keyauthorization "$keyauthorization"
ec603bee 1911 fi
1912
d35bf517 1913
a63b05a9 1914 dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
4c3b3608 1915 _debug dvlist "$dvlist"
1916
1917 vlist="$vlist$dvlist,"
1918
1919 done
1920
1921 #add entry
1922 dnsadded=""
1923 ventries=$(echo "$vlist" | tr ',' ' ' )
1924 for ventry in $ventries
1925 do
1926 d=$(echo $ventry | cut -d $sep -f 1)
1927 keyauthorization=$(echo $ventry | cut -d $sep -f 2)
a63b05a9 1928 vtype=$(echo $ventry | cut -d $sep -f 4)
1929 _currentRoot=$(echo $ventry | cut -d $sep -f 5)
ec603bee 1930
bd5e57d8 1931 if [ "$keyauthorization" = "$STATE_VERIFIED" ] ; then
ec603bee 1932 _info "$d is already verified, skip $vtype."
1933 continue
1934 fi
1935
8663fb7e 1936 if [ "$vtype" = "$VTYPE_DNS" ] ; then
4c3b3608 1937 dnsadded='0'
1938 txtdomain="_acme-challenge.$d"
1939 _debug txtdomain "$txtdomain"
22ea4004 1940 txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)"
4c3b3608 1941 _debug txt "$txt"
1942 #dns
1943 #1. check use api
1944 d_api=""
8663fb7e 1945 if [ -f "$LE_WORKING_DIR/$d/$_currentRoot" ] ; then
a63b05a9 1946 d_api="$LE_WORKING_DIR/$d/$_currentRoot"
8663fb7e 1947 elif [ -f "$LE_WORKING_DIR/$d/$_currentRoot.sh" ] ; then
a63b05a9 1948 d_api="$LE_WORKING_DIR/$d/$_currentRoot.sh"
8663fb7e 1949 elif [ -f "$LE_WORKING_DIR/$_currentRoot" ] ; then
a63b05a9 1950 d_api="$LE_WORKING_DIR/$_currentRoot"
8663fb7e 1951 elif [ -f "$LE_WORKING_DIR/$_currentRoot.sh" ] ; then
a63b05a9 1952 d_api="$LE_WORKING_DIR/$_currentRoot.sh"
8663fb7e 1953 elif [ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot" ] ; then
a63b05a9 1954 d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot"
8663fb7e 1955 elif [ -f "$LE_WORKING_DIR/dnsapi/$_currentRoot.sh" ] ; then
a63b05a9 1956 d_api="$LE_WORKING_DIR/dnsapi/$_currentRoot.sh"
4c3b3608 1957 fi
1958 _debug d_api "$d_api"
1959
8663fb7e 1960 if [ "$d_api" ] ; then
4c3b3608 1961 _info "Found domain api file: $d_api"
1962 else
1963 _err "Add the following TXT record:"
cbcd7e0f 1964 _err "Domain: '$(__green $txtdomain)'"
1965 _err "TXT value: '$(__green $txt)'"
4c3b3608 1966 _err "Please be aware that you prepend _acme-challenge. before your domain"
1967 _err "so the resulting subdomain will be: $txtdomain"
1968 continue
1969 fi
4c3b3608 1970
73b8b120 1971 (
8663fb7e 1972 if ! . $d_api ; then
73b8b120 1973 _err "Load file $d_api error. Please check your api file and try again."
b0070f03 1974 _on_issue_err
73b8b120 1975 return 1
1976 fi
1977
158f22f7 1978 addcommand="${_currentRoot}_add"
d53289d7 1979 if ! _exists $addcommand ; then
73b8b120 1980 _err "It seems that your api file is not correct, it must have a function named: $addcommand"
b0070f03 1981 _on_issue_err
73b8b120 1982 return 1
1983 fi
1984
1985 if ! $addcommand $txtdomain $txt ; then
1986 _err "Error add txt for domain:$txtdomain"
b0070f03 1987 _on_issue_err
73b8b120 1988 return 1
1989 fi
1990 )
4c3b3608 1991
8663fb7e 1992 if [ "$?" != "0" ] ; then
5ef501c5 1993 _clearup
b0070f03 1994 _on_issue_err
4c3b3608 1995 return 1
1996 fi
1997 dnsadded='1'
1998 fi
1999 done
2000
8663fb7e 2001 if [ "$dnsadded" = '0' ] ; then
4d2f38b0 2002 _savedomainconf "Le_Vlist" "$vlist"
4c3b3608 2003 _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
2004 _err "Please add the TXT records to the domains, and retry again."
5ef501c5 2005 _clearup
b0070f03 2006 _on_issue_err
4c3b3608 2007 return 1
2008 fi
2009
2010 fi
2011
8663fb7e 2012 if [ "$dnsadded" = '1' ] ; then
0e38c60d 2013 if [ -z "$Le_DNSSleep" ] ; then
4a4dacb5 2014 Le_DNSSleep=$DEFAULT_DNS_SLEEP
0e38c60d 2015 else
2016 _savedomainconf "Le_DNSSleep" "$Le_DNSSleep"
2017 fi
2018
5fbc47eb 2019 _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect"
0e38c60d 2020 sleep $Le_DNSSleep
4c3b3608 2021 fi
2022
2023 _debug "ok, let's start to verify"
a63b05a9 2024
4c3b3608 2025 ventries=$(echo "$vlist" | tr ',' ' ' )
2026 for ventry in $ventries
2027 do
2028 d=$(echo $ventry | cut -d $sep -f 1)
2029 keyauthorization=$(echo $ventry | cut -d $sep -f 2)
2030 uri=$(echo $ventry | cut -d $sep -f 3)
a63b05a9 2031 vtype=$(echo $ventry | cut -d $sep -f 4)
2032 _currentRoot=$(echo $ventry | cut -d $sep -f 5)
ec603bee 2033
bd5e57d8 2034 if [ "$keyauthorization" = "$STATE_VERIFIED" ] ; then
ec603bee 2035 _info "$d is already verified, skip $vtype."
2036 continue
2037 fi
2038
4c3b3608 2039 _info "Verifying:$d"
2040 _debug "d" "$d"
2041 _debug "keyauthorization" "$keyauthorization"
2042 _debug "uri" "$uri"
2043 removelevel=""
e22bcf7c 2044 token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)"
a63b05a9 2045
2046 _debug "_currentRoot" "$_currentRoot"
2047
2048
8663fb7e 2049 if [ "$vtype" = "$VTYPE_HTTP" ] ; then
2050 if [ "$_currentRoot" = "no" ] ; then
4c3b3608 2051 _info "Standalone mode server"
2052 _startserver "$keyauthorization" &
8663fb7e 2053 if [ "$?" != "0" ] ; then
5ef501c5 2054 _clearup
b0070f03 2055 _on_issue_err
6fc1447f 2056 return 1
2057 fi
4c3b3608 2058 serverproc="$!"
2059 sleep 2
2060 _debug serverproc $serverproc
6fc1447f 2061
4c3b3608 2062 else
8663fb7e 2063 if [ "$_currentRoot" = "apache" ] ; then
6f930641 2064 wellknown_path="$ACME_DIR"
2065 else
a63b05a9 2066 wellknown_path="$_currentRoot/.well-known/acme-challenge"
8663fb7e 2067 if [ ! -d "$_currentRoot/.well-known" ] ; then
6f930641 2068 removelevel='1'
8663fb7e 2069 elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ] ; then
6f930641 2070 removelevel='2'
2071 else
2072 removelevel='3'
2073 fi
4c3b3608 2074 fi
6f930641 2075
4c3b3608 2076 _debug wellknown_path "$wellknown_path"
6f930641 2077
4c3b3608 2078 _debug "writing token:$token to $wellknown_path/$token"
2079
2080 mkdir -p "$wellknown_path"
7939b419 2081 printf "%s" "$keyauthorization" > "$wellknown_path/$token"
8663fb7e 2082 if [ ! "$usingApache" ] ; then
32fdc196
TB
2083 if webroot_owner=$(_stat $_currentRoot) ; then
2084 _debug "Changing owner/group of .well-known to $webroot_owner"
2085 chown -R $webroot_owner "$_currentRoot/.well-known"
2086 else
2087 _debug "not chaning owner/group of webroot";
2088 fi
df886ffa 2089 fi
4c3b3608 2090
2091 fi
e22bcf7c 2092
2093 elif [ "$vtype" = "$VTYPE_TLS" ] ; then
2094 #create A
2095 #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )"
2096 #_debug2 _hash_A "$_hash_A"
2097 #_x="$(echo $_hash_A | cut -c 1-32)"
2098 #_debug2 _x "$_x"
2099 #_y="$(echo $_hash_A | cut -c 33-64)"
2100 #_debug2 _y "$_y"
2101 #_SAN_A="$_x.$_y.token.acme.invalid"
2102 #_debug2 _SAN_A "$_SAN_A"
2103
2104 #create B
2105 _hash_B="$(printf "%s" $keyauthorization | _digest "sha256" "hex" )"
2106 _debug2 _hash_B "$_hash_B"
2107 _x="$(echo $_hash_B | cut -c 1-32)"
2108 _debug2 _x "$_x"
2109 _y="$(echo $_hash_B | cut -c 33-64)"
2110 _debug2 _y "$_y"
2111
2112 #_SAN_B="$_x.$_y.ka.acme.invalid"
2113
2114 _SAN_B="$_x.$_y.acme.invalid"
2115 _debug2 _SAN_B "$_SAN_B"
2116
2117 if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" ; then
2118 _err "Start tls server error."
2119 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2120 _clearup
b0070f03 2121 _on_issue_err
e22bcf7c 2122 return 1
2123 fi
4c3b3608 2124 fi
2125
c4d8fd83 2126 if ! _send_signed_request $uri "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}" ; then
2127 _err "$d:Can not get challenge: $response"
2128 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2129 _clearup
b0070f03 2130 _on_issue_err
c4d8fd83 2131 return 1
2132 fi
4c3b3608 2133
8663fb7e 2134 if [ ! -z "$code" ] && [ ! "$code" = '202' ] ; then
c60883ef 2135 _err "$d:Challenge error: $response"
a63b05a9 2136 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2137 _clearup
b0070f03 2138 _on_issue_err
4c3b3608 2139 return 1
2140 fi
2141
6fc1447f 2142 waittimes=0
8663fb7e 2143 if [ -z "$MAX_RETRY_TIMES" ] ; then
6fc1447f 2144 MAX_RETRY_TIMES=30
2145 fi
2146
2ee5d873 2147 while true ; do
00a50605 2148 waittimes=$(_math $waittimes + 1)
8663fb7e 2149 if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ] ; then
6fc1447f 2150 _err "$d:Timeout"
2151 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2152 _clearup
b0070f03 2153 _on_issue_err
6fc1447f 2154 return 1
2155 fi
2156
4c3b3608 2157 _debug "sleep 5 secs to verify"
2158 sleep 5
2159 _debug "checking"
9aaf36cd 2160 response="$(_get $uri)"
8663fb7e 2161 if [ "$?" != "0" ] ; then
c60883ef 2162 _err "$d:Verify error:$response"
a63b05a9 2163 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2164 _clearup
b0070f03 2165 _on_issue_err
4c3b3608 2166 return 1
2167 fi
9aaf36cd 2168 _debug2 original "$response"
2169
2170 response="$(echo "$response" | _normalizeJson )"
7012b91f 2171 _debug2 response "$response"
4c3b3608 2172
22ea4004 2173 status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
8663fb7e 2174 if [ "$status" = "valid" ] ; then
4c3b3608 2175 _info "Success"
2176 _stopserver $serverproc
2177 serverproc=""
a63b05a9 2178 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2179 break;
2180 fi
2181
8663fb7e 2182 if [ "$status" = "invalid" ] ; then
22ea4004 2183 error="$(echo "$response" | _egrep_o '"error":\{[^}]*}')"
b7ec6789 2184 _debug2 error "$error"
22ea4004 2185 errordetail="$(echo $error | _egrep_o '"detail": *"[^"]*"' | cut -d '"' -f 4)"
b7ec6789 2186 _debug2 errordetail "$errordetail"
2187 if [ "$errordetail" ] ; then
2188 _err "$d:Verify error:$errordetail"
2189 else
2190 _err "$d:Verify error:$error"
2191 fi
dcf9cb58 2192 if [ "$DEBUG" ] ; then
2193 if [ "$vtype" = "$VTYPE_HTTP" ] ; then
276b51d9 2194 _debug "Debug: get token url."
dcf9cb58 2195 _get "http://$d/.well-known/acme-challenge/$token"
2196 fi
2197 fi
a63b05a9 2198 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2199 _clearup
b0070f03 2200 _on_issue_err
4c3b3608 2201 return 1;
2202 fi
2203
8663fb7e 2204 if [ "$status" = "pending" ] ; then
4c3b3608 2205 _info "Pending"
2206 else
2207 _err "$d:Verify error:$response"
a63b05a9 2208 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 2209 _clearup
b0070f03 2210 _on_issue_err
4c3b3608 2211 return 1
2212 fi
2213
2214 done
2215
2216 done
2217
2218 _clearup
2219 _info "Verify finished, start to sign."
fa8311dc 2220 der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)"
c4d8fd83 2221
2222 if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64" ; then
2223 _err "Sign failed."
b0070f03 2224 _on_issue_err
c4d8fd83 2225 return 1
2226 fi
4c3b3608 2227
2228
22ea4004 2229 Le_LinkCert="$(grep -i '^Location.*$' $HTTP_HEADER | head -1 | tr -d "\r\n" | cut -d " " -f 2)"
4d2f38b0 2230 _savedomainconf "Le_LinkCert" "$Le_LinkCert"
4c3b3608 2231
8663fb7e 2232 if [ "$Le_LinkCert" ] ; then
88fab7d6 2233 echo "$BEGIN_CERT" > "$CERT_PATH"
c60883ef 2234 _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH"
88fab7d6 2235 echo "$END_CERT" >> "$CERT_PATH"
43822d37 2236 _info "$(__green "Cert success.")"
4c3b3608 2237 cat "$CERT_PATH"
2238
66f08eb2 2239 _info "Your cert is in $( __green " $CERT_PATH ")"
5980ebc7 2240
2241 if [ -f "$CERT_KEY_PATH" ] ; then
2242 _info "Your cert key is in $( __green " $CERT_KEY_PATH ")"
2243 fi
2244
caf1fc10 2245 cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
281aa349 2246
8663fb7e 2247 if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ] ; then
281aa349 2248 USER_PATH="$PATH"
2249 _saveaccountconf "USER_PATH" "$USER_PATH"
2250 fi
4c3b3608 2251 fi
2252
2253
8663fb7e 2254 if [ -z "$Le_LinkCert" ] ; then
eae29099 2255 response="$(echo $response | _dbase64 "multiline" | _normalizeJson )"
22ea4004 2256 _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')"
b0070f03 2257 _on_issue_err
4c3b3608 2258 return 1
2259 fi
2260
4d2f38b0 2261 _cleardomainconf "Le_Vlist"
4c3b3608 2262
bbbdcb09 2263 Le_LinkIssuer=$(grep -i '^Link' $HTTP_HEADER | head -1 | cut -d " " -f 2| cut -d ';' -f 1 | tr -d '<>' )
fac1e367 2264 if ! _contains "$Le_LinkIssuer" ":" ; then
2265 Le_LinkIssuer="$API$Le_LinkIssuer"
2266 fi
2267
4d2f38b0 2268 _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
4c3b3608 2269
8663fb7e 2270 if [ "$Le_LinkIssuer" ] ; then
88fab7d6 2271 echo "$BEGIN_CERT" > "$CA_CERT_PATH"
c60883ef 2272 _get "$Le_LinkIssuer" | _base64 "multiline" >> "$CA_CERT_PATH"
88fab7d6 2273 echo "$END_CERT" >> "$CA_CERT_PATH"
66f08eb2 2274 _info "The intermediate CA cert is in $( __green " $CA_CERT_PATH ")"
caf1fc10 2275 cat "$CA_CERT_PATH" >> "$CERT_FULLCHAIN_PATH"
66f08eb2 2276 _info "And the full chain certs is there: $( __green " $CERT_FULLCHAIN_PATH ")"
4c3b3608 2277 fi
2278
3aae1ae3 2279 Le_CertCreateTime=$(_time)
4d2f38b0 2280 _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
4c3b3608 2281
2282 Le_CertCreateTimeStr=$(date -u )
4d2f38b0 2283 _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
4c3b3608 2284
523c7682 2285 if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ] ; then
2286 Le_RenewalDays=$MAX_RENEW
054cb72e 2287 else
2288 _savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
13d7cae9 2289 fi
2290
78009539
PS
2291 if [ "$CA_BUNDLE" ] ; then
2292 _saveaccountconf CA_BUNDLE "$CA_BUNDLE"
2293 else
2294 _clearaccountconf "CA_BUNDLE"
2295 fi
2296
fac1e367 2297 if [ "$HTTPS_INSECURE" ] ; then
2298 _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE"
2299 else
2300 _clearaccountconf "HTTPS_INSECURE"
13d7cae9 2301 fi
00a50605 2302
2303 Le_NextRenewTime=$(_math $Le_CertCreateTime + $Le_RenewalDays \* 24 \* 60 \* 60)
028e1747 2304
4c3b3608 2305
2306 Le_NextRenewTimeStr=$( _time2str $Le_NextRenewTime )
4d2f38b0 2307 _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr"
028e1747 2308
2309 Le_NextRenewTime=$(_math $Le_NextRenewTime - 86400)
2310 _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
2311
b0070f03 2312 _on_issue_success
4c3b3608 2313
4c0d3f1b 2314 if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ] ; then
43822d37 2315 _installcert
01f54558 2316 fi
4c0d3f1b 2317
4c3b3608 2318}
2319
43822d37 2320#domain [isEcc]
4c3b3608 2321renew() {
2322 Le_Domain="$1"
8663fb7e 2323 if [ -z "$Le_Domain" ] ; then
43822d37 2324 _usage "Usage: $PROJECT_ENTRY --renew -d domain.com [--ecc]"
4c3b3608 2325 return 1
2326 fi
2327
43822d37 2328 _isEcc="$2"
2329
2330 _initpath $Le_Domain "$_isEcc"
2331
e2053b22 2332 _info "$(__green "Renew: '$Le_Domain'")"
8663fb7e 2333 if [ ! -f "$DOMAIN_CONF" ] ; then
43822d37 2334 _info "'$Le_Domain' is not a issued domain, skip."
4c3b3608 2335 return 0;
2336 fi
2337
1e6b68f5 2338 if [ "$Le_RenewalDays" ] ; then
2339 _savedomainconf Le_RenewalDays "$Le_RenewalDays"
2340 fi
2341
8663fb7e 2342 . "$DOMAIN_CONF"
3aae1ae3 2343 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ] ; then
e2053b22 2344 _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")"
2345 _info "Add '$(__red '--force')' to force to renew."
cc179731 2346 return $RENEW_SKIP
4c3b3608 2347 fi
2348
2349 IS_RENEW="1"
b0070f03 2350 issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook"
22ea4004 2351 res=$?
4c3b3608 2352 IS_RENEW=""
2353
2354 return $res
2355}
2356
cc179731 2357#renewAll [stopRenewOnError]
4c3b3608 2358renewAll() {
2359 _initpath
cc179731 2360 _stopRenewOnError="$1"
2361 _debug "_stopRenewOnError" "$_stopRenewOnError"
2362 _ret="0"
43822d37 2363
b2817897 2364 for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do
4c3b3608 2365 d=$(echo $d | cut -d '/' -f 1)
43822d37 2366 (
2367 if _endswith $d "$ECC_SUFFIX" ; then
2368 _isEcc=$(echo $d | cut -d "$ECC_SEP" -f 2)
2369 d=$(echo $d | cut -d "$ECC_SEP" -f 1)
2370 fi
2371 renew "$d" "$_isEcc"
4d2f38b0 2372 )
cc179731 2373 rc="$?"
2374 _debug "Return code: $rc"
2375 if [ "$rc" != "0" ] ; then
2376 if [ "$rc" = "$RENEW_SKIP" ] ; then
2377 _info "Skipped $d"
2378 elif [ "$_stopRenewOnError" ] ; then
2379 _err "Error renew $d, stop now."
2380 return $rc
2381 else
2382 _ret="$rc"
2383 _err "Error renew $d, Go ahead to next one."
2384 fi
2385 fi
4c3b3608 2386 done
cc179731 2387 return $_ret
4c3b3608 2388}
2389
dcf4f8f6 2390
10afcaca 2391#csr webroot
2392signcsr(){
2393 _csrfile="$1"
2394 _csrW="$2"
2395 if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then
2396 _usage "Usage: $PROJECT_ENTRY --signcsr --csr mycsr.csr -w /path/to/webroot/a.com/ "
2397 return 1
2398 fi
2399
2400 _initpath
2401
2402 _csrsubj=$(_readSubjectFromCSR "$_csrfile")
2403 if [ "$?" != "0" ] || [ -z "$_csrsubj" ] ; then
2404 _err "Can not read subject from csr: $_csrfile"
2405 return 1
2406 fi
2407
2408 _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
2409 if [ "$?" != "0" ] ; then
2410 _err "Can not read domain list from csr: $_csrfile"
2411 return 1
2412 fi
2413 _debug "_csrdomainlist" "$_csrdomainlist"
2414
2415 _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile")
2416 if [ "$?" != "0" ] || [ -z "$_csrkeylength" ] ; then
2417 _err "Can not read key length from csr: $_csrfile"
2418 return 1
2419 fi
2420
2421 _initpath "$_csrsubj" "$_csrkeylength"
2422 mkdir -p "$DOMAIN_PATH"
2423
2424 _info "Copy csr to: $CSR_PATH"
2425 cp "$_csrfile" "$CSR_PATH"
2426
2427 issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength"
2428
2429}
2430
2431showcsr() {
2432 _csrfile="$1"
2433 _csrd="$2"
2434 if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then
2435 _usage "Usage: $PROJECT_ENTRY --showcsr --csr mycsr.csr"
2436 return 1
2437 fi
2438
2439 _initpath
2440
2441 _csrsubj=$(_readSubjectFromCSR "$_csrfile")
2442 if [ "$?" != "0" ] || [ -z "$_csrsubj" ] ; then
2443 _err "Can not read subject from csr: $_csrfile"
2444 return 1
2445 fi
2446
2447 _info "Subject=$_csrsubj"
2448
2449 _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
2450 if [ "$?" != "0" ] ; then
2451 _err "Can not read domain list from csr: $_csrfile"
2452 return 1
2453 fi
2454 _debug "_csrdomainlist" "$_csrdomainlist"
2455
2456 _info "SubjectAltNames=$_csrdomainlist"
2457
2458
2459 _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile")
2460 if [ "$?" != "0" ] || [ -z "$_csrkeylength" ] ; then
2461 _err "Can not read key length from csr: $_csrfile"
2462 return 1
2463 fi
2464 _info "KeyLength=$_csrkeylength"
2465}
2466
6d7eda3e 2467list() {
22ea4004 2468 _raw="$1"
6d7eda3e 2469 _initpath
dcf4f8f6 2470
2471 _sep="|"
2472 if [ "$_raw" ] ; then
43822d37 2473 printf "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew\n"
dcf4f8f6 2474 for d in $(ls -F ${CERT_HOME}/ | grep [^.].*[.].*/$ ) ; do
2475 d=$(echo $d | cut -d '/' -f 1)
2476 (
43822d37 2477 if _endswith $d "$ECC_SUFFIX" ; then
2478 _isEcc=$(echo $d | cut -d "$ECC_SEP" -f 2)
2479 d=$(echo $d | cut -d "$ECC_SEP" -f 1)
2480 fi
2481 _initpath $d "$_isEcc"
dcf4f8f6 2482 if [ -f "$DOMAIN_CONF" ] ; then
2483 . "$DOMAIN_CONF"
43822d37 2484 printf "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr\n"
dcf4f8f6 2485 fi
2486 )
2487 done
2488 else
22ea4004 2489 if _exists column ; then
2490 list "raw" | column -t -s "$_sep"
2491 else
43822d37 2492 list "raw" | tr "$_sep" '\t'
22ea4004 2493 fi
dcf4f8f6 2494 fi
6d7eda3e 2495
2496
2497}
2498
4c3b3608 2499installcert() {
2500 Le_Domain="$1"
8663fb7e 2501 if [ -z "$Le_Domain" ] ; then
43822d37 2502 _usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--certpath cert-file-path] [--keypath key-file-path] [--capath ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchainpath fullchain-path]"
4c3b3608 2503 return 1
2504 fi
2505
2506 Le_RealCertPath="$2"
2507 Le_RealKeyPath="$3"
2508 Le_RealCACertPath="$4"
2509 Le_ReloadCmd="$5"
a63b05a9 2510 Le_RealFullChainPath="$6"
43822d37 2511 _isEcc="$7"
2512
2513 _initpath $Le_Domain "$_isEcc"
2514 if [ ! -d "$DOMAIN_PATH" ] ; then
2515 _err "Domain is not valid:'$Le_Domain'"
2516 return 1
2517 fi
2518
2519 _installcert
2520}
4c3b3608 2521
43822d37 2522
2523_installcert() {
4c3b3608 2524
4d2f38b0 2525 _savedomainconf "Le_RealCertPath" "$Le_RealCertPath"
2526 _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath"
2527 _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath"
2528 _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd"
2529 _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath"
4c3b3608 2530
4d2f38b0 2531 if [ "$Le_RealCertPath" = "no" ] ; then
2532 Le_RealCertPath=""
2533 fi
2534 if [ "$Le_RealKeyPath" = "no" ] ; then
2535 Le_RealKeyPath=""
2536 fi
2537 if [ "$Le_RealCACertPath" = "no" ] ; then
2538 Le_RealCACertPath=""
2539 fi
2540 if [ "$Le_ReloadCmd" = "no" ] ; then
2541 Le_ReloadCmd=""
2542 fi
2543 if [ "$Le_RealFullChainPath" = "no" ] ; then
2544 Le_RealFullChainPath=""
2545 fi
2546
2547 _installed="0"
8663fb7e 2548 if [ "$Le_RealCertPath" ] ; then
4d2f38b0 2549 _installed=1
2550 _info "Installing cert to:$Le_RealCertPath"
43822d37 2551 if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ] ; then
ff3bce32 2552 cp "$Le_RealCertPath" "$Le_RealCertPath".bak
4c3b3608 2553 fi
2554 cat "$CERT_PATH" > "$Le_RealCertPath"
2555 fi
2556
8663fb7e 2557 if [ "$Le_RealCACertPath" ] ; then
4d2f38b0 2558 _installed=1
2559 _info "Installing CA to:$Le_RealCACertPath"
8663fb7e 2560 if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ] ; then
4c3b3608 2561 echo "" >> "$Le_RealCACertPath"
2562 cat "$CA_CERT_PATH" >> "$Le_RealCACertPath"
2563 else
43822d37 2564 if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ] ; then
ff3bce32 2565 cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak
78552b18 2566 fi
4c3b3608 2567 cat "$CA_CERT_PATH" > "$Le_RealCACertPath"
2568 fi
2569 fi
2570
2571
8663fb7e 2572 if [ "$Le_RealKeyPath" ] ; then
4d2f38b0 2573 _installed=1
2574 _info "Installing key to:$Le_RealKeyPath"
43822d37 2575 if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ] ; then
ff3bce32 2576 cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak
4c3b3608 2577 fi
2578 cat "$CERT_KEY_PATH" > "$Le_RealKeyPath"
2579 fi
a63b05a9 2580
8663fb7e 2581 if [ "$Le_RealFullChainPath" ] ; then
4d2f38b0 2582 _installed=1
2583 _info "Installing full chain to:$Le_RealFullChainPath"
43822d37 2584 if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ] ; then
ff3bce32 2585 cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak
a63b05a9 2586 fi
2587 cat "$CERT_FULLCHAIN_PATH" > "$Le_RealFullChainPath"
2588 fi
4c3b3608 2589
8663fb7e 2590 if [ "$Le_ReloadCmd" ] ; then
4d2f38b0 2591 _installed=1
4c3b3608 2592 _info "Run Le_ReloadCmd: $Le_ReloadCmd"
4d2f38b0 2593 if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd") ; then
43822d37 2594 _info "$(__green "Reload success")"
4d2f38b0 2595 else
2596 _err "Reload error for :$Le_Domain"
2597 fi
2598 fi
2599
4c3b3608 2600
2601}
2602
2603installcronjob() {
2604 _initpath
77546ea5 2605 if ! _exists "crontab" ; then
2606 _err "crontab doesn't exist, so, we can not install cron jobs."
2607 _err "All your certs will not be renewed automatically."
a7b7355d 2608 _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
77546ea5 2609 return 1
2610 fi
2611
4c3b3608 2612 _info "Installing cron job"
a7b7355d 2613 if ! crontab -l | grep "$PROJECT_ENTRY --cron" ; then
8663fb7e 2614 if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ] ; then
a7b7355d 2615 lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
4c3b3608 2616 else
a7b7355d 2617 _err "Can not install cronjob, $PROJECT_ENTRY not found."
4c3b3608 2618 return 1
2619 fi
22ea4004 2620 if _exists uname && uname -a | grep solaris >/dev/null ; then
2621 crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab --
2622 else
2623 crontab -l | { cat; echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"; } | crontab -
2624 fi
4c3b3608 2625 fi
8663fb7e 2626 if [ "$?" != "0" ] ; then
4c3b3608 2627 _err "Install cron job failed. You need to manually renew your certs."
2628 _err "Or you can add cronjob by yourself:"
a7b7355d 2629 _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
4c3b3608 2630 return 1
2631 fi
2632}
2633
2634uninstallcronjob() {
37db5b81 2635 if ! _exists "crontab" ; then
2636 return
2637 fi
4c3b3608 2638 _info "Removing cron job"
a7b7355d 2639 cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")"
8663fb7e 2640 if [ "$cr" ] ; then
22ea4004 2641 if _exists uname && uname -a | grep solaris >/dev/null ; then
2642 crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab --
2643 else
2644 crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -
2645 fi
a7b7355d 2646 LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')"
4c3b3608 2647 _info LE_WORKING_DIR "$LE_WORKING_DIR"
2648 fi
2649 _initpath
a7b7355d 2650
4c3b3608 2651}
2652
6cb415f5 2653revoke() {
2654 Le_Domain="$1"
8663fb7e 2655 if [ -z "$Le_Domain" ] ; then
43822d37 2656 _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com"
6cb415f5 2657 return 1
2658 fi
2659
43822d37 2660 _isEcc="$2"
2661
2662 _initpath $Le_Domain "$_isEcc"
8663fb7e 2663 if [ ! -f "$DOMAIN_CONF" ] ; then
6cb415f5 2664 _err "$Le_Domain is not a issued domain, skip."
2665 return 1;
2666 fi
2667
8663fb7e 2668 if [ ! -f "$CERT_PATH" ] ; then
6cb415f5 2669 _err "Cert for $Le_Domain $CERT_PATH is not found, skip."
2670 return 1
2671 fi
2672
2673 cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}"| tr -d "\r\n" | _urlencode)"
2674
8663fb7e 2675 if [ -z "$cert" ] ; then
6cb415f5 2676 _err "Cert for $Le_Domain is empty found, skip."
2677 return 1
2678 fi
2679
2680 data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
2681 uri="$API/acme/revoke-cert"
2682
2683 _info "Try domain key first."
2684 if _send_signed_request $uri "$data" "" "$CERT_KEY_PATH"; then
8663fb7e 2685 if [ -z "$response" ] ; then
6cb415f5 2686 _info "Revoke success."
2687 rm -f $CERT_PATH
2688 return 0
2689 else
2690 _err "Revoke error by domain key."
c9c31c04 2691 _err "$response"
6cb415f5 2692 fi
2693 fi
2694
2695 _info "Then try account key."
2696
2697 if _send_signed_request $uri "$data" "" "$ACCOUNT_KEY_PATH" ; then
8663fb7e 2698 if [ -z "$response" ] ; then
6cb415f5 2699 _info "Revoke success."
2700 rm -f $CERT_PATH
2701 return 0
2702 else
2703 _err "Revoke error."
c9c31c04 2704 _debug "$response"
6cb415f5 2705 fi
2706 fi
2707 return 1
2708}
4c3b3608 2709
2710# Detect profile file if not specified as environment variable
2711_detect_profile() {
a63b05a9 2712 if [ -n "$PROFILE" -a -f "$PROFILE" ] ; then
4c3b3608 2713 echo "$PROFILE"
2714 return
2715 fi
2716
4c3b3608 2717 DETECTED_PROFILE=''
4c3b3608 2718 SHELLTYPE="$(basename "/$SHELL")"
2719
8663fb7e 2720 if [ "$SHELLTYPE" = "bash" ] ; then
2721 if [ -f "$HOME/.bashrc" ] ; then
4c3b3608 2722 DETECTED_PROFILE="$HOME/.bashrc"
8663fb7e 2723 elif [ -f "$HOME/.bash_profile" ] ; then
4c3b3608 2724 DETECTED_PROFILE="$HOME/.bash_profile"
2725 fi
8663fb7e 2726 elif [ "$SHELLTYPE" = "zsh" ] ; then
4c3b3608 2727 DETECTED_PROFILE="$HOME/.zshrc"
2728 fi
2729
8663fb7e 2730 if [ -z "$DETECTED_PROFILE" ] ; then
2731 if [ -f "$HOME/.profile" ] ; then
4c3b3608 2732 DETECTED_PROFILE="$HOME/.profile"
8663fb7e 2733 elif [ -f "$HOME/.bashrc" ] ; then
4c3b3608 2734 DETECTED_PROFILE="$HOME/.bashrc"
8663fb7e 2735 elif [ -f "$HOME/.bash_profile" ] ; then
4c3b3608 2736 DETECTED_PROFILE="$HOME/.bash_profile"
8663fb7e 2737 elif [ -f "$HOME/.zshrc" ] ; then
4c3b3608 2738 DETECTED_PROFILE="$HOME/.zshrc"
2739 fi
2740 fi
2741
8663fb7e 2742 if [ ! -z "$DETECTED_PROFILE" ] ; then
4c3b3608 2743 echo "$DETECTED_PROFILE"
2744 fi
2745}
2746
2747_initconf() {
2748 _initpath
8663fb7e 2749 if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
d53289d7 2750 echo "#ACCOUNT_CONF_PATH=xxxx
2751
2752#Account configurations:
4c3b3608 2753#Here are the supported macros, uncomment them to make them take effect.
d53289d7 2754
4c3b3608 2755#ACCOUNT_EMAIL=aaa@aaa.com # the account email used to register account.
5fd3f21b 2756#ACCOUNT_KEY_PATH=\"/path/to/account.key\"
b2817897 2757#CERT_HOME=\"/path/to/cert/home\"
4c3b3608 2758
d0871bda 2759#LOG_FILE=\"$DEFAULT_LOG_FILE\"
5ea6e9c9 2760
251d1c5c 2761#AUTO_UPGRADE=\"1\"
89002ed2 2762
4c3b3608 2763#STAGE=1 # Use the staging api
2764#FORCE=1 # Force to issue cert
2765#DEBUG=1 # Debug mode
2766
166096dc 2767#ACCOUNT_KEY_HASH=account key hash
2768
8814a348 2769#USER_AGENT=\"$USER_AGENT\"
281aa349 2770
2771#USER_PATH=""
2772
4c3b3608 2773#dns api
2774#######################
2775#Cloudflare:
2776#api key
3d49985a 2777#CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"
4c3b3608 2778#account email
3d49985a 2779#CF_Email=\"xxxx@sss.com\"
4c3b3608 2780
2781#######################
2782#Dnspod.cn:
2783#api key id
3d49985a 2784#DP_Id=\"1234\"
4c3b3608 2785#api key
3d49985a 2786#DP_Key=\"sADDsdasdgdsf\"
4c3b3608 2787
2788#######################
2789#Cloudxns.com:
3d49985a 2790#CX_Key=\"1234\"
4c3b3608 2791#
3d49985a 2792#CX_Secret=\"sADDsdasdgdsf\"
30de13b4 2793
2794#######################
2795#Godaddy.com:
2796#GD_Key=\"sdfdsgdgdfdasfds\"
2797#
2798#GD_Secret=\"sADDsdasdfsdfdssdgdsf\"
4c3b3608 2799
2800 " > $ACCOUNT_CONF_PATH
2801 fi
2802}
2803
c8e9a31e 2804# nocron
c60883ef 2805_precheck() {
c8e9a31e 2806 _nocron="$1"
2807
c60883ef 2808 if ! _exists "curl" && ! _exists "wget"; then
2809 _err "Please install curl or wget first, we need to access http resources."
4c3b3608 2810 return 1
2811 fi
2812
c8e9a31e 2813 if [ -z "$_nocron" ] ; then
2814 if ! _exists "crontab" ; then
2815 _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
2816 _err "We need to set cron job to renew the certs automatically."
2817 _err "Otherwise, your certs will not be able to be renewed automatically."
2818 if [ -z "$FORCE" ] ; then
2819 _err "Please add '--force' and try install again to go without crontab."
2820 _err "./$PROJECT_ENTRY --install --force"
2821 return 1
2822 fi
77546ea5 2823 fi
4c3b3608 2824 fi
2825
c60883ef 2826 if ! _exists "openssl" ; then
2827 _err "Please install openssl first."
2828 _err "We need openssl to generate keys."
4c3b3608 2829 return 1
2830 fi
2831
c60883ef 2832 if ! _exists "nc" ; then
2833 _err "It is recommended to install nc first, try to install 'nc' or 'netcat'."
2834 _err "We use nc for standalone server if you use standalone mode."
2835 _err "If you don't use standalone mode, just ignore this warning."
2836 fi
2837
2838 return 0
2839}
2840
0a7c9364 2841_setShebang() {
2842 _file="$1"
2843 _shebang="$2"
2844 if [ -z "$_shebang" ] ; then
43822d37 2845 _usage "Usage: file shebang"
0a7c9364 2846 return 1
2847 fi
2848 cp "$_file" "$_file.tmp"
2849 echo "$_shebang" > "$_file"
2850 sed -n 2,99999p "$_file.tmp" >> "$_file"
2851 rm -f "$_file.tmp"
2852}
2853
94dc5f33 2854_installalias() {
2855 _initpath
2856
2857 _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env"
2858 if [ "$_upgrading" ] && [ "$_upgrading" = "1" ] ; then
2859 echo "$(cat $_envfile)" | sed "s|^LE_WORKING_DIR.*$||" > "$_envfile"
2860 echo "$(cat $_envfile)" | sed "s|^alias le.*$||" > "$_envfile"
2861 echo "$(cat $_envfile)" | sed "s|^alias le.sh.*$||" > "$_envfile"
2862 fi
2863
1786a5e5 2864 _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\""
94dc5f33 2865 _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
2866
2867 _profile="$(_detect_profile)"
2868 if [ "$_profile" ] ; then
2869 _debug "Found profile: $_profile"
2870 _setopt "$_profile" ". \"$_envfile\""
2871 _info "OK, Close and reopen your terminal to start using $PROJECT_NAME"
2872 else
2873 _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME"
2874 fi
2875
2876
2877 #for csh
2878 _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh"
94dc5f33 2879 _csh_profile="$HOME/.cshrc"
2880 if [ -f "$_csh_profile" ] ; then
6626371d 2881 _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
2882 _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
94dc5f33 2883 _setopt "$_csh_profile" "source \"$_cshfile\""
2884 fi
acafa585 2885
2886 #for tcsh
2887 _tcsh_profile="$HOME/.tcshrc"
2888 if [ -f "$_tcsh_profile" ] ; then
2889 _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
2890 _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
2891 _setopt "$_tcsh_profile" "source \"$_cshfile\""
2892 fi
94dc5f33 2893
2894}
2895
c8e9a31e 2896# nocron
c60883ef 2897install() {
f3e4cea3 2898
2899 if [ -z "$LE_WORKING_DIR" ] ; then
2900 LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
2901 fi
2902
c8e9a31e 2903 _nocron="$1"
c60883ef 2904 if ! _initpath ; then
2905 _err "Install failed."
4c3b3608 2906 return 1
2907 fi
52677b0a 2908 if [ "$_nocron" ] ; then
2909 _debug "Skip install cron job"
2910 fi
2911
c8e9a31e 2912 if ! _precheck "$_nocron" ; then
c60883ef 2913 _err "Pre-check failed, can not install."
4c3b3608 2914 return 1
2915 fi
c60883ef 2916
6cc11ffb 2917 #convert from le
8663fb7e 2918 if [ -d "$HOME/.le" ] ; then
6cc11ffb 2919 for envfile in "le.env" "le.sh.env"
2920 do
8663fb7e 2921 if [ -f "$HOME/.le/$envfile" ] ; then
6cc11ffb 2922 if grep "le.sh" "$HOME/.le/$envfile" >/dev/null ; then
2923 _upgrading="1"
2924 _info "You are upgrading from le.sh"
2925 _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR"
2926 mv "$HOME/.le" "$LE_WORKING_DIR"
2927 mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env"
2928 break;
2929 fi
2930 fi
2931 done
2932 fi
2933
4c3b3608 2934 _info "Installing to $LE_WORKING_DIR"
635695ec 2935
4a0f23e2 2936 if ! mkdir -p "$LE_WORKING_DIR" ; then
90035252 2937 _err "Can not create working dir: $LE_WORKING_DIR"
4a0f23e2 2938 return 1
2939 fi
2940
762978f8 2941 chmod 700 "$LE_WORKING_DIR"
2942
a7b7355d 2943 cp $PROJECT_ENTRY "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY"
4c3b3608 2944
8663fb7e 2945 if [ "$?" != "0" ] ; then
a7b7355d 2946 _err "Install failed, can not copy $PROJECT_ENTRY"
4c3b3608 2947 return 1
2948 fi
2949
a7b7355d 2950 _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY"
4c3b3608 2951
94dc5f33 2952 _installalias
4c3b3608 2953
8663fb7e 2954 if [ -d "dnsapi" ] ; then
6ed1c718 2955 mkdir -p $LE_WORKING_DIR/dnsapi
2956 cp dnsapi/* $LE_WORKING_DIR/dnsapi/
2957 fi
d53289d7 2958
8663fb7e 2959 if [ ! -f "$ACCOUNT_CONF_PATH" ] ; then
4c3b3608 2960 _initconf
2961 fi
6cc11ffb 2962
8663fb7e 2963 if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ] ; then
635695ec 2964 _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\""
6cc11ffb 2965 fi
2966
8663fb7e 2967 if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ] ; then
b2817897 2968 _saveaccountconf "CERT_HOME" "$CERT_HOME"
2969 fi
2970
8663fb7e 2971 if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ] ; then
b2817897 2972 _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH"
2973 fi
2974
c8e9a31e 2975 if [ -z "$_nocron" ] ; then
2976 installcronjob
2977 fi
0a7c9364 2978
641989fd 2979 if [ -z "$NO_DETECT_SH" ] ; then
2980 #Modify shebang
2981 if _exists bash ; then
2982 _info "Good, bash is installed, change the shebang to use bash as prefered."
2983 _shebang='#!/usr/bin/env bash'
2984 _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang"
2985 if [ -d "$LE_WORKING_DIR/dnsapi" ] ; then
2986 for _apifile in $(ls "$LE_WORKING_DIR/dnsapi/"*.sh) ; do
2987 _setShebang "$_apifile" "$_shebang"
2988 done
2989 fi
0a7c9364 2990 fi
2991 fi
2992
4c3b3608 2993 _info OK
2994}
2995
52677b0a 2996# nocron
4c3b3608 2997uninstall() {
52677b0a 2998 _nocron="$1"
2999 if [ -z "$_nocron" ] ; then
3000 uninstallcronjob
3001 fi
4c3b3608 3002 _initpath
3003
3004 _profile="$(_detect_profile)"
8663fb7e 3005 if [ "$_profile" ] ; then
7203a1c1 3006 text="$(cat $_profile)"
94dc5f33 3007 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" > "$_profile"
4c3b3608 3008 fi
3009
94dc5f33 3010 _csh_profile="$HOME/.cshrc"
3011 if [ -f "$_csh_profile" ] ; then
3012 text="$(cat $_csh_profile)"
3013 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_csh_profile"
3014 fi
3015
acafa585 3016 _tcsh_profile="$HOME/.tcshrc"
3017 if [ -f "$_tcsh_profile" ] ; then
3018 text="$(cat $_tcsh_profile)"
3019 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" > "$_tcsh_profile"
3020 fi
3021
a7b7355d 3022 rm -f $LE_WORKING_DIR/$PROJECT_ENTRY
4c3b3608 3023 _info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself."
3024
3025}
3026
3027cron() {
281aa349 3028 IN_CRON=1
89002ed2 3029 _initpath
3030 if [ "$AUTO_UPGRADE" ] ; then
3031 export LE_WORKING_DIR
3032 (
3033 . $LE_WORKING_DIR/$PROJECT_ENTRY >/dev/null
3034 if ! upgrade ; then
3035 _err "Cron:Upgrade failed!"
3036 return 1
3037 fi
3038 )
3039 . $LE_WORKING_DIR/$PROJECT_ENTRY >/dev/null
1ab63043 3040
3041 if [ -t 1 ] ; then
3042 __INTERACTIVE="1"
3043 fi
3044
89002ed2 3045 _info "Auto upgraded to: $VER"
3046 fi
4c3b3608 3047 renewAll
cc179731 3048 _ret="$?"
281aa349 3049 IN_CRON=""
cc179731 3050 return $_ret
4c3b3608 3051}
3052
3053version() {
a63b05a9 3054 echo "$PROJECT"
3055 echo "v$VER"
4c3b3608 3056}
3057
3058showhelp() {
d0871bda 3059 _initpath
4c3b3608 3060 version
a7b7355d 3061 echo "Usage: $PROJECT_ENTRY command ...[parameters]....
a63b05a9 3062Commands:
3063 --help, -h Show this help message.
3064 --version, -v Show version info.
a7b7355d 3065 --install Install $PROJECT_NAME to your system.
3066 --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job.
10afcaca 3067 --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT .
a63b05a9 3068 --issue Issue a cert.
10afcaca 3069 --signcsr Issue a cert from an existing csr.
a63b05a9 3070 --installcert Install the issued cert to apache/nginx or any other server.
3071 --renew, -r Renew a cert.
10afcaca 3072 --renewAll Renew all the certs.
a63b05a9 3073 --revoke Revoke a cert.
10afcaca 3074 --list List all the certs.
3075 --showcsr Show the content of a csr.
a63b05a9 3076 --installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
3077 --uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
3078 --cron Run cron job to renew all the certs.
3079 --toPkcs Export the certificate and key to a pfx file.
3080 --createAccountKey, -cak Create an account private key, professional use.
3081 --createDomainKey, -cdk Create an domain private key, professional use.
3082 --createCSR, -ccsr Create CSR , professional use.
3083
3084Parameters:
3085 --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc.
3086 --force, -f Used to force to install or force to renew a cert immediately.
3087 --staging, --test Use staging server, just for test.
3088 --debug Output debug info.
3089
3090 --webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
3091 --standalone Use standalone mode.
e22bcf7c 3092 --tls Use standalone tls mode.
a63b05a9 3093 --apache Use apache mode.
eccec5f6 3094 --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
4a4dacb5 3095 --dnssleep [$DEFAULT_DNS_SLEEP] The time in seconds to wait for all the txt records to take effect in dns api mode. Default $DEFAULT_DNS_SLEEP seconds.
a63b05a9 3096
3097 --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384.
3098 --accountkeylength, -ak [2048] Specifies the account key length.
d0871bda 3099 --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here.
a63b05a9 3100
3101 These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
3102
3103 --certpath /path/to/real/cert/file After issue/renew, the cert will be copied to this path.
3104 --keypath /path/to/real/key/file After issue/renew, the key will be copied to this path.
3105 --capath /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path.
3106 --fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path.
3107
3108 --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
3109
3110 --accountconf Specifies a customized account config file.
635695ec 3111 --home Specifies the home dir for $PROJECT_NAME .
39c8f79f 3112 --certhome Specifies the home dir to save all the certs, only valid for '--install' command.
635695ec 3113 --useragent Specifies the user agent string. it will be saved for future use too.
b5eb4b90 3114 --accountemail Specifies the account email for registering, Only valid for the '--install' command.
06625071 3115 --accountkey Specifies the account key path, Only valid for the '--install' command.
523c7682 3116 --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
39c8f79f 3117 --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
e22bcf7c 3118 --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
dcf4f8f6 3119 --listraw Only used for '--list' command, list the certs in raw format.
c8e9a31e 3120 --stopRenewOnError, -se Only valid for '--renewall' command. Stop if one cert has error in renewal.
13d7cae9 3121 --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted.
78009539 3122 --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate.
bc96082f 3123 --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.
43822d37 3124 --ecc Specifies to use the ECC cert. Valid for '--installcert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
10afcaca 3125 --csr Specifies the input csr.
b0070f03 3126 --pre-hook Command to be run before obtaining any certificates.
3127 --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed.
3128 --renew-hook Command to be run once for each successfully renewed certificate.
0c9546cc 3129 --ocsp-must-staple, --ocsp Generate ocsp must Staple extension.
4c3b3608 3130 "
3131}
3132
52677b0a 3133# nocron
4a0f23e2 3134_installOnline() {
3135 _info "Installing from online archive."
52677b0a 3136 _nocron="$1"
8663fb7e 3137 if [ ! "$BRANCH" ] ; then
4a0f23e2 3138 BRANCH="master"
3139 fi
a8df88ab 3140
4a0f23e2 3141 target="$PROJECT/archive/$BRANCH.tar.gz"
3142 _info "Downloading $target"
3143 localname="$BRANCH.tar.gz"
3144 if ! _get "$target" > $localname ; then
df9547ae 3145 _err "Download error."
4a0f23e2 3146 return 1
3147 fi
0bbe6eef 3148 (
4a0f23e2 3149 _info "Extracting $localname"
3150 tar xzf $localname
0bbe6eef 3151
6cc11ffb 3152 cd "$PROJECT_NAME-$BRANCH"
a7b7355d 3153 chmod +x $PROJECT_ENTRY
52677b0a 3154 if ./$PROJECT_ENTRY install "$_nocron" ; then
4a0f23e2 3155 _info "Install success!"
3156 fi
3157
3158 cd ..
0bbe6eef 3159
6cc11ffb 3160 rm -rf "$PROJECT_NAME-$BRANCH"
4a0f23e2 3161 rm -f "$localname"
0bbe6eef 3162 )
4a0f23e2 3163}
3164
52677b0a 3165upgrade() {
3166 if (
267f283a 3167 _initpath
3168 export LE_WORKING_DIR
d0b748a4 3169 cd "$LE_WORKING_DIR"
52677b0a 3170 _installOnline "nocron"
3171 ) ; then
3172 _info "Upgrade success!"
096d8992 3173 exit 0
52677b0a 3174 else
3175 _err "Upgrade failed!"
096d8992 3176 exit 1
52677b0a 3177 fi
3178}
a63b05a9 3179
5ea6e9c9 3180_processAccountConf() {
3181 if [ "$_useragent" ] ; then
3182 _saveaccountconf "USER_AGENT" "$_useragent"
d0871bda 3183 elif [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ] ; then
3184 _saveaccountconf "USER_AGENT" "$USER_AGENT"
5ea6e9c9 3185 fi
3186
3187 if [ "$_accountemail" ] ; then
3188 _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail"
d0871bda 3189 elif [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ] ; then
3190 _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL"
5ea6e9c9 3191 fi
3192
3193}
3194
a63b05a9 3195_process() {
3196 _CMD=""
3197 _domain=""
3198 _altdomains="no"
3199 _webroot=""
bdbf323f 3200 _keylength=""
3201 _accountkeylength=""
3202 _certpath=""
3203 _keypath=""
3204 _capath=""
3205 _fullchainpath=""
4d2f38b0 3206 _reloadcmd=""
a63b05a9 3207 _password=""
635695ec 3208 _accountconf=""
3209 _useragent=""
b5eb4b90 3210 _accountemail=""
3211 _accountkey=""
b2817897 3212 _certhome=""
39c8f79f 3213 _httpport=""
e22bcf7c 3214 _tlsport=""
0e38c60d 3215 _dnssleep=""
dcf4f8f6 3216 _listraw=""
cc179731 3217 _stopRenewOnError=""
13d7cae9 3218 _insecure=""
78009539 3219 _ca_bundle=""
c8e9a31e 3220 _nocron=""
43822d37 3221 _ecc=""
10afcaca 3222 _csr=""
b0070f03 3223 _pre_hook=""
3224 _post_hook=""
3225 _renew_hook=""
5ea6e9c9 3226 _logfile=""
d0871bda 3227 _log=""
8663fb7e 3228 while [ ${#} -gt 0 ] ; do
a63b05a9 3229 case "${1}" in
3230
3231 --help|-h)
3232 showhelp
3233 return
3234 ;;
3235 --version|-v)
3236 version
3237 return
3238 ;;
3239 --install)
3240 _CMD="install"
3241 ;;
3242 --uninstall)
3243 _CMD="uninstall"
3244 ;;
52677b0a 3245 --upgrade)
3246 _CMD="upgrade"
3247 ;;
a63b05a9 3248 --issue)
3249 _CMD="issue"
3250 ;;
10afcaca 3251 --signcsr)
3252 _CMD="signcsr"
3253 ;;
3254 --showcsr)
3255 _CMD="showcsr"
3256 ;;
a63b05a9 3257 --installcert|-i)
3258 _CMD="installcert"
3259 ;;
3260 --renew|-r)
3261 _CMD="renew"
3262 ;;
4d2f38b0 3263 --renewAll|--renewall)
a63b05a9 3264 _CMD="renewAll"
3265 ;;
3266 --revoke)
3267 _CMD="revoke"
3268 ;;
6d7eda3e 3269 --list)
3270 _CMD="list"
3271 ;;
a63b05a9 3272 --installcronjob)
3273 _CMD="installcronjob"
3274 ;;
3275 --uninstallcronjob)
3276 _CMD="uninstallcronjob"
3277 ;;
3278 --cron)
3279 _CMD="cron"
3280 ;;
3281 --toPkcs)
3282 _CMD="toPkcs"
3283 ;;
3284 --createAccountKey|--createaccountkey|-cak)
3285 _CMD="createAccountKey"
3286 ;;
3287 --createDomainKey|--createdomainkey|-cdk)
3288 _CMD="createDomainKey"
3289 ;;
3290 --createCSR|--createcsr|-ccr)
3291 _CMD="createCSR"
3292 ;;
3293
3294
3295 --domain|-d)
3296 _dvalue="$2"
3297
ee1737a5 3298 if [ "$_dvalue" ] ; then
3299 if _startswith "$_dvalue" "-" ; then
3300 _err "'$_dvalue' is not a valid domain for parameter '$1'"
3301 return 1
3302 fi
3303
3304 if [ -z "$_domain" ] ; then
3305 _domain="$_dvalue"
a63b05a9 3306 else
ee1737a5 3307 if [ "$_altdomains" = "no" ] ; then
3308 _altdomains="$_dvalue"
3309 else
3310 _altdomains="$_altdomains,$_dvalue"
3311 fi
a63b05a9 3312 fi
3313 fi
ee1737a5 3314
a63b05a9 3315 shift
3316 ;;
3317
3318 --force|-f)
3319 FORCE="1"
3320 ;;
3321 --staging|--test)
3322 STAGE="1"
3323 ;;
3324 --debug)
8663fb7e 3325 if [ -z "$2" ] || _startswith "$2" "-" ; then
a63b05a9 3326 DEBUG="1"
3327 else
3328 DEBUG="$2"
3329 shift
6fc1447f 3330 fi
a63b05a9 3331 ;;
a63b05a9 3332 --webroot|-w)
3333 wvalue="$2"
8663fb7e 3334 if [ -z "$_webroot" ] ; then
a63b05a9 3335 _webroot="$wvalue"
3336 else
3337 _webroot="$_webroot,$wvalue"
3338 fi
3339 shift
3340 ;;
3341 --standalone)
3342 wvalue="no"
8663fb7e 3343 if [ -z "$_webroot" ] ; then
a63b05a9 3344 _webroot="$wvalue"
3345 else
3346 _webroot="$_webroot,$wvalue"
3347 fi
3348 ;;
3349 --apache)
3350 wvalue="apache"
8663fb7e 3351 if [ -z "$_webroot" ] ; then
a63b05a9 3352 _webroot="$wvalue"
3353 else
3354 _webroot="$_webroot,$wvalue"
3355 fi
3356 ;;
e22bcf7c 3357 --tls)
3358 wvalue="$W_TLS"
3359 if [ -z "$_webroot" ] ; then
3360 _webroot="$wvalue"
3361 else
3362 _webroot="$_webroot,$wvalue"
3363 fi
3364 ;;
a63b05a9 3365 --dns)
3366 wvalue="dns"
dceb3aca 3367 if ! _startswith "$2" "-" ; then
a63b05a9 3368 wvalue="$2"
3369 shift
3370 fi
8663fb7e 3371 if [ -z "$_webroot" ] ; then
a63b05a9 3372 _webroot="$wvalue"
3373 else
3374 _webroot="$_webroot,$wvalue"
3375 fi
3376 ;;
0e38c60d 3377 --dnssleep)
3378 _dnssleep="$2"
3379 Le_DNSSleep="$_dnssleep"
3380 shift
3381 ;;
3382
a63b05a9 3383 --keylength|-k)
3384 _keylength="$2"
2ce87fe2 3385 if [ "$_accountkeylength" = "no" ] ; then
3386 _accountkeylength="$2"
3387 fi
a63b05a9 3388 shift
3389 ;;
3390 --accountkeylength|-ak)
2ce87fe2 3391 _accountkeylength="$2"
a63b05a9 3392 shift
3393 ;;
3394
3395 --certpath)
3396 _certpath="$2"
3397 shift
3398 ;;
3399 --keypath)
3400 _keypath="$2"
3401 shift
3402 ;;
3403 --capath)
3404 _capath="$2"
3405 shift
3406 ;;
3407 --fullchainpath)
3408 _fullchainpath="$2"
3409 shift
3410 ;;
635695ec 3411 --reloadcmd|--reloadCmd)
a63b05a9 3412 _reloadcmd="$2"
3413 shift
3414 ;;
3415 --password)
3416 _password="$2"
3417 shift
3418 ;;
3419 --accountconf)
635695ec 3420 _accountconf="$2"
3421 ACCOUNT_CONF_PATH="$_accountconf"
a7b7355d 3422 shift
a63b05a9 3423 ;;
a7b7355d 3424 --home)
a63b05a9 3425 LE_WORKING_DIR="$2"
a7b7355d 3426 shift
a63b05a9 3427 ;;
b2817897 3428 --certhome)
3429 _certhome="$2"
3430 CERT_HOME="$_certhome"
3431 shift
3432 ;;
635695ec 3433 --useragent)
3434 _useragent="$2"
3435 USER_AGENT="$_useragent"
3436 shift
3437 ;;
b5eb4b90 3438 --accountemail )
3439 _accountemail="$2"
3440 ACCOUNT_EMAIL="$_accountemail"
3441 shift
3442 ;;
3443 --accountkey )
3444 _accountkey="$2"
3445 ACCOUNT_KEY_PATH="$_accountkey"
3446 shift
3447 ;;
06625071 3448 --days )
3449 _days="$2"
3450 Le_RenewalDays="$_days"
3451 shift
3452 ;;
39c8f79f 3453 --httpport )
3454 _httpport="$2"
3455 Le_HTTPPort="$_httpport"
3456 shift
3457 ;;
e22bcf7c 3458 --tlsport )
3459 _tlsport="$2"
3460 Le_TLSPort="$_tlsport"
3461 shift
3462 ;;
3463
dcf4f8f6 3464 --listraw )
3465 _listraw="raw"
3466 ;;
cc179731 3467 --stopRenewOnError|--stoprenewonerror|-se )
3468 _stopRenewOnError="1"
3469 ;;
13d7cae9 3470 --insecure)
3471 _insecure="1"
fac1e367 3472 HTTPS_INSECURE="1"
13d7cae9 3473 ;;
78009539 3474 --ca-bundle)
775bd1ab 3475 _ca_bundle="$(readlink -f $2)"
78009539
PS
3476 CA_BUNDLE="$_ca_bundle"
3477 shift
3478 ;;
c8e9a31e 3479 --nocron)
3480 _nocron="1"
3481 ;;
43822d37 3482 --ecc)
3483 _ecc="isEcc"
3484 ;;
10afcaca 3485 --csr)
3486 _csr="$2"
3487 shift
3488 ;;
b0070f03 3489 --pre-hook)
3490 _pre_hook="$2"
3491 shift
3492 ;;
3493 --post-hook)
3494 _post_hook="$2"
3495 shift
3496 ;;
3497 --renew-hook)
3498 _renew_hook="$2"
3499 shift
3500 ;;
0c9546cc 3501 --ocsp-must-staple|--ocsp)
3502 Le_OCSP_Stable="1"
3503 ;;
d0871bda 3504 --log|--logfile)
3505 _log="1"
5ea6e9c9 3506 _logfile="$2"
d0871bda 3507 if [ -z "$_logfile" ] || _startswith "$_logfile" '-' ; then
3508 _logfile=""
3509 else
3510 shift
3511 fi
5ea6e9c9 3512 LOG_FILE="$_logfile"
5ea6e9c9 3513 ;;
3514
a63b05a9 3515 *)
3516 _err "Unknown parameter : $1"
3517 return 1
3518 ;;
3519 esac
3520
3521 shift 1
3522 done
3523
5ea6e9c9 3524 if [ "${_CMD}" != "install" ] ; then
3525 __initHome
d0871bda 3526 if [ "$_log" ] && [ -z "$_logfile" ] ; then
3527 _logfile="$DEFAULT_LOG_FILE"
3528 fi
5ea6e9c9 3529 if [ "$_logfile" ] ; then
3530 _saveaccountconf "LOG_FILE" "$_logfile"
3531 fi
d0871bda 3532 LOG_FILE="$_logfile"
5ea6e9c9 3533 _processAccountConf
3534 fi
3535
dcf9cb58 3536 if [ "$DEBUG" ] ; then
3537 version
3538 fi
a63b05a9 3539
3540 case "${_CMD}" in
c8e9a31e 3541 install) install "$_nocron" ;;
bc96082f 3542 uninstall) uninstall "$_nocron" ;;
52677b0a 3543 upgrade) upgrade ;;
a63b05a9 3544 issue)
b0070f03 3545 issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook"
a63b05a9 3546 ;;
10afcaca 3547 signcsr)
3548 signcsr "$_csr" "$_webroot"
3549 ;;
3550 showcsr)
3551 showcsr "$_csr" "$_domain"
3552 ;;
a63b05a9 3553 installcert)
43822d37 3554 installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc"
a63b05a9 3555 ;;
3556 renew)
43822d37 3557 renew "$_domain" "$_ecc"
a63b05a9 3558 ;;
3559 renewAll)
cc179731 3560 renewAll "$_stopRenewOnError"
a63b05a9 3561 ;;
3562 revoke)
43822d37 3563 revoke "$_domain" "$_ecc"
a63b05a9 3564 ;;
6d7eda3e 3565 list)
dcf4f8f6 3566 list "$_listraw"
6d7eda3e 3567 ;;
a63b05a9 3568 installcronjob) installcronjob ;;
3569 uninstallcronjob) uninstallcronjob ;;
3570 cron) cron ;;
3571 toPkcs)
43822d37 3572 toPkcs "$_domain" "$_password" "$_ecc"
a63b05a9 3573 ;;
3574 createAccountKey)
5fbc47eb 3575 createAccountKey "$_accountkeylength"
a63b05a9 3576 ;;
3577 createDomainKey)
3578 createDomainKey "$_domain" "$_keylength"
3579 ;;
3580 createCSR)
43822d37 3581 createCSR "$_domain" "$_altdomains" "$_ecc"
a63b05a9 3582 ;;
3583
3584 *)
3585 _err "Invalid command: $_CMD"
3586 showhelp;
3587 return 1
3588 ;;
3589 esac
d3595686 3590 _ret="$?"
3591 if [ "$_ret" != "0" ] ; then
3592 return $_ret
3593 fi
a63b05a9 3594
5ea6e9c9 3595 if [ "${_CMD}" = "install" ] ; then
d0871bda 3596 if [ "$_log" ] ; then
3597 if [ -z "$LOG_FILE" ] ; then
3598 LOG_FILE="$DEFAULT_LOG_FILE"
3599 fi
3600 _saveaccountconf "LOG_FILE" "$LOG_FILE"
5ea6e9c9 3601 fi
3602 _processAccountConf
b5eb4b90 3603 fi
635695ec 3604
a63b05a9 3605}
3606
3607
8663fb7e 3608if [ "$INSTALLONLINE" ] ; then
d1f97fc8 3609 INSTALLONLINE=""
4a0f23e2 3610 _installOnline $BRANCH
3611 exit
3612fi
4c3b3608 3613
a63b05a9 3614
276b51d9 3615
e69a7c38 3616[ -z "$1" ] && showhelp
276b51d9 3617
a63b05a9 3618
e69a7c38 3619
3620if _startswith "$1" '-' ; then _process "$@" ; else "$@"; fi ;