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