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