]> git.proxmox.com Git - mirror_acme.sh.git/blame - acme.sh
add _utc_date function
[mirror_acme.sh.git] / acme.sh
CommitLineData
0a7c9364 1#!/usr/bin/env sh
bfdf1f48 2
27dbe77f 3VER=2.6.6
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
a61fe418 14_SUB_FOLDERS="dnsapi deploy"
f3e4cea3 15
4c3b3608 16DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
c93ec933 17DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
4c3b3608 18
07af4247 19DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
d0871bda 20DEFAULT_ACCOUNT_EMAIL=""
bbbdcb09 21
57e58ce7 22DEFAULT_ACCOUNT_KEY_LENGTH=2048
23DEFAULT_DOMAIN_KEY_LENGTH=2048
24
a746139c 25DEFAULT_OPENSSL_BIN="openssl"
26
4c3b3608 27STAGE_CA="https://acme-staging.api.letsencrypt.org"
28
29VTYPE_HTTP="http-01"
30VTYPE_DNS="dns-01"
e22bcf7c 31VTYPE_TLS="tls-sni-01"
e591d5cf 32#VTYPE_TLS2="tls-sni-02"
e22bcf7c 33
0463b5d6 34LOCAL_ANY_ADDRESS="0.0.0.0"
35
656bd330 36MAX_RENEW=60
523c7682 37
4a4dacb5 38DEFAULT_DNS_SLEEP=120
39
3f4513b3 40NO_VALUE="no"
41
e22bcf7c 42W_TLS="tls"
4c3b3608 43
ec603bee 44STATE_VERIFIED="verified_ok"
45
88fab7d6 46BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----"
47END_CSR="-----END CERTIFICATE REQUEST-----"
48
49BEGIN_CERT="-----BEGIN CERTIFICATE-----"
50END_CERT="-----END CERTIFICATE-----"
51
cc179731 52RENEW_SKIP=2
53
43822d37 54ECC_SEP="_"
55ECC_SUFFIX="${ECC_SEP}ecc"
56
a73c5b33 57LOG_LEVEL_1=1
58LOG_LEVEL_2=2
59LOG_LEVEL_3=3
60DEFAULT_LOG_LEVEL="$LOG_LEVEL_1"
61
62_DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh"
4c3b3608 63
562a4c05 64_PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations"
65
08ee072f 66__INTERACTIVE=""
4c2a3841 67if [ -t 1 ]; then
08ee072f 68 __INTERACTIVE="1"
69fi
00a50605 70
43822d37 71__green() {
4c2a3841 72 if [ "$__INTERACTIVE" ]; then
2d12b689 73 printf '\033[1;31;32m'
74 fi
43822d37 75 printf -- "$1"
4c2a3841 76 if [ "$__INTERACTIVE" ]; then
2d12b689 77 printf '\033[0m'
78 fi
43822d37 79}
80
81__red() {
4c2a3841 82 if [ "$__INTERACTIVE" ]; then
2d12b689 83 printf '\033[1;31;40m'
84 fi
43822d37 85 printf -- "$1"
4c2a3841 86 if [ "$__INTERACTIVE" ]; then
2d12b689 87 printf '\033[0m'
88 fi
43822d37 89}
00a50605 90
a73c5b33 91_printargs() {
569d6c55 92 if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
93 printf -- "%s" "[$(date)] "
94 fi
4c2a3841 95 if [ -z "$2" ]; then
569d6c55 96 printf -- "%s" "$1"
43822d37 97 else
569d6c55 98 printf -- "%s" "$1='$2'"
43822d37 99 fi
a73c5b33 100 printf "\n"
43822d37 101}
102
9d548d81 103_dlg_versions() {
104 echo "Diagnosis versions: "
a746139c 105 echo "openssl:$OPENSSL_BIN"
106 if _exists "$OPENSSL_BIN"; then
107 $OPENSSL_BIN version 2>&1
9d548d81 108 else
a746139c 109 echo "$OPENSSL_BIN doesn't exists."
9d548d81 110 fi
4c2a3841 111
9d548d81 112 echo "apache:"
4c2a3841 113 if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then
9d548d81 114 _APACHECTL -V 2>&1
115 else
116 echo "apache doesn't exists."
117 fi
4c2a3841 118
9d548d81 119 echo "nc:"
4c2a3841 120 if _exists "nc"; then
9d548d81 121 nc -h 2>&1
122 else
123 _debug "nc doesn't exists."
124 fi
125}
43822d37 126
a73c5b33 127_log() {
128 [ -z "$LOG_FILE" ] && return
95e06de5 129 _printargs "$@" >>"$LOG_FILE"
a73c5b33 130}
131
132_info() {
133 _log "$@"
134 _printargs "$@"
4c3b3608 135}
136
137_err() {
a73c5b33 138 _log "$@"
569d6c55 139 if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
140 printf -- "%s" "[$(date)] " >&2
141 fi
4c2a3841 142 if [ -z "$2" ]; then
65de3110 143 __red "$1" >&2
144 else
145 __red "$1='$2'" >&2
146 fi
b19ba13a 147 printf "\n" >&2
4c3b3608 148 return 1
149}
150
43822d37 151_usage() {
4c2a3841 152 __red "$@" >&2
65de3110 153 printf "\n" >&2
43822d37 154}
155
c60883ef 156_debug() {
4c2a3841 157 if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ]; then
a73c5b33 158 _log "$@"
159 fi
4c2a3841 160 if [ -z "$DEBUG" ]; then
c60883ef 161 return
162 fi
a73c5b33 163 _printargs "$@" >&2
c60883ef 164}
165
a63b05a9 166_debug2() {
4c2a3841 167 if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ]; then
a73c5b33 168 _log "$@"
169 fi
4c2a3841 170 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
a63b05a9 171 _debug "$@"
172 fi
a63b05a9 173}
174
22ea4004 175_debug3() {
4c2a3841 176 if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ]; then
a73c5b33 177 _log "$@"
178 fi
4c2a3841 179 if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ]; then
22ea4004 180 _debug "$@"
181 fi
22ea4004 182}
183
4c2a3841 184_startswith() {
dceb3aca 185 _str="$1"
186 _sub="$2"
19539575 187 echo "$_str" | grep "^$_sub" >/dev/null 2>&1
dceb3aca 188}
189
4c2a3841 190_endswith() {
43822d37 191 _str="$1"
192 _sub="$2"
193 echo "$_str" | grep -- "$_sub\$" >/dev/null 2>&1
194}
195
4c2a3841 196_contains() {
dceb3aca 197 _str="$1"
198 _sub="$2"
43822d37 199 echo "$_str" | grep -- "$_sub" >/dev/null 2>&1
dceb3aca 200}
201
c53da1ef 202_hasfield() {
203 _str="$1"
204 _field="$2"
205 _sep="$3"
4c2a3841 206 if [ -z "$_field" ]; then
43822d37 207 _usage "Usage: str field [sep]"
c53da1ef 208 return 1
209 fi
4c2a3841 210
211 if [ -z "$_sep" ]; then
c53da1ef 212 _sep=","
213 fi
4c2a3841 214
215 for f in $(echo "$_str" | tr ',' ' '); do
216 if [ "$f" = "$_field" ]; then
0c9546cc 217 _debug2 "'$_str' contains '$_field'"
c53da1ef 218 return 0 #contains ok
219 fi
220 done
0c9546cc 221 _debug2 "'$_str' does not contain '$_field'"
c53da1ef 222 return 1 #not contains
223}
224
4c2a3841 225_getfield() {
0463b5d6 226 _str="$1"
227 _findex="$2"
228 _sep="$3"
4c2a3841 229
230 if [ -z "$_findex" ]; then
0463b5d6 231 _usage "Usage: str field [sep]"
232 return 1
233 fi
4c2a3841 234
235 if [ -z "$_sep" ]; then
0463b5d6 236 _sep=","
237 fi
238
201aa244 239 _ffi="$_findex"
4c2a3841 240 while [ "$_ffi" -gt "0" ]; do
201aa244 241 _fv="$(echo "$_str" | cut -d "$_sep" -f "$_ffi")"
4c2a3841 242 if [ "$_fv" ]; then
0463b5d6 243 printf -- "%s" "$_fv"
244 return 0
245 fi
95e06de5 246 _ffi="$(_math "$_ffi" - 1)"
0463b5d6 247 done
4c2a3841 248
0463b5d6 249 printf -- "%s" "$_str"
250
251}
252
4c2a3841 253_exists() {
c60883ef 254 cmd="$1"
4c2a3841 255 if [ -z "$cmd" ]; then
43822d37 256 _usage "Usage: _exists cmd"
c60883ef 257 return 1
258 fi
82dc2244 259
260 if eval type type >/dev/null 2>&1; then
261 eval type "$cmd" >/dev/null 2>&1
262 elif command >/dev/null 2>&1; then
19539575 263 command -v "$cmd" >/dev/null 2>&1
ce4be4e9 264 else
e591d5cf 265 which "$cmd" >/dev/null 2>&1
eac18b1c 266 fi
c60883ef 267 ret="$?"
690a5e20 268 _debug3 "$cmd exists=$ret"
c60883ef 269 return $ret
270}
271
00a50605 272#a + b
4c2a3841 273_math() {
be68fbd4 274 _m_opts="$@"
275 printf "%s" "$(($_m_opts))"
00a50605 276}
277
278_h_char_2_dec() {
279 _ch=$1
280 case "${_ch}" in
4c2a3841 281 a | A)
19539575 282 printf "10"
4c2a3841 283 ;;
284 b | B)
19539575 285 printf "11"
4c2a3841 286 ;;
287 c | C)
19539575 288 printf "12"
4c2a3841 289 ;;
290 d | D)
19539575 291 printf "13"
4c2a3841 292 ;;
293 e | E)
19539575 294 printf "14"
4c2a3841 295 ;;
296 f | F)
19539575 297 printf "15"
4c2a3841 298 ;;
00a50605 299 *)
19539575 300 printf "%s" "$_ch"
4c2a3841 301 ;;
19539575 302 esac
00a50605 303
304}
305
fac1e367 306_URGLY_PRINTF=""
4c2a3841 307if [ "$(printf '\x41')" != 'A' ]; then
fac1e367 308 _URGLY_PRINTF=1
309fi
310
4c3b3608 311_h2b() {
312 hex=$(cat)
313 i=1
314 j=2
e591d5cf 315
690a5e20 316 _debug3 _URGLY_PRINTF "$_URGLY_PRINTF"
4c2a3841 317 while true; do
318 if [ -z "$_URGLY_PRINTF" ]; then
f9a6988e 319 h="$(printf "%s" "$hex" | cut -c $i-$j)"
4c2a3841 320 if [ -z "$h" ]; then
321 break
00a50605 322 fi
e591d5cf 323 printf "\x$h%s"
00a50605 324 else
95e06de5 325 ic="$(printf "%s" "$hex" | cut -c $i)"
326 jc="$(printf "%s" "$hex" | cut -c $j)"
4c2a3841 327 if [ -z "$ic$jc" ]; then
328 break
00a50605 329 fi
19539575 330 ic="$(_h_char_2_dec "$ic")"
331 jc="$(_h_char_2_dec "$jc")"
e51bef6d 332 printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
4c3b3608 333 fi
e591d5cf 334
335 i="$(_math "$i" + 2)"
336 j="$(_math "$j" + 2)"
337
4c3b3608 338 done
339}
340
542d7977 341_is_solaris() {
342 _contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS"
343}
344
9bdb799b 345#_ascii_hex str
346#this can only process ascii chars, should only be used when od command is missing as a backup way.
347_ascii_hex() {
348 _debug2 "Using _ascii_hex"
349 _str="$1"
350 _str_len=${#_str}
351 _h_i=1
352 while [ "$_h_i" -le "$_str_len" ]; do
353 _str_c="$(printf "%s" "$_str" | cut -c "$_h_i")"
354 printf " %02x" "'$_str_c"
355 _h_i="$(_math "$_h_i" + 1)"
356 done
357}
358
542d7977 359#stdin output hexstr splited by one space
360#input:"abc"
361#output: " 61 62 63"
362_hex_dump() {
9bdb799b 363 #in wired some system, the od command is missing.
364 if ! od -A n -v -t x1 | tr -d "\r\t" | tr -s " " | sed "s/ $//" | tr -d "\n" 2>/dev/null; then
365 str=$(cat)
366 _ascii_hex "$str"
367 fi
542d7977 368}
369
370#url encode, no-preserved chars
371#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
372#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a
373
374#a b c d e f g h i j k l m n o p q r s t u v w x y z
375#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a
376
377#0 1 2 3 4 5 6 7 8 9 - _ . ~
378#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e
379
380#stdin stdout
381_url_encode() {
382 _hex_str=$(_hex_dump)
383 _debug3 "_url_encode"
384 _debug3 "_hex_str" "$_hex_str"
385 for _hex_code in $_hex_str; do
386 #upper case
387 case "${_hex_code}" in
c3b1eb08 388 "41")
389 printf "%s" "A"
390 ;;
391 "42")
392 printf "%s" "B"
393 ;;
394 "43")
395 printf "%s" "C"
396 ;;
397 "44")
398 printf "%s" "D"
399 ;;
400 "45")
401 printf "%s" "E"
402 ;;
403 "46")
404 printf "%s" "F"
405 ;;
406 "47")
407 printf "%s" "G"
408 ;;
409 "48")
410 printf "%s" "H"
411 ;;
412 "49")
413 printf "%s" "I"
414 ;;
415 "4a")
416 printf "%s" "J"
417 ;;
418 "4b")
419 printf "%s" "K"
420 ;;
421 "4c")
422 printf "%s" "L"
423 ;;
424 "4d")
425 printf "%s" "M"
426 ;;
427 "4e")
428 printf "%s" "N"
429 ;;
430 "4f")
431 printf "%s" "O"
432 ;;
433 "50")
434 printf "%s" "P"
435 ;;
436 "51")
437 printf "%s" "Q"
438 ;;
439 "52")
440 printf "%s" "R"
441 ;;
442 "53")
443 printf "%s" "S"
444 ;;
445 "54")
446 printf "%s" "T"
447 ;;
448 "55")
449 printf "%s" "U"
450 ;;
451 "56")
452 printf "%s" "V"
453 ;;
454 "57")
455 printf "%s" "W"
456 ;;
457 "58")
458 printf "%s" "X"
459 ;;
460 "59")
461 printf "%s" "Y"
462 ;;
463 "5a")
464 printf "%s" "Z"
465 ;;
466
467 #lower case
468 "61")
469 printf "%s" "a"
470 ;;
471 "62")
472 printf "%s" "b"
473 ;;
474 "63")
475 printf "%s" "c"
476 ;;
477 "64")
478 printf "%s" "d"
479 ;;
480 "65")
481 printf "%s" "e"
482 ;;
483 "66")
484 printf "%s" "f"
485 ;;
486 "67")
487 printf "%s" "g"
488 ;;
489 "68")
490 printf "%s" "h"
491 ;;
492 "69")
493 printf "%s" "i"
494 ;;
495 "6a")
496 printf "%s" "j"
497 ;;
498 "6b")
499 printf "%s" "k"
500 ;;
501 "6c")
502 printf "%s" "l"
503 ;;
504 "6d")
505 printf "%s" "m"
506 ;;
507 "6e")
508 printf "%s" "n"
509 ;;
510 "6f")
511 printf "%s" "o"
512 ;;
513 "70")
514 printf "%s" "p"
515 ;;
516 "71")
517 printf "%s" "q"
518 ;;
519 "72")
520 printf "%s" "r"
521 ;;
522 "73")
523 printf "%s" "s"
524 ;;
525 "74")
526 printf "%s" "t"
527 ;;
528 "75")
529 printf "%s" "u"
530 ;;
531 "76")
532 printf "%s" "v"
533 ;;
534 "77")
535 printf "%s" "w"
536 ;;
537 "78")
538 printf "%s" "x"
539 ;;
540 "79")
541 printf "%s" "y"
542 ;;
543 "7a")
544 printf "%s" "z"
545 ;;
546 #numbers
547 "30")
548 printf "%s" "0"
549 ;;
550 "31")
551 printf "%s" "1"
552 ;;
553 "32")
554 printf "%s" "2"
555 ;;
556 "33")
557 printf "%s" "3"
558 ;;
559 "34")
560 printf "%s" "4"
561 ;;
562 "35")
563 printf "%s" "5"
564 ;;
565 "36")
566 printf "%s" "6"
567 ;;
568 "37")
569 printf "%s" "7"
570 ;;
571 "38")
572 printf "%s" "8"
573 ;;
574 "39")
575 printf "%s" "9"
576 ;;
577 "2d")
578 printf "%s" "-"
579 ;;
580 "5f")
581 printf "%s" "_"
582 ;;
583 "2e")
584 printf "%s" "."
585 ;;
586 "7e")
587 printf "%s" "~"
588 ;;
589 #other hex
542d7977 590 *)
c3b1eb08 591 printf '%%%s' "$_hex_code"
592 ;;
542d7977 593 esac
e009ec8b 594 done
595}
596
c60883ef 597#options file
598_sed_i() {
599 options="$1"
600 filename="$2"
4c2a3841 601 if [ -z "$filename" ]; then
43822d37 602 _usage "Usage:_sed_i options filename"
c60883ef 603 return 1
604 fi
14f3dbb7 605 _debug2 options "$options"
606 if sed -h 2>&1 | grep "\-i\[SUFFIX]" >/dev/null 2>&1; then
c60883ef 607 _debug "Using sed -i"
14f3dbb7 608 sed -i "$options" "$filename"
c60883ef 609 else
610 _debug "No -i support in sed"
19539575 611 text="$(cat "$filename")"
4c2a3841 612 echo "$text" | sed "$options" >"$filename"
c60883ef 613 fi
614}
615
22ea4004 616_egrep_o() {
a3c0c754 617 if ! egrep -o "$1" 2>/dev/null; then
22ea4004 618 sed -n 's/.*\('"$1"'\).*/\1/p'
22ea4004 619 fi
620}
621
88fab7d6 622#Usage: file startline endline
623_getfile() {
624 filename="$1"
625 startline="$2"
626 endline="$3"
4c2a3841 627 if [ -z "$endline" ]; then
43822d37 628 _usage "Usage: file startline endline"
88fab7d6 629 return 1
630 fi
4c2a3841 631
632 i="$(grep -n -- "$startline" "$filename" | cut -d : -f 1)"
633 if [ -z "$i" ]; then
88fab7d6 634 _err "Can not find start line: $startline"
635 return 1
636 fi
19539575 637 i="$(_math "$i" + 1)"
638 _debug i "$i"
4c2a3841 639
640 j="$(grep -n -- "$endline" "$filename" | cut -d : -f 1)"
641 if [ -z "$j" ]; then
88fab7d6 642 _err "Can not find end line: $endline"
643 return 1
644 fi
19539575 645 j="$(_math "$j" - 1)"
646 _debug j "$j"
4c2a3841 647
648 sed -n "$i,${j}p" "$filename"
88fab7d6 649
650}
651
652#Usage: multiline
4c3b3608 653_base64() {
ec9975c3 654 [ "" ] #urgly
4c2a3841 655 if [ "$1" ]; then
24d2a8b9 656 _debug3 "base64 multiline:'$1'"
a746139c 657 $OPENSSL_BIN base64 -e
88fab7d6 658 else
4d8b99a3 659 _debug3 "base64 single line."
a746139c 660 $OPENSSL_BIN base64 -e | tr -d '\r\n'
88fab7d6 661 fi
662}
663
664#Usage: multiline
665_dbase64() {
4c2a3841 666 if [ "$1" ]; then
a746139c 667 $OPENSSL_BIN base64 -d -A
88fab7d6 668 else
a746139c 669 $OPENSSL_BIN base64 -d
88fab7d6 670 fi
671}
672
e22bcf7c 673#Usage: hashalg [outputhex]
88fab7d6 674#Output Base64-encoded digest
675_digest() {
676 alg="$1"
4c2a3841 677 if [ -z "$alg" ]; then
43822d37 678 _usage "Usage: _digest hashalg"
88fab7d6 679 return 1
680 fi
4c2a3841 681
e22bcf7c 682 outputhex="$2"
4c2a3841 683
c7b16249 684 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
4c2a3841 685 if [ "$outputhex" ]; then
a746139c 686 $OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
e22bcf7c 687 else
a746139c 688 $OPENSSL_BIN dgst -"$alg" -binary | _base64
b001840d 689 fi
690 else
691 _err "$alg is not supported yet"
692 return 1
693 fi
694
695}
696
e009ec8b 697#Usage: hashalg secret_hex [outputhex]
698#Output binary hmac
b001840d 699_hmac() {
700 alg="$1"
e009ec8b 701 secret_hex="$2"
b001840d 702 outputhex="$3"
4c2a3841 703
e009ec8b 704 if [ -z "$secret_hex" ]; then
4c2a3841 705 _usage "Usage: _hmac hashalg secret [outputhex]"
b001840d 706 return 1
707 fi
708
a6014bf0 709 if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
4c2a3841 710 if [ "$outputhex" ]; then
a746139c 711 $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" | cut -d = -f 2 | tr -d ' '
e22bcf7c 712 else
a746139c 713 $OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary
e22bcf7c 714 fi
88fab7d6 715 else
716 _err "$alg is not supported yet"
717 return 1
718 fi
719
720}
721
722#Usage: keyfile hashalg
723#Output: Base64-encoded signature value
724_sign() {
725 keyfile="$1"
726 alg="$2"
4c2a3841 727 if [ -z "$alg" ]; then
43822d37 728 _usage "Usage: _sign keyfile hashalg"
88fab7d6 729 return 1
730 fi
4c2a3841 731
a746139c 732 _sign_openssl="$OPENSSL_BIN dgst -sign $keyfile "
4c2a3841 733 if [ "$alg" = "sha256" ]; then
998783eb 734 _sign_openssl="$_sign_openssl -$alg"
88fab7d6 735 else
736 _err "$alg is not supported yet"
737 return 1
fac1e367 738 fi
4c2a3841 739
740 if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
998783eb 741 $_sign_openssl | _base64
4c2a3841 742 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
a746139c 743 if ! _signedECText="$($_sign_openssl | $OPENSSL_BIN asn1parse -inform DER)"; then
67184d7b 744 _err "Sign failed: $_sign_openssl"
745 _err "Key file: $keyfile"
f9a6988e 746 _err "Key content:$(wc -l <"$keyfile") lises"
67184d7b 747 return 1
748 fi
998783eb 749 _debug3 "_signedECText" "$_signedECText"
750 _ec_r="$(echo "$_signedECText" | _head_n 2 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
751 _debug3 "_ec_r" "$_ec_r"
752 _ec_s="$(echo "$_signedECText" | _head_n 3 | _tail_n 1 | cut -d : -f 4 | tr -d "\r\n")"
753 _debug3 "_ec_s" "$_ec_s"
754 printf "%s" "$_ec_r$_ec_s" | _h2b | _base64
755 else
756 _err "Unknown key file format."
757 return 1
758 fi
4c2a3841 759
4c3b3608 760}
761
43822d37 762#keylength
763_isEccKey() {
764 _length="$1"
765
4c2a3841 766 if [ -z "$_length" ]; then
43822d37 767 return 1
768 fi
769
770 [ "$_length" != "1024" ] \
4c2a3841 771 && [ "$_length" != "2048" ] \
772 && [ "$_length" != "3072" ] \
773 && [ "$_length" != "4096" ] \
774 && [ "$_length" != "8192" ]
43822d37 775}
776
e22bcf7c 777# _createkey 2048|ec-256 file
778_createkey() {
779 length="$1"
780 f="$2"
c4236e58 781 _debug2 "_createkey for file:$f"
43822d37 782 eccname="$length"
4c2a3841 783 if _startswith "$length" "ec-"; then
f9a6988e 784 length=$(printf "%s" "$length" | cut -d '-' -f 2-100)
e22bcf7c 785
4c2a3841 786 if [ "$length" = "256" ]; then
e22bcf7c 787 eccname="prime256v1"
788 fi
4c2a3841 789 if [ "$length" = "384" ]; then
e22bcf7c 790 eccname="secp384r1"
791 fi
4c2a3841 792 if [ "$length" = "521" ]; then
e22bcf7c 793 eccname="secp521r1"
794 fi
43822d37 795
e22bcf7c 796 fi
797
4c2a3841 798 if [ -z "$length" ]; then
799 length=2048
43822d37 800 fi
4c2a3841 801
cbcd7e0f 802 _debug "Use length $length"
43822d37 803
4c2a3841 804 if _isEccKey "$length"; then
cbcd7e0f 805 _debug "Using ec name: $eccname"
a746139c 806 $OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f"
e22bcf7c 807 else
cbcd7e0f 808 _debug "Using RSA: $length"
a746139c 809 $OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f"
e22bcf7c 810 fi
43822d37 811
4c2a3841 812 if [ "$?" != "0" ]; then
43822d37 813 _err "Create key error."
814 return 1
815 fi
e22bcf7c 816}
817
9774b01b 818#domain
819_is_idn() {
820 _is_idn_d="$1"
049be104 821 _debug2 _is_idn_d "$_is_idn_d"
d11d4761 822 _idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-')
049be104 823 _debug2 _idn_temp "$_idn_temp"
824 [ "$_idn_temp" ]
9774b01b 825}
826
827#aa.com
828#aa.com,bb.com,cc.com
829_idn() {
830 __idn_d="$1"
4c2a3841 831 if ! _is_idn "$__idn_d"; then
9774b01b 832 printf "%s" "$__idn_d"
833 return 0
834 fi
4c2a3841 835
836 if _exists idn; then
837 if _contains "$__idn_d" ','; then
9774b01b 838 _i_first="1"
4c2a3841 839 for f in $(echo "$__idn_d" | tr ',' ' '); do
9774b01b 840 [ -z "$f" ] && continue
4c2a3841 841 if [ -z "$_i_first" ]; then
9774b01b 842 printf "%s" ","
843 else
844 _i_first=""
845 fi
2a1e06f8 846 idn --quiet "$f" | tr -d "\r\n"
9774b01b 847 done
848 else
849 idn "$__idn_d" | tr -d "\r\n"
850 fi
851 else
852 _err "Please install idn to process IDN names."
853 fi
854}
855
e22bcf7c 856#_createcsr cn san_list keyfile csrfile conf
857_createcsr() {
858 _debug _createcsr
859 domain="$1"
860 domainlist="$2"
0c9546cc 861 csrkey="$3"
e22bcf7c 862 csr="$4"
863 csrconf="$5"
864 _debug2 domain "$domain"
865 _debug2 domainlist "$domainlist"
0c9546cc 866 _debug2 csrkey "$csrkey"
867 _debug2 csr "$csr"
868 _debug2 csrconf "$csrconf"
4c2a3841 869
870 printf "[ req_distinguished_name ]\n[ req ]\ndistinguished_name = req_distinguished_name\nreq_extensions = v3_req\n[ v3_req ]\n\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment" >"$csrconf"
871
3f4513b3 872 if [ -z "$domainlist" ] || [ "$domainlist" = "$NO_VALUE" ]; then
e22bcf7c 873 #single domain
874 _info "Single domain" "$domain"
e22bcf7c 875 else
f9a6988e 876 domainlist="$(_idn "$domainlist")"
9774b01b 877 _debug2 domainlist "$domainlist"
4c2a3841 878 if _contains "$domainlist" ","; then
f9a6988e 879 alt="DNS:$(echo "$domainlist" | sed "s/,/,DNS:/g")"
e22bcf7c 880 else
881 alt="DNS:$domainlist"
882 fi
883 #multi
884 _info "Multi domain" "$alt"
4c2a3841 885 printf -- "\nsubjectAltName=$alt" >>"$csrconf"
0c9546cc 886 fi
0a3b6c48 887 if [ "$Le_OCSP_Staple" ] || [ "$Le_OCSP_Stable" ]; then
96db9362 888 _savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple"
0a3b6c48 889 _cleardomainconf Le_OCSP_Stable
4c2a3841 890 printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
e22bcf7c 891 fi
4c2a3841 892
9774b01b 893 _csr_cn="$(_idn "$domain")"
894 _debug2 _csr_cn "$_csr_cn"
a746139c 895 $OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr"
e22bcf7c 896}
897
898#_signcsr key csr conf cert
899_signcsr() {
900 key="$1"
901 csr="$2"
902 conf="$3"
903 cert="$4"
5aa146a5 904 _debug "_signcsr"
4c2a3841 905
a746139c 906 _msg="$($OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
5aa146a5 907 _ret="$?"
908 _debug "$_msg"
909 return $_ret
e22bcf7c 910}
911
10afcaca 912#_csrfile
913_readSubjectFromCSR() {
914 _csrfile="$1"
4c2a3841 915 if [ -z "$_csrfile" ]; then
10afcaca 916 _usage "_readSubjectFromCSR mycsr.csr"
917 return 1
918 fi
b22b085b 919 $OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
10afcaca 920}
921
922#_csrfile
923#echo comma separated domain list
924_readSubjectAltNamesFromCSR() {
925 _csrfile="$1"
4c2a3841 926 if [ -z "$_csrfile" ]; then
10afcaca 927 _usage "_readSubjectAltNamesFromCSR mycsr.csr"
928 return 1
929 fi
4c2a3841 930
10afcaca 931 _csrsubj="$(_readSubjectFromCSR "$_csrfile")"
932 _debug _csrsubj "$_csrsubj"
4c2a3841 933
a746139c 934 _dnsAltnames="$($OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')"
10afcaca 935 _debug _dnsAltnames "$_dnsAltnames"
4c2a3841 936
937 if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
10afcaca 938 _debug "AltNames contains subject"
1643b476 939 _dnsAltnames="$(printf "%s" "$_dnsAltnames," | sed "s/DNS:$_csrsubj,//g")"
10afcaca 940 else
941 _debug "AltNames doesn't contain subject"
942 fi
4c2a3841 943
1643b476 944 printf "%s" "$_dnsAltnames" | sed "s/DNS://g"
10afcaca 945}
946
947#_csrfile
948_readKeyLengthFromCSR() {
949 _csrfile="$1"
4c2a3841 950 if [ -z "$_csrfile" ]; then
1643b476 951 _usage "_readKeyLengthFromCSR mycsr.csr"
10afcaca 952 return 1
953 fi
4c2a3841 954
a746139c 955 _outcsr="$($OPENSSL_BIN req -noout -text -in "$_csrfile")"
4c2a3841 956 if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then
10afcaca 957 _debug "ECC CSR"
958 echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
959 else
960 _debug "RSA CSR"
961 echo "$_outcsr" | _egrep_o "^ *Public-Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
962 fi
963}
964
34c27e09 965_ss() {
966 _port="$1"
4c2a3841 967
968 if _exists "ss"; then
edf08da6 969 _debug "Using: ss"
19539575 970 ss -ntpl | grep ":$_port "
edf08da6 971 return 0
972 fi
973
4c2a3841 974 if _exists "netstat"; then
251fc37c 975 _debug "Using: netstat"
4c2a3841 976 if netstat -h 2>&1 | grep "\-p proto" >/dev/null; then
ccb96535 977 #for windows version netstat tool
0463b5d6 978 netstat -an -p tcp | grep "LISTENING" | grep ":$_port "
ccb96535 979 else
4c2a3841 980 if netstat -help 2>&1 | grep "\-p protocol" >/dev/null; then
19539575 981 netstat -an -p tcp | grep LISTEN | grep ":$_port "
4c2a3841 982 elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then
22ea4004 983 #for solaris
e3c66532 984 netstat -an -P tcp | grep "\.$_port " | grep "LISTEN"
edf08da6 985 else
19539575 986 netstat -ntpl | grep ":$_port "
edf08da6 987 fi
ccb96535 988 fi
34c27e09 989 return 0
990 fi
edf08da6 991
34c27e09 992 return 1
993}
994
43822d37 995#domain [password] [isEcc]
ac2d5123 996toPkcs() {
997 domain="$1"
998 pfxPassword="$2"
4c2a3841 999 if [ -z "$domain" ]; then
43822d37 1000 _usage "Usage: $PROJECT_ENTRY --toPkcs -d domain [--password pfx-password]"
ac2d5123 1001 return 1
1002 fi
1003
43822d37 1004 _isEcc="$3"
4c2a3841 1005
43822d37 1006 _initpath "$domain" "$_isEcc"
1007
4c2a3841 1008 if [ "$pfxPassword" ]; then
a746139c 1009 $OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
ac2d5123 1010 else
a746139c 1011 $OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
ac2d5123 1012 fi
4c2a3841 1013
1014 if [ "$?" = "0" ]; then
ac2d5123 1015 _info "Success, Pfx is exported to: $CERT_PFX_PATH"
1016 fi
1017
1018}
1019
5fbc47eb 1020#[2048]
4c3b3608 1021createAccountKey() {
1022 _info "Creating account key"
4c2a3841 1023 if [ -z "$1" ]; then
5fbc47eb 1024 _usage "Usage: $PROJECT_ENTRY --createAccountKey --accountkeylength 2048"
4c3b3608 1025 return
1026 fi
4c2a3841 1027
5fbc47eb 1028 length=$1
57e58ce7 1029 _create_account_key "$length"
1030
1031}
1032
1033_create_account_key() {
1034
5fbc47eb 1035 length=$1
4c2a3841 1036
1037 if [ -z "$length" ] || [ "$length" = "$NO_VALUE" ]; then
57e58ce7 1038 _debug "Use default length $DEFAULT_ACCOUNT_KEY_LENGTH"
1039 length="$DEFAULT_ACCOUNT_KEY_LENGTH"
4c3b3608 1040 fi
4c2a3841 1041
5fbc47eb 1042 _debug length "$length"
4c3b3608 1043 _initpath
5fbc47eb 1044
57e58ce7 1045 mkdir -p "$CA_DIR"
4c2a3841 1046 if [ -f "$ACCOUNT_KEY_PATH" ]; then
4c3b3608 1047 _info "Account key exists, skip"
1048 return
1049 else
1050 #generate account key
31a5487c 1051 _createkey "$length" "$ACCOUNT_KEY_PATH"
4c3b3608 1052 fi
1053
1054}
1055
43822d37 1056#domain [length]
4c3b3608 1057createDomainKey() {
1058 _info "Creating domain key"
4c2a3841 1059 if [ -z "$1" ]; then
43822d37 1060 _usage "Usage: $PROJECT_ENTRY --createDomainKey -d domain.com [ --keylength 2048 ]"
4c3b3608 1061 return
1062 fi
4c2a3841 1063
4c3b3608 1064 domain=$1
e22bcf7c 1065 length=$2
1066
4c2a3841 1067 if [ -z "$length" ]; then
57e58ce7 1068 _debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH"
1069 length="$DEFAULT_DOMAIN_KEY_LENGTH"
1070 fi
e22bcf7c 1071
f9a6988e 1072 _initpath "$domain" "$length"
4c2a3841 1073
1074 if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then
e22bcf7c 1075 _createkey "$length" "$CERT_KEY_PATH"
4c3b3608 1076 else
4c2a3841 1077 if [ "$IS_RENEW" ]; then
4c3b3608 1078 _info "Domain key exists, skip"
1079 return 0
1080 else
1081 _err "Domain key exists, do you want to overwrite the key?"
41e3eafa 1082 _err "Add '--force', and try again."
4c3b3608 1083 return 1
1084 fi
1085 fi
1086
1087}
1088
43822d37 1089# domain domainlist isEcc
4c3b3608 1090createCSR() {
1091 _info "Creating csr"
4c2a3841 1092 if [ -z "$1" ]; then
43822d37 1093 _usage "Usage: $PROJECT_ENTRY --createCSR -d domain1.com [-d domain2.com -d domain3.com ... ]"
4c3b3608 1094 return
1095 fi
4c2a3841 1096
43822d37 1097 domain="$1"
1098 domainlist="$2"
1099 _isEcc="$3"
4c2a3841 1100
43822d37 1101 _initpath "$domain" "$_isEcc"
4c2a3841 1102
1103 if [ -f "$CSR_PATH" ] && [ "$IS_RENEW" ] && [ -z "$FORCE" ]; then
4c3b3608 1104 _info "CSR exists, skip"
1105 return
1106 fi
4c2a3841 1107
1108 if [ ! -f "$CERT_KEY_PATH" ]; then
43822d37 1109 _err "The key file is not found: $CERT_KEY_PATH"
1110 _err "Please create the key file first."
1111 return 1
1112 fi
e22bcf7c 1113 _createcsr "$domain" "$domainlist" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"
4c2a3841 1114
4c3b3608 1115}
1116
11927a76 1117_url_replace() {
f9a6988e 1118 tr '/+' '_-' | tr -d '= '
4c3b3608 1119}
1120
1121_time2str() {
1122 #BSD
f9a6988e 1123 if date -u -d@"$1" 2>/dev/null; then
4c3b3608 1124 return
1125 fi
4c2a3841 1126
4c3b3608 1127 #Linux
f9a6988e 1128 if date -u -r "$1" 2>/dev/null; then
4c3b3608 1129 return
1130 fi
4c2a3841 1131
22ea4004 1132 #Soaris
4c2a3841 1133 if _exists adb; then
031e885e 1134 _t_s_a=$(echo "0t${1}=Y" | adb)
1135 echo "$_t_s_a"
22ea4004 1136 fi
4c2a3841 1137
4c3b3608 1138}
1139
eae29099 1140_normalizeJson() {
1141 sed "s/\" *: *\([\"{\[]\)/\":\1/g" | sed "s/^ *\([^ ]\)/\1/" | tr -d "\r\n"
1142}
1143
44df2967 1144_stat() {
1145 #Linux
4c2a3841 1146 if stat -c '%U:%G' "$1" 2>/dev/null; then
44df2967 1147 return
1148 fi
4c2a3841 1149
44df2967 1150 #BSD
4c2a3841 1151 if stat -f '%Su:%Sg' "$1" 2>/dev/null; then
44df2967 1152 return
1153 fi
4c2a3841 1154
1155 return 1 #error, 'stat' not found
44df2967 1156}
1157
166096dc 1158#keyfile
1159_calcjwk() {
1160 keyfile="$1"
4c2a3841 1161 if [ -z "$keyfile" ]; then
43822d37 1162 _usage "Usage: _calcjwk keyfile"
166096dc 1163 return 1
1164 fi
4c2a3841 1165
1166 if [ "$JWK_HEADER" ] && [ "$__CACHED_JWK_KEY_FILE" = "$keyfile" ]; then
ae2db62f 1167 _debug2 "Use cached jwk for file: $__CACHED_JWK_KEY_FILE"
1168 return 0
1169 fi
4c2a3841 1170
4c2a3841 1171 if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
166096dc 1172 _debug "RSA key"
a746139c 1173 pub_exp=$($OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
4c2a3841 1174 if [ "${#pub_exp}" = "5" ]; then
166096dc 1175 pub_exp=0$pub_exp
1176 fi
22ea4004 1177 _debug3 pub_exp "$pub_exp"
4c2a3841 1178
f9a6988e 1179 e=$(echo "$pub_exp" | _h2b | _base64)
22ea4004 1180 _debug3 e "$e"
4c2a3841 1181
a746139c 1182 modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2)
22ea4004 1183 _debug3 modulus "$modulus"
11927a76 1184 n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)"
4d8b99a3 1185 _debug3 n "$n"
1186
166096dc 1187 jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
22ea4004 1188 _debug3 jwk "$jwk"
4c2a3841 1189
5982f4bc 1190 JWK_HEADER='{"alg": "RS256", "jwk": '$jwk'}'
1191 JWK_HEADERPLACE_PART1='{"nonce": "'
1192 JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}'
4c2a3841 1193 elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
166096dc 1194 _debug "EC key"
a746139c 1195 crv="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
22ea4004 1196 _debug3 crv "$crv"
4c2a3841 1197
1198 if [ -z "$crv" ]; then
d22b7938 1199 _debug "Let's try ASN1 OID"
a746139c 1200 crv_oid="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")"
cae9cee2 1201 _debug3 crv_oid "$crv_oid"
d22b7938 1202 case "${crv_oid}" in
1203 "prime256v1")
4c2a3841 1204 crv="P-256"
1205 ;;
d22b7938 1206 "secp384r1")
4c2a3841 1207 crv="P-384"
1208 ;;
d22b7938 1209 "secp521r1")
4c2a3841 1210 crv="P-521"
1211 ;;
d22b7938 1212 *)
4c2a3841 1213 _err "ECC oid : $crv_oid"
1214 return 1
1215 ;;
067d586c 1216 esac
d22b7938 1217 _debug3 crv "$crv"
1218 fi
4c2a3841 1219
a746139c 1220 pubi="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
79a267ab 1221 pubi=$(_math "$pubi" + 1)
22ea4004 1222 _debug3 pubi "$pubi"
4c2a3841 1223
a746139c 1224 pubj="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
79a267ab 1225 pubj=$(_math "$pubj" - 1)
22ea4004 1226 _debug3 pubj "$pubj"
4c2a3841 1227
a746139c 1228 pubtext="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
22ea4004 1229 _debug3 pubtext "$pubtext"
4c2a3841 1230
95e06de5 1231 xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)"
79a267ab 1232 xlen=$(_math "$xlen" / 4)
22ea4004 1233 _debug3 xlen "$xlen"
00a50605 1234
998783eb 1235 xend=$(_math "$xlen" + 1)
f9a6988e 1236 x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")"
22ea4004 1237 _debug3 x "$x"
4c2a3841 1238
11927a76 1239 x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _url_replace)"
22ea4004 1240 _debug3 x64 "$x64"
00a50605 1241
19539575 1242 xend=$(_math "$xend" + 1)
f9a6988e 1243 y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)"
22ea4004 1244 _debug3 y "$y"
4c2a3841 1245
11927a76 1246 y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)"
22ea4004 1247 _debug3 y64 "$y64"
4c2a3841 1248
ae2db62f 1249 jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}'
22ea4004 1250 _debug3 jwk "$jwk"
4c2a3841 1251
5982f4bc 1252 JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}'
1253 JWK_HEADERPLACE_PART1='{"nonce": "'
1254 JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}'
166096dc 1255 else
1256 _err "Only RSA or EC key is supported."
1257 return 1
1258 fi
1259
5982f4bc 1260 _debug3 JWK_HEADER "$JWK_HEADER"
ae2db62f 1261 __CACHED_JWK_KEY_FILE="$keyfile"
166096dc 1262}
fac1e367 1263
3aae1ae3 1264_time() {
1265 date -u "+%s"
1266}
fac1e367 1267
5d2c5b01 1268_utc_date() {
1269 date -u "+%Y-%m-%d %H:%M:%S"
1270}
1271
fac1e367 1272_mktemp() {
4c2a3841 1273 if _exists mktemp; then
1274 if mktemp 2>/dev/null; then
610e0f21 1275 return 0
4c2a3841 1276 elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then
5c48e139 1277 #for Mac osx
610e0f21 1278 return 0
b19ba13a 1279 fi
fac1e367 1280 fi
4c2a3841 1281 if [ -d "/tmp" ]; then
3aae1ae3 1282 echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp"
1283 return 0
4c2a3841 1284 elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then
610e0f21 1285 echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp"
1286 return 0
3aae1ae3 1287 fi
1288 _err "Can not create temp file."
fac1e367 1289}
1290
1291_inithttp() {
1292
4c2a3841 1293 if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then
fac1e367 1294 HTTP_HEADER="$(_mktemp)"
1295 _debug2 HTTP_HEADER "$HTTP_HEADER"
1296 fi
1297
4c2a3841 1298 if [ "$__HTTP_INITIALIZED" ]; then
1299 if [ "$_ACME_CURL$_ACME_WGET" ]; then
1befee5a 1300 _debug2 "Http already initialized."
1301 return 0
1302 fi
1303 fi
4c2a3841 1304
1305 if [ -z "$_ACME_CURL" ] && _exists "curl"; then
1befee5a 1306 _ACME_CURL="curl -L --silent --dump-header $HTTP_HEADER "
4c2a3841 1307 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
fac1e367 1308 _CURL_DUMP="$(_mktemp)"
1befee5a 1309 _ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP "
fac1e367 1310 fi
1311
4c2a3841 1312 if [ "$CA_BUNDLE" ]; then
1befee5a 1313 _ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE "
78009539
PS
1314 fi
1315
fac1e367 1316 fi
4c2a3841 1317
1befee5a 1318 if [ -z "$_ACME_WGET" ] && _exists "wget"; then
1319 _ACME_WGET="wget -q"
4c2a3841 1320 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
1befee5a 1321 _ACME_WGET="$_ACME_WGET -d "
fac1e367 1322 fi
4c2a3841 1323 if [ "$CA_BUNDLE" ]; then
1befee5a 1324 _ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE "
78009539 1325 fi
fac1e367 1326 fi
1327
1befee5a 1328 __HTTP_INITIALIZED=1
fac1e367 1329
fac1e367 1330}
fac1e367 1331
c839b2b0 1332# body url [needbase64] [POST|PUT]
c60883ef 1333_post() {
1334 body="$1"
1335 url="$2"
1336 needbase64="$3"
a4270efa 1337 httpmethod="$4"
c60883ef 1338
4c2a3841 1339 if [ -z "$httpmethod" ]; then
a4270efa 1340 httpmethod="POST"
1341 fi
1342 _debug $httpmethod
484d9d2a 1343 _debug "url" "$url"
30de13b4 1344 _debug2 "body" "$body"
4c2a3841 1345
fac1e367 1346 _inithttp
4c2a3841 1347
1348 if [ "$_ACME_CURL" ]; then
1befee5a 1349 _CURL="$_ACME_CURL"
7834c252 1350 if [ "$HTTPS_INSECURE" ]; then
1351 _CURL="$_CURL --insecure "
1352 fi
ec9fc8cb 1353 _debug "_CURL" "$_CURL"
4c2a3841 1354 if [ "$needbase64" ]; then
690a5e20 1355 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url" | _base64)"
c60883ef 1356 else
4c2a3841 1357 response="$($_CURL --user-agent "$USER_AGENT" -X $httpmethod -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" --data "$body" "$url")"
c60883ef 1358 fi
16679b57 1359 _ret="$?"
4c2a3841 1360 if [ "$_ret" != "0" ]; then
87ab2d90 1361 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $_ret"
4c2a3841 1362 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
87ab2d90 1363 _err "Here is the curl dump log:"
1364 _err "$(cat "$_CURL_DUMP")"
1365 fi
687cfcc2 1366 fi
4c2a3841 1367 elif [ "$_ACME_WGET" ]; then
7834c252 1368 _WGET="$_ACME_WGET"
1369 if [ "$HTTPS_INSECURE" ]; then
1370 _WGET="$_WGET --no-check-certificate "
1371 fi
1372 _debug "_WGET" "$_WGET"
4c2a3841 1373 if [ "$needbase64" ]; then
1374 if [ "$httpmethod" = "POST" ]; then
7834c252 1375 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 1376 else
7834c252 1377 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 1378 fi
c60883ef 1379 else
4c2a3841 1380 if [ "$httpmethod" = "POST" ]; then
7834c252 1381 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 1382 else
7834c252 1383 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 1384 fi
c60883ef 1385 fi
16679b57 1386 _ret="$?"
4c2a3841 1387 if [ "$_ret" = "8" ]; then
9f43c270 1388 _ret=0
1389 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later."
1390 fi
4c2a3841 1391 if [ "$_ret" != "0" ]; then
1392 _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
687cfcc2 1393 fi
c60883ef 1394 _sed_i "s/^ *//g" "$HTTP_HEADER"
d0b748a4 1395 else
1396 _ret="$?"
1397 _err "Neither curl nor wget is found, can not do $httpmethod."
c60883ef 1398 fi
16679b57 1399 _debug "_ret" "$_ret"
19539575 1400 printf "%s" "$response"
16679b57 1401 return $_ret
c60883ef 1402}
1403
75da0713 1404# url getheader timeout
c60883ef 1405_get() {
a4270efa 1406 _debug GET
c60883ef 1407 url="$1"
1408 onlyheader="$2"
75da0713 1409 t="$3"
79a267ab 1410 _debug url "$url"
75da0713 1411 _debug "timeout" "$t"
fac1e367 1412
1413 _inithttp
1414
4c2a3841 1415 if [ "$_ACME_CURL" ]; then
1befee5a 1416 _CURL="$_ACME_CURL"
7834c252 1417 if [ "$HTTPS_INSECURE" ]; then
1418 _CURL="$_CURL --insecure "
1419 fi
4c2a3841 1420 if [ "$t" ]; then
75da0713 1421 _CURL="$_CURL --connect-timeout $t"
1422 fi
1423 _debug "_CURL" "$_CURL"
4c2a3841 1424 if [ "$onlyheader" ]; then
f9a6988e 1425 $_CURL -I --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
c60883ef 1426 else
f9a6988e 1427 $_CURL --user-agent "$USER_AGENT" -H "$_H1" -H "$_H2" -H "$_H3" -H "$_H4" -H "$_H5" "$url"
c60883ef 1428 fi
9aaf36cd 1429 ret=$?
4c2a3841 1430 if [ "$ret" != "0" ]; then
d529eb6d 1431 _err "Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: $ret"
4c2a3841 1432 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
fac1e367 1433 _err "Here is the curl dump log:"
1434 _err "$(cat "$_CURL_DUMP")"
1435 fi
1436 fi
4c2a3841 1437 elif [ "$_ACME_WGET" ]; then
1befee5a 1438 _WGET="$_ACME_WGET"
7834c252 1439 if [ "$HTTPS_INSECURE" ]; then
1440 _WGET="$_WGET --no-check-certificate "
1441 fi
4c2a3841 1442 if [ "$t" ]; then
75da0713 1443 _WGET="$_WGET --timeout=$t"
1444 fi
1445 _debug "_WGET" "$_WGET"
4c2a3841 1446 if [ "$onlyheader" ]; then
f9a6988e 1447 $_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 1448 else
f9a6988e 1449 $_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url"
c60883ef 1450 fi
9aaf36cd 1451 ret=$?
4c2a3841 1452 if [ "$_ret" = "8" ]; then
9f43c270 1453 _ret=0
1454 _debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later."
1455 fi
4c2a3841 1456 if [ "$ret" != "0" ]; then
1457 _err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
fac1e367 1458 fi
d0b748a4 1459 else
1460 ret=$?
1461 _err "Neither curl nor wget is found, can not do GET."
9aaf36cd 1462 fi
ec9fc8cb 1463 _debug "ret" "$ret"
c60883ef 1464 return $ret
1465}
166096dc 1466
c2c8f320 1467_head_n() {
79a267ab 1468 head -n "$1"
c2c8f320 1469}
1470
1471_tail_n() {
f9a6988e 1472 if ! tail -n "$1" 2>/dev/null; then
19ab2a29 1473 #fix for solaris
f9a6988e 1474 tail -"$1"
19ab2a29 1475 fi
c2c8f320 1476}
fac1e367 1477
166096dc 1478# url payload needbase64 keyfile
4c3b3608 1479_send_signed_request() {
1480 url=$1
1481 payload=$2
1482 needbase64=$3
166096dc 1483 keyfile=$4
4c2a3841 1484 if [ -z "$keyfile" ]; then
166096dc 1485 keyfile="$ACCOUNT_KEY_PATH"
1486 fi
f9a6988e 1487 _debug url "$url"
4c3b3608 1488 _debug payload "$payload"
4c2a3841 1489
1490 if ! _calcjwk "$keyfile"; then
166096dc 1491 return 1
1492 fi
c60883ef 1493
11927a76 1494 payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
f9a6988e 1495 _debug3 payload64 "$payload64"
4c2a3841 1496
1497 if [ -z "$_CACHED_NONCE" ]; then
00bcbd36 1498 _debug2 "Get nonce."
1499 nonceurl="$API/directory"
79a267ab 1500 _headers="$(_get "$nonceurl" "onlyheader")"
4c2a3841 1501
1502 if [ "$?" != "0" ]; then
00bcbd36 1503 _err "Can not connect to $nonceurl to get nonce."
1504 return 1
1505 fi
4c2a3841 1506
1cbf416b 1507 _debug2 _headers "$_headers"
4c2a3841 1508
1509 _CACHED_NONCE="$(echo "$_headers" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
1cbf416b 1510 _debug2 _CACHED_NONCE "$_CACHED_NONCE"
00bcbd36 1511 else
1512 _debug2 "Use _CACHED_NONCE" "$_CACHED_NONCE"
7012b91f 1513 fi
00bcbd36 1514 nonce="$_CACHED_NONCE"
1cbf416b 1515 _debug2 nonce "$nonce"
a272ee4f 1516
5982f4bc 1517 protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2"
22ea4004 1518 _debug3 protected "$protected"
4c2a3841 1519
11927a76 1520 protected64="$(printf "%s" "$protected" | _base64 | _url_replace)"
22ea4004 1521 _debug3 protected64 "$protected64"
166096dc 1522
4c2a3841 1523 if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then
29b75109 1524 _err "Sign request failed."
1525 return 1
1526 fi
1527 _debug3 _sig_t "$_sig_t"
4c2a3841 1528
11927a76 1529 sig="$(printf "%s" "$_sig_t" | _url_replace)"
22ea4004 1530 _debug3 sig "$sig"
4c2a3841 1531
5982f4bc 1532 body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
22ea4004 1533 _debug3 body "$body"
bbbdcb09 1534
f9a6988e 1535 response="$(_post "$body" "$url" "$needbase64")"
00bcbd36 1536 _CACHED_NONCE=""
4c2a3841 1537 if [ "$?" != "0" ]; then
9f43c270 1538 _err "Can not post to $url"
7012b91f 1539 return 1
1540 fi
eae29099 1541 _debug2 original "$response"
4c3b3608 1542
4c2a3841 1543 response="$(echo "$response" | _normalizeJson)"
4c3b3608 1544
00bcbd36 1545 responseHeaders="$(cat "$HTTP_HEADER")"
4c2a3841 1546
a63b05a9 1547 _debug2 responseHeaders "$responseHeaders"
4c2a3841 1548 _debug2 response "$response"
79a267ab 1549 code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\r\n")"
1550 _debug code "$code"
4c3b3608 1551
00bcbd36 1552 _CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
4c3b3608 1553
4c3b3608 1554}
4c3b3608 1555
1556#setopt "file" "opt" "=" "value" [";"]
1557_setopt() {
1558 __conf="$1"
1559 __opt="$2"
1560 __sep="$3"
1561 __val="$4"
1562 __end="$5"
4c2a3841 1563 if [ -z "$__opt" ]; then
1564 _usage usage: _setopt '"file" "opt" "=" "value" [";"]'
4c3b3608 1565 return
1566 fi
4c2a3841 1567 if [ ! -f "$__conf" ]; then
4c3b3608 1568 touch "$__conf"
1569 fi
1570
4c2a3841 1571 if grep -n "^$__opt$__sep" "$__conf" >/dev/null; then
22ea4004 1572 _debug3 OK
4c2a3841 1573 if _contains "$__val" "&"; then
79a267ab 1574 __val="$(echo "$__val" | sed 's/&/\\&/g')"
4c3b3608 1575 fi
79a267ab 1576 text="$(cat "$__conf")"
4c2a3841 1577 echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
4c3b3608 1578
4c2a3841 1579 elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then
1580 if _contains "$__val" "&"; then
79a267ab 1581 __val="$(echo "$__val" | sed 's/&/\\&/g')"
4c3b3608 1582 fi
79a267ab 1583 text="$(cat "$__conf")"
4c2a3841 1584 echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
4c3b3608 1585
1586 else
22ea4004 1587 _debug3 APP
4c2a3841 1588 echo "$__opt$__sep$__val$__end" >>"$__conf"
4c3b3608 1589 fi
79a267ab 1590 _debug2 "$(grep -n "^$__opt$__sep" "$__conf")"
4c3b3608 1591}
1592
8a29fbc8 1593#_save_conf file key value
1594#save to conf
1595_save_conf() {
1596 _s_c_f="$1"
1597 _sdkey="$2"
1598 _sdvalue="$3"
4c2a3841 1599 if [ "$_s_c_f" ]; then
8a29fbc8 1600 _setopt "$_s_c_f" "$_sdkey" "=" "'$_sdvalue'"
4d2f38b0 1601 else
8a29fbc8 1602 _err "config file is empty, can not save $_sdkey=$_sdvalue"
4d2f38b0 1603 fi
1604}
1605
8a29fbc8 1606#_clear_conf file key
1607_clear_conf() {
1608 _c_c_f="$1"
1609 _sdkey="$2"
4c2a3841 1610 if [ "$_c_c_f" ]; then
20ea8591 1611 _conf_data="$(cat "$_c_c_f")"
fa574fe8 1612 echo "$_conf_data" | sed "s/^$_sdkey *=.*$//" >"$_c_c_f"
4c3b3608 1613 else
8a29fbc8 1614 _err "config file is empty, can not clear"
4c3b3608 1615 fi
1616}
1617
8a29fbc8 1618#_read_conf file key
1619_read_conf() {
1620 _r_c_f="$1"
1621 _sdkey="$2"
4c2a3841 1622 if [ -f "$_r_c_f" ]; then
1623 (
79a267ab 1624 eval "$(grep "^$_sdkey *=" "$_r_c_f")"
4c2a3841 1625 eval "printf \"%s\" \"\$$_sdkey\""
1626 )
61623d22 1627 else
57e58ce7 1628 _debug "config file is empty, can not read $_sdkey"
4c3b3608 1629 fi
4c3b3608 1630}
1631
1632#_savedomainconf key value
1633#save to domain.conf
1634_savedomainconf() {
8a29fbc8 1635 _save_conf "$DOMAIN_CONF" "$1" "$2"
4d2f38b0 1636}
1637
1638#_cleardomainconf key
1639_cleardomainconf() {
8a29fbc8 1640 _clear_conf "$DOMAIN_CONF" "$1"
4c3b3608 1641}
1642
61623d22 1643#_readdomainconf key
1644_readdomainconf() {
8a29fbc8 1645 _read_conf "$DOMAIN_CONF" "$1"
61623d22 1646}
1647
4c3b3608 1648#_saveaccountconf key value
1649_saveaccountconf() {
8a29fbc8 1650 _save_conf "$ACCOUNT_CONF_PATH" "$1" "$2"
4c3b3608 1651}
1652
fac1e367 1653#_clearaccountconf key
1654_clearaccountconf() {
8a29fbc8 1655 _clear_conf "$ACCOUNT_CONF_PATH" "$1"
1656}
1657
1658#_savecaconf key value
1659_savecaconf() {
1660 _save_conf "$CA_CONF" "$1" "$2"
1661}
1662
1663#_readcaconf key
1664_readcaconf() {
1665 _read_conf "$CA_CONF" "$1"
1666}
1667
1668#_clearaccountconf key
1669_clearcaconf() {
1670 _clear_conf "$CA_CONF" "$1"
fac1e367 1671}
1672
0463b5d6 1673# content localaddress
4c3b3608 1674_startserver() {
1675 content="$1"
0463b5d6 1676 ncaddr="$2"
1677 _debug "ncaddr" "$ncaddr"
1678
6fc1447f 1679 _debug "startserver: $$"
1b2e940d 1680 nchelp="$(nc -h 2>&1)"
4c2a3841 1681
39c8f79f 1682 _debug Le_HTTPPort "$Le_HTTPPort"
6ae0f7f5 1683 _debug Le_Listen_V4 "$Le_Listen_V4"
1684 _debug Le_Listen_V6 "$Le_Listen_V6"
f78babfa 1685 _NC="nc"
4c2a3841 1686
1687 if [ "$Le_Listen_V4" ]; then
6ae0f7f5 1688 _NC="$_NC -4"
4c2a3841 1689 elif [ "$Le_Listen_V6" ]; then
6ae0f7f5 1690 _NC="$_NC -6"
1691 fi
4c2a3841 1692
562a4c05 1693 if [ "$Le_Listen_V4$Le_Listen_V6$ncaddr" ]; then
dba26c32 1694 if ! _contains "$nchelp" "-4"; then
562a4c05 1695 _err "The nc doesn't support '-4', '-6' or local-address, please install 'netcat-openbsd' and try again."
1696 _err "See $(__green $_PREPARE_LINK)"
1697 return 1
1698 fi
1699 fi
1700
4c2a3841 1701 if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then
f78babfa 1702 _NC="$_NC -q 1 -l $ncaddr"
1703 else
4c2a3841 1704 if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null; then
f78babfa 1705 _NC="$_NC -c -l $ncaddr"
4c2a3841 1706 elif echo "$nchelp" | grep "\-N" | grep "Shutdown the network socket after EOF on stdin" >/dev/null; then
f78babfa 1707 _NC="$_NC -N -l $ncaddr"
1708 else
1709 _NC="$_NC -l $ncaddr"
1710 fi
1711 fi
1712
6ae0f7f5 1713 _debug "_NC" "$_NC"
1714
c9febbdd 1715 #for centos ncat
4c2a3841 1716 if _contains "$nchelp" "nmap.org"; then
c9febbdd 1717 _debug "Using ncat: nmap.org"
3e5b1024 1718 if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"; then
1719 _exec_err
1720 return 1
c9febbdd 1721 fi
fa574fe8 1722 if [ "$DEBUG" ]; then
3e5b1024 1723 _exec_err
1724 fi
1725 return
c9febbdd 1726 fi
4c2a3841 1727
1728 # while true ; do
3e5b1024 1729 if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC -p \"$Le_HTTPPort\" >&2"; then
1730 _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"
4c2a3841 1731 fi
3e5b1024 1732
4c2a3841 1733 if [ "$?" != "0" ]; then
1734 _err "nc listen error."
3e5b1024 1735 _exec_err
4c2a3841 1736 exit 1
1737 fi
fa574fe8 1738 if [ "$DEBUG" ]; then
3e5b1024 1739 _exec_err
1740 fi
4c2a3841 1741 # done
4c3b3608 1742}
1743
4c2a3841 1744_stopserver() {
4c3b3608 1745 pid="$1"
6fc1447f 1746 _debug "pid" "$pid"
4c2a3841 1747 if [ -z "$pid" ]; then
6fc1447f 1748 return
1749 fi
e22bcf7c 1750
dcf9cb58 1751 _debug2 "Le_HTTPPort" "$Le_HTTPPort"
4c2a3841 1752 if [ "$Le_HTTPPort" ]; then
1753 if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then
22ea4004 1754 _get "http://localhost:$Le_HTTPPort" "" 1
dcf9cb58 1755 else
22ea4004 1756 _get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1
dcf9cb58 1757 fi
1758 fi
4c2a3841 1759
dcf9cb58 1760 _debug2 "Le_TLSPort" "$Le_TLSPort"
4c2a3841 1761 if [ "$Le_TLSPort" ]; then
1762 if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then
75da0713 1763 _get "https://localhost:$Le_TLSPort" "" 1
1764 _get "https://localhost:$Le_TLSPort" "" 1
dcf9cb58 1765 else
75da0713 1766 _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
1767 _get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
dcf9cb58 1768 fi
1769 fi
4c3b3608 1770}
1771
fdcb6b72 1772# sleep sec
1773_sleep() {
1774 _sleep_sec="$1"
4c2a3841 1775 if [ "$__INTERACTIVE" ]; then
fdcb6b72 1776 _sleep_c="$_sleep_sec"
4c2a3841 1777 while [ "$_sleep_c" -ge "0" ]; do
c583d6bb 1778 printf "\r \r"
fdcb6b72 1779 __green "$_sleep_c"
79a267ab 1780 _sleep_c="$(_math "$_sleep_c" - 1)"
fdcb6b72 1781 sleep 1
1782 done
c583d6bb 1783 printf "\r"
fdcb6b72 1784 else
1785 sleep "$_sleep_sec"
1786 fi
1787}
e22bcf7c 1788
6ae0f7f5 1789# _starttlsserver san_a san_b port content _ncaddr
e22bcf7c 1790_starttlsserver() {
1791 _info "Starting tls server."
1792 san_a="$1"
1793 san_b="$2"
1794 port="$3"
1795 content="$4"
6ae0f7f5 1796 opaddr="$5"
4c2a3841 1797
e22bcf7c 1798 _debug san_a "$san_a"
1799 _debug san_b "$san_b"
1800 _debug port "$port"
4c2a3841 1801
e22bcf7c 1802 #create key TLS_KEY
4c2a3841 1803 if ! _createkey "2048" "$TLS_KEY"; then
e22bcf7c 1804 _err "Create tls validation key error."
1805 return 1
1806 fi
4c2a3841 1807
e22bcf7c 1808 #create csr
1809 alt="$san_a"
4c2a3841 1810 if [ "$san_b" ]; then
e22bcf7c 1811 alt="$alt,$san_b"
1812 fi
4c2a3841 1813 if ! _createcsr "tls.acme.sh" "$alt" "$TLS_KEY" "$TLS_CSR" "$TLS_CONF"; then
e22bcf7c 1814 _err "Create tls validation csr error."
1815 return 1
1816 fi
4c2a3841 1817
e22bcf7c 1818 #self signed
4c2a3841 1819 if ! _signcsr "$TLS_KEY" "$TLS_CSR" "$TLS_CONF" "$TLS_CERT"; then
e22bcf7c 1820 _err "Create tls validation cert error."
1821 return 1
1822 fi
4c2a3841 1823
a746139c 1824 __S_OPENSSL="$OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY "
4c2a3841 1825 if [ "$opaddr" ]; then
6ae0f7f5 1826 __S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port"
1827 else
1828 __S_OPENSSL="$__S_OPENSSL -accept $port"
1829 fi
1830
1831 _debug Le_Listen_V4 "$Le_Listen_V4"
1832 _debug Le_Listen_V6 "$Le_Listen_V6"
4c2a3841 1833 if [ "$Le_Listen_V4" ]; then
6ae0f7f5 1834 __S_OPENSSL="$__S_OPENSSL -4"
4c2a3841 1835 elif [ "$Le_Listen_V6" ]; then
6ae0f7f5 1836 __S_OPENSSL="$__S_OPENSSL -6"
1837 fi
4c2a3841 1838
6ae0f7f5 1839 _debug "$__S_OPENSSL"
4c2a3841 1840 if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
d5ec5f80 1841 (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) &
331c4bb6 1842 else
d5ec5f80 1843 (printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL >/dev/null 2>&1) &
331c4bb6 1844 fi
1845
e22bcf7c 1846 serverproc="$!"
5dbf664a 1847 sleep 1
d5ec5f80 1848 _debug serverproc "$serverproc"
e22bcf7c 1849}
1850
18e46962 1851#file
1852_readlink() {
1853 _rf="$1"
1854 if ! readlink -f "$_rf" 2>/dev/null; then
6c4cc357 1855 if _startswith "$_rf" "/"; then
1856 echo "$_rf"
7da50703 1857 return 0
1858 fi
6c4cc357 1859 echo "$(pwd)/$_rf" | _conapath
18e46962 1860 fi
1861}
1862
6c4cc357 1863_conapath() {
1864 sed "s#/\./#/#g"
1865}
1866
5ea6e9c9 1867__initHome() {
4c2a3841 1868 if [ -z "$_SCRIPT_HOME" ]; then
1869 if _exists readlink && _exists dirname; then
66990cf8 1870 _debug "Lets find script dir."
f3e4cea3 1871 _debug "_SCRIPT_" "$_SCRIPT_"
18e46962 1872 _script="$(_readlink "$_SCRIPT_")"
f3e4cea3 1873 _debug "_script" "$_script"
1874 _script_home="$(dirname "$_script")"
1875 _debug "_script_home" "$_script_home"
4c2a3841 1876 if [ -d "$_script_home" ]; then
f3e4cea3 1877 _SCRIPT_HOME="$_script_home"
1878 else
1879 _err "It seems the script home is not correct:$_script_home"
1880 fi
1881 fi
1882 fi
1883
219e9115 1884 # if [ -z "$LE_WORKING_DIR" ]; then
1885 # if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then
1886 # _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME"
1887 # LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
1888 # else
1889 # LE_WORKING_DIR="$_SCRIPT_HOME"
1890 # fi
1891 # fi
4c2a3841 1892
1893 if [ -z "$LE_WORKING_DIR" ]; then
f3e4cea3 1894 _debug "Using default home:$DEFAULT_INSTALL_HOME"
1895 LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
1896 fi
7da50703 1897 export LE_WORKING_DIR
f3e4cea3 1898
f5b546b3 1899 if [ -z "$LE_CONFIG_HOME" ]; then
1900 LE_CONFIG_HOME="$LE_WORKING_DIR"
27dbe77f 1901 fi
f5b546b3 1902 _debug "Using config home:$LE_CONFIG_HOME"
1903 export LE_CONFIG_HOME
27dbe77f 1904
f5b546b3 1905 _DEFAULT_ACCOUNT_CONF_PATH="$LE_CONFIG_HOME/account.conf"
d53289d7 1906
4c2a3841 1907 if [ -z "$ACCOUNT_CONF_PATH" ]; then
1908 if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then
8663fb7e 1909 . "$_DEFAULT_ACCOUNT_CONF_PATH"
635695ec 1910 fi
d53289d7 1911 fi
4c2a3841 1912
1913 if [ -z "$ACCOUNT_CONF_PATH" ]; then
d53289d7 1914 ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH"
4c3b3608 1915 fi
4c2a3841 1916
f5b546b3 1917 DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log"
4c2a3841 1918
f5b546b3 1919 DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca"
4c2a3841 1920
1921 if [ -z "$LE_TEMP_DIR" ]; then
f5b546b3 1922 LE_TEMP_DIR="$LE_CONFIG_HOME/tmp"
610e0f21 1923 fi
5ea6e9c9 1924}
1925
1926#[domain] [keylength]
1927_initpath() {
1928
1929 __initHome
1930
4c2a3841 1931 if [ -f "$ACCOUNT_CONF_PATH" ]; then
8663fb7e 1932 . "$ACCOUNT_CONF_PATH"
4c3b3608 1933 fi
1934
4c2a3841 1935 if [ "$IN_CRON" ]; then
1936 if [ ! "$_USER_PATH_EXPORTED" ]; then
281aa349 1937 _USER_PATH_EXPORTED=1
1938 export PATH="$USER_PATH:$PATH"
1939 fi
1940 fi
4c2a3841 1941
1942 if [ -z "$CA_HOME" ]; then
5c48e139 1943 CA_HOME="$DEFAULT_CA_HOME"
1944 fi
281aa349 1945
4c2a3841 1946 if [ -z "$API" ]; then
1947 if [ -z "$STAGE" ]; then
4c3b3608 1948 API="$DEFAULT_CA"
1949 else
1950 API="$STAGE_CA"
1951 _info "Using stage api:$API"
4c2a3841 1952 fi
4c3b3608 1953 fi
4c2a3841 1954
5c48e139 1955 _API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')"
1956 CA_DIR="$CA_HOME/$_API_HOST"
4c2a3841 1957
5c48e139 1958 _DEFAULT_CA_CONF="$CA_DIR/ca.conf"
4c2a3841 1959
1960 if [ -z "$CA_CONF" ]; then
5c48e139 1961 CA_CONF="$_DEFAULT_CA_CONF"
1962 fi
c4236e58 1963 _debug3 CA_CONF "$CA_CONF"
4c2a3841 1964
1965 if [ -f "$CA_CONF" ]; then
5c48e139 1966 . "$CA_CONF"
1967 fi
1968
4c2a3841 1969 if [ -z "$ACME_DIR" ]; then
4c3b3608 1970 ACME_DIR="/home/.acme"
1971 fi
4c2a3841 1972
1973 if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then
f5b546b3 1974 APACHE_CONF_BACKUP_DIR="$LE_CONFIG_HOME"
4c3b3608 1975 fi
4c2a3841 1976
1977 if [ -z "$USER_AGENT" ]; then
bbbdcb09 1978 USER_AGENT="$DEFAULT_USER_AGENT"
1979 fi
4c2a3841 1980
1981 if [ -z "$HTTP_HEADER" ]; then
f5b546b3 1982 HTTP_HEADER="$LE_CONFIG_HOME/http.header"
933c169d 1983 fi
b2817897 1984
5c48e139 1985 _OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key"
1986 _OLD_ACCOUNT_JSON="$LE_WORKING_DIR/account.json"
4c2a3841 1987
5c48e139 1988 _DEFAULT_ACCOUNT_KEY_PATH="$CA_DIR/account.key"
1989 _DEFAULT_ACCOUNT_JSON_PATH="$CA_DIR/account.json"
4c2a3841 1990 if [ -z "$ACCOUNT_KEY_PATH" ]; then
b2817897 1991 ACCOUNT_KEY_PATH="$_DEFAULT_ACCOUNT_KEY_PATH"
4c3b3608 1992 fi
4c2a3841 1993
1994 if [ -z "$ACCOUNT_JSON_PATH" ]; then
5c48e139 1995 ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH"
1996 fi
4c2a3841 1997
f5b546b3 1998 _DEFAULT_CERT_HOME="$LE_CONFIG_HOME"
4c2a3841 1999 if [ -z "$CERT_HOME" ]; then
a79b26af
RD
2000 CERT_HOME="$_DEFAULT_CERT_HOME"
2001 fi
2002
a746139c 2003 if [ -z "$OPENSSL_BIN" ]; then
2004 OPENSSL_BIN="$DEFAULT_OPENSSL_BIN"
2005 fi
2006
4c2a3841 2007 if [ -z "$1" ]; then
4c3b3608 2008 return 0
2009 fi
4c2a3841 2010
5fbc47eb 2011 domain="$1"
2012 _ilength="$2"
4c3b3608 2013
4c2a3841 2014 if [ -z "$DOMAIN_PATH" ]; then
43822d37 2015 domainhome="$CERT_HOME/$domain"
2016 domainhomeecc="$CERT_HOME/$domain$ECC_SUFFIX"
4c2a3841 2017
4c3b3608 2018 DOMAIN_PATH="$domainhome"
4c2a3841 2019
2020 if _isEccKey "$_ilength"; then
43822d37 2021 DOMAIN_PATH="$domainhomeecc"
2022 else
4c2a3841 2023 if [ ! -d "$domainhome" ] && [ -d "$domainhomeecc" ]; then
6d4e903b 2024 _info "The domain '$domain' seems to have a ECC cert already, please add '$(__red "--ecc")' parameter if you want to use that cert."
43822d37 2025 fi
2026 fi
2027 _debug DOMAIN_PATH "$DOMAIN_PATH"
4c3b3608 2028 fi
4c2a3841 2029
4c2a3841 2030 if [ -z "$DOMAIN_CONF" ]; then
43822d37 2031 DOMAIN_CONF="$DOMAIN_PATH/$domain.conf"
4c3b3608 2032 fi
4c2a3841 2033
2034 if [ -z "$DOMAIN_SSL_CONF" ]; then
0c9546cc 2035 DOMAIN_SSL_CONF="$DOMAIN_PATH/$domain.csr.conf"
4c3b3608 2036 fi
4c2a3841 2037
2038 if [ -z "$CSR_PATH" ]; then
43822d37 2039 CSR_PATH="$DOMAIN_PATH/$domain.csr"
4c3b3608 2040 fi
4c2a3841 2041 if [ -z "$CERT_KEY_PATH" ]; then
43822d37 2042 CERT_KEY_PATH="$DOMAIN_PATH/$domain.key"
4c3b3608 2043 fi
4c2a3841 2044 if [ -z "$CERT_PATH" ]; then
43822d37 2045 CERT_PATH="$DOMAIN_PATH/$domain.cer"
4c3b3608 2046 fi
4c2a3841 2047 if [ -z "$CA_CERT_PATH" ]; then
43822d37 2048 CA_CERT_PATH="$DOMAIN_PATH/ca.cer"
4c3b3608 2049 fi
4c2a3841 2050 if [ -z "$CERT_FULLCHAIN_PATH" ]; then
43822d37 2051 CERT_FULLCHAIN_PATH="$DOMAIN_PATH/fullchain.cer"
caf1fc10 2052 fi
4c2a3841 2053 if [ -z "$CERT_PFX_PATH" ]; then
43822d37 2054 CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx"
ac2d5123 2055 fi
4c2a3841 2056
2057 if [ -z "$TLS_CONF" ]; then
43822d37 2058 TLS_CONF="$DOMAIN_PATH/tls.valdation.conf"
e22bcf7c 2059 fi
4c2a3841 2060 if [ -z "$TLS_CERT" ]; then
43822d37 2061 TLS_CERT="$DOMAIN_PATH/tls.valdation.cert"
e22bcf7c 2062 fi
4c2a3841 2063 if [ -z "$TLS_KEY" ]; then
43822d37 2064 TLS_KEY="$DOMAIN_PATH/tls.valdation.key"
e22bcf7c 2065 fi
4c2a3841 2066 if [ -z "$TLS_CSR" ]; then
43822d37 2067 TLS_CSR="$DOMAIN_PATH/tls.valdation.csr"
e22bcf7c 2068 fi
4c2a3841 2069
4c3b3608 2070}
2071
610e0f21 2072_exec() {
4c2a3841 2073 if [ -z "$_EXEC_TEMP_ERR" ]; then
610e0f21 2074 _EXEC_TEMP_ERR="$(_mktemp)"
2075 fi
2076
4c2a3841 2077 if [ "$_EXEC_TEMP_ERR" ]; then
3e5b1024 2078 eval "$@ 2>>$_EXEC_TEMP_ERR"
610e0f21 2079 else
3e5b1024 2080 eval "$@"
610e0f21 2081 fi
2082}
2083
2084_exec_err() {
3e5b1024 2085 [ "$_EXEC_TEMP_ERR" ] && _err "$(cat "$_EXEC_TEMP_ERR")" && echo "" >"$_EXEC_TEMP_ERR"
610e0f21 2086}
4c3b3608 2087
2088_apachePath() {
c3dd3ef0 2089 _APACHECTL="apachectl"
4c2a3841 2090 if ! _exists apachectl; then
2091 if _exists apache2ctl; then
2092 _APACHECTL="apache2ctl"
e4a19585 2093 else
bc96082f 2094 _err "'apachectl not found. It seems that apache is not installed, or you are not root user.'"
e4a19585 2095 _err "Please use webroot mode to try again."
2096 return 1
2097 fi
80a0a7b5 2098 fi
4c2a3841 2099
2100 if ! _exec $_APACHECTL -V >/dev/null; then
610e0f21 2101 _exec_err
2102 return 1
2103 fi
4c2a3841 2104
2105 if [ "$APACHE_HTTPD_CONF" ]; then
5be1449d 2106 _saveaccountconf APACHE_HTTPD_CONF "$APACHE_HTTPD_CONF"
2107 httpdconf="$APACHE_HTTPD_CONF"
79a267ab 2108 httpdconfname="$(basename "$httpdconfname")"
d62ee940 2109 else
4c2a3841 2110 httpdconfname="$($_APACHECTL -V | grep SERVER_CONFIG_FILE= | cut -d = -f 2 | tr -d '"')"
5be1449d 2111 _debug httpdconfname "$httpdconfname"
4c2a3841 2112
2113 if [ -z "$httpdconfname" ]; then
5be1449d 2114 _err "Can not read apache config file."
2115 return 1
2116 fi
4c2a3841 2117
2118 if _startswith "$httpdconfname" '/'; then
5be1449d 2119 httpdconf="$httpdconfname"
79a267ab 2120 httpdconfname="$(basename "$httpdconfname")"
5be1449d 2121 else
4c2a3841 2122 httpdroot="$($_APACHECTL -V | grep HTTPD_ROOT= | cut -d = -f 2 | tr -d '"')"
5be1449d 2123 _debug httpdroot "$httpdroot"
2124 httpdconf="$httpdroot/$httpdconfname"
79a267ab 2125 httpdconfname="$(basename "$httpdconfname")"
5be1449d 2126 fi
d62ee940 2127 fi
78768e98 2128 _debug httpdconf "$httpdconf"
8f63baf7 2129 _debug httpdconfname "$httpdconfname"
4c2a3841 2130 if [ ! -f "$httpdconf" ]; then
78768e98 2131 _err "Apache Config file not found" "$httpdconf"
4c3b3608 2132 return 1
2133 fi
2134 return 0
2135}
2136
2137_restoreApache() {
4c2a3841 2138 if [ -z "$usingApache" ]; then
4c3b3608 2139 return 0
2140 fi
2141 _initpath
4c2a3841 2142 if ! _apachePath; then
4c3b3608 2143 return 1
2144 fi
4c2a3841 2145
2146 if [ ! -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname" ]; then
4c3b3608 2147 _debug "No config file to restore."
2148 return 0
2149 fi
4c2a3841 2150
2151 cat "$APACHE_CONF_BACKUP_DIR/$httpdconfname" >"$httpdconf"
5ef501c5 2152 _debug "Restored: $httpdconf."
4c2a3841 2153 if ! _exec $_APACHECTL -t; then
610e0f21 2154 _exec_err
4c3b3608 2155 _err "Sorry, restore apache config error, please contact me."
4c2a3841 2156 return 1
4c3b3608 2157 fi
5ef501c5 2158 _debug "Restored successfully."
4c3b3608 2159 rm -f "$APACHE_CONF_BACKUP_DIR/$httpdconfname"
4c2a3841 2160 return 0
4c3b3608 2161}
2162
2163_setApache() {
2164 _initpath
4c2a3841 2165 if ! _apachePath; then
4c3b3608 2166 return 1
2167 fi
2168
5fc5016d 2169 #test the conf first
869578ce 2170 _info "Checking if there is an error in the apache config file before starting."
4c2a3841 2171
44edb2bd 2172 if ! _exec "$_APACHECTL" -t >/dev/null; then
610e0f21 2173 _exec_err
2174 _err "The apache config file has error, please fix it first, then try again."
869578ce 2175 _err "Don't worry, there is nothing changed to your system."
4c2a3841 2176 return 1
5fc5016d 2177 else
2178 _info "OK"
2179 fi
4c2a3841 2180
4c3b3608 2181 #backup the conf
5778811a 2182 _debug "Backup apache config file" "$httpdconf"
4c2a3841 2183 if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then
869578ce 2184 _err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed."
8f63baf7 2185 _err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT"
2186 return 1
2187 fi
4c3b3608 2188 _info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname"
2189 _info "In case there is an error that can not be restored automatically, you may try restore it yourself."
329174b6 2190 _info "The backup file will be deleted on success, just forget it."
4c2a3841 2191
4c3b3608 2192 #add alias
4c2a3841 2193
2194 apacheVer="$($_APACHECTL -V | grep "Server version:" | cut -d : -f 2 | cut -d " " -f 2 | cut -d '/' -f 2)"
b09d597c 2195 _debug "apacheVer" "$apacheVer"
2196 apacheMajer="$(echo "$apacheVer" | cut -d . -f 1)"
2197 apacheMinor="$(echo "$apacheVer" | cut -d . -f 2)"
2198
4c2a3841 2199 if [ "$apacheVer" ] && [ "$apacheMajer$apacheMinor" -ge "24" ]; then
b09d597c 2200 echo "
4c3b3608 2201Alias /.well-known/acme-challenge $ACME_DIR
2202
2203<Directory $ACME_DIR >
2204Require all granted
b09d597c 2205</Directory>
4c2a3841 2206 " >>"$httpdconf"
b09d597c 2207 else
2208 echo "
2209Alias /.well-known/acme-challenge $ACME_DIR
2210
2211<Directory $ACME_DIR >
2212Order allow,deny
2213Allow from all
4c3b3608 2214</Directory>
4c2a3841 2215 " >>"$httpdconf"
b09d597c 2216 fi
2217
4c2a3841 2218 _msg="$($_APACHECTL -t 2>&1)"
2219 if [ "$?" != "0" ]; then
5fc5016d 2220 _err "Sorry, apache config error"
4c2a3841 2221 if _restoreApache; then
869578ce 2222 _err "The apache config file is restored."
5fc5016d 2223 else
869578ce 2224 _err "Sorry, The apache config file can not be restored, please report bug."
5fc5016d 2225 fi
4c2a3841 2226 return 1
4c3b3608 2227 fi
4c2a3841 2228
2229 if [ ! -d "$ACME_DIR" ]; then
4c3b3608 2230 mkdir -p "$ACME_DIR"
2231 chmod 755 "$ACME_DIR"
2232 fi
4c2a3841 2233
44edb2bd 2234 if ! _exec "$_APACHECTL" graceful; then
4c2a3841 2235 _exec_err
610e0f21 2236 _err "$_APACHECTL graceful error, please contact me."
4c3b3608 2237 _restoreApache
4c2a3841 2238 return 1
4c3b3608 2239 fi
2240 usingApache="1"
2241 return 0
2242}
2243
5ef501c5 2244_clearup() {
44edb2bd 2245 _stopserver "$serverproc"
4c3b3608 2246 serverproc=""
2247 _restoreApache
800e3f45 2248 _clearupdns
4c2a3841 2249 if [ -z "$DEBUG" ]; then
e22bcf7c 2250 rm -f "$TLS_CONF"
2251 rm -f "$TLS_CERT"
2252 rm -f "$TLS_KEY"
2253 rm -f "$TLS_CSR"
2254 fi
4c3b3608 2255}
2256
800e3f45 2257_clearupdns() {
2258 _debug "_clearupdns"
4c2a3841 2259 if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then
93fc48a2 2260 _debug "Dns not added, skip."
800e3f45 2261 return
2262 fi
2263
4c2a3841 2264 ventries=$(echo "$vlist" | tr ',' ' ')
2265 for ventry in $ventries; do
0c538f75 2266 d=$(echo "$ventry" | cut -d "$sep" -f 1)
2267 keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
2268 vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
2269 _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
11927a76 2270 txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
21f201e3 2271 _debug txt "$txt"
4c2a3841 2272 if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
800e3f45 2273 _info "$d is already verified, skip $vtype."
2274 continue
2275 fi
2276
4c2a3841 2277 if [ "$vtype" != "$VTYPE_DNS" ]; then
800e3f45 2278 _info "Skip $d for $vtype"
2279 continue
2280 fi
4c2a3841 2281
0c538f75 2282 d_api="$(_findHook "$d" dnsapi "$_currentRoot")"
800e3f45 2283 _debug d_api "$d_api"
4c2a3841 2284
2285 if [ -z "$d_api" ]; then
800e3f45 2286 _info "Not Found domain api file: $d_api"
2287 continue
2288 fi
4c2a3841 2289
800e3f45 2290 (
d5ec5f80 2291 if ! . "$d_api"; then
800e3f45 2292 _err "Load file $d_api error. Please check your api file and try again."
2293 return 1
2294 fi
4c2a3841 2295
800e3f45 2296 rmcommand="${_currentRoot}_rm"
d5ec5f80 2297 if ! _exists "$rmcommand"; then
800e3f45 2298 _err "It seems that your api file doesn't define $rmcommand"
2299 return 1
2300 fi
4c2a3841 2301
800e3f45 2302 txtdomain="_acme-challenge.$d"
4c2a3841 2303
21f201e3 2304 if ! $rmcommand "$txtdomain" "$txt"; then
800e3f45 2305 _err "Error removing txt for domain:$txtdomain"
2306 return 1
2307 fi
2308 )
4c2a3841 2309
800e3f45 2310 done
2311}
2312
4c3b3608 2313# webroot removelevel tokenfile
2314_clearupwebbroot() {
2315 __webroot="$1"
4c2a3841 2316 if [ -z "$__webroot" ]; then
4c3b3608 2317 _debug "no webroot specified, skip"
2318 return 0
2319 fi
4c2a3841 2320
dcf9cb58 2321 _rmpath=""
4c2a3841 2322 if [ "$2" = '1' ]; then
dcf9cb58 2323 _rmpath="$__webroot/.well-known"
4c2a3841 2324 elif [ "$2" = '2' ]; then
dcf9cb58 2325 _rmpath="$__webroot/.well-known/acme-challenge"
4c2a3841 2326 elif [ "$2" = '3' ]; then
dcf9cb58 2327 _rmpath="$__webroot/.well-known/acme-challenge/$3"
4c3b3608 2328 else
cc179731 2329 _debug "Skip for removelevel:$2"
4c3b3608 2330 fi
4c2a3841 2331
2332 if [ "$_rmpath" ]; then
2333 if [ "$DEBUG" ]; then
dcf9cb58 2334 _debug "Debugging, skip removing: $_rmpath"
2335 else
2336 rm -rf "$_rmpath"
2337 fi
2338 fi
4c2a3841 2339
4c3b3608 2340 return 0
2341
2342}
2343
b0070f03 2344_on_before_issue() {
30c2d84c 2345 _debug _on_before_issue
d0f7c309 2346 #run pre hook
2347 if [ "$Le_PreHook" ]; then
2348 _info "Run pre hook:'$Le_PreHook'"
2349 if ! (
2350 cd "$DOMAIN_PATH" && eval "$Le_PreHook"
2351 ); then
2352 _err "Error when run pre hook."
2353 return 1
2354 fi
2355 fi
2356
4c2a3841 2357 if _hasfield "$Le_Webroot" "$NO_VALUE"; then
2358 if ! _exists "nc"; then
0463b5d6 2359 _err "Please install netcat(nc) tools first."
2360 return 1
2361 fi
0463b5d6 2362 fi
2363
2364 _debug Le_LocalAddress "$Le_LocalAddress"
4c2a3841 2365
2366 alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ')
0463b5d6 2367 _index=1
2368 _currentRoot=""
2369 _addrIndex=1
4c2a3841 2370 for d in $alldomains; do
d5ec5f80 2371 _debug "Check for domain" "$d"
0463b5d6 2372 _currentRoot="$(_getfield "$Le_Webroot" $_index)"
2373 _debug "_currentRoot" "$_currentRoot"
2374 _index=$(_math $_index + 1)
2375 _checkport=""
4c2a3841 2376 if [ "$_currentRoot" = "$NO_VALUE" ]; then
0463b5d6 2377 _info "Standalone mode."
4c2a3841 2378 if [ -z "$Le_HTTPPort" ]; then
0463b5d6 2379 Le_HTTPPort=80
2380 else
4c2a3841 2381 _savedomainconf "Le_HTTPPort" "$Le_HTTPPort"
0463b5d6 2382 fi
2383 _checkport="$Le_HTTPPort"
4c2a3841 2384 elif [ "$_currentRoot" = "$W_TLS" ]; then
0463b5d6 2385 _info "Standalone tls mode."
4c2a3841 2386 if [ -z "$Le_TLSPort" ]; then
0463b5d6 2387 Le_TLSPort=443
2388 else
4c2a3841 2389 _savedomainconf "Le_TLSPort" "$Le_TLSPort"
0463b5d6 2390 fi
2391 _checkport="$Le_TLSPort"
2392 fi
4c2a3841 2393
2394 if [ "$_checkport" ]; then
0463b5d6 2395 _debug _checkport "$_checkport"
2396 _checkaddr="$(_getfield "$Le_LocalAddress" $_addrIndex)"
2397 _debug _checkaddr "$_checkaddr"
4c2a3841 2398
0463b5d6 2399 _addrIndex="$(_math $_addrIndex + 1)"
4c2a3841 2400
0463b5d6 2401 _netprc="$(_ss "$_checkport" | grep "$_checkport")"
2402 netprc="$(echo "$_netprc" | grep "$_checkaddr")"
4c2a3841 2403 if [ -z "$netprc" ]; then
0463b5d6 2404 netprc="$(echo "$_netprc" | grep "$LOCAL_ANY_ADDRESS")"
2405 fi
4c2a3841 2406 if [ "$netprc" ]; then
0463b5d6 2407 _err "$netprc"
4c2a3841 2408 _err "tcp port $_checkport is already used by $(echo "$netprc" | cut -d : -f 4)"
0463b5d6 2409 _err "Please stop it first"
2410 return 1
2411 fi
2412 fi
2413 done
2414
4c2a3841 2415 if _hasfield "$Le_Webroot" "apache"; then
2416 if ! _setApache; then
0463b5d6 2417 _err "set up apache error. Report error to me."
2418 return 1
2419 fi
2420 else
2421 usingApache=""
2422 fi
2423
b0070f03 2424}
2425
2426_on_issue_err() {
30c2d84c 2427 _debug _on_issue_err
4c2a3841 2428 if [ "$LOG_FILE" ]; then
a73c5b33 2429 _err "Please check log file for more details: $LOG_FILE"
2430 else
54ae008d 2431 _err "Please add '--debug' or '--log' to check more details."
a73c5b33 2432 _err "See: $_DEBUG_WIKI"
2433 fi
4c2a3841 2434
2435 if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
9d548d81 2436 _debug "$(_dlg_versions)"
2437 fi
4c2a3841 2438
b0070f03 2439 #run the post hook
4c2a3841 2440 if [ "$Le_PostHook" ]; then
b0070f03 2441 _info "Run post hook:'$Le_PostHook'"
2442 if ! (
2443 cd "$DOMAIN_PATH" && eval "$Le_PostHook"
4c2a3841 2444 ); then
b0070f03 2445 _err "Error when run post hook."
2446 return 1
2447 fi
2448 fi
2449}
2450
2451_on_issue_success() {
30c2d84c 2452 _debug _on_issue_success
b0070f03 2453 #run the post hook
4c2a3841 2454 if [ "$Le_PostHook" ]; then
b0070f03 2455 _info "Run post hook:'$Le_PostHook'"
2456 if ! (
2457 cd "$DOMAIN_PATH" && eval "$Le_PostHook"
4c2a3841 2458 ); then
b0070f03 2459 _err "Error when run post hook."
2460 return 1
2461 fi
2462 fi
4c2a3841 2463
b0070f03 2464 #run renew hook
4c2a3841 2465 if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ]; then
b0070f03 2466 _info "Run renew hook:'$Le_RenewHook'"
2467 if ! (
2468 cd "$DOMAIN_PATH" && eval "$Le_RenewHook"
4c2a3841 2469 ); then
b0070f03 2470 _err "Error when run renew hook."
2471 return 1
2472 fi
4c2a3841 2473 fi
2474
b0070f03 2475}
2476
eb59817e 2477updateaccount() {
2478 _initpath
2479 _regAccount
2480}
b0070f03 2481
eb59817e 2482registeraccount() {
57e58ce7 2483 _reg_length="$1"
eb59817e 2484 _initpath
57e58ce7 2485 _regAccount "$_reg_length"
eb59817e 2486}
d404e92d 2487
8a29fbc8 2488__calcAccountKeyHash() {
ca7202eb 2489 [ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH"
8a29fbc8 2490}
2491
57e58ce7 2492#keylength
d404e92d 2493_regAccount() {
2494 _initpath
57e58ce7 2495 _reg_length="$1"
4c2a3841 2496
5c48e139 2497 if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
08b6cf02 2498 mkdir -p "$CA_DIR"
5c48e139 2499 _info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
2500 mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
2501 fi
4c2a3841 2502
5c48e139 2503 if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then
08b6cf02 2504 mkdir -p "$CA_DIR"
5c48e139 2505 _info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH"
2506 mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH"
2507 fi
4c2a3841 2508
2509 if [ ! -f "$ACCOUNT_KEY_PATH" ]; then
2510 if ! _create_account_key "$_reg_length"; then
d404e92d 2511 _err "Create account key error."
2512 return 1
2513 fi
2514 fi
4c2a3841 2515
2516 if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
d404e92d 2517 return 1
2518 fi
2519
2520 _updateTos=""
2521 _reg_res="new-reg"
4c2a3841 2522 while true; do
d404e92d 2523 _debug AGREEMENT "$AGREEMENT"
4c2a3841 2524
d404e92d 2525 regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}'
2526
4c2a3841 2527 if [ "$ACCOUNT_EMAIL" ]; then
d404e92d 2528 regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}'
2529 fi
2530
4c2a3841 2531 if [ -z "$_updateTos" ]; then
d404e92d 2532 _info "Registering account"
2533
4c2a3841 2534 if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then
d404e92d 2535 _err "Register account Error: $response"
2536 return 1
2537 fi
2538
4c2a3841 2539 if [ "$code" = "" ] || [ "$code" = '201' ]; then
ca7202eb 2540 echo "$response" >"$ACCOUNT_JSON_PATH"
d404e92d 2541 _info "Registered"
4c2a3841 2542 elif [ "$code" = '409' ]; then
d404e92d 2543 _info "Already registered"
2544 else
2545 _err "Register account Error: $response"
2546 return 1
2547 fi
2548
4c2a3841 2549 _accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
d404e92d 2550 _debug "_accUri" "$_accUri"
d404e92d 2551
c2c8f320 2552 _tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')"
d404e92d 2553 _debug "_tos" "$_tos"
4c2a3841 2554 if [ -z "$_tos" ]; then
d404e92d 2555 _debug "Use default tos: $DEFAULT_AGREEMENT"
2556 _tos="$DEFAULT_AGREEMENT"
2557 fi
2558 if [ "$_tos" != "$AGREEMENT" ]; then
2559 _updateTos=1
2560 AGREEMENT="$_tos"
2561 _reg_res="reg"
2562 continue
2563 fi
4c2a3841 2564
d404e92d 2565 else
2566 _debug "Update tos: $_tos"
4c2a3841 2567 if ! _send_signed_request "$_accUri" "$regjson"; then
d404e92d 2568 _err "Update tos error."
2569 return 1
2570 fi
4c2a3841 2571 if [ "$code" = '202' ]; then
eb59817e 2572 _info "Update success."
4c2a3841 2573
8a29fbc8 2574 CA_KEY_HASH="$(__calcAccountKeyHash)"
2575 _debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
2576 _savecaconf CA_KEY_HASH "$CA_KEY_HASH"
d404e92d 2577 else
800e3f45 2578 _err "Update account error."
d404e92d 2579 return 1
2580 fi
2581 fi
2582 return 0
2583 done
2584
2585}
2586
a61fe418 2587# domain folder file
2588_findHook() {
2589 _hookdomain="$1"
2590 _hookcat="$2"
2591 _hookname="$3"
2592
c7b16249 2593 if [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname" ]; then
2594 d_api="$_SCRIPT_HOME/$_hookcat/$_hookname"
2595 elif [ -f "$_SCRIPT_HOME/$_hookcat/$_hookname.sh" ]; then
2596 d_api="$_SCRIPT_HOME/$_hookcat/$_hookname.sh"
4c2a3841 2597 elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname" ]; then
a61fe418 2598 d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname"
4c2a3841 2599 elif [ -f "$LE_WORKING_DIR/$_hookdomain/$_hookname.sh" ]; then
a61fe418 2600 d_api="$LE_WORKING_DIR/$_hookdomain/$_hookname.sh"
4c2a3841 2601 elif [ -f "$LE_WORKING_DIR/$_hookname" ]; then
a61fe418 2602 d_api="$LE_WORKING_DIR/$_hookname"
4c2a3841 2603 elif [ -f "$LE_WORKING_DIR/$_hookname.sh" ]; then
a61fe418 2604 d_api="$LE_WORKING_DIR/$_hookname.sh"
4c2a3841 2605 elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname" ]; then
a61fe418 2606 d_api="$LE_WORKING_DIR/$_hookcat/$_hookname"
4c2a3841 2607 elif [ -f "$LE_WORKING_DIR/$_hookcat/$_hookname.sh" ]; then
a61fe418 2608 d_api="$LE_WORKING_DIR/$_hookcat/$_hookname.sh"
2609 fi
2610
2611 printf "%s" "$d_api"
2612}
2613
f940b2a5 2614#domain
2615__get_domain_new_authz() {
2616 _gdnd="$1"
2617 _info "Getting new-authz for domain" "$_gdnd"
4c2a3841 2618
f940b2a5 2619 _Max_new_authz_retry_times=5
2620 _authz_i=0
4c2a3841 2621 while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do
efd96153 2622 _debug "Try new-authz for the $_authz_i time."
4c2a3841 2623 if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then
f940b2a5 2624 _err "Can not get domain new authz."
2625 return 1
2626 fi
5413bf87 2627 if _contains "$response" "No registration exists matching provided key"; then
2628 _err "It seems there is an error, but it's recovered now, please try again."
2629 _err "If you see this message for a second time, please report bug: $(__green "$PROJECT")"
2630 _clearcaconf "CA_KEY_HASH"
2631 break
2632 fi
4c2a3841 2633 if ! _contains "$response" "An error occurred while processing your request"; then
f940b2a5 2634 _info "The new-authz request is ok."
2635 break
2636 fi
2637 _authz_i="$(_math "$_authz_i" + 1)"
9e45ac93 2638 _info "The server is busy, Sleep $_authz_i to retry."
f940b2a5 2639 _sleep "$_authz_i"
4c2a3841 2640 done
f940b2a5 2641
4c2a3841 2642 if [ "$_authz_i" = "$_Max_new_authz_retry_times" ]; then
efd96153 2643 _err "new-authz retry reach the max $_Max_new_authz_retry_times times."
f940b2a5 2644 fi
4c2a3841 2645
2646 if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then
f940b2a5 2647 _err "new-authz error: $response"
2648 return 1
2649 fi
2650
2651}
2652
10afcaca 2653#webroot, domain domainlist keylength
4c3b3608 2654issue() {
4c2a3841 2655 if [ -z "$2" ]; then
43822d37 2656 _usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
4c3b3608 2657 return 1
2658 fi
2659 Le_Webroot="$1"
2660 Le_Domain="$2"
2661 Le_Alt="$3"
2aff36e7 2662 if _contains "$Le_Domain" ","; then
2663 Le_Domain=$(echo "$2,$3" | cut -d , -f 1)
2664 Le_Alt=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//")
2665 fi
4c3b3608 2666 Le_Keylength="$4"
2667 Le_RealCertPath="$5"
2668 Le_RealKeyPath="$6"
2669 Le_RealCACertPath="$7"
2670 Le_ReloadCmd="$8"
a63b05a9 2671 Le_RealFullChainPath="$9"
b0070f03 2672 Le_PreHook="${10}"
2673 Le_PostHook="${11}"
2674 Le_RenewHook="${12}"
0463b5d6 2675 Le_LocalAddress="${13}"
4c2a3841 2676
eccec5f6 2677 #remove these later.
4c2a3841 2678 if [ "$Le_Webroot" = "dns-cf" ]; then
eccec5f6 2679 Le_Webroot="dns_cf"
2680 fi
4c2a3841 2681 if [ "$Le_Webroot" = "dns-dp" ]; then
eccec5f6 2682 Le_Webroot="dns_dp"
2683 fi
4c2a3841 2684 if [ "$Le_Webroot" = "dns-cx" ]; then
eccec5f6 2685 Le_Webroot="dns_cx"
2686 fi
950172dc 2687 _debug "Using api: $API"
4c2a3841 2688
2689 if [ ! "$IS_RENEW" ]; then
ca7202eb 2690 _initpath "$Le_Domain" "$Le_Keylength"
43822d37 2691 mkdir -p "$DOMAIN_PATH"
2692 fi
eccec5f6 2693
4c2a3841 2694 if [ -f "$DOMAIN_CONF" ]; then
61623d22 2695 Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
a4270efa 2696 _debug Le_NextRenewTime "$Le_NextRenewTime"
95e06de5 2697 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
bb25febd 2698 _saved_domain=$(_readdomainconf Le_Domain)
2699 _debug _saved_domain "$_saved_domain"
2700 _saved_alt=$(_readdomainconf Le_Alt)
2701 _debug _saved_alt "$_saved_alt"
4c2a3841 2702 if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ]; then
bb25febd 2703 _info "Domains not changed."
2704 _info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")"
4c2a3841 2705 _info "Add '$(__red '--force')' to force to renew."
bb25febd 2706 return $RENEW_SKIP
2707 else
2708 _info "Domains have changed."
2709 fi
4c3b3608 2710 fi
2711 fi
96a46cfc 2712
4c2a3841 2713 _savedomainconf "Le_Domain" "$Le_Domain"
2714 _savedomainconf "Le_Alt" "$Le_Alt"
2715 _savedomainconf "Le_Webroot" "$Le_Webroot"
2716
2717 _savedomainconf "Le_PreHook" "$Le_PreHook"
2718 _savedomainconf "Le_PostHook" "$Le_PostHook"
2719 _savedomainconf "Le_RenewHook" "$Le_RenewHook"
2720
2721 if [ "$Le_LocalAddress" ]; then
2722 _savedomainconf "Le_LocalAddress" "$Le_LocalAddress"
72518d48 2723 else
2724 _cleardomainconf "Le_LocalAddress"
2725 fi
6ae0f7f5 2726
f6dcd989 2727 Le_API="$API"
2728 _savedomainconf "Le_API" "$Le_API"
4c2a3841 2729
2730 if [ "$Le_Alt" = "$NO_VALUE" ]; then
4c3b3608 2731 Le_Alt=""
2732 fi
4c2a3841 2733
2734 if [ "$Le_Keylength" = "$NO_VALUE" ]; then
d404e92d 2735 Le_Keylength=""
2736 fi
4c2a3841 2737
2738 if ! _on_before_issue; then
0463b5d6 2739 _err "_on_before_issue."
2740 return 1
4c3b3608 2741 fi
0463b5d6 2742
8a29fbc8 2743 _saved_account_key_hash="$(_readcaconf "CA_KEY_HASH")"
2744 _debug2 _saved_account_key_hash "$_saved_account_key_hash"
4c2a3841 2745
2746 if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
57e58ce7 2747 if ! _regAccount "$_accountkeylength"; then
8a29fbc8 2748 _on_issue_err
2749 return 1
2750 fi
57e58ce7 2751 else
2752 _debug "_saved_account_key_hash is not changed, skip register account."
166096dc 2753 fi
166096dc 2754
4c2a3841 2755 if [ -f "$CSR_PATH" ] && [ ! -f "$CERT_KEY_PATH" ]; then
10afcaca 2756 _info "Signing from existing CSR."
2757 else
2758 _key=$(_readdomainconf Le_Keylength)
2759 _debug "Read key length:$_key"
4c2a3841 2760 if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then
ca7202eb 2761 if ! createDomainKey "$Le_Domain" "$Le_Keylength"; then
10afcaca 2762 _err "Create domain key error."
2763 _clearup
b0070f03 2764 _on_issue_err
10afcaca 2765 return 1
2766 fi
2767 fi
2768
4c2a3841 2769 if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then
10afcaca 2770 _err "Create CSR error."
5ef501c5 2771 _clearup
b0070f03 2772 _on_issue_err
41e3eafa 2773 return 1
2774 fi
4c3b3608 2775 fi
10afcaca 2776
4c2a3841 2777 _savedomainconf "Le_Keylength" "$Le_Keylength"
2778
4c3b3608 2779 vlist="$Le_Vlist"
cae203be 2780
2781 _info "Getting domain auth token for each domain"
4c3b3608 2782 sep='#'
4c2a3841 2783 if [ -z "$vlist" ]; then
2784 alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ')
a63b05a9 2785 _index=1
2786 _currentRoot=""
4c2a3841 2787 for d in $alldomains; do
ca7202eb 2788 _info "Getting webroot for domain" "$d"
a63b05a9 2789 _w="$(echo $Le_Webroot | cut -d , -f $_index)"
0463b5d6 2790 _info _w "$_w"
4c2a3841 2791 if [ "$_w" ]; then
a63b05a9 2792 _currentRoot="$_w"
2793 fi
2794 _debug "_currentRoot" "$_currentRoot"
00a50605 2795 _index=$(_math $_index + 1)
4c2a3841 2796
a63b05a9 2797 vtype="$VTYPE_HTTP"
4c2a3841 2798 if _startswith "$_currentRoot" "dns"; then
a63b05a9 2799 vtype="$VTYPE_DNS"
2800 fi
4c2a3841 2801
2802 if [ "$_currentRoot" = "$W_TLS" ]; then
e22bcf7c 2803 vtype="$VTYPE_TLS"
2804 fi
c4d8fd83 2805
4c2a3841 2806 if ! __get_domain_new_authz "$d"; then
c4d8fd83 2807 _clearup
b0070f03 2808 _on_issue_err
c4d8fd83 2809 return 1
2810 fi
2811
4c2a3841 2812 if [ -z "$thumbprint" ]; then
2813 accountkey_json=$(printf "%s" "$jwk" | tr -d ' ')
11927a76 2814 thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _url_replace)
4c3b3608 2815 fi
2816
4c2a3841 2817 entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
4c3b3608 2818 _debug entry "$entry"
4c2a3841 2819 if [ -z "$entry" ]; then
19539575 2820 _err "Error, can not get domain token $d"
2821 _clearup
b0070f03 2822 _on_issue_err
19539575 2823 return 1
2824 fi
22ea4004 2825 token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
ca7202eb 2826 _debug token "$token"
4c2a3841 2827
2828 uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
ca7202eb 2829 _debug uri "$uri"
cae203be 2830
4c3b3608 2831 keyauthorization="$token.$thumbprint"
2832 _debug keyauthorization "$keyauthorization"
2833
95e06de5 2834 if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
d35bf517 2835 _info "$d is already verified, skip."
ca7202eb 2836 keyauthorization="$STATE_VERIFIED"
d35bf517 2837 _debug keyauthorization "$keyauthorization"
ec603bee 2838 fi
2839
a63b05a9 2840 dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
4c3b3608 2841 _debug dvlist "$dvlist"
4c2a3841 2842
4c3b3608 2843 vlist="$vlist$dvlist,"
2844
2845 done
2846
2847 #add entry
2848 dnsadded=""
4c2a3841 2849 ventries=$(echo "$vlist" | tr ',' ' ')
2850 for ventry in $ventries; do
ca7202eb 2851 d=$(echo "$ventry" | cut -d "$sep" -f 1)
2852 keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
2853 vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
2854 _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
ec603bee 2855
4c2a3841 2856 if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
ec603bee 2857 _info "$d is already verified, skip $vtype."
2858 continue
2859 fi
2860
4c2a3841 2861 if [ "$vtype" = "$VTYPE_DNS" ]; then
4c3b3608 2862 dnsadded='0'
2863 txtdomain="_acme-challenge.$d"
2864 _debug txtdomain "$txtdomain"
11927a76 2865 txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
4c3b3608 2866 _debug txt "$txt"
a61fe418 2867
0c538f75 2868 d_api="$(_findHook "$d" dnsapi "$_currentRoot")"
a61fe418 2869
4c3b3608 2870 _debug d_api "$d_api"
4c2a3841 2871
2872 if [ "$d_api" ]; then
4c3b3608 2873 _info "Found domain api file: $d_api"
2874 else
2875 _err "Add the following TXT record:"
0c538f75 2876 _err "Domain: '$(__green "$txtdomain")'"
2877 _err "TXT value: '$(__green "$txt")'"
4c3b3608 2878 _err "Please be aware that you prepend _acme-challenge. before your domain"
2879 _err "so the resulting subdomain will be: $txtdomain"
2880 continue
2881 fi
4c2a3841 2882
73b8b120 2883 (
ca7202eb 2884 if ! . "$d_api"; then
73b8b120 2885 _err "Load file $d_api error. Please check your api file and try again."
2886 return 1
2887 fi
4c2a3841 2888
158f22f7 2889 addcommand="${_currentRoot}_add"
ca7202eb 2890 if ! _exists "$addcommand"; then
73b8b120 2891 _err "It seems that your api file is not correct, it must have a function named: $addcommand"
2892 return 1
2893 fi
4c2a3841 2894
ca7202eb 2895 if ! $addcommand "$txtdomain" "$txt"; then
73b8b120 2896 _err "Error add txt for domain:$txtdomain"
2897 return 1
2898 fi
2899 )
4c2a3841 2900
2901 if [ "$?" != "0" ]; then
5ef501c5 2902 _clearup
b0070f03 2903 _on_issue_err
4c3b3608 2904 return 1
2905 fi
2906 dnsadded='1'
2907 fi
2908 done
2909
4c2a3841 2910 if [ "$dnsadded" = '0' ]; then
2911 _savedomainconf "Le_Vlist" "$vlist"
4c3b3608 2912 _debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
2913 _err "Please add the TXT records to the domains, and retry again."
5ef501c5 2914 _clearup
b0070f03 2915 _on_issue_err
4c3b3608 2916 return 1
2917 fi
4c2a3841 2918
4c3b3608 2919 fi
4c2a3841 2920
2921 if [ "$dnsadded" = '1' ]; then
2922 if [ -z "$Le_DNSSleep" ]; then
ca7202eb 2923 Le_DNSSleep="$DEFAULT_DNS_SLEEP"
0e38c60d 2924 else
4c2a3841 2925 _savedomainconf "Le_DNSSleep" "$Le_DNSSleep"
0e38c60d 2926 fi
2927
5fbc47eb 2928 _info "Sleep $(__green $Le_DNSSleep) seconds for the txt records to take effect"
ca7202eb 2929 _sleep "$Le_DNSSleep"
4c3b3608 2930 fi
4c2a3841 2931
4c3b3608 2932 _debug "ok, let's start to verify"
a63b05a9 2933
0463b5d6 2934 _ncIndex=1
4c2a3841 2935 ventries=$(echo "$vlist" | tr ',' ' ')
2936 for ventry in $ventries; do
ca7202eb 2937 d=$(echo "$ventry" | cut -d "$sep" -f 1)
2938 keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
2939 uri=$(echo "$ventry" | cut -d "$sep" -f 3)
2940 vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
2941 _currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
ec603bee 2942
4c2a3841 2943 if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
ec603bee 2944 _info "$d is already verified, skip $vtype."
2945 continue
2946 fi
2947
4c3b3608 2948 _info "Verifying:$d"
2949 _debug "d" "$d"
2950 _debug "keyauthorization" "$keyauthorization"
2951 _debug "uri" "$uri"
2952 removelevel=""
e22bcf7c 2953 token="$(printf "%s" "$keyauthorization" | cut -d '.' -f 1)"
a63b05a9 2954
2955 _debug "_currentRoot" "$_currentRoot"
2956
4c2a3841 2957 if [ "$vtype" = "$VTYPE_HTTP" ]; then
2958 if [ "$_currentRoot" = "$NO_VALUE" ]; then
4c3b3608 2959 _info "Standalone mode server"
4c2a3841 2960 _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")"
0463b5d6 2961 _ncIndex="$(_math $_ncIndex + 1)"
2962 _startserver "$keyauthorization" "$_ncaddr" &
4c2a3841 2963 if [ "$?" != "0" ]; then
5ef501c5 2964 _clearup
b0070f03 2965 _on_issue_err
6fc1447f 2966 return 1
2967 fi
4c3b3608 2968 serverproc="$!"
5dbf664a 2969 sleep 1
ca7202eb 2970 _debug serverproc "$serverproc"
6fc1447f 2971
4c3b3608 2972 else
4c2a3841 2973 if [ "$_currentRoot" = "apache" ]; then
6f930641 2974 wellknown_path="$ACME_DIR"
2975 else
a63b05a9 2976 wellknown_path="$_currentRoot/.well-known/acme-challenge"
4c2a3841 2977 if [ ! -d "$_currentRoot/.well-known" ]; then
6f930641 2978 removelevel='1'
4c2a3841 2979 elif [ ! -d "$_currentRoot/.well-known/acme-challenge" ]; then
6f930641 2980 removelevel='2'
2981 else
2982 removelevel='3'
2983 fi
4c3b3608 2984 fi
6f930641 2985
4c3b3608 2986 _debug wellknown_path "$wellknown_path"
6f930641 2987
4c3b3608 2988 _debug "writing token:$token to $wellknown_path/$token"
2989
2990 mkdir -p "$wellknown_path"
93fc48a2 2991
4c2a3841 2992 if ! printf "%s" "$keyauthorization" >"$wellknown_path/$token"; then
93fc48a2 2993 _err "$d:Can not write token to file : $wellknown_path/$token"
2994 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
2995 _clearup
2996 _on_issue_err
2997 return 1
2998 fi
2999
4c2a3841 3000 if [ ! "$usingApache" ]; then
44edb2bd 3001 if webroot_owner=$(_stat "$_currentRoot"); then
32fdc196 3002 _debug "Changing owner/group of .well-known to $webroot_owner"
ca7202eb 3003 chown -R "$webroot_owner" "$_currentRoot/.well-known"
32fdc196 3004 else
4c2a3841 3005 _debug "not chaning owner/group of webroot"
32fdc196 3006 fi
df886ffa 3007 fi
4c2a3841 3008
4c3b3608 3009 fi
4c2a3841 3010
3011 elif [ "$vtype" = "$VTYPE_TLS" ]; then
e22bcf7c 3012 #create A
3013 #_hash_A="$(printf "%s" $token | _digest "sha256" "hex" )"
3014 #_debug2 _hash_A "$_hash_A"
3015 #_x="$(echo $_hash_A | cut -c 1-32)"
3016 #_debug2 _x "$_x"
3017 #_y="$(echo $_hash_A | cut -c 33-64)"
3018 #_debug2 _y "$_y"
3019 #_SAN_A="$_x.$_y.token.acme.invalid"
3020 #_debug2 _SAN_A "$_SAN_A"
4c2a3841 3021
e22bcf7c 3022 #create B
0c538f75 3023 _hash_B="$(printf "%s" "$keyauthorization" | _digest "sha256" "hex")"
e22bcf7c 3024 _debug2 _hash_B "$_hash_B"
0c538f75 3025 _x="$(echo "$_hash_B" | cut -c 1-32)"
e22bcf7c 3026 _debug2 _x "$_x"
0c538f75 3027 _y="$(echo "$_hash_B" | cut -c 33-64)"
e22bcf7c 3028 _debug2 _y "$_y"
4c2a3841 3029
e22bcf7c 3030 #_SAN_B="$_x.$_y.ka.acme.invalid"
4c2a3841 3031
e22bcf7c 3032 _SAN_B="$_x.$_y.acme.invalid"
3033 _debug2 _SAN_B "$_SAN_B"
4c2a3841 3034
3035 _ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")"
0c538f75 3036 _ncIndex="$(_math "$_ncIndex" + 1)"
0463b5d6 3037 if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then
e22bcf7c 3038 _err "Start tls server error."
3039 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
3040 _clearup
b0070f03 3041 _on_issue_err
e22bcf7c 3042 return 1
3043 fi
4c3b3608 3044 fi
4c2a3841 3045
ca7202eb 3046 if ! _send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then
c4d8fd83 3047 _err "$d:Can not get challenge: $response"
3048 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
3049 _clearup
b0070f03 3050 _on_issue_err
c4d8fd83 3051 return 1
3052 fi
4c2a3841 3053
3054 if [ ! -z "$code" ] && [ ! "$code" = '202' ]; then
c60883ef 3055 _err "$d:Challenge error: $response"
a63b05a9 3056 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 3057 _clearup
b0070f03 3058 _on_issue_err
4c3b3608 3059 return 1
3060 fi
4c2a3841 3061
6fc1447f 3062 waittimes=0
4c2a3841 3063 if [ -z "$MAX_RETRY_TIMES" ]; then
6fc1447f 3064 MAX_RETRY_TIMES=30
3065 fi
4c2a3841 3066
3067 while true; do
0c538f75 3068 waittimes=$(_math "$waittimes" + 1)
4c2a3841 3069 if [ "$waittimes" -ge "$MAX_RETRY_TIMES" ]; then
6fc1447f 3070 _err "$d:Timeout"
3071 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
3072 _clearup
b0070f03 3073 _on_issue_err
6fc1447f 3074 return 1
3075 fi
4c2a3841 3076
5dbf664a 3077 _debug "sleep 2 secs to verify"
3078 sleep 2
4c3b3608 3079 _debug "checking"
44edb2bd 3080 response="$(_get "$uri")"
4c2a3841 3081 if [ "$?" != "0" ]; then
c60883ef 3082 _err "$d:Verify error:$response"
a63b05a9 3083 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 3084 _clearup
b0070f03 3085 _on_issue_err
4c3b3608 3086 return 1
3087 fi
9aaf36cd 3088 _debug2 original "$response"
4c2a3841 3089
3090 response="$(echo "$response" | _normalizeJson)"
7012b91f 3091 _debug2 response "$response"
4c2a3841 3092
3093 status=$(echo "$response" | _egrep_o '"status":"[^"]*' | cut -d : -f 2 | tr -d '"')
3094 if [ "$status" = "valid" ]; then
93f3098a 3095 _info "$(__green Success)"
ca7202eb 3096 _stopserver "$serverproc"
4c3b3608 3097 serverproc=""
a63b05a9 3098 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c2a3841 3099 break
4c3b3608 3100 fi
4c2a3841 3101
3102 if [ "$status" = "invalid" ]; then
3103 error="$(echo "$response" | tr -d "\r\n" | _egrep_o '"error":\{[^\}]*')"
3104 _debug2 error "$error"
3105 errordetail="$(echo "$error" | _egrep_o '"detail": *"[^"]*' | cut -d '"' -f 4)"
3106 _debug2 errordetail "$errordetail"
3107 if [ "$errordetail" ]; then
3108 _err "$d:Verify error:$errordetail"
3109 else
3110 _err "$d:Verify error:$error"
3111 fi
3112 if [ "$DEBUG" ]; then
3113 if [ "$vtype" = "$VTYPE_HTTP" ]; then
3114 _debug "Debug: get token url."
3115 _get "http://$d/.well-known/acme-challenge/$token" "" 1
3116 fi
3117 fi
a63b05a9 3118 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 3119 _clearup
b0070f03 3120 _on_issue_err
4c2a3841 3121 return 1
4c3b3608 3122 fi
4c2a3841 3123
3124 if [ "$status" = "pending" ]; then
4c3b3608 3125 _info "Pending"
3126 else
4c2a3841 3127 _err "$d:Verify error:$response"
a63b05a9 3128 _clearupwebbroot "$_currentRoot" "$removelevel" "$token"
4c3b3608 3129 _clearup
b0070f03 3130 _on_issue_err
4c3b3608 3131 return 1
3132 fi
4c2a3841 3133
4c3b3608 3134 done
4c2a3841 3135
4c3b3608 3136 done
3137
3138 _clearup
3139 _info "Verify finished, start to sign."
11927a76 3140 der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)"
4c2a3841 3141
3142 if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then
c4d8fd83 3143 _err "Sign failed."
b0070f03 3144 _on_issue_err
c4d8fd83 3145 return 1
3146 fi
4c2a3841 3147
d404e92d 3148 _rcert="$response"
0c538f75 3149 Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
4c2a3841 3150 _savedomainconf "Le_LinkCert" "$Le_LinkCert"
4c3b3608 3151
4c2a3841 3152 if [ "$Le_LinkCert" ]; then
3153 echo "$BEGIN_CERT" >"$CERT_PATH"
4c3b3608 3154
72518d48 3155 #if ! _get "$Le_LinkCert" | _base64 "multiline" >> "$CERT_PATH" ; then
3156 # _debug "Get cert failed. Let's try last response."
3157 # printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >> "$CERT_PATH"
3158 #fi
4c2a3841 3159
3160 if ! printf -- "%s" "$_rcert" | _dbase64 "multiline" | _base64 "multiline" >>"$CERT_PATH"; then
72518d48 3161 _debug "Try cert link."
4c2a3841 3162 _get "$Le_LinkCert" | _base64 "multiline" >>"$CERT_PATH"
d404e92d 3163 fi
3164
4c2a3841 3165 echo "$END_CERT" >>"$CERT_PATH"
43822d37 3166 _info "$(__green "Cert success.")"
4c3b3608 3167 cat "$CERT_PATH"
5980ebc7 3168
4c2a3841 3169 _info "Your cert is in $(__green " $CERT_PATH ")"
3170
3171 if [ -f "$CERT_KEY_PATH" ]; then
3172 _info "Your cert key is in $(__green " $CERT_KEY_PATH ")"
5980ebc7 3173 fi
3174
caf1fc10 3175 cp "$CERT_PATH" "$CERT_FULLCHAIN_PATH"
281aa349 3176
4c2a3841 3177 if [ ! "$USER_PATH" ] || [ ! "$IN_CRON" ]; then
281aa349 3178 USER_PATH="$PATH"
3179 _saveaccountconf "USER_PATH" "$USER_PATH"
3180 fi
4c3b3608 3181 fi
4c3b3608 3182
4c2a3841 3183 if [ -z "$Le_LinkCert" ]; then
0c538f75 3184 response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)"
4c2a3841 3185 _err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')"
b0070f03 3186 _on_issue_err
4c3b3608 3187 return 1
3188 fi
4c2a3841 3189
3190 _cleardomainconf "Le_Vlist"
3191
0c538f75 3192 Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>')
4c2a3841 3193 if ! _contains "$Le_LinkIssuer" ":"; then
fac1e367 3194 Le_LinkIssuer="$API$Le_LinkIssuer"
3195 fi
4c2a3841 3196
3197 _savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
3198
3199 if [ "$Le_LinkIssuer" ]; then
3200 echo "$BEGIN_CERT" >"$CA_CERT_PATH"
3201 _get "$Le_LinkIssuer" | _base64 "multiline" >>"$CA_CERT_PATH"
3202 echo "$END_CERT" >>"$CA_CERT_PATH"
3203 _info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")"
3204 cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH"
3205 _info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")"
4c3b3608 3206 fi
4c2a3841 3207
3aae1ae3 3208 Le_CertCreateTime=$(_time)
4c2a3841 3209 _savedomainconf "Le_CertCreateTime" "$Le_CertCreateTime"
3210
3211 Le_CertCreateTimeStr=$(date -u)
3212 _savedomainconf "Le_CertCreateTimeStr" "$Le_CertCreateTimeStr"
3213
3214 if [ -z "$Le_RenewalDays" ] || [ "$Le_RenewalDays" -lt "0" ] || [ "$Le_RenewalDays" -gt "$MAX_RENEW" ]; then
ca7202eb 3215 Le_RenewalDays="$MAX_RENEW"
054cb72e 3216 else
4c2a3841 3217 _savedomainconf "Le_RenewalDays" "$Le_RenewalDays"
13d7cae9 3218 fi
4c2a3841 3219
3220 if [ "$CA_BUNDLE" ]; then
78009539
PS
3221 _saveaccountconf CA_BUNDLE "$CA_BUNDLE"
3222 else
3223 _clearaccountconf "CA_BUNDLE"
3224 fi
3225
4c2a3841 3226 if [ "$HTTPS_INSECURE" ]; then
fac1e367 3227 _saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE"
3228 else
4c2a3841 3229 _clearaccountconf "HTTPS_INSECURE"
13d7cae9 3230 fi
00a50605 3231
4c2a3841 3232 if [ "$Le_Listen_V4" ]; then
3233 _savedomainconf "Le_Listen_V4" "$Le_Listen_V4"
50827188 3234 _cleardomainconf Le_Listen_V6
4c2a3841 3235 elif [ "$Le_Listen_V6" ]; then
3236 _savedomainconf "Le_Listen_V6" "$Le_Listen_V6"
50827188 3237 _cleardomainconf Le_Listen_V4
3238 fi
f6dcd989 3239
ca7202eb 3240 Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60)
4c2a3841 3241
ca7202eb 3242 Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime")
4c2a3841 3243 _savedomainconf "Le_NextRenewTimeStr" "$Le_NextRenewTimeStr"
3244
ca7202eb 3245 Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
4c2a3841 3246 _savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
f6dcd989 3247
b0070f03 3248 _on_issue_success
4c3b3608 3249
4c2a3841 3250 if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ]; then
43822d37 3251 _installcert
01f54558 3252 fi
4c0d3f1b 3253
4c3b3608 3254}
3255
43822d37 3256#domain [isEcc]
4c3b3608 3257renew() {
3258 Le_Domain="$1"
4c2a3841 3259 if [ -z "$Le_Domain" ]; then
43822d37 3260 _usage "Usage: $PROJECT_ENTRY --renew -d domain.com [--ecc]"
4c3b3608 3261 return 1
3262 fi
3263
43822d37 3264 _isEcc="$2"
3265
e799ef29 3266 _initpath "$Le_Domain" "$_isEcc"
43822d37 3267
e2053b22 3268 _info "$(__green "Renew: '$Le_Domain'")"
4c2a3841 3269 if [ ! -f "$DOMAIN_CONF" ]; then
43822d37 3270 _info "'$Le_Domain' is not a issued domain, skip."
4c2a3841 3271 return 0
4c3b3608 3272 fi
4c2a3841 3273
3274 if [ "$Le_RenewalDays" ]; then
1e6b68f5 3275 _savedomainconf Le_RenewalDays "$Le_RenewalDays"
3276 fi
3277
8663fb7e 3278 . "$DOMAIN_CONF"
4c2a3841 3279
3280 if [ "$Le_API" ]; then
5c48e139 3281 API="$Le_API"
c4236e58 3282 #reload ca configs
3283 ACCOUNT_KEY_PATH=""
3284 ACCOUNT_JSON_PATH=""
3285 CA_CONF=""
3286 _debug3 "initpath again."
3287 _initpath "$Le_Domain" "$_isEcc"
5c48e139 3288 fi
4c2a3841 3289
3290 if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
e2053b22 3291 _info "Skip, Next renewal time is: $(__green "$Le_NextRenewTimeStr")"
3292 _info "Add '$(__red '--force')' to force to renew."
e799ef29 3293 return "$RENEW_SKIP"
4c3b3608 3294 fi
4c2a3841 3295
4c3b3608 3296 IS_RENEW="1"
0463b5d6 3297 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" "$Le_LocalAddress"
e799ef29 3298 res="$?"
4c2a3841 3299 if [ "$res" != "0" ]; then
e799ef29 3300 return "$res"
a61fe418 3301 fi
4c2a3841 3302
3303 if [ "$Le_DeployHook" ]; then
e799ef29 3304 deploy "$Le_Domain" "$Le_DeployHook" "$Le_Keylength"
3305 res="$?"
a61fe418 3306 fi
4c2a3841 3307
4c3b3608 3308 IS_RENEW=""
3309
e799ef29 3310 return "$res"
4c3b3608 3311}
3312
cc179731 3313#renewAll [stopRenewOnError]
4c3b3608 3314renewAll() {
3315 _initpath
cc179731 3316 _stopRenewOnError="$1"
3317 _debug "_stopRenewOnError" "$_stopRenewOnError"
3318 _ret="0"
43822d37 3319
e591d5cf 3320 for di in "${CERT_HOME}"/*.*/; do
3321 _debug di "$di"
44483dba 3322 if ! [ -d "$di" ]; then
3498a585 3323 _debug "Not directory, skip: $di"
3324 continue
3325 fi
e591d5cf 3326 d=$(basename "$di")
201aa244 3327 _debug d "$d"
43822d37 3328 (
201aa244 3329 if _endswith "$d" "$ECC_SUFFIX"; then
3330 _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2)
3331 d=$(echo "$d" | cut -d "$ECC_SEP" -f 1)
43822d37 3332 fi
3333 renew "$d" "$_isEcc"
4d2f38b0 3334 )
cc179731 3335 rc="$?"
3336 _debug "Return code: $rc"
4c2a3841 3337 if [ "$rc" != "0" ]; then
3338 if [ "$rc" = "$RENEW_SKIP" ]; then
cc179731 3339 _info "Skipped $d"
4c2a3841 3340 elif [ "$_stopRenewOnError" ]; then
cc179731 3341 _err "Error renew $d, stop now."
201aa244 3342 return "$rc"
cc179731 3343 else
3344 _ret="$rc"
3345 _err "Error renew $d, Go ahead to next one."
3346 fi
3347 fi
4c3b3608 3348 done
201aa244 3349 return "$_ret"
4c3b3608 3350}
3351
10afcaca 3352#csr webroot
4c2a3841 3353signcsr() {
10afcaca 3354 _csrfile="$1"
3355 _csrW="$2"
3356 if [ -z "$_csrfile" ] || [ -z "$_csrW" ]; then
3357 _usage "Usage: $PROJECT_ENTRY --signcsr --csr mycsr.csr -w /path/to/webroot/a.com/ "
3358 return 1
3359 fi
3360
3361 _initpath
3362
3363 _csrsubj=$(_readSubjectFromCSR "$_csrfile")
4c2a3841 3364 if [ "$?" != "0" ]; then
10afcaca 3365 _err "Can not read subject from csr: $_csrfile"
3366 return 1
3367 fi
ad752b31 3368 _debug _csrsubj "$_csrsubj"
10afcaca 3369
3370 _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
4c2a3841 3371 if [ "$?" != "0" ]; then
10afcaca 3372 _err "Can not read domain list from csr: $_csrfile"
3373 return 1
3374 fi
3375 _debug "_csrdomainlist" "$_csrdomainlist"
4c2a3841 3376
3377 if [ -z "$_csrsubj" ]; then
ad752b31 3378 _csrsubj="$(_getfield "$_csrdomainlist" 1)"
3379 _debug _csrsubj "$_csrsubj"
3380 _csrdomainlist="$(echo "$_csrdomainlist" | cut -d , -f 2-)"
3381 _debug "_csrdomainlist" "$_csrdomainlist"
3382 fi
4c2a3841 3383
3384 if [ -z "$_csrsubj" ]; then
ad752b31 3385 _err "Can not read subject from csr: $_csrfile"
3386 return 1
3387 fi
4c2a3841 3388
10afcaca 3389 _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile")
4c2a3841 3390 if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then
10afcaca 3391 _err "Can not read key length from csr: $_csrfile"
3392 return 1
3393 fi
4c2a3841 3394
10afcaca 3395 _initpath "$_csrsubj" "$_csrkeylength"
3396 mkdir -p "$DOMAIN_PATH"
4c2a3841 3397
10afcaca 3398 _info "Copy csr to: $CSR_PATH"
3399 cp "$_csrfile" "$CSR_PATH"
4c2a3841 3400
10afcaca 3401 issue "$_csrW" "$_csrsubj" "$_csrdomainlist" "$_csrkeylength"
4c2a3841 3402
10afcaca 3403}
3404
3405showcsr() {
4c2a3841 3406 _csrfile="$1"
10afcaca 3407 _csrd="$2"
3408 if [ -z "$_csrfile" ] && [ -z "$_csrd" ]; then
3409 _usage "Usage: $PROJECT_ENTRY --showcsr --csr mycsr.csr"
3410 return 1
3411 fi
3412
3413 _initpath
4c2a3841 3414
10afcaca 3415 _csrsubj=$(_readSubjectFromCSR "$_csrfile")
4c2a3841 3416 if [ "$?" != "0" ] || [ -z "$_csrsubj" ]; then
10afcaca 3417 _err "Can not read subject from csr: $_csrfile"
3418 return 1
3419 fi
4c2a3841 3420
10afcaca 3421 _info "Subject=$_csrsubj"
3422
3423 _csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
4c2a3841 3424 if [ "$?" != "0" ]; then
10afcaca 3425 _err "Can not read domain list from csr: $_csrfile"
3426 return 1
3427 fi
3428 _debug "_csrdomainlist" "$_csrdomainlist"
3429
3430 _info "SubjectAltNames=$_csrdomainlist"
3431
10afcaca 3432 _csrkeylength=$(_readKeyLengthFromCSR "$_csrfile")
4c2a3841 3433 if [ "$?" != "0" ] || [ -z "$_csrkeylength" ]; then
10afcaca 3434 _err "Can not read key length from csr: $_csrfile"
3435 return 1
3436 fi
3437 _info "KeyLength=$_csrkeylength"
3438}
3439
6d7eda3e 3440list() {
22ea4004 3441 _raw="$1"
6d7eda3e 3442 _initpath
4c2a3841 3443
dcf4f8f6 3444 _sep="|"
4c2a3841 3445 if [ "$_raw" ]; then
d5ec5f80 3446 printf "%s\n" "Main_Domain${_sep}KeyLength${_sep}SAN_Domains${_sep}Created${_sep}Renew"
e591d5cf 3447 for di in "${CERT_HOME}"/*.*/; do
44483dba 3448 if ! [ -d "$di" ]; then
3498a585 3449 _debug "Not directory, skip: $di"
3450 continue
3451 fi
e591d5cf 3452 d=$(basename "$di")
201aa244 3453 _debug d "$d"
dcf4f8f6 3454 (
201aa244 3455 if _endswith "$d" "$ECC_SUFFIX"; then
3456 _isEcc=$(echo "$d" | cut -d "$ECC_SEP" -f 2)
3457 d=$(echo "$d" | cut -d "$ECC_SEP" -f 1)
43822d37 3458 fi
e591d5cf 3459 _initpath "$d" "$_isEcc"
4c2a3841 3460 if [ -f "$DOMAIN_CONF" ]; then
dcf4f8f6 3461 . "$DOMAIN_CONF"
d5ec5f80 3462 printf "%s\n" "$Le_Domain${_sep}\"$Le_Keylength\"${_sep}$Le_Alt${_sep}$Le_CertCreateTimeStr${_sep}$Le_NextRenewTimeStr"
dcf4f8f6 3463 fi
3464 )
3465 done
3466 else
4c2a3841 3467 if _exists column; then
22ea4004 3468 list "raw" | column -t -s "$_sep"
3469 else
43822d37 3470 list "raw" | tr "$_sep" '\t'
22ea4004 3471 fi
dcf4f8f6 3472 fi
6d7eda3e 3473
6d7eda3e 3474}
3475
a61fe418 3476deploy() {
3477 Le_Domain="$1"
3478 Le_DeployHook="$2"
3479 _isEcc="$3"
4c2a3841 3480 if [ -z "$Le_DeployHook" ]; then
a61fe418 3481 _usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] "
3482 return 1
3483 fi
3484
e591d5cf 3485 _initpath "$Le_Domain" "$_isEcc"
4c2a3841 3486 if [ ! -d "$DOMAIN_PATH" ]; then
a61fe418 3487 _err "Domain is not valid:'$Le_Domain'"
3488 return 1
3489 fi
3490
e591d5cf 3491 _deployApi="$(_findHook "$Le_Domain" deploy "$Le_DeployHook")"
4c2a3841 3492 if [ -z "$_deployApi" ]; then
a61fe418 3493 _err "The deploy hook $Le_DeployHook is not found."
3494 return 1
3495 fi
3496 _debug _deployApi "$_deployApi"
4c2a3841 3497
a61fe418 3498 _savedomainconf Le_DeployHook "$Le_DeployHook"
4c2a3841 3499
a61fe418 3500 if ! (
e591d5cf 3501 if ! . "$_deployApi"; then
a61fe418 3502 _err "Load file $_deployApi error. Please check your api file and try again."
3503 return 1
3504 fi
4c2a3841 3505
a61fe418 3506 d_command="${Le_DeployHook}_deploy"
e591d5cf 3507 if ! _exists "$d_command"; then
a61fe418 3508 _err "It seems that your api file is not correct, it must have a function named: $d_command"
3509 return 1
3510 fi
4c2a3841 3511
e591d5cf 3512 if ! $d_command "$Le_Domain" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then
a61fe418 3513 _err "Error deploy for domain:$Le_Domain"
3514 _on_issue_err
3515 return 1
3516 fi
4c2a3841 3517 ); then
a61fe418 3518 _err "Deploy error."
3519 return 1
3520 else
3521 _info "$(__green Success)"
3522 fi
4c2a3841 3523
a61fe418 3524}
3525
4c3b3608 3526installcert() {
3527 Le_Domain="$1"
4c2a3841 3528 if [ -z "$Le_Domain" ]; then
43822d37 3529 _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 3530 return 1
3531 fi
3532
3533 Le_RealCertPath="$2"
3534 Le_RealKeyPath="$3"
3535 Le_RealCACertPath="$4"
3536 Le_ReloadCmd="$5"
a63b05a9 3537 Le_RealFullChainPath="$6"
43822d37 3538 _isEcc="$7"
3539
4bd31f49 3540 _initpath "$Le_Domain" "$_isEcc"
4c2a3841 3541 if [ ! -d "$DOMAIN_PATH" ]; then
43822d37 3542 _err "Domain is not valid:'$Le_Domain'"
3543 return 1
3544 fi
3545
3546 _installcert
3547}
4c3b3608 3548
43822d37 3549_installcert() {
4c2a3841 3550 _savedomainconf "Le_RealCertPath" "$Le_RealCertPath"
3551 _savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath"
3552 _savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath"
3553 _savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd"
3554 _savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath"
4c3b3608 3555
4c2a3841 3556 if [ "$Le_RealCertPath" = "$NO_VALUE" ]; then
4d2f38b0 3557 Le_RealCertPath=""
3558 fi
4c2a3841 3559 if [ "$Le_RealKeyPath" = "$NO_VALUE" ]; then
4d2f38b0 3560 Le_RealKeyPath=""
3561 fi
4c2a3841 3562 if [ "$Le_RealCACertPath" = "$NO_VALUE" ]; then
4d2f38b0 3563 Le_RealCACertPath=""
3564 fi
4c2a3841 3565 if [ "$Le_ReloadCmd" = "$NO_VALUE" ]; then
4d2f38b0 3566 Le_ReloadCmd=""
3567 fi
4c2a3841 3568 if [ "$Le_RealFullChainPath" = "$NO_VALUE" ]; then
4d2f38b0 3569 Le_RealFullChainPath=""
3570 fi
4c2a3841 3571
4c2a3841 3572 if [ "$Le_RealCertPath" ]; then
4bd31f49 3573
4d2f38b0 3574 _info "Installing cert to:$Le_RealCertPath"
4c2a3841 3575 if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then
ff3bce32 3576 cp "$Le_RealCertPath" "$Le_RealCertPath".bak
4c3b3608 3577 fi
4c2a3841 3578 cat "$CERT_PATH" >"$Le_RealCertPath"
4c3b3608 3579 fi
4c2a3841 3580
3581 if [ "$Le_RealCACertPath" ]; then
4bd31f49 3582
4d2f38b0 3583 _info "Installing CA to:$Le_RealCACertPath"
4c2a3841 3584 if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ]; then
3585 echo "" >>"$Le_RealCACertPath"
3586 cat "$CA_CERT_PATH" >>"$Le_RealCACertPath"
4c3b3608 3587 else
4c2a3841 3588 if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then
ff3bce32 3589 cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak
78552b18 3590 fi
4c2a3841 3591 cat "$CA_CERT_PATH" >"$Le_RealCACertPath"
4c3b3608 3592 fi
3593 fi
3594
4c2a3841 3595 if [ "$Le_RealKeyPath" ]; then
4c3b3608 3596
4d2f38b0 3597 _info "Installing key to:$Le_RealKeyPath"
4c2a3841 3598 if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then
ff3bce32 3599 cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak
4c3b3608 3600 fi
4c2a3841 3601 cat "$CERT_KEY_PATH" >"$Le_RealKeyPath"
4c3b3608 3602 fi
4c2a3841 3603
3604 if [ "$Le_RealFullChainPath" ]; then
4bd31f49 3605
4d2f38b0 3606 _info "Installing full chain to:$Le_RealFullChainPath"
4c2a3841 3607 if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then
ff3bce32 3608 cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak
a63b05a9 3609 fi
4c2a3841 3610 cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath"
3611 fi
4c3b3608 3612
4c2a3841 3613 if [ "$Le_ReloadCmd" ]; then
4c3b3608 3614 _info "Run Le_ReloadCmd: $Le_ReloadCmd"
25555b8c 3615 if (
839bf0e2 3616 export CERT_PATH
3617 export CERT_KEY_PATH
3618 export CA_CERT_PATH
3619 export CERT_FULLCHAIN_PATH
3620 cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd"
3621 ); then
43822d37 3622 _info "$(__green "Reload success")"
4d2f38b0 3623 else
3624 _err "Reload error for :$Le_Domain"
3625 fi
3626 fi
3627
4c3b3608 3628}
3629
27dbe77f 3630#confighome
4c3b3608 3631installcronjob() {
27dbe77f 3632 _c_home="$1"
4c3b3608 3633 _initpath
4c2a3841 3634 if ! _exists "crontab"; then
77546ea5 3635 _err "crontab doesn't exist, so, we can not install cron jobs."
3636 _err "All your certs will not be renewed automatically."
a7b7355d 3637 _err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
77546ea5 3638 return 1
3639 fi
3640
4c3b3608 3641 _info "Installing cron job"
4c2a3841 3642 if ! crontab -l | grep "$PROJECT_ENTRY --cron"; then
3643 if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then
a7b7355d 3644 lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
4c3b3608 3645 else
a7b7355d 3646 _err "Can not install cronjob, $PROJECT_ENTRY not found."
4c3b3608 3647 return 1
3648 fi
27dbe77f 3649
3650 if [ "$_c_home" ]; then
80941f84 3651 _c_entry="--config-home \"$_c_home\" "
27dbe77f 3652 fi
32b3717c 3653 _t=$(_time)
3654 random_minute=$(_math $_t % 60)
e2c939fb 3655 if _exists uname && uname -a | grep SunOS >/dev/null; then
4c2a3841 3656 crontab -l | {
3657 cat
0533bde9 3658 echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
4c2a3841 3659 } | crontab --
22ea4004 3660 else
4c2a3841 3661 crontab -l | {
3662 cat
0533bde9 3663 echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
4c2a3841 3664 } | crontab -
22ea4004 3665 fi
4c3b3608 3666 fi
4c2a3841 3667 if [ "$?" != "0" ]; then
4c3b3608 3668 _err "Install cron job failed. You need to manually renew your certs."
3669 _err "Or you can add cronjob by yourself:"
a7b7355d 3670 _err "$lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
4c3b3608 3671 return 1
3672 fi
3673}
3674
3675uninstallcronjob() {
4c2a3841 3676 if ! _exists "crontab"; then
37db5b81 3677 return
3678 fi
4c3b3608 3679 _info "Removing cron job"
a7b7355d 3680 cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")"
4c2a3841 3681 if [ "$cr" ]; then
3682 if _exists uname && uname -a | grep solaris >/dev/null; then
22ea4004 3683 crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab --
3684 else
3685 crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -
3686 fi
a7b7355d 3687 LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')"
4c3b3608 3688 _info LE_WORKING_DIR "$LE_WORKING_DIR"
27dbe77f 3689 if _contains "$cr" "--config-home"; then
f5b546b3 3690 LE_CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')"
3691 _debug LE_CONFIG_HOME "$LE_CONFIG_HOME"
27dbe77f 3692 fi
4c2a3841 3693 fi
4c3b3608 3694 _initpath
a7b7355d 3695
4c3b3608 3696}
3697
6cb415f5 3698revoke() {
3699 Le_Domain="$1"
4c2a3841 3700 if [ -z "$Le_Domain" ]; then
78f0201d 3701 _usage "Usage: $PROJECT_ENTRY --revoke -d domain.com [--ecc]"
6cb415f5 3702 return 1
3703 fi
4c2a3841 3704
43822d37 3705 _isEcc="$2"
3706
c4a375b3 3707 _initpath "$Le_Domain" "$_isEcc"
4c2a3841 3708 if [ ! -f "$DOMAIN_CONF" ]; then
6cb415f5 3709 _err "$Le_Domain is not a issued domain, skip."
4c2a3841 3710 return 1
6cb415f5 3711 fi
4c2a3841 3712
3713 if [ ! -f "$CERT_PATH" ]; then
6cb415f5 3714 _err "Cert for $Le_Domain $CERT_PATH is not found, skip."
3715 return 1
3716 fi
6cb415f5 3717
11927a76 3718 cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)"
4c2a3841 3719
3720 if [ -z "$cert" ]; then
6cb415f5 3721 _err "Cert for $Le_Domain is empty found, skip."
3722 return 1
3723 fi
4c2a3841 3724
6cb415f5 3725 data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
3726 uri="$API/acme/revoke-cert"
3727
4c2a3841 3728 if [ -f "$CERT_KEY_PATH" ]; then
1befee5a 3729 _info "Try domain key first."
c4a375b3 3730 if _send_signed_request "$uri" "$data" "" "$CERT_KEY_PATH"; then
4c2a3841 3731 if [ -z "$response" ]; then
1befee5a 3732 _info "Revoke success."
c4a375b3 3733 rm -f "$CERT_PATH"
1befee5a 3734 return 0
4c2a3841 3735 else
1befee5a 3736 _err "Revoke error by domain key."
3737 _err "$response"
3738 fi
6cb415f5 3739 fi
4c2a3841 3740 else
1befee5a 3741 _info "Domain key file doesn't exists."
6cb415f5 3742 fi
6cb415f5 3743
1befee5a 3744 _info "Try account key."
6cb415f5 3745
c4a375b3 3746 if _send_signed_request "$uri" "$data" "" "$ACCOUNT_KEY_PATH"; then
4c2a3841 3747 if [ -z "$response" ]; then
6cb415f5 3748 _info "Revoke success."
c4a375b3 3749 rm -f "$CERT_PATH"
6cb415f5 3750 return 0
4c2a3841 3751 else
6cb415f5 3752 _err "Revoke error."
c9c31c04 3753 _debug "$response"
6cb415f5 3754 fi
3755 fi
3756 return 1
3757}
4c3b3608 3758
78f0201d 3759#domain ecc
3760remove() {
3761 Le_Domain="$1"
3762 if [ -z "$Le_Domain" ]; then
3763 _usage "Usage: $PROJECT_ENTRY --remove -d domain.com [--ecc]"
3764 return 1
3765 fi
3766
3767 _isEcc="$2"
3768
3769 _initpath "$Le_Domain" "$_isEcc"
3770 _removed_conf="$DOMAIN_CONF.removed"
3771 if [ ! -f "$DOMAIN_CONF" ]; then
3772 if [ -f "$_removed_conf" ]; then
3773 _err "$Le_Domain is already removed, You can remove the folder by yourself: $DOMAIN_PATH"
3774 else
3775 _err "$Le_Domain is not a issued domain, skip."
3776 fi
3777 return 1
3778 fi
3779
3780 if mv "$DOMAIN_CONF" "$_removed_conf"; then
68aea3af 3781 _info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH)"
78f0201d 3782 _info "You can remove them by yourself."
3783 return 0
3784 else
3785 _err "Remove $Le_Domain failed."
3786 return 1
3787 fi
3788}
3789
0c00e870 3790#domain vtype
3791_deactivate() {
3792 _d_domain="$1"
3793 _d_type="$2"
3794 _initpath
4c2a3841 3795
0c00e870 3796 _d_i=0
3797 _d_max_retry=9
4c2a3841 3798 while [ "$_d_i" -lt "$_d_max_retry" ]; do
0407c4e0 3799 _info "Deactivate: $_d_domain"
0c00e870 3800 _d_i="$(_math $_d_i + 1)"
4c2a3841 3801
3802 if ! __get_domain_new_authz "$_d_domain"; then
f940b2a5 3803 _err "Can not get domain new authz token."
0c00e870 3804 return 1
3805 fi
4c2a3841 3806
c2c8f320 3807 authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
3f4513b3 3808 _debug "authzUri" "$authzUri"
0c00e870 3809
4c2a3841 3810 if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then
0c00e870 3811 _err "new-authz error: $response"
3812 return 1
3813 fi
4c2a3841 3814
947d14ff 3815 entry="$(printf "%s\n" "$response" | _egrep_o '{"type":"[^"]*","status":"valid","uri"[^}]*')"
0c00e870 3816 _debug entry "$entry"
4c2a3841 3817
3818 if [ -z "$entry" ]; then
fb2029e7 3819 _info "No more valid entry found."
0c00e870 3820 break
3821 fi
4c2a3841 3822
0c00e870 3823 _vtype="$(printf "%s\n" "$entry" | _egrep_o '"type": *"[^"]*"' | cut -d : -f 2 | tr -d '"')"
c4a375b3 3824 _debug _vtype "$_vtype"
0c00e870 3825 _info "Found $_vtype"
3826
4c2a3841 3827 uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
c4a375b3 3828 _debug uri "$uri"
4c2a3841 3829
3830 if [ "$_d_type" ] && [ "$_d_type" != "$_vtype" ]; then
0c00e870 3831 _info "Skip $_vtype"
3832 continue
3833 fi
4c2a3841 3834
0c00e870 3835 _info "Deactivate: $_vtype"
4c2a3841 3836
3837 if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}"; then
0c00e870 3838 _err "Can not deactivate $_vtype."
3839 return 1
3840 fi
4c2a3841 3841
fb2029e7 3842 _info "Deactivate: $_vtype success."
4c2a3841 3843
0c00e870 3844 done
3845 _debug "$_d_i"
4c2a3841 3846 if [ "$_d_i" -lt "$_d_max_retry" ]; then
0c00e870 3847 _info "Deactivated success!"
3848 else
3849 _err "Deactivate failed."
3850 fi
3851
3852}
3853
3854deactivate() {
3f4513b3 3855 _d_domain_list="$1"
0c00e870 3856 _d_type="$2"
3857 _initpath
3f4513b3 3858 _debug _d_domain_list "$_d_domain_list"
4c2a3841 3859 if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then
3f4513b3 3860 _usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]"
0c00e870 3861 return 1
3862 fi
4c2a3841 3863 for _d_dm in $(echo "$_d_domain_list" | tr ',' ' '); do
3864 if [ -z "$_d_dm" ] || [ "$_d_dm" = "$NO_VALUE" ]; then
3f4513b3 3865 continue
3866 fi
c4a375b3 3867 if ! _deactivate "$_d_dm" "$_d_type"; then
86c017ec 3868 return 1
3869 fi
3f4513b3 3870 done
0c00e870 3871}
3872
4c3b3608 3873# Detect profile file if not specified as environment variable
3874_detect_profile() {
4c2a3841 3875 if [ -n "$PROFILE" -a -f "$PROFILE" ]; then
4c3b3608 3876 echo "$PROFILE"
3877 return
3878 fi
3879
4c3b3608 3880 DETECTED_PROFILE=''
4c3b3608 3881 SHELLTYPE="$(basename "/$SHELL")"
3882
4c2a3841 3883 if [ "$SHELLTYPE" = "bash" ]; then
3884 if [ -f "$HOME/.bashrc" ]; then
4c3b3608 3885 DETECTED_PROFILE="$HOME/.bashrc"
4c2a3841 3886 elif [ -f "$HOME/.bash_profile" ]; then
4c3b3608 3887 DETECTED_PROFILE="$HOME/.bash_profile"
3888 fi
4c2a3841 3889 elif [ "$SHELLTYPE" = "zsh" ]; then
4c3b3608 3890 DETECTED_PROFILE="$HOME/.zshrc"
3891 fi
3892
4c2a3841 3893 if [ -z "$DETECTED_PROFILE" ]; then
3894 if [ -f "$HOME/.profile" ]; then
4c3b3608 3895 DETECTED_PROFILE="$HOME/.profile"
4c2a3841 3896 elif [ -f "$HOME/.bashrc" ]; then
4c3b3608 3897 DETECTED_PROFILE="$HOME/.bashrc"
4c2a3841 3898 elif [ -f "$HOME/.bash_profile" ]; then
4c3b3608 3899 DETECTED_PROFILE="$HOME/.bash_profile"
4c2a3841 3900 elif [ -f "$HOME/.zshrc" ]; then
4c3b3608 3901 DETECTED_PROFILE="$HOME/.zshrc"
3902 fi
3903 fi
3904
4c2a3841 3905 if [ ! -z "$DETECTED_PROFILE" ]; then
4c3b3608 3906 echo "$DETECTED_PROFILE"
3907 fi
3908}
3909
3910_initconf() {
3911 _initpath
4c2a3841 3912 if [ ! -f "$ACCOUNT_CONF_PATH" ]; then
0ca5b799 3913 echo "
d404e92d 3914
d0871bda 3915#LOG_FILE=\"$DEFAULT_LOG_FILE\"
6b500036 3916#LOG_LEVEL=1
5ea6e9c9 3917
251d1c5c 3918#AUTO_UPGRADE=\"1\"
89002ed2 3919
569d6c55 3920#NO_TIMESTAMP=1
5b771039 3921
d5ec5f80 3922 " >"$ACCOUNT_CONF_PATH"
4c3b3608 3923 fi
3924}
3925
c8e9a31e 3926# nocron
c60883ef 3927_precheck() {
c8e9a31e 3928 _nocron="$1"
4c2a3841 3929
3930 if ! _exists "curl" && ! _exists "wget"; then
c60883ef 3931 _err "Please install curl or wget first, we need to access http resources."
4c3b3608 3932 return 1
3933 fi
4c2a3841 3934
3935 if [ -z "$_nocron" ]; then
3936 if ! _exists "crontab"; then
c8e9a31e 3937 _err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
3938 _err "We need to set cron job to renew the certs automatically."
3939 _err "Otherwise, your certs will not be able to be renewed automatically."
4c2a3841 3940 if [ -z "$FORCE" ]; then
c8e9a31e 3941 _err "Please add '--force' and try install again to go without crontab."
3942 _err "./$PROJECT_ENTRY --install --force"
3943 return 1
3944 fi
77546ea5 3945 fi
4c3b3608 3946 fi
4c2a3841 3947
a746139c 3948 if ! _exists "$OPENSSL_BIN"; then
c60883ef 3949 _err "Please install openssl first."
3950 _err "We need openssl to generate keys."
4c3b3608 3951 return 1
3952 fi
4c2a3841 3953
3954 if ! _exists "nc"; then
c60883ef 3955 _err "It is recommended to install nc first, try to install 'nc' or 'netcat'."
3956 _err "We use nc for standalone server if you use standalone mode."
3957 _err "If you don't use standalone mode, just ignore this warning."
3958 fi
4c2a3841 3959
c60883ef 3960 return 0
3961}
3962
0a7c9364 3963_setShebang() {
3964 _file="$1"
3965 _shebang="$2"
4c2a3841 3966 if [ -z "$_shebang" ]; then
43822d37 3967 _usage "Usage: file shebang"
0a7c9364 3968 return 1
3969 fi
3970 cp "$_file" "$_file.tmp"
4c2a3841 3971 echo "$_shebang" >"$_file"
3972 sed -n 2,99999p "$_file.tmp" >>"$_file"
3973 rm -f "$_file.tmp"
0a7c9364 3974}
3975
27dbe77f 3976#confighome
94dc5f33 3977_installalias() {
27dbe77f 3978 _c_home="$1"
94dc5f33 3979 _initpath
3980
3981 _envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env"
4c2a3841 3982 if [ "$_upgrading" ] && [ "$_upgrading" = "1" ]; then
44edb2bd 3983 echo "$(cat "$_envfile")" | sed "s|^LE_WORKING_DIR.*$||" >"$_envfile"
3984 echo "$(cat "$_envfile")" | sed "s|^alias le.*$||" >"$_envfile"
3985 echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile"
94dc5f33 3986 fi
3987
27dbe77f 3988 if [ "$_c_home" ]; then
be83a6a3 3989 _c_entry=" --config-home '$_c_home'"
27dbe77f 3990 fi
3991
1786a5e5 3992 _setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\""
f5b546b3 3993 if [ "$_c_home" ]; then
3994 _setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\""
3995 fi
be83a6a3 3996 _setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
94dc5f33 3997
3998 _profile="$(_detect_profile)"
4c2a3841 3999 if [ "$_profile" ]; then
94dc5f33 4000 _debug "Found profile: $_profile"
aba5c634 4001 _info "Installing alias to '$_profile'"
94dc5f33 4002 _setopt "$_profile" ". \"$_envfile\""
4003 _info "OK, Close and reopen your terminal to start using $PROJECT_NAME"
4004 else
4005 _info "No profile is found, you will need to go into $LE_WORKING_DIR to use $PROJECT_NAME"
4006 fi
94dc5f33 4007
4008 #for csh
4009 _cshfile="$LE_WORKING_DIR/$PROJECT_ENTRY.csh"
94dc5f33 4010 _csh_profile="$HOME/.cshrc"
4c2a3841 4011 if [ -f "$_csh_profile" ]; then
aba5c634 4012 _info "Installing alias to '$_csh_profile'"
6626371d 4013 _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
f5b546b3 4014 if [ "$_c_home" ]; then
4015 _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\""
4016 fi
be83a6a3 4017 _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
4c2a3841 4018 _setopt "$_csh_profile" "source \"$_cshfile\""
94dc5f33 4019 fi
4c2a3841 4020
acafa585 4021 #for tcsh
4022 _tcsh_profile="$HOME/.tcshrc"
4c2a3841 4023 if [ -f "$_tcsh_profile" ]; then
aba5c634 4024 _info "Installing alias to '$_tcsh_profile'"
acafa585 4025 _setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
f5b546b3 4026 if [ "$_c_home" ]; then
4027 _setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\""
4028 fi
be83a6a3 4029 _setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
4c2a3841 4030 _setopt "$_tcsh_profile" "source \"$_cshfile\""
acafa585 4031 fi
94dc5f33 4032
4033}
4034
27dbe77f 4035# nocron confighome
c60883ef 4036install() {
f3e4cea3 4037
4c2a3841 4038 if [ -z "$LE_WORKING_DIR" ]; then
f3e4cea3 4039 LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
4040 fi
4c2a3841 4041
c8e9a31e 4042 _nocron="$1"
27dbe77f 4043 _c_home="$2"
4c2a3841 4044 if ! _initpath; then
c60883ef 4045 _err "Install failed."
4c3b3608 4046 return 1
4047 fi
4c2a3841 4048 if [ "$_nocron" ]; then
52677b0a 4049 _debug "Skip install cron job"
4050 fi
4c2a3841 4051
4052 if ! _precheck "$_nocron"; then
c60883ef 4053 _err "Pre-check failed, can not install."
4c3b3608 4054 return 1
4055 fi
4c2a3841 4056
6cc11ffb 4057 #convert from le
4c2a3841 4058 if [ -d "$HOME/.le" ]; then
4059 for envfile in "le.env" "le.sh.env"; do
4060 if [ -f "$HOME/.le/$envfile" ]; then
4061 if grep "le.sh" "$HOME/.le/$envfile" >/dev/null; then
4062 _upgrading="1"
4063 _info "You are upgrading from le.sh"
4064 _info "Renaming \"$HOME/.le\" to $LE_WORKING_DIR"
4065 mv "$HOME/.le" "$LE_WORKING_DIR"
4066 mv "$LE_WORKING_DIR/$envfile" "$LE_WORKING_DIR/$PROJECT_ENTRY.env"
4067 break
6cc11ffb 4068 fi
4069 fi
4070 done
4071 fi
4072
4c3b3608 4073 _info "Installing to $LE_WORKING_DIR"
635695ec 4074
4c2a3841 4075 if ! mkdir -p "$LE_WORKING_DIR"; then
90035252 4076 _err "Can not create working dir: $LE_WORKING_DIR"
4a0f23e2 4077 return 1
4078 fi
4c2a3841 4079
762978f8 4080 chmod 700 "$LE_WORKING_DIR"
4081
f5b546b3 4082 if ! mkdir -p "$LE_CONFIG_HOME"; then
4083 _err "Can not create config dir: $LE_CONFIG_HOME"
27dbe77f 4084 return 1
4085 fi
4086
f5b546b3 4087 chmod 700 "$LE_CONFIG_HOME"
27dbe77f 4088
d5ec5f80 4089 cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY"
4c3b3608 4090
4c2a3841 4091 if [ "$?" != "0" ]; then
a7b7355d 4092 _err "Install failed, can not copy $PROJECT_ENTRY"
4c3b3608 4093 return 1
4094 fi
4095
a7b7355d 4096 _info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY"
4c3b3608 4097
27dbe77f 4098 _installalias "$_c_home"
4c3b3608 4099
4c2a3841 4100 for subf in $_SUB_FOLDERS; do
4101 if [ -d "$subf" ]; then
d5ec5f80 4102 mkdir -p "$LE_WORKING_DIR/$subf"
4103 cp "$subf"/* "$LE_WORKING_DIR"/"$subf"/
a61fe418 4104 fi
4105 done
4106
4c2a3841 4107 if [ ! -f "$ACCOUNT_CONF_PATH" ]; then
4c3b3608 4108 _initconf
4109 fi
6cc11ffb 4110
4c2a3841 4111 if [ "$_DEFAULT_ACCOUNT_CONF_PATH" != "$ACCOUNT_CONF_PATH" ]; then
635695ec 4112 _setopt "$_DEFAULT_ACCOUNT_CONF_PATH" "ACCOUNT_CONF_PATH" "=" "\"$ACCOUNT_CONF_PATH\""
6cc11ffb 4113 fi
4114
4c2a3841 4115 if [ "$_DEFAULT_CERT_HOME" != "$CERT_HOME" ]; then
b2817897 4116 _saveaccountconf "CERT_HOME" "$CERT_HOME"
4117 fi
4118
4c2a3841 4119 if [ "$_DEFAULT_ACCOUNT_KEY_PATH" != "$ACCOUNT_KEY_PATH" ]; then
b2817897 4120 _saveaccountconf "ACCOUNT_KEY_PATH" "$ACCOUNT_KEY_PATH"
4121 fi
4c2a3841 4122
4123 if [ -z "$_nocron" ]; then
27dbe77f 4124 installcronjob "$_c_home"
c8e9a31e 4125 fi
0a7c9364 4126
4c2a3841 4127 if [ -z "$NO_DETECT_SH" ]; then
641989fd 4128 #Modify shebang
4c2a3841 4129 if _exists bash; then
329174b6 4130 _info "Good, bash is found, so change the shebang to use bash as preferred."
641989fd 4131 _shebang='#!/usr/bin/env bash'
4132 _setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang"
4c2a3841 4133 for subf in $_SUB_FOLDERS; do
4134 if [ -d "$LE_WORKING_DIR/$subf" ]; then
4135 for _apifile in "$LE_WORKING_DIR/$subf/"*.sh; do
a61fe418 4136 _setShebang "$_apifile" "$_shebang"
4137 done
4138 fi
4139 done
0a7c9364 4140 fi
4141 fi
4142
4c3b3608 4143 _info OK
4144}
4145
52677b0a 4146# nocron
4c3b3608 4147uninstall() {
52677b0a 4148 _nocron="$1"
4c2a3841 4149 if [ -z "$_nocron" ]; then
52677b0a 4150 uninstallcronjob
4151 fi
4c3b3608 4152 _initpath
4153
9aa3be7f 4154 _uninstallalias
4c2a3841 4155
d5ec5f80 4156 rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY"
f5b546b3 4157 _info "The keys and certs are in \"$(__green "$LE_CONFIG_HOME")\", you can remove them by yourself."
9aa3be7f 4158
4159}
4160
4161_uninstallalias() {
4162 _initpath
4163
4c3b3608 4164 _profile="$(_detect_profile)"
4c2a3841 4165 if [ "$_profile" ]; then
9aa3be7f 4166 _info "Uninstalling alias from: '$_profile'"
d5ec5f80 4167 text="$(cat "$_profile")"
4c2a3841 4168 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.env\"$||" >"$_profile"
4c3b3608 4169 fi
4170
94dc5f33 4171 _csh_profile="$HOME/.cshrc"
4c2a3841 4172 if [ -f "$_csh_profile" ]; then
9aa3be7f 4173 _info "Uninstalling alias from: '$_csh_profile'"
d5ec5f80 4174 text="$(cat "$_csh_profile")"
4c2a3841 4175 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_csh_profile"
94dc5f33 4176 fi
4c2a3841 4177
acafa585 4178 _tcsh_profile="$HOME/.tcshrc"
4c2a3841 4179 if [ -f "$_tcsh_profile" ]; then
9aa3be7f 4180 _info "Uninstalling alias from: '$_csh_profile'"
d5ec5f80 4181 text="$(cat "$_tcsh_profile")"
4c2a3841 4182 echo "$text" | sed "s|^.*\"$LE_WORKING_DIR/$PROJECT_NAME.csh\"$||" >"$_tcsh_profile"
acafa585 4183 fi
4c3b3608 4184
4185}
4186
4187cron() {
281aa349 4188 IN_CRON=1
89002ed2 4189 _initpath
4c2a3841 4190 if [ "$AUTO_UPGRADE" = "1" ]; then
89002ed2 4191 export LE_WORKING_DIR
4192 (
4c2a3841 4193 if ! upgrade; then
4194 _err "Cron:Upgrade failed!"
4195 return 1
4196 fi
89002ed2 4197 )
d5ec5f80 4198 . "$LE_WORKING_DIR/$PROJECT_ENTRY" >/dev/null
1ab63043 4199
4c2a3841 4200 if [ -t 1 ]; then
1ab63043 4201 __INTERACTIVE="1"
4202 fi
4c2a3841 4203
89002ed2 4204 _info "Auto upgraded to: $VER"
4205 fi
4c3b3608 4206 renewAll
cc179731 4207 _ret="$?"
281aa349 4208 IN_CRON=""
0ba95a3d 4209 exit $_ret
4c3b3608 4210}
4211
4212version() {
a63b05a9 4213 echo "$PROJECT"
4214 echo "v$VER"
4c3b3608 4215}
4216
4217showhelp() {
d0871bda 4218 _initpath
4c3b3608 4219 version
a7b7355d 4220 echo "Usage: $PROJECT_ENTRY command ...[parameters]....
a63b05a9 4221Commands:
4222 --help, -h Show this help message.
4223 --version, -v Show version info.
a7b7355d 4224 --install Install $PROJECT_NAME to your system.
4225 --uninstall Uninstall $PROJECT_NAME, and uninstall the cron job.
10afcaca 4226 --upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT .
a63b05a9 4227 --issue Issue a cert.
10afcaca 4228 --signcsr Issue a cert from an existing csr.
a61fe418 4229 --deploy Deploy the cert to your server.
27dbe77f 4230 --install-cert Install the issued cert to apache/nginx or any other server.
a63b05a9 4231 --renew, -r Renew a cert.
27dbe77f 4232 --renew-all Renew all the certs.
a63b05a9 4233 --revoke Revoke a cert.
78f0201d 4234 --remove Remove the cert from $PROJECT
10afcaca 4235 --list List all the certs.
4236 --showcsr Show the content of a csr.
27dbe77f 4237 --install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
4238 --uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
a63b05a9 4239 --cron Run cron job to renew all the certs.
4240 --toPkcs Export the certificate and key to a pfx file.
27dbe77f 4241 --update-account Update account info.
4242 --register-account Register account key.
a63b05a9 4243 --createAccountKey, -cak Create an account private key, professional use.
4244 --createDomainKey, -cdk Create an domain private key, professional use.
4245 --createCSR, -ccsr Create CSR , professional use.
0c00e870 4246 --deactivate Deactivate the domain authz, professional use.
a63b05a9 4247
4248Parameters:
4249 --domain, -d domain.tld Specifies a domain, used to issue, renew or revoke etc.
4250 --force, -f Used to force to install or force to renew a cert immediately.
4251 --staging, --test Use staging server, just for test.
4252 --debug Output debug info.
4253
4254 --webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
4255 --standalone Use standalone mode.
e22bcf7c 4256 --tls Use standalone tls mode.
a63b05a9 4257 --apache Use apache mode.
eccec5f6 4258 --dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
4a4dacb5 4259 --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 4260
4261 --keylength, -k [2048] Specifies the domain key length: 2048, 3072, 4096, 8192 or ec-256, ec-384.
4262 --accountkeylength, -ak [2048] Specifies the account key length.
d0871bda 4263 --log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here.
a73c5b33 4264 --log-level 1|2 Specifies the log level, default is 1.
a63b05a9 4265
4266 These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
4267
4268 --certpath /path/to/real/cert/file After issue/renew, the cert will be copied to this path.
4269 --keypath /path/to/real/key/file After issue/renew, the key will be copied to this path.
4270 --capath /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path.
4271 --fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path.
4272
4273 --reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
4274
4275 --accountconf Specifies a customized account config file.
635695ec 4276 --home Specifies the home dir for $PROJECT_NAME .
27dbe77f 4277 --cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
4278 --config-home Specifies the home dir to save all the configurations.
635695ec 4279 --useragent Specifies the user agent string. it will be saved for future use too.
b5eb4b90 4280 --accountemail Specifies the account email for registering, Only valid for the '--install' command.
06625071 4281 --accountkey Specifies the account key path, Only valid for the '--install' command.
523c7682 4282 --days Specifies the days to renew the cert when using '--issue' command. The max value is $MAX_RENEW days.
39c8f79f 4283 --httpport Specifies the standalone listening port. Only valid if the server is behind a reverse proxy or load balancer.
e22bcf7c 4284 --tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
6ae0f7f5 4285 --local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
dcf4f8f6 4286 --listraw Only used for '--list' command, list the certs in raw format.
27dbe77f 4287 --stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
13d7cae9 4288 --insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted.
78009539 4289 --ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate.
bc96082f 4290 --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.
27dbe77f 4291 --ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
10afcaca 4292 --csr Specifies the input csr.
b0070f03 4293 --pre-hook Command to be run before obtaining any certificates.
4294 --post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed.
4295 --renew-hook Command to be run once for each successfully renewed certificate.
a61fe418 4296 --deploy-hook The hook file to deploy cert
0c9546cc 4297 --ocsp-must-staple, --ocsp Generate ocsp must Staple extension.
6bf281f9 4298 --auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future.
6ae0f7f5 4299 --listen-v4 Force standalone/tls server to listen at ipv4.
4300 --listen-v6 Force standalone/tls server to listen at ipv6.
a746139c 4301 --openssl-bin Specifies a custom openssl bin location.
4c3b3608 4302 "
4303}
4304
52677b0a 4305# nocron
4a0f23e2 4306_installOnline() {
4307 _info "Installing from online archive."
52677b0a 4308 _nocron="$1"
4c2a3841 4309 if [ ! "$BRANCH" ]; then
4a0f23e2 4310 BRANCH="master"
4311 fi
a8df88ab 4312
4a0f23e2 4313 target="$PROJECT/archive/$BRANCH.tar.gz"
4314 _info "Downloading $target"
4315 localname="$BRANCH.tar.gz"
4c2a3841 4316 if ! _get "$target" >$localname; then
df9547ae 4317 _err "Download error."
4a0f23e2 4318 return 1
4319 fi
0bbe6eef 4320 (
4c2a3841 4321 _info "Extracting $localname"
3a3b0dd5 4322 if ! (tar xzf $localname || gtar xzf $localname); then
4323 _err "Extraction error."
4324 exit 1
4325 fi
4c2a3841 4326
4327 cd "$PROJECT_NAME-$BRANCH"
4328 chmod +x $PROJECT_ENTRY
4329 if ./$PROJECT_ENTRY install "$_nocron"; then
4330 _info "Install success!"
4331 fi
4332
4333 cd ..
4334
4335 rm -rf "$PROJECT_NAME-$BRANCH"
4336 rm -f "$localname"
0bbe6eef 4337 )
4a0f23e2 4338}
4339
52677b0a 4340upgrade() {
4341 if (
267f283a 4342 _initpath
4343 export LE_WORKING_DIR
d0b748a4 4344 cd "$LE_WORKING_DIR"
52677b0a 4345 _installOnline "nocron"
4c2a3841 4346 ); then
52677b0a 4347 _info "Upgrade success!"
096d8992 4348 exit 0
52677b0a 4349 else
4350 _err "Upgrade failed!"
096d8992 4351 exit 1
52677b0a 4352 fi
4353}
a63b05a9 4354
5ea6e9c9 4355_processAccountConf() {
4c2a3841 4356 if [ "$_useragent" ]; then
5ea6e9c9 4357 _saveaccountconf "USER_AGENT" "$_useragent"
4c2a3841 4358 elif [ "$USER_AGENT" ] && [ "$USER_AGENT" != "$DEFAULT_USER_AGENT" ]; then
d0871bda 4359 _saveaccountconf "USER_AGENT" "$USER_AGENT"
5ea6e9c9 4360 fi
4c2a3841 4361
4362 if [ "$_accountemail" ]; then
5ea6e9c9 4363 _saveaccountconf "ACCOUNT_EMAIL" "$_accountemail"
4c2a3841 4364 elif [ "$ACCOUNT_EMAIL" ] && [ "$ACCOUNT_EMAIL" != "$DEFAULT_ACCOUNT_EMAIL" ]; then
d0871bda 4365 _saveaccountconf "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL"
5ea6e9c9 4366 fi
4c2a3841 4367
a746139c 4368 if [ "$_openssl_bin" ]; then
4369 _saveaccountconf "OPENSSL_BIN" "$_openssl_bin"
4370 elif [ "$OPENSSL_BIN" ] && [ "$OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then
4371 _saveaccountconf "OPENSSL_BIN" "$OPENSSL_BIN"
4372 fi
4373
4c2a3841 4374 if [ "$_auto_upgrade" ]; then
6bf281f9 4375 _saveaccountconf "AUTO_UPGRADE" "$_auto_upgrade"
4c2a3841 4376 elif [ "$AUTO_UPGRADE" ]; then
6bf281f9 4377 _saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE"
4378 fi
4c2a3841 4379
5ea6e9c9 4380}
4381
a63b05a9 4382_process() {
4383 _CMD=""
4384 _domain=""
3f4513b3 4385 _altdomains="$NO_VALUE"
a63b05a9 4386 _webroot=""
bdbf323f 4387 _keylength=""
4388 _accountkeylength=""
4389 _certpath=""
4390 _keypath=""
4391 _capath=""
4392 _fullchainpath=""
4d2f38b0 4393 _reloadcmd=""
a63b05a9 4394 _password=""
635695ec 4395 _accountconf=""
4396 _useragent=""
b5eb4b90 4397 _accountemail=""
4398 _accountkey=""
b2817897 4399 _certhome=""
27dbe77f 4400 _confighome=""
39c8f79f 4401 _httpport=""
e22bcf7c 4402 _tlsport=""
0e38c60d 4403 _dnssleep=""
dcf4f8f6 4404 _listraw=""
cc179731 4405 _stopRenewOnError=""
e3698edd 4406 #_insecure=""
78009539 4407 _ca_bundle=""
c8e9a31e 4408 _nocron=""
43822d37 4409 _ecc=""
10afcaca 4410 _csr=""
b0070f03 4411 _pre_hook=""
4412 _post_hook=""
4413 _renew_hook=""
a61fe418 4414 _deploy_hook=""
5ea6e9c9 4415 _logfile=""
d0871bda 4416 _log=""
0463b5d6 4417 _local_address=""
a73c5b33 4418 _log_level=""
6bf281f9 4419 _auto_upgrade=""
6ae0f7f5 4420 _listen_v4=""
4421 _listen_v6=""
a746139c 4422 _openssl_bin=""
4c2a3841 4423 while [ ${#} -gt 0 ]; do
a63b05a9 4424 case "${1}" in
4c2a3841 4425
4426 --help | -h)
a63b05a9 4427 showhelp
4428 return
4429 ;;
4c2a3841 4430 --version | -v)
a63b05a9 4431 version
4432 return
4433 ;;
4c2a3841 4434 --install)
a63b05a9 4435 _CMD="install"
4436 ;;
4c2a3841 4437 --uninstall)
a63b05a9 4438 _CMD="uninstall"
4439 ;;
4c2a3841 4440 --upgrade)
52677b0a 4441 _CMD="upgrade"
4442 ;;
4c2a3841 4443 --issue)
a63b05a9 4444 _CMD="issue"
4445 ;;
4c2a3841 4446 --deploy)
a61fe418 4447 _CMD="deploy"
4448 ;;
4c2a3841 4449 --signcsr)
10afcaca 4450 _CMD="signcsr"
4451 ;;
4c2a3841 4452 --showcsr)
10afcaca 4453 _CMD="showcsr"
4454 ;;
db7e4bf9 4455 --installcert | -i | --install-cert)
a63b05a9 4456 _CMD="installcert"
4457 ;;
4c2a3841 4458 --renew | -r)
a63b05a9 4459 _CMD="renew"
4460 ;;
db7e4bf9 4461 --renewAll | --renewall | --renew-all)
a63b05a9 4462 _CMD="renewAll"
4463 ;;
4c2a3841 4464 --revoke)
a63b05a9 4465 _CMD="revoke"
4466 ;;
78f0201d 4467 --remove)
4468 _CMD="remove"
4469 ;;
4c2a3841 4470 --list)
6d7eda3e 4471 _CMD="list"
4472 ;;
ee20015d 4473 --installcronjob | --install-cronjob)
a63b05a9 4474 _CMD="installcronjob"
4475 ;;
db7e4bf9 4476 --uninstallcronjob | --uninstall-cronjob)
a63b05a9 4477 _CMD="uninstallcronjob"
4478 ;;
4c2a3841 4479 --cron)
a63b05a9 4480 _CMD="cron"
4481 ;;
4c2a3841 4482 --toPkcs)
a63b05a9 4483 _CMD="toPkcs"
4c2a3841 4484 ;;
4485 --createAccountKey | --createaccountkey | -cak)
a63b05a9 4486 _CMD="createAccountKey"
4487 ;;
4c2a3841 4488 --createDomainKey | --createdomainkey | -cdk)
a63b05a9 4489 _CMD="createDomainKey"
4490 ;;
4c2a3841 4491 --createCSR | --createcsr | -ccr)
a63b05a9 4492 _CMD="createCSR"
4493 ;;
4c2a3841 4494 --deactivate)
0c00e870 4495 _CMD="deactivate"
4496 ;;
ee20015d 4497 --updateaccount | --update-account)
eb59817e 4498 _CMD="updateaccount"
4499 ;;
ee20015d 4500 --registeraccount | --register-account)
eb59817e 4501 _CMD="registeraccount"
4502 ;;
4c2a3841 4503 --domain | -d)
a63b05a9 4504 _dvalue="$2"
4c2a3841 4505
4506 if [ "$_dvalue" ]; then
4507 if _startswith "$_dvalue" "-"; then
ee1737a5 4508 _err "'$_dvalue' is not a valid domain for parameter '$1'"
4509 return 1
4510 fi
4c2a3841 4511 if _is_idn "$_dvalue" && ! _exists idn; then
9774b01b 4512 _err "It seems that $_dvalue is an IDN( Internationalized Domain Names), please install 'idn' command first."
4513 return 1
4514 fi
4c2a3841 4515
4516 if [ -z "$_domain" ]; then
ee1737a5 4517 _domain="$_dvalue"
a63b05a9 4518 else
4c2a3841 4519 if [ "$_altdomains" = "$NO_VALUE" ]; then
ee1737a5 4520 _altdomains="$_dvalue"
4521 else
4522 _altdomains="$_altdomains,$_dvalue"
4523 fi
a63b05a9 4524 fi
4525 fi
4c2a3841 4526
a63b05a9 4527 shift
4528 ;;
4529
4c2a3841 4530 --force | -f)
a63b05a9 4531 FORCE="1"
4532 ;;
4c2a3841 4533 --staging | --test)
a63b05a9 4534 STAGE="1"
4535 ;;
4c2a3841 4536 --debug)
4537 if [ -z "$2" ] || _startswith "$2" "-"; then
a63b05a9 4538 DEBUG="1"
4539 else
4540 DEBUG="$2"
4541 shift
4c2a3841 4542 fi
a63b05a9 4543 ;;
4c2a3841 4544 --webroot | -w)
a63b05a9 4545 wvalue="$2"
4c2a3841 4546 if [ -z "$_webroot" ]; then
a63b05a9 4547 _webroot="$wvalue"
4548 else
4549 _webroot="$_webroot,$wvalue"
4550 fi
4551 shift
4c2a3841 4552 ;;
4553 --standalone)
3f4513b3 4554 wvalue="$NO_VALUE"
4c2a3841 4555 if [ -z "$_webroot" ]; then
a63b05a9 4556 _webroot="$wvalue"
4557 else
4558 _webroot="$_webroot,$wvalue"
4559 fi
4560 ;;
4c2a3841 4561 --local-address)
0463b5d6 4562 lvalue="$2"
4563 _local_address="$_local_address$lvalue,"
4564 shift
4565 ;;
4c2a3841 4566 --apache)
a63b05a9 4567 wvalue="apache"
4c2a3841 4568 if [ -z "$_webroot" ]; then
a63b05a9 4569 _webroot="$wvalue"
4570 else
4571 _webroot="$_webroot,$wvalue"
4572 fi
4573 ;;
4c2a3841 4574 --tls)
e22bcf7c 4575 wvalue="$W_TLS"
4c2a3841 4576 if [ -z "$_webroot" ]; then
e22bcf7c 4577 _webroot="$wvalue"
4578 else
4579 _webroot="$_webroot,$wvalue"
4580 fi
4581 ;;
4c2a3841 4582 --dns)
a63b05a9 4583 wvalue="dns"
4c2a3841 4584 if ! _startswith "$2" "-"; then
a63b05a9 4585 wvalue="$2"
4586 shift
4587 fi
4c2a3841 4588 if [ -z "$_webroot" ]; then
a63b05a9 4589 _webroot="$wvalue"
4590 else
4591 _webroot="$_webroot,$wvalue"
4592 fi
4593 ;;
4c2a3841 4594 --dnssleep)
0e38c60d 4595 _dnssleep="$2"
4596 Le_DNSSleep="$_dnssleep"
4597 shift
4598 ;;
4c2a3841 4599
4600 --keylength | -k)
a63b05a9 4601 _keylength="$2"
a63b05a9 4602 shift
4603 ;;
4c2a3841 4604 --accountkeylength | -ak)
2ce87fe2 4605 _accountkeylength="$2"
a63b05a9 4606 shift
4607 ;;
4608
4c2a3841 4609 --certpath)
a63b05a9 4610 _certpath="$2"
4611 shift
4612 ;;
4c2a3841 4613 --keypath)
a63b05a9 4614 _keypath="$2"
4615 shift
4616 ;;
4c2a3841 4617 --capath)
a63b05a9 4618 _capath="$2"
4619 shift
4620 ;;
4c2a3841 4621 --fullchainpath)
a63b05a9 4622 _fullchainpath="$2"
4623 shift
4624 ;;
4c2a3841 4625 --reloadcmd | --reloadCmd)
a63b05a9 4626 _reloadcmd="$2"
4627 shift
4628 ;;
4c2a3841 4629 --password)
a63b05a9 4630 _password="$2"
4631 shift
4632 ;;
4c2a3841 4633 --accountconf)
635695ec 4634 _accountconf="$2"
4635 ACCOUNT_CONF_PATH="$_accountconf"
a7b7355d 4636 shift
a63b05a9 4637 ;;
4c2a3841 4638 --home)
a63b05a9 4639 LE_WORKING_DIR="$2"
a7b7355d 4640 shift
a63b05a9 4641 ;;
ee20015d 4642 --certhome | --cert-home)
b2817897 4643 _certhome="$2"
4644 CERT_HOME="$_certhome"
4645 shift
4c2a3841 4646 ;;
27dbe77f 4647 --config-home)
4648 _confighome="$2"
f5b546b3 4649 LE_CONFIG_HOME="$_confighome"
27dbe77f 4650 shift
4651 ;;
4c2a3841 4652 --useragent)
635695ec 4653 _useragent="$2"
4654 USER_AGENT="$_useragent"
4655 shift
4656 ;;
4c2a3841 4657 --accountemail)
b5eb4b90 4658 _accountemail="$2"
4659 ACCOUNT_EMAIL="$_accountemail"
4660 shift
4661 ;;
4c2a3841 4662 --accountkey)
b5eb4b90 4663 _accountkey="$2"
4664 ACCOUNT_KEY_PATH="$_accountkey"
4665 shift
4666 ;;
4c2a3841 4667 --days)
06625071 4668 _days="$2"
4669 Le_RenewalDays="$_days"
4670 shift
4671 ;;
4c2a3841 4672 --httpport)
39c8f79f 4673 _httpport="$2"
4674 Le_HTTPPort="$_httpport"
4675 shift
4676 ;;
4c2a3841 4677 --tlsport)
e22bcf7c 4678 _tlsport="$2"
4679 Le_TLSPort="$_tlsport"
4680 shift
4681 ;;
4c2a3841 4682
4683 --listraw)
dcf4f8f6 4684 _listraw="raw"
4c2a3841 4685 ;;
4686 --stopRenewOnError | --stoprenewonerror | -se)
cc179731 4687 _stopRenewOnError="1"
4688 ;;
4c2a3841 4689 --insecure)
e3698edd 4690 #_insecure="1"
fac1e367 4691 HTTPS_INSECURE="1"
13d7cae9 4692 ;;
4c2a3841 4693 --ca-bundle)
6c4cc357 4694 _ca_bundle="$(_readlink -f "$2")"
78009539
PS
4695 CA_BUNDLE="$_ca_bundle"
4696 shift
4697 ;;
4c2a3841 4698 --nocron)
c8e9a31e 4699 _nocron="1"
4700 ;;
4c2a3841 4701 --ecc)
43822d37 4702 _ecc="isEcc"
4703 ;;
4c2a3841 4704 --csr)
10afcaca 4705 _csr="$2"
4706 shift
4707 ;;
4c2a3841 4708 --pre-hook)
b0070f03 4709 _pre_hook="$2"
4710 shift
4711 ;;
4c2a3841 4712 --post-hook)
b0070f03 4713 _post_hook="$2"
4714 shift
4715 ;;
4c2a3841 4716 --renew-hook)
b0070f03 4717 _renew_hook="$2"
4718 shift
4719 ;;
4c2a3841 4720 --deploy-hook)
a61fe418 4721 _deploy_hook="$2"
4722 shift
4723 ;;
4c2a3841 4724 --ocsp-must-staple | --ocsp)
96db9362 4725 Le_OCSP_Staple="1"
0c9546cc 4726 ;;
4c2a3841 4727 --log | --logfile)
d0871bda 4728 _log="1"
5ea6e9c9 4729 _logfile="$2"
4c2a3841 4730 if _startswith "$_logfile" '-'; then
d0871bda 4731 _logfile=""
4732 else
4733 shift
4734 fi
5ea6e9c9 4735 LOG_FILE="$_logfile"
4c2a3841 4736 if [ -z "$LOG_LEVEL" ]; then
a73c5b33 4737 LOG_LEVEL="$DEFAULT_LOG_LEVEL"
4738 fi
4739 ;;
4c2a3841 4740 --log-level)
30bfc2ce 4741 _log_level="$2"
a73c5b33 4742 LOG_LEVEL="$_log_level"
4743 shift
5ea6e9c9 4744 ;;
4c2a3841 4745 --auto-upgrade)
6bf281f9 4746 _auto_upgrade="$2"
4c2a3841 4747 if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then
6bf281f9 4748 _auto_upgrade="1"
4749 else
4750 shift
4751 fi
4752 AUTO_UPGRADE="$_auto_upgrade"
4753 ;;
4c2a3841 4754 --listen-v4)
6ae0f7f5 4755 _listen_v4="1"
4756 Le_Listen_V4="$_listen_v4"
4757 ;;
4c2a3841 4758 --listen-v6)
6ae0f7f5 4759 _listen_v6="1"
4760 Le_Listen_V6="$_listen_v6"
4761 ;;
a746139c 4762 --openssl-bin)
4763 _openssl_bin="$2"
4764 OPENSSL_BIN="$_openssl_bin"
4765 ;;
4c2a3841 4766 *)
a63b05a9 4767 _err "Unknown parameter : $1"
4768 return 1
4769 ;;
4770 esac
4771
4772 shift 1
4773 done
4774
4c2a3841 4775 if [ "${_CMD}" != "install" ]; then
5ea6e9c9 4776 __initHome
661f0583 4777 if [ "$_log" ]; then
4c2a3841 4778 if [ -z "$_logfile" ]; then
661f0583 4779 _logfile="$DEFAULT_LOG_FILE"
4780 fi
d0871bda 4781 fi
4c2a3841 4782 if [ "$_logfile" ]; then
5ea6e9c9 4783 _saveaccountconf "LOG_FILE" "$_logfile"
661f0583 4784 LOG_FILE="$_logfile"
5ea6e9c9 4785 fi
a73c5b33 4786
4c2a3841 4787 if [ "$_log_level" ]; then
a73c5b33 4788 _saveaccountconf "LOG_LEVEL" "$_log_level"
4789 LOG_LEVEL="$_log_level"
4790 fi
4c2a3841 4791
5ea6e9c9 4792 _processAccountConf
4793 fi
4c2a3841 4794
9d548d81 4795 _debug2 LE_WORKING_DIR "$LE_WORKING_DIR"
4c2a3841 4796
4797 if [ "$DEBUG" ]; then
dcf9cb58 4798 version
4799 fi
a63b05a9 4800
4801 case "${_CMD}" in
27dbe77f 4802 install) install "$_nocron" "$_confighome" ;;
bc96082f 4803 uninstall) uninstall "$_nocron" ;;
52677b0a 4804 upgrade) upgrade ;;
a63b05a9 4805 issue)
4c2a3841 4806 issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address"
a63b05a9 4807 ;;
a61fe418 4808 deploy)
4809 deploy "$_domain" "$_deploy_hook" "$_ecc"
4810 ;;
10afcaca 4811 signcsr)
4812 signcsr "$_csr" "$_webroot"
4813 ;;
4814 showcsr)
4815 showcsr "$_csr" "$_domain"
4816 ;;
a63b05a9 4817 installcert)
43822d37 4818 installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc"
a63b05a9 4819 ;;
4c2a3841 4820 renew)
43822d37 4821 renew "$_domain" "$_ecc"
a63b05a9 4822 ;;
4c2a3841 4823 renewAll)
cc179731 4824 renewAll "$_stopRenewOnError"
a63b05a9 4825 ;;
4c2a3841 4826 revoke)
43822d37 4827 revoke "$_domain" "$_ecc"
a63b05a9 4828 ;;
78f0201d 4829 remove)
4830 remove "$_domain" "$_ecc"
4831 ;;
4c2a3841 4832 deactivate)
3f4513b3 4833 deactivate "$_domain,$_altdomains"
eb59817e 4834 ;;
4c2a3841 4835 registeraccount)
57e58ce7 4836 registeraccount "$_accountkeylength"
eb59817e 4837 ;;
4c2a3841 4838 updateaccount)
eb59817e 4839 updateaccount
4840 ;;
4c2a3841 4841 list)
dcf4f8f6 4842 list "$_listraw"
6d7eda3e 4843 ;;
27dbe77f 4844 installcronjob) installcronjob "$_confighome" ;;
a63b05a9 4845 uninstallcronjob) uninstallcronjob ;;
4846 cron) cron ;;
4c2a3841 4847 toPkcs)
43822d37 4848 toPkcs "$_domain" "$_password" "$_ecc"
a63b05a9 4849 ;;
4c2a3841 4850 createAccountKey)
5fbc47eb 4851 createAccountKey "$_accountkeylength"
a63b05a9 4852 ;;
4c2a3841 4853 createDomainKey)
a63b05a9 4854 createDomainKey "$_domain" "$_keylength"
4855 ;;
4c2a3841 4856 createCSR)
43822d37 4857 createCSR "$_domain" "$_altdomains" "$_ecc"
a63b05a9 4858 ;;
4859
4860 *)
27dbe77f 4861 if [ "$_CMD" ]; then
4862 _err "Invalid command: $_CMD"
4863 fi
4c2a3841 4864 showhelp
a63b05a9 4865 return 1
4c2a3841 4866 ;;
a63b05a9 4867 esac
d3595686 4868 _ret="$?"
4c2a3841 4869 if [ "$_ret" != "0" ]; then
d3595686 4870 return $_ret
4871 fi
4c2a3841 4872
4873 if [ "${_CMD}" = "install" ]; then
4874 if [ "$_log" ]; then
4875 if [ -z "$LOG_FILE" ]; then
d0871bda 4876 LOG_FILE="$DEFAULT_LOG_FILE"
4877 fi
4878 _saveaccountconf "LOG_FILE" "$LOG_FILE"
5ea6e9c9 4879 fi
4c2a3841 4880
4881 if [ "$_log_level" ]; then
a73c5b33 4882 _saveaccountconf "LOG_LEVEL" "$_log_level"
4883 fi
5ea6e9c9 4884 _processAccountConf
b5eb4b90 4885 fi
635695ec 4886
a63b05a9 4887}
4888
4c2a3841 4889if [ "$INSTALLONLINE" ]; then
d1f97fc8 4890 INSTALLONLINE=""
2fbf3991 4891 _installOnline
4a0f23e2 4892 exit
4893fi
4c3b3608 4894
319e0ae3 4895main() {
4896 [ -z "$1" ] && showhelp && return
4c2a3841 4897 if _startswith "$1" '-'; then _process "$@"; else "$@"; fi
319e0ae3 4898}
e69a7c38 4899
aa7b82de 4900main "$@"