Unverified Commit 6e2669ed authored by sjau's avatar sjau Committed by GitHub
Browse files

Merge pull request #1 from Neilpang/master

Update from original
parents 5eed02f7 7b8a82ce
<!--
请确保已经更新到最新的代码, 然后贴上来 `--debug 2` 的调试输出. 没有调试输出,我帮不了你.
如何调试 https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh
If it is a bug report:
- make sure you are able to repro it on the latest released version.
......@@ -8,13 +10,11 @@ You can install the latest version by: `acme.sh --upgrade`
- Refer to the [WIKI](https://wiki.acme.sh).
- Debug info [Debug](https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh).
-->
Steps to reproduce
------------------
Debug log
-----------------
......
<!--
Do NOT send pull request to `master` branch.
Please send to `dev` branch instead.
Any PR to `master` branch will NOT be merged.
-->
\ No newline at end of file
language: shell
sudo: required
dist: trusty
os:
- linux
- osx
services:
- docker
env:
global:
- SHFMT_URL=https://github.com/mvdan/sh/releases/download/v0.4.0/shfmt_v0.4.0_linux_amd64
......@@ -17,35 +21,24 @@ addons:
- shellcheck
install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew update && brew install openssl;
brew info openssl;
ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/;
ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/;
ln -s /usr/local/Cellar/openssl/1.0.2j/bin/openssl /usr/local/openssl;
_old_path="$PATH";
echo "PATH=$PATH";
export PATH="";
export OPENSSL_BIN="/usr/local/openssl";
openssl version 2>&1 || true;
$OPENSSL_BIN version 2>&1 || true;
export PATH="$_old_path";
- if [ "$TRAVIS_OS_NAME" = 'osx' ]; then
brew update && brew install socat;
export PATH="/usr/local/opt/openssl@1.1/bin:$PATH" ;
fi
script:
- echo "TEST_LOCAL=$TEST_LOCAL"
- echo "NGROK_TOKEN=$(echo "$NGROK_TOKEN" | wc -c)"
- which openssl && openssl version
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then chmod +x ~/shfmt ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ~/shfmt -l -w -i 2 . ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then git diff --exit-code && echo "shfmt OK" ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -V ; fi
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then shellcheck -e SC2021,SC2126,SC2034 **/*.sh && echo "shellcheck OK" ; fi
- command -V openssl && openssl version
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then curl -sSL $SHFMT_URL -o ~/shfmt ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then chmod +x ~/shfmt ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then ~/shfmt -l -w -i 2 . ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then git diff --exit-code && echo "shfmt OK" ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -V ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then shellcheck -e SC2181 **/*.sh && echo "shellcheck OK" ; fi
- cd ..
- git clone https://github.com/Neilpang/acmetest.git && cp -r acme.sh acmetest/ && cd acmetest
- if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" ./letest.sh ; fi
- if [[ "$TRAVIS_OS_NAME" == "osx" ]] && [[ "$NGROK_TOKEN" ]]; then sudo NGROK_TOKEN="$NGROK_TOKEN" OPENSSL_BIN="$OPENSSL_BIN" ./letest.sh ; fi
- if [ "$TRAVIS_OS_NAME" = "linux" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ./rundocker.sh testplat ubuntu:latest ; fi
- if [ "$TRAVIS_OS_NAME" = "osx" -a "$NGROK_TOKEN" ]; then sudo TEST_LOCAL="$TEST_LOCAL" NGROK_TOKEN="$NGROK_TOKEN" ACME_OPENSSL_BIN="$ACME_OPENSSL_BIN" ./letest.sh ; fi
matrix:
......
FROM alpine:3.6
RUN apk update -f \
&& apk --no-cache add -f \
openssl \
curl \
socat \
&& rm -rf /var/cache/apk/*
ENV LE_CONFIG_HOME /acme.sh
ENV AUTO_UPGRADE 1
#Install
ADD ./ /install_acme.sh/
RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab -
RUN for verb in help \
version \
install \
uninstall \
upgrade \
issue \
signcsr \
deploy \
install-cert \
renew \
renew-all \
revoke \
remove \
list \
showcsr \
install-cronjob \
uninstall-cronjob \
cron \
toPkcs \
toPkcs8 \
update-account \
register-account \
create-account-key \
create-domain-key \
createCSR \
deactivate \
deactivate-account \
; do \
printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \
; done
RUN printf "%b" '#!'"/usr/bin/env sh\n \
if [ \"\$1\" = \"daemon\" ]; then \n \
trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
crond && while true; do sleep 1; done;\n \
else \n \
exec -- \"\$@\"\n \
fi" >/entry.sh && chmod +x /entry.sh
VOLUME /acme.sh
ENTRYPOINT ["/entry.sh"]
CMD ["--help"]
# An ACME Shell script: acme.sh [![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)
[![Join the chat at https://gitter.im/acme-sh/Lobby](https://badges.gitter.im/acme-sh/Lobby.svg)](https://gitter.im/acme-sh/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
- An ACME protocol client written purely in Shell (Unix shell) language.
- Full ACME protocol implementation.
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
......@@ -7,14 +9,33 @@
- Purely written in Shell with no dependencies on python or the official Let's Encrypt client.
- Just one script to issue, renew and install your certificates automatically.
- DOES NOT require `root/sudoer` access.
- Docker friendly
- IPv6 support
It's probably the `easiest&smallest&smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
Wiki: https://github.com/Neilpang/acme.sh/wiki
For Docker Fans: [acme.sh :two_hearts: Docker ](https://github.com/Neilpang/acme.sh/wiki/Run-acme.sh-in-docker)
Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
# [中文说明](https://github.com/Neilpang/acme.sh/wiki/%E8%AF%B4%E6%98%8E)
# Who are using **acme.sh**
- [FreeBSD.org](https://blog.crashed.org/letsencrypt-in-freebsd-org/)
- [ruby-china.org](https://ruby-china.org/topics/31983)
- [Proxmox](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x_and_newer))
- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89)
- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt)
- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty)
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
- [Centminmod](http://centminmod.com/letsencrypt-acmetool-https.html)
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
- [archlinux](https://aur.archlinux.org/packages/acme.sh-git/)
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
- [more...](https://github.com/Neilpang/acme.sh/wiki/Blogs-and-tutorials)
# Tested OS
......@@ -39,8 +60,9 @@ Wiki: https://github.com/Neilpang/acme.sh/wiki
|17|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/Neilpang/acme.sh/wiki/How-to-run-on-OpenWRT)
|18|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/solaris.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|SunOS/Solaris
|19|[![](https://cdn.rawgit.com/Neilpang/acmetest/master/status/gentoo-stage3-amd64.svg)](https://github.com/Neilpang/letest#here-are-the-latest-status)|Gentoo Linux
|20|[![Build Status](https://travis-ci.org/Neilpang/acme.sh.svg?branch=master)](https://travis-ci.org/Neilpang/acme.sh)|Mac OSX
For all build statuses, check our [daily build project](https://github.com/Neilpang/acmetest):
For all build statuses, check our [weekly build project](https://github.com/Neilpang/acmetest):
https://github.com/Neilpang/acmetest
......@@ -50,7 +72,9 @@ https://github.com/Neilpang/acmetest
- Webroot mode
- Standalone mode
- Apache mode
- Nginx mode ( Beta )
- DNS mode
- [Stateless mode](https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode)
# 1. How to install
......@@ -115,13 +139,25 @@ root@v1:~# acme.sh -h
acme.sh --issue -d example.com -w /home/wwwroot/example.com
```
or:
```bash
acme.sh --issue -d example.com -w /home/username/public_html
```
or:
```bash
acme.sh --issue -d example.com -w /var/www/html
```
**Example 2:** Multiple domains in the same cert.
```bash
acme.sh --issue -d example.com -d www.example.com -d cp.example.com -w /home/wwwroot/example.com
```
The parameter `/home/wwwroot/example.com` is the web root folder. You **MUST** have `write access` to this folder.
The parameter `/home/wwwroot/example.com` or `/home/username/public_html` or `/var/www/html` is the web root folder where you host your website files. You **MUST** have `write access` to this folder.
Second argument **"example.com"** is the main domain you want to issue the cert for.
You must have at least one domain there.
......@@ -142,26 +178,28 @@ You **MUST** use this command to copy the certs to the target files, **DO NOT**
**Apache** example:
```bash
acme.sh --installcert -d example.com \
--certpath /path/to/certfile/in/apache/cert.pem \
--keypath /path/to/keyfile/in/apache/key.pem \
--fullchainpath /path/to/fullchain/certfile/apache/fullchain.pem \
--reloadcmd "service apache2 restart"
acme.sh --install-cert -d example.com \
--cert-file /path/to/certfile/in/apache/cert.pem \
--key-file /path/to/keyfile/in/apache/key.pem \
--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \
--reloadcmd "service apache2 force-reload"
```
**Nginx** example:
```bash
acme.sh --installcert -d example.com \
--keypath /path/to/keyfile/in/nginx/key.pem \
--fullchainpath /path/to/fullchain/nginx/cert.pem \
--reloadcmd "service nginx restart"
acme.sh --install-cert -d example.com \
--key-file /path/to/keyfile/in/nginx/key.pem \
--fullchain-file /path/to/fullchain/nginx/cert.pem \
--reloadcmd "service nginx force-reload"
```
Only the domain is required, all the other parameters are optional.
The ownership and permission info of existing files are preserved. You may want to precreate the files to have defined ownership and permission.
Install/copy the issued cert/key to the production Apache or Nginx path.
The cert will be `renewed every **60** days by default` (which is configurable). Once the cert is renewed, the Apache/Nginx service will be restarted automatically by the command: `service apache2 restart` or `service nginx restart`.
The cert will be renewed every **60** days by default (which is configurable). Once the cert is renewed, the Apache/Nginx service will be reloaded automatically by the command: `service apache2 force-reload` or `service nginx force-reload`.
# 4. Use Standalone server to issue cert
......@@ -208,8 +246,27 @@ acme.sh --issue --apache -d example.com -d www.example.com -d cp.example.com
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 7. Use Nginx mode
**(requires you to be root/sudoer, since it is required to interact with Nginx server)**
If you are running a web server, Apache or Nginx, it is recommended to use the `Webroot mode`.
Particularly, if you are running an nginx server, you can use nginx mode instead. This mode doesn't write any files to your web root folder.
Just set string "nginx" as the second argument.
It will configure nginx server automatically to verify the domain and then restore the nginx config to the original version.
So, the config is not changed.
# 7. Use DNS mode:
```
acme.sh --issue --nginx -d example.com -d www.example.com -d cp.example.com
```
More examples: https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert
# 8. Use DNS mode:
Support the `dns-01` challenge.
......@@ -239,8 +296,11 @@ acme.sh --renew -d example.com
Ok, it's finished.
**Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.**
# 8. Automatic DNS API integration
**Please use dns api mode instead.**
# 9. Automatic DNS API integration
If your DNS provider supports API access, we can use that API to automatically issue the certs.
......@@ -252,16 +312,44 @@ You don't have to do anything manually!
1. DNSPod.cn API
1. CloudXNS.com API
1. GoDaddy.com API
1. OVH, kimsufi, soyoustart and runabove API
1. AWS Route 53
1. PowerDNS.com API
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
(DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)
1. OVH, kimsufi, soyoustart and runabove API
1. nsupdate API
1. LuaDNS.com API
1. DNSMadeEasy.com API
1. nsupdate API
1. AWS Route 53
1. aliyun.com(阿里云) API
1. ISPConfig 3.1 API
1. Alwaysdata.com API
1. Linode.com API
1. FreeDNS (https://freedns.afraid.org/)
1. cyon.ch
1. Domain-Offensive/Resellerinterface/Domainrobot API
1. Gandi LiveDNS API
1. Knot DNS API
1. DigitalOcean API (native)
1. ClouDNS.net API
1. Infoblox NIOS API (https://www.infoblox.com/)
1. VSCALE (https://vscale.io/)
1. Dynu API (https://www.dynu.com)
1. DNSimple API
1. NS1.com API
1. DuckDNS.org API
1. Name.com API
1. Dyn Managed DNS API
1. Yandex PDD API (https://pdd.yandex.ru)
1. Hurricane Electric DNS service (https://dns.he.net)
1. UnoEuro API (https://www.unoeuro.com/)
1. INWX (https://www.inwx.de/)
1. Servercow (https://servercow.de)
And:
1. lexicon DNS API: https://github.com/Neilpang/acme.sh/wiki/How-to-use-lexicon-dns-api
(DigitalOcean, DNSimple, DNSMadeEasy, DNSPark, EasyDNS, Namesilo, NS1, PointHQ, Rage4 and Vultr etc.)
**More APIs coming soon...**
......@@ -270,7 +358,7 @@ If your DNS provider is not on the supported list above, you can write your own
For more details: [How to use DNS API](dnsapi)
# 9. Issue ECC certificates
# 10. Issue ECC certificates
`Let's Encrypt` can now issue **ECDSA** certificates.
......@@ -280,7 +368,7 @@ Just set the `length` parameter with a prefix `ec-`.
For example:
### Single domain ECC cerfiticate
### Single domain ECC certificate
```bash
acme.sh --issue -w /home/wwwroot/example.com -d example.com --keylength ec-256
......@@ -301,7 +389,7 @@ Valid values are:
3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
# 10. How to renew the issued certs
# 11. How to renew the issued certs
No, you don't need to renew the certs manually. All the certs will be renewed automatically every **60** days.
......@@ -318,9 +406,9 @@ acme.sh --renew -d example.com --force --ecc
```
# 11. How to upgrade `acme.sh`
# 12. How to upgrade `acme.sh`
acme.sh is in constant developement, so it's strongly recommended to use the latest code.
acme.sh is in constant development, so it's strongly recommended to use the latest code.
You can update acme.sh to the latest code:
......@@ -343,26 +431,26 @@ acme.sh --upgrade --auto-upgrade 0
```
# 12. Issue a cert from an existing CSR
# 13. Issue a cert from an existing CSR
https://github.com/Neilpang/acme.sh/wiki/Issue-a-cert-from-existing-CSR
# Under the Hood
# 14. Under the Hood
Speak ACME language using shell, directly to "Let's Encrypt".
TODO:
# Acknowledgments
# 15. Acknowledgments
1. Acme-tiny: https://github.com/diafygi/acme-tiny
2. ACME protocol: https://github.com/ietf-wg-acme/acme
3. Certbot: https://github.com/certbot/certbot
# License & Others
# 16. License & Others
License is GPLv3
......@@ -371,8 +459,9 @@ Please Star and Fork me.
[Issues](https://github.com/Neilpang/acme.sh/issues) and [pull requests](https://github.com/Neilpang/acme.sh/pulls) are welcome.
# Donate
# 17. Donate
Your donation makes **acme.sh** better:
1. PayPal: donate@acme.sh
1. PayPal/Alipay(支付宝)/Wechat(微信): [https://donate.acme.sh/](https://donate.acme.sh/)
[Donate List](https://github.com/Neilpang/acme.sh/wiki/Donate-list)
#!/usr/bin/env sh
VER=2.6.5
VER=2.7.6
PROJECT_NAME="acme.sh"
......@@ -13,8 +13,8 @@ _SCRIPT_="$0"
_SUB_FOLDERS="dnsapi deploy"
DEFAULT_CA="https://acme-v01.api.letsencrypt.org"
DEFAULT_AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
_OLD_CA_HOST="https://acme-v01.api.letsencrypt.org"
DEFAULT_CA="https://acme-v01.api.letsencrypt.org/directory"
DEFAULT_USER_AGENT="$PROJECT_NAME/$VER ($PROJECT)"
DEFAULT_ACCOUNT_EMAIL=""
......@@ -24,7 +24,8 @@ DEFAULT_DOMAIN_KEY_LENGTH=2048
DEFAULT_OPENSSL_BIN="openssl"
STAGE_CA="https://acme-staging.api.letsencrypt.org"
STAGE_CA="https://acme-staging.api.letsencrypt.org/directory"
_OLD_STAGE_CA_HOST="https://acme-staging.api.letsencrypt.org"
VTYPE_HTTP="http-01"
VTYPE_DNS="dns-01"
......@@ -41,8 +42,14 @@ NO_VALUE="no"
W_TLS="tls"
MODE_STATELESS="stateless"
STATE_VERIFIED="verified_ok"
NGINX="nginx:"
NGINX_START="#ACME_NGINX_START"
NGINX_END="#ACME_NGINX_END"
BEGIN_CSR="-----BEGIN CERTIFICATE REQUEST-----"
END_CSR="-----END CERTIFICATE REQUEST-----"
......@@ -59,66 +66,128 @@ LOG_LEVEL_2=2
LOG_LEVEL_3=3
DEFAULT_LOG_LEVEL="$LOG_LEVEL_1"
DEBUG_LEVEL_1=1
DEBUG_LEVEL_2=2
DEBUG_LEVEL_3=3
DEBUG_LEVEL_DEFAULT=$DEBUG_LEVEL_1
DEBUG_LEVEL_NONE=0
HIDDEN_VALUE="[hidden](please add '--output-insecure' to see this value)"
SYSLOG_ERROR="user.error"
SYSLOG_INFO="user.info"
SYSLOG_DEBUG="user.debug"
#error
SYSLOG_LEVEL_ERROR=3
#info
SYSLOG_LEVEL_INFO=6
#debug
SYSLOG_LEVEL_DEBUG=7
#debug2
SYSLOG_LEVEL_DEBUG_2=8
#debug3
SYSLOG_LEVEL_DEBUG_3=9
SYSLOG_LEVEL_DEFAULT=$SYSLOG_LEVEL_ERROR
#none
SYSLOG_LEVEL_NONE=0
_DEBUG_WIKI="https://github.com/Neilpang/acme.sh/wiki/How-to-debug-acme.sh"
_PREPARE_LINK="https://github.com/Neilpang/acme.sh/wiki/Install-preparations"
_STATELESS_WIKI="https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode"
_DNS_MANUAL_ERR="The dns manual mode can not renew automatically, you must issue it again manually. You'd better use the other modes instead."
_DNS_MANUAL_WARN="It seems that you are using dns manual mode. please take care: $_DNS_MANUAL_ERR"
__INTERACTIVE=""
if [ -t 1 ]; then
__INTERACTIVE="1"
fi
__green() {
if [ "$__INTERACTIVE" ]; then
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
printf '\033[1;31;32m'
fi
printf -- "$1"
if [ "$__INTERACTIVE" ]; then
printf -- "%b" "$1"
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
printf '\033[0m'
fi
}
__red() {
if [ "$__INTERACTIVE" ]; then
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
printf '\033[1;31;40m'
fi
printf -- "$1"
if [ "$__INTERACTIVE" ]; then
printf -- "%b" "$1"
if [ "$__INTERACTIVE${ACME_NO_COLOR}" = "1" ]; then
printf '\033[0m'
fi
}
_printargs() {
if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
printf -- "%s" "[$(date)] "
fi
if [ -z "$2" ]; then
printf -- "[$(date)] $1"
printf -- "%s" "$1"
else
printf -- "%s" "[$(date)] $1='$2'"
printf -- "%s" "$1='$2'"
fi
printf "\n"
}
_dlg_versions() {
echo "Diagnosis versions: "
echo "openssl:$OPENSSL_BIN"
if _exists "$OPENSSL_BIN"; then
$OPENSSL_BIN version 2>&1
echo "openssl:$ACME_OPENSSL_BIN"
if _exists "${ACME_OPENSSL_BIN:-openssl}"; then
${ACME_OPENSSL_BIN:-openssl} version 2>&1
else
echo "$OPENSSL_BIN doesn't exists."
echo "$ACME_OPENSSL_BIN doesn't exists."
fi
echo "apache:"
if [ "$_APACHECTL" ] && _exists "$_APACHECTL"; then
_APACHECTL -V 2>&1
$_APACHECTL -V 2>&1
else
echo "apache doesn't exists."
fi
echo "nc:"
if _exists "nc"; then
nc -h 2>&1
echo "nginx:"
if _exists "nginx"; then
nginx -V 2>&1
else
echo "nginx doesn't exists."
fi
echo "socat:"
if _exists "socat"; then
socat -h 2>&1
else
_debug "nc doesn't exists."
_debug "socat doesn't exists."
fi
}
#class
_syslog() {
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" = "$SYSLOG_LEVEL_NONE" ]; then
return
fi
_logclass="$1"
shift
if [ -z "$__logger_i" ]; then
if _contains "$(logger --help 2>&1)" "-i"; then
__logger_i="logger -i"
else
__logger_i="logger"
fi
fi
$__logger_i -t "$PROJECT_NAME" -p "$_logclass" "$(_printargs "$@")" >/dev/null 2>&1
}
_log() {
[ -z "$LOG_FILE" ] && return
_printargs "$@" >>"$LOG_FILE"
......@@ -126,12 +195,18 @@ _log() {
_info() {
_log "$@"
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_INFO" ]; then
_syslog "$SYSLOG_INFO" "$@"
fi
_printargs "$@"
}
_err() {
_syslog "$SYSLOG_ERROR" "$@"
_log "$@"
printf -- "[$(date)] " >&2
if [ -z "$NO_TIMESTAMP" ] || [ "$NO_TIMESTAMP" = "0" ]; then
printf -- "%s" "[$(date)] " >&2
fi
if [ -z "$2" ]; then
__red "$1" >&2
else
......@@ -147,31 +222,110 @@ _usage() {
}
_debug() {
if [ -z "$LOG_LEVEL" ] || [ "$LOG_LEVEL" -ge "$LOG_LEVEL_1" ]; then
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then
_log "$@"
fi
if [ -z "$DEBUG" ]; then
return
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then
_syslog "$SYSLOG_DEBUG" "$@"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then
_printargs "$@" >&2
fi
}
#output the sensitive messages
_secure_debug() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_1" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_1" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_debug2() {
if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_2" ]; then
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then
_log "$@"
fi
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
_debug "$@"
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then
_syslog "$SYSLOG_DEBUG" "$@"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then
_printargs "$@" >&2
fi
}
_secure_debug2() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_2" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_2" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_2" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_debug3() {
if [ "$LOG_LEVEL" ] && [ "$LOG_LEVEL" -ge "$LOG_LEVEL_3" ]; then
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then
_log "$@"
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then
_syslog "$SYSLOG_DEBUG" "$@"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then
_printargs "$@" >&2
fi
}
_secure_debug3() {
if [ "${LOG_LEVEL:-$DEFAULT_LOG_LEVEL}" -ge "$LOG_LEVEL_3" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_log "$@"
else
_log "$1" "$HIDDEN_VALUE"
fi
if [ "$DEBUG" ] && [ "$DEBUG" -ge "3" ]; then
_debug "$@"
fi
if [ "${SYS_LOG:-$SYSLOG_LEVEL_NONE}" -ge "$SYSLOG_LEVEL_DEBUG_3" ]; then
_syslog "$SYSLOG_DEBUG" "$1" "$HIDDEN_VALUE"
fi
if [ "${DEBUG:-$DEBUG_LEVEL_NONE}" -ge "$DEBUG_LEVEL_3" ]; then
if [ "$OUTPUT_INSECURE" = "1" ]; then
_printargs "$@" >&2
else
_printargs "$1" "$HIDDEN_VALUE" >&2
fi
fi
}
_upper_case() {
# shellcheck disable=SC2018,SC2019
tr 'a-z' 'A-Z'
}
_lower_case() {
# shellcheck disable=SC2018,SC2019
tr 'A-Z' 'a-z'
}
_startswith() {
......@@ -205,7 +359,7 @@ _hasfield() {
_sep=","
fi
for f in $(echo "$_str" | tr ',' ' '); do
for f in $(echo "$_str" | tr "$_sep" ' '); do
if [ "$f" = "$_field" ]; then
_debug2 "'$_str' contains '$_field'"
return 0 #contains ok
......@@ -215,6 +369,7 @@ _hasfield() {
return 1 #not contains
}
# str index [sep]
_getfield() {
_str="$1"
_findex="$2"
......@@ -301,48 +456,313 @@ if [ "$(printf '\x41')" != 'A' ]; then
_URGLY_PRINTF=1
fi
_ESCAPE_XARGS=""
if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then
_ESCAPE_XARGS=1
fi
_h2b() {
hex=$(cat)
i=1
j=2
if _exists xxd && xxd -r -p 2>/dev/null; then
return
fi
_debug3 _URGLY_PRINTF "$_URGLY_PRINTF"
while true; do
hex=$(cat)
ic=""
jc=""
_debug2 _URGLY_PRINTF "$_URGLY_PRINTF"
if [ -z "$_URGLY_PRINTF" ]; then
h="$(printf "%s" "$hex" | cut -c $i-$j)"
if [ "$_ESCAPE_XARGS" ] && _exists xargs; then
_debug2 "xargs"
echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf
else
for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do
if [ -z "$h" ]; then
break
fi
printf "\x$h%s"
done
fi
else
ic="$(printf "%s" "$hex" | cut -c $i)"
jc="$(printf "%s" "$hex" | cut -c $j)"
if [ -z "$ic$jc" ]; then
break
for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do
if [ -z "$ic" ]; then
ic=$c
continue
fi
jc=$c
ic="$(_h_char_2_dec "$ic")"
jc="$(_h_char_2_dec "$jc")"
printf '\'"$(printf "%o" "$(_math "$ic" \* 16 + $jc)")""%s"
ic=""
jc=""
done
fi
i="$(_math "$i" + 2)"
j="$(_math "$j" + 2)"
}
done
_is_solaris() {
_contains "${__OS__:=$(uname -a)}" "solaris" || _contains "${__OS__:=$(uname -a)}" "SunOS"
}
#hex string
_hex() {
#_ascii_hex str
#this can only process ascii chars, should only be used when od command is missing as a backup way.
_ascii_hex() {
_debug2 "Using _ascii_hex"
_str="$1"
_str_len=${#_str}
_h_i=1
while [ "$_h_i" -le "$_str_len" ]; do
_str_c="$(printf "%s" "$_str" | cut -c "$_h_i")"
printf "%02x" "'$_str_c"
printf " %02x" "'$_str_c"
_h_i="$(_math "$_h_i" + 1)"
done
}
#stdin output hexstr splited by one space
#input:"abc"
#output: " 61 62 63"
_hex_dump() {
if _exists od; then
od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n"
elif _exists hexdump; then
_debug3 "using hexdump"
hexdump -v -e '/1 ""' -e '/1 " %02x" ""'
elif _exists xxd; then
_debug3 "using xxd"
xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " "
else
_debug3 "using _ascii_hex"
str=$(cat)
_ascii_hex "$str"
fi
}
#url encode, no-preserved chars
#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a
#a b c d e f g h i j k l m n o p q r s t u v w x y z
#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a
#0 1 2 3 4 5 6 7 8 9 - _ . ~
#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e
#stdin stdout
_url_encode() {
_hex_str=$(_hex_dump)
_debug3 "_url_encode"
_debug3 "_hex_str" "$_hex_str"
for _hex_code in $_hex_str; do
#upper case
case "${_hex_code}" in
"41")
printf "%s" "A"
;;
"42")
printf "%s" "B"
;;
"43")
printf "%s" "C"
;;
"44")
printf "%s" "D"
;;
"45")
printf "%s" "E"
;;
"46")
printf "%s" "F"
;;
"47")
printf "%s" "G"
;;
"48")
printf "%s" "H"
;;
"49")
printf "%s" "I"
;;
"4a")
printf "%s" "J"
;;
"4b")
printf "%s" "K"
;;
"4c")
printf "%s" "L"
;;
"4d")
printf "%s" "M"
;;
"4e")
printf "%s" "N"
;;
"4f")
printf "%s" "O"
;;
"50")
printf "%s" "P"
;;
"51")
printf "%s" "Q"
;;
"52")
printf "%s" "R"
;;
"53")
printf "%s" "S"
;;
"54")
printf "%s" "T"
;;
"55")
printf "%s" "U"
;;
"56")
printf "%s" "V"
;;
"57")
printf "%s" "W"
;;
"58")
printf "%s" "X"
;;
"59")
printf "%s" "Y"
;;
"5a")
printf "%s" "Z"
;;
#lower case
"61")
printf "%s" "a"
;;
"62")
printf "%s" "b"
;;
"63")
printf "%s" "c"
;;
"64")
printf "%s" "d"
;;
"65")
printf "%s" "e"
;;
"66")
printf "%s" "f"
;;
"67")
printf "%s" "g"
;;
"68")
printf "%s" "h"
;;
"69")
printf "%s" "i"
;;
"6a")
printf "%s" "j"
;;
"6b")
printf "%s" "k"
;;
"6c")
printf "%s" "l"
;;
"6d")
printf "%s" "m"
;;
"6e")
printf "%s" "n"
;;
"6f")
printf "%s" "o"
;;
"70")
printf "%s" "p"
;;
"71")
printf "%s" "q"
;;
"72")
printf "%s" "r"
;;
"73")
printf "%s" "s"
;;
"74")
printf "%s" "t"
;;
"75")
printf "%s" "u"
;;
"76")
printf "%s" "v"
;;
"77")
printf "%s" "w"
;;
"78")
printf "%s" "x"
;;
"79")
printf "%s" "y"
;;
"7a")
printf "%s" "z"
;;
#numbers
"30")
printf "%s" "0"
;;
"31")
printf "%s" "1"
;;
"32")
printf "%s" "2"
;;
"33")
printf "%s" "3"
;;
"34")
printf "%s" "4"
;;
"35")
printf "%s" "5"
;;
"36")
printf "%s" "6"
;;
"37")
printf "%s" "7"
;;
"38")
printf "%s" "8"
;;
"39")
printf "%s" "9"
;;
"2d")
printf "%s" "-"
;;
"5f")
printf "%s" "_"
;;
"2e")
printf "%s" "."
;;
"7e")
printf "%s" "~"
;;
#other hex
*)
printf '%%%s' "$_hex_code"
;;
esac
done
}
#options file
_sed_i() {
options="$1"
......@@ -400,19 +820,22 @@ _getfile() {
#Usage: multiline
_base64() {
[ "" ] #urgly
if [ "$1" ]; then
$OPENSSL_BIN base64 -e
_debug3 "base64 multiline:'$1'"
${ACME_OPENSSL_BIN:-openssl} base64 -e
else
$OPENSSL_BIN base64 -e | tr -d '\r\n'
_debug3 "base64 single line."
${ACME_OPENSSL_BIN:-openssl} base64 -e | tr -d '\r\n'
fi
}
#Usage: multiline
_dbase64() {
if [ "$1" ]; then
$OPENSSL_BIN base64 -d -A
${ACME_OPENSSL_BIN:-openssl} base64 -d -A
else
$OPENSSL_BIN base64 -d
${ACME_OPENSSL_BIN:-openssl} base64 -d
fi
}
......@@ -429,9 +852,9 @@ _digest() {
if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ] || [ "$alg" = "md5" ]; then
if [ "$outputhex" ]; then
$OPENSSL_BIN dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hex | cut -d = -f 2 | tr -d ' '
else
$OPENSSL_BIN dgst -"$alg" -binary | _base64
${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -binary | _base64
fi
else
_err "$alg is not supported yet"
......@@ -454,9 +877,9 @@ _hmac() {
if [ "$alg" = "sha256" ] || [ "$alg" = "sha1" ]; then
if [ "$outputhex" ]; then
$OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" | cut -d = -f 2 | tr -d ' '
(${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)") | cut -d = -f 2 | tr -d ' '
else
$OPENSSL_BIN dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary
${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -mac HMAC -macopt "hexkey:$secret_hex" -binary 2>/dev/null || ${ACME_OPENSSL_BIN:-openssl} dgst -"$alg" -hmac "$(printf "%s" "$secret_hex" | _h2b)" -binary
fi
else
_err "$alg is not supported yet"
......@@ -475,21 +898,15 @@ _sign() {
return 1
fi
_sign_openssl="$OPENSSL_BIN dgst -sign $keyfile "
if [ "$alg" = "sha256" ]; then
_sign_openssl="$_sign_openssl -$alg"
else
_err "$alg is not supported yet"
return 1
fi
_sign_openssl="${ACME_OPENSSL_BIN:-openssl} dgst -sign $keyfile "
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
$_sign_openssl | _base64
$_sign_openssl -$alg | _base64
elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
if ! _signedECText="$($_sign_openssl | $OPENSSL_BIN asn1parse -inform DER)"; then
if ! _signedECText="$($_sign_openssl -sha$__ECC_KEY_LEN | ${ACME_OPENSSL_BIN:-openssl} asn1parse -inform DER)"; then
_err "Sign failed: $_sign_openssl"
_err "Key file: $keyfile"
_err "Key content:$(wc -l <"$keyfile") lises"
_err "Key content:$(wc -l <"$keyfile") lines"
return 1
fi
_debug3 "_signedECText" "$_signedECText"
......@@ -505,7 +922,7 @@ _sign() {
}
#keylength
#keylength or isEcc flag (empty str => not ecc)
_isEccKey() {
_length="$1"
......@@ -524,6 +941,7 @@ _isEccKey() {
_createkey() {
length="$1"
f="$2"
_debug2 "_createkey for file:$f"
eccname="$length"
if _startswith "$length" "ec-"; then
length=$(printf "%s" "$length" | cut -d '-' -f 2-100)
......@@ -546,12 +964,21 @@ _createkey() {
_debug "Use length $length"
if ! touch "$f" >/dev/null 2>&1; then
_f_path="$(dirname "$f")"
_debug _f_path "$_f_path"
if ! mkdir -p "$_f_path"; then
_err "Can not create path: $_f_path"
return 1
fi
fi
if _isEccKey "$length"; then
_debug "Using ec name: $eccname"
$OPENSSL_BIN ecparam -name "$eccname" -genkey 2>/dev/null >"$f"
${ACME_OPENSSL_BIN:-openssl} ecparam -name "$eccname" -genkey 2>/dev/null >"$f"
else
_debug "Using RSA: $length"
$OPENSSL_BIN genrsa "$length" 2>/dev/null >"$f"
${ACME_OPENSSL_BIN:-openssl} genrsa "$length" 2>/dev/null >"$f"
fi
if [ "$?" != "0" ]; then
......@@ -564,7 +991,7 @@ _createkey() {
_is_idn() {
_is_idn_d="$1"
_debug2 _is_idn_d "$_is_idn_d"
_idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '[0-9]' | tr -d '[a-z]' | tr -d '[A-Z]' | tr -d '.,-')
_idn_temp=$(printf "%s" "$_is_idn_d" | tr -d '0-9' | tr -d 'a-z' | tr -d 'A-Z' | tr -d '.,-')
_debug2 _idn_temp "$_idn_temp"
[ "$_idn_temp" ]
}
......@@ -629,14 +1056,19 @@ _createcsr() {
_info "Multi domain" "$alt"
printf -- "\nsubjectAltName=$alt" >>"$csrconf"
fi
if [ "$Le_OCSP_Stable" ]; then
_savedomainconf Le_OCSP_Stable "$Le_OCSP_Stable"
if [ "$Le_OCSP_Staple" ] || [ "$Le_OCSP_Stable" ]; then
_savedomainconf Le_OCSP_Staple "$Le_OCSP_Staple"
_cleardomainconf Le_OCSP_Stable
printf -- "\nbasicConstraints = CA:FALSE\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >>"$csrconf"
fi
_csr_cn="$(_idn "$domain")"
_debug2 _csr_cn "$_csr_cn"
$OPENSSL_BIN req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr"
if _contains "$(uname -a)" "MINGW"; then
${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "//CN=$_csr_cn" -config "$csrconf" -out "$csr"
else
${ACME_OPENSSL_BIN:-openssl} req -new -sha256 -key "$csrkey" -subj "/CN=$_csr_cn" -config "$csrconf" -out "$csr"
fi
}
#_signcsr key csr conf cert
......@@ -647,7 +1079,7 @@ _signcsr() {
cert="$4"
_debug "_signcsr"
_msg="$($OPENSSL_BIN x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
_msg="$(${ACME_OPENSSL_BIN:-openssl} x509 -req -days 365 -in "$csr" -signkey "$key" -extensions v3_req -extfile "$conf" -out "$cert" 2>&1)"
_ret="$?"
_debug "$_msg"
return $_ret
......@@ -660,7 +1092,7 @@ _readSubjectFromCSR() {
_usage "_readSubjectFromCSR mycsr.csr"
return 1
fi
$OPENSSL_BIN req -noout -in "$_csrfile" -subject | _egrep_o "CN=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d '\n'
${ACME_OPENSSL_BIN:-openssl} req -noout -in "$_csrfile" -subject | tr ',' "\n" | _egrep_o "CN *=.*" | cut -d = -f 2 | cut -d / -f 1 | tr -d ' \n'
}
#_csrfile
......@@ -675,7 +1107,7 @@ _readSubjectAltNamesFromCSR() {
_csrsubj="$(_readSubjectFromCSR "$_csrfile")"
_debug _csrsubj "$_csrsubj"
_dnsAltnames="$($OPENSSL_BIN req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')"
_dnsAltnames="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile" | grep "^ *DNS:.*" | tr -d ' \n')"
_debug _dnsAltnames "$_dnsAltnames"
if _contains "$_dnsAltnames," "DNS:$_csrsubj,"; then
......@@ -696,13 +1128,19 @@ _readKeyLengthFromCSR() {
return 1
fi
_outcsr="$($OPENSSL_BIN req -noout -text -in "$_csrfile")"
_outcsr="$(${ACME_OPENSSL_BIN:-openssl} req -noout -text -in "$_csrfile")"
_debug2 _outcsr "$_outcsr"
if _contains "$_outcsr" "Public Key Algorithm: id-ecPublicKey"; then
_debug "ECC CSR"
echo "$_outcsr" | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *ASN1 OID:.*" | cut -d ':' -f 2 | tr -d ' '
else
_debug "RSA CSR"
echo "$_outcsr" | _egrep_o "^ *Public-Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
_rkl="$(echo "$_outcsr" | tr "\t" " " | _egrep_o "^ *Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1)"
if [ "$_rkl" ]; then
echo "$_rkl"
else
echo "$_outcsr" | tr "\t" " " | _egrep_o "RSA Public.Key:.*" | cut -d '(' -f 2 | cut -d ' ' -f 1
fi
fi
}
......@@ -711,7 +1149,7 @@ _ss() {
if _exists "ss"; then
_debug "Using: ss"
ss -ntpl | grep ":$_port "
ss -ntpl 2>/dev/null | grep ":$_port "
return 0
fi
......@@ -726,8 +1164,12 @@ _ss() {
elif netstat -help 2>&1 | grep -- '-P protocol' >/dev/null; then
#for solaris
netstat -an -P tcp | grep "\.$_port " | grep "LISTEN"
else
elif netstat -help 2>&1 | grep "\-p" >/dev/null; then
#for full linux
netstat -ntpl | grep ":$_port "
else
#for busybox (embedded linux; no pid support)
netstat -ntl 2>/dev/null | grep ":$_port "
fi
fi
return 0
......@@ -736,6 +1178,28 @@ _ss() {
return 1
}
#outfile key cert cacert [password [name [caname]]]
_toPkcs() {
_cpfx="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
pfxPassword="$5"
pfxName="$6"
pfxCaname="$7"
if [ "$pfxCaname" ]; then
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName" -caname "$pfxCaname"
elif [ "$pfxName" ]; then
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword" -name "$pfxName"
elif [ "$pfxPassword" ]; then
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca" -password "pass:$pfxPassword"
else
${ACME_OPENSSL_BIN:-openssl} pkcs12 -export -out "$_cpfx" -inkey "$_ckey" -in "$_ccert" -certfile "$_cca"
fi
}
#domain [password] [isEcc]
toPkcs() {
domain="$1"
......@@ -749,11 +1213,7 @@ toPkcs() {
_initpath "$domain" "$_isEcc"
if [ "$pfxPassword" ]; then
$OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH" -password "pass:$pfxPassword"
else
$OPENSSL_BIN pkcs12 -export -out "$CERT_PFX_PATH" -inkey "$CERT_KEY_PATH" -in "$CERT_PATH" -certfile "$CA_CERT_PATH"
fi
_toPkcs "$CERT_PFX_PATH" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$pfxPassword"
if [ "$?" = "0" ]; then
_info "Success, Pfx is exported to: $CERT_PFX_PATH"
......@@ -761,6 +1221,27 @@ toPkcs() {
}
#domain [isEcc]
toPkcs8() {
domain="$1"
if [ -z "$domain" ]; then
_usage "Usage: $PROJECT_ENTRY --toPkcs8 -d domain [--ecc]"
return 1
fi
_isEcc="$2"
_initpath "$domain" "$_isEcc"
${ACME_OPENSSL_BIN:-openssl} pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in "$CERT_KEY_PATH" -out "$CERT_PKCS8_PATH"
if [ "$?" = "0" ]; then
_info "Success, $CERT_PKCS8_PATH"
fi
}
#[2048]
createAccountKey() {
_info "Creating account key"
......@@ -806,17 +1287,20 @@ createDomainKey() {
fi
domain=$1
length=$2
_cdl=$2
if [ -z "$length" ]; then
if [ -z "$_cdl" ]; then
_debug "Use DEFAULT_DOMAIN_KEY_LENGTH=$DEFAULT_DOMAIN_KEY_LENGTH"
length="$DEFAULT_DOMAIN_KEY_LENGTH"
_cdl="$DEFAULT_DOMAIN_KEY_LENGTH"
fi
_initpath "$domain" "$length"
_initpath "$domain" "$_cdl"
if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]); then
_createkey "$length" "$CERT_KEY_PATH"
if [ ! -f "$CERT_KEY_PATH" ] || ([ "$FORCE" ] && ! [ "$IS_RENEW" ]) || [ "$Le_ForceNewDomainKey" = "1" ]; then
if _createkey "$_cdl" "$CERT_KEY_PATH"; then
_savedomainconf Le_Keylength "$_cdl"
_info "The domain key is here: $(__green $CERT_KEY_PATH)"
fi
else
if [ "$IS_RENEW" ]; then
_info "Domain key exists, skip"
......@@ -858,17 +1342,17 @@ createCSR() {
}
_urlencode() {
_url_replace() {
tr '/+' '_-' | tr -d '= '
}
_time2str() {
#BSD
#Linux
if date -u -d@"$1" 2>/dev/null; then
return
fi
#Linux
#BSD
if date -u -r "$1" 2>/dev/null; then
return
fi
......@@ -879,6 +1363,10 @@ _time2str() {
echo "$_t_s_a"
fi
#Busybox
if echo "$1" | awk '{ print strftime("%c", $0); }' 2>/dev/null; then
return
fi
}
_normalizeJson() {
......@@ -914,7 +1402,7 @@ _calcjwk() {
if grep "BEGIN RSA PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
_debug "RSA key"
pub_exp=$($OPENSSL_BIN rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
pub_exp=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -noout -text | grep "^publicExponent:" | cut -d '(' -f 2 | cut -d 'x' -f 2 | cut -d ')' -f 1)
if [ "${#pub_exp}" = "5" ]; then
pub_exp=0$pub_exp
fi
......@@ -923,9 +1411,11 @@ _calcjwk() {
e=$(echo "$pub_exp" | _h2b | _base64)
_debug3 e "$e"
modulus=$($OPENSSL_BIN rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2)
modulus=$(${ACME_OPENSSL_BIN:-openssl} rsa -in "$keyfile" -modulus -noout | cut -d '=' -f 2)
_debug3 modulus "$modulus"
n="$(printf "%s" "$modulus" | _h2b | _base64 | _urlencode)"
n="$(printf "%s" "$modulus" | _h2b | _base64 | _url_replace)"
_debug3 n "$n"
jwk='{"e": "'$e'", "kty": "RSA", "n": "'$n'"}'
_debug3 jwk "$jwk"
......@@ -934,22 +1424,29 @@ _calcjwk() {
JWK_HEADERPLACE_PART2='", "alg": "RS256", "jwk": '$jwk'}'
elif grep "BEGIN EC PRIVATE KEY" "$keyfile" >/dev/null 2>&1; then
_debug "EC key"
crv="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
crv="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^NIST CURVE:" | cut -d ":" -f 2 | tr -d " \r\n")"
_debug3 crv "$crv"
__ECC_KEY_LEN=$(echo "$crv" | cut -d "-" -f 2)
if [ "$__ECC_KEY_LEN" = "521" ]; then
__ECC_KEY_LEN=512
fi
_debug3 __ECC_KEY_LEN "$__ECC_KEY_LEN"
if [ -z "$crv" ]; then
_debug "Let's try ASN1 OID"
crv_oid="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")"
crv_oid="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep "^ASN1 OID:" | cut -d ":" -f 2 | tr -d " \r\n")"
_debug3 crv_oid "$crv_oid"
case "${crv_oid}" in
"prime256v1")
crv="P-256"
__ECC_KEY_LEN=256
;;
"secp384r1")
crv="P-384"
__ECC_KEY_LEN=384
;;
"secp521r1")
crv="P-521"
__ECC_KEY_LEN=512
;;
*)
_err "ECC oid : $crv_oid"
......@@ -959,15 +1456,15 @@ _calcjwk() {
_debug3 crv "$crv"
fi
pubi="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
pubi="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n pub: | cut -d : -f 1)"
pubi=$(_math "$pubi" + 1)
_debug3 pubi "$pubi"
pubj="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
pubj="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | grep -n "ASN1 OID:" | cut -d : -f 1)"
pubj=$(_math "$pubj" - 1)
_debug3 pubj "$pubj"
pubtext="$($OPENSSL_BIN ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
pubtext="$(${ACME_OPENSSL_BIN:-openssl} ec -in "$keyfile" -noout -text 2>/dev/null | sed -n "$pubi,${pubj}p" | tr -d " \n\r")"
_debug3 pubtext "$pubtext"
xlen="$(printf "%s" "$pubtext" | tr -d ':' | wc -c)"
......@@ -978,22 +1475,22 @@ _calcjwk() {
x="$(printf "%s" "$pubtext" | cut -d : -f 2-"$xend")"
_debug3 x "$x"
x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _urlencode)"
x64="$(printf "%s" "$x" | tr -d : | _h2b | _base64 | _url_replace)"
_debug3 x64 "$x64"
xend=$(_math "$xend" + 1)
y="$(printf "%s" "$pubtext" | cut -d : -f "$xend"-10000)"
_debug3 y "$y"
y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _urlencode)"
y64="$(printf "%s" "$y" | tr -d : | _h2b | _base64 | _url_replace)"
_debug3 y64 "$y64"
jwk='{"crv": "'$crv'", "kty": "EC", "x": "'$x64'", "y": "'$y64'"}'
_debug3 jwk "$jwk"
JWK_HEADER='{"alg": "ES256", "jwk": '$jwk'}'
JWK_HEADER='{"alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}'
JWK_HEADERPLACE_PART1='{"nonce": "'
JWK_HEADERPLACE_PART2='", "alg": "ES256", "jwk": '$jwk'}'
JWK_HEADERPLACE_PART2='", "alg": "ES'$__ECC_KEY_LEN'", "jwk": '$jwk'}'
else
_err "Only RSA or EC key is supported."
return 1
......@@ -1007,6 +1504,10 @@ _time() {
date -u "+%s"
}
_utc_date() {
date -u "+%Y-%m-%d %H:%M:%S"
}
_mktemp() {
if _exists mktemp; then
if mktemp 2>/dev/null; then
......@@ -1047,7 +1548,9 @@ _inithttp() {
_ACME_CURL="$_ACME_CURL --trace-ascii $_CURL_DUMP "
fi
if [ "$CA_BUNDLE" ]; then
if [ "$CA_PATH" ]; then
_ACME_CURL="$_ACME_CURL --capath $CA_PATH "
elif [ "$CA_BUNDLE" ]; then
_ACME_CURL="$_ACME_CURL --cacert $CA_BUNDLE "
fi
......@@ -1058,11 +1561,18 @@ _inithttp() {
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
_ACME_WGET="$_ACME_WGET -d "
fi
if [ "$CA_BUNDLE" ]; then
_ACME_WGET="$_ACME_WGET --ca-certificate $CA_BUNDLE "
if [ "$CA_PATH" ]; then
_ACME_WGET="$_ACME_WGET --ca-directory=$CA_PATH "
elif [ "$CA_BUNDLE" ]; then
_ACME_WGET="$_ACME_WGET --ca-certificate=$CA_BUNDLE "
fi
fi
#from wget 1.14: do not skip body on 404 error
if [ "$_ACME_WGET" ] && _contains "$($_ACME_WGET --help 2>&1)" "--content-on-error"; then
_ACME_WGET="$_ACME_WGET --content-on-error "
fi
__HTTP_INITIALIZED=1
}
......@@ -1083,7 +1593,7 @@ _post() {
_inithttp
if [ "$_ACME_CURL" ]; then
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
_CURL="$_ACME_CURL"
if [ "$HTTPS_INSECURE" ]; then
_CURL="$_CURL --insecure "
......@@ -1124,7 +1634,7 @@ _post() {
_ret="$?"
if [ "$_ret" = "8" ]; then
_ret=0
_debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later."
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
fi
if [ "$_ret" != "0" ]; then
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $_ret"
......@@ -1150,7 +1660,7 @@ _get() {
_inithttp
if [ "$_ACME_CURL" ]; then
if [ "$_ACME_CURL" ] && [ "${ACME_USE_WGET:-0}" = "0" ]; then
_CURL="$_ACME_CURL"
if [ "$HTTPS_INSECURE" ]; then
_CURL="$_CURL --insecure "
......@@ -1187,9 +1697,9 @@ _get() {
$_WGET --user-agent="$USER_AGENT" --header "$_H5" --header "$_H4" --header "$_H3" --header "$_H2" --header "$_H1" -O - "$url"
fi
ret=$?
if [ "$_ret" = "8" ]; then
_ret=0
_debug "wget returns 8, the server returns a 'Bad request' respons, lets process the response later."
if [ "$ret" = "8" ]; then
ret=0
_debug "wget returns 8, the server returns a 'Bad request' response, lets process the response later."
fi
if [ "$ret" != "0" ]; then
_err "Please refer to https://www.gnu.org/software/wget/manual/html_node/Exit-Status.html for error code: $ret"
......@@ -1229,13 +1739,27 @@ _send_signed_request() {
return 1
fi
payload64=$(printf "%s" "$payload" | _base64 | _urlencode)
payload64=$(printf "%s" "$payload" | _base64 | _url_replace)
_debug3 payload64 "$payload64"
MAX_REQUEST_RETRY_TIMES=5
_request_retry_times=0
while [ "${_request_retry_times}" -lt "$MAX_REQUEST_RETRY_TIMES" ]; do
_debug3 _request_retry_times "$_request_retry_times"
if [ -z "$_CACHED_NONCE" ]; then
_debug2 "Get nonce."
nonceurl="$API/directory"
_headers=""
if [ "$ACME_NEW_NONCE" ]; then
_debug2 "Get nonce. ACME_NEW_NONCE" "$ACME_NEW_NONCE"
nonceurl="$ACME_NEW_NONCE"
if _post "" "$nonceurl" "" "HEAD"; then
_headers="$(cat "$HTTP_HEADER")"
fi
fi
if [ -z "$_headers" ]; then
_debug2 "Get nonce. ACME_DIRECTORY" "$ACME_DIRECTORY"
nonceurl="$ACME_DIRECTORY"
_headers="$(_get "$nonceurl" "onlyheader")"
fi
if [ "$?" != "0" ]; then
_err "Can not connect to $nonceurl to get nonce."
......@@ -1252,10 +1776,10 @@ _send_signed_request() {
nonce="$_CACHED_NONCE"
_debug2 nonce "$nonce"
protected="$JWK_HEADERPLACE_PART1$nonce$JWK_HEADERPLACE_PART2"
protected="$JWK_HEADERPLACE_PART1$nonce\", \"url\": \"${url}$JWK_HEADERPLACE_PART2"
_debug3 protected "$protected"
protected64="$(printf "%s" "$protected" | _base64 | _urlencode)"
protected64="$(printf "%s" "$protected" | _base64 | _url_replace)"
_debug3 protected64 "$protected64"
if ! _sig_t="$(printf "%s" "$protected64.$payload64" | _sign "$keyfile" "sha256")"; then
......@@ -1264,7 +1788,7 @@ _send_signed_request() {
fi
_debug3 _sig_t "$_sig_t"
sig="$(printf "%s" "$_sig_t" | _urlencode)"
sig="$(printf "%s" "$_sig_t" | _url_replace)"
_debug3 sig "$sig"
body="{\"header\": $JWK_HEADER, \"protected\": \"$protected64\", \"payload\": \"$payload64\", \"signature\": \"$sig\"}"
......@@ -1272,12 +1796,12 @@ _send_signed_request() {
response="$(_post "$body" "$url" "$needbase64")"
_CACHED_NONCE=""
if [ "$?" != "0" ]; then
_err "Can not post to $url"
return 1
fi
_debug2 original "$response"
response="$(echo "$response" | _normalizeJson)"
responseHeaders="$(cat "$HTTP_HEADER")"
......@@ -1289,6 +1813,21 @@ _send_signed_request() {
_CACHED_NONCE="$(echo "$responseHeaders" | grep "Replay-Nonce:" | _head_n 1 | tr -d "\r\n " | cut -d ':' -f 2)"
_body="$response"
if [ "$needbase64" ]; then
_body="$(echo "$_body" | _dbase64)"
_debug2 _body "$_body"
fi
if _contains "$_body" "JWS has invalid anti-replay nonce"; then
_info "It seems the CA server is busy now, let's wait and retry."
_request_retry_times=$(_math "$_request_retry_times" + 1)
_sleep 5
continue
fi
break
done
}
#setopt "file" "opt" "=" "value" [";"]
......@@ -1312,20 +1851,20 @@ _setopt() {
__val="$(echo "$__val" | sed 's/&/\\&/g')"
fi
text="$(cat "$__conf")"
echo "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
printf -- "%s\n" "$text" | sed "s|^$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
elif grep -n "^#$__opt$__sep" "$__conf" >/dev/null; then
if _contains "$__val" "&"; then
__val="$(echo "$__val" | sed 's/&/\\&/g')"
fi
text="$(cat "$__conf")"
echo "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
printf -- "%s\n" "$text" | sed "s|^#$__opt$__sep.*$|$__opt$__sep$__val$__end|" >"$__conf"
else
_debug3 APP
echo "$__opt$__sep$__val$__end" >>"$__conf"
fi
_debug2 "$(grep -n "^$__opt$__sep" "$__conf")"
_debug3 "$(grep -n "^$__opt$__sep" "$__conf")"
}
#_save_conf file key value
......@@ -1388,6 +1927,24 @@ _saveaccountconf() {
_save_conf "$ACCOUNT_CONF_PATH" "$1" "$2"
}
#key value
_saveaccountconf_mutable() {
_save_conf "$ACCOUNT_CONF_PATH" "SAVED_$1" "$2"
#remove later
_clearaccountconf "$1"
}
#key
_readaccountconf() {
_read_conf "$ACCOUNT_CONF_PATH" "$1"
}
#key
_readaccountconf_mutable() {
_rac_key="$1"
_readaccountconf "SAVED_$_rac_key"
}
#_clearaccountconf key
_clearaccountconf() {
_clear_conf "$ACCOUNT_CONF_PATH" "$1"
......@@ -1415,60 +1972,22 @@ _startserver() {
_debug "ncaddr" "$ncaddr"
_debug "startserver: $$"
nchelp="$(nc -h 2>&1)"
_debug Le_HTTPPort "$Le_HTTPPort"
_debug Le_Listen_V4 "$Le_Listen_V4"
_debug Le_Listen_V6 "$Le_Listen_V6"
_NC="nc"
_NC="socat"
if [ "$Le_Listen_V4" ]; then
_NC="$_NC -4"
elif [ "$Le_Listen_V6" ]; then
_NC="$_NC -6"
fi
if echo "$nchelp" | grep "\-q[ ,]" >/dev/null; then
_NC="$_NC -q 1 -l $ncaddr"
else
if echo "$nchelp" | grep "GNU netcat" >/dev/null && echo "$nchelp" | grep "\-c, \-\-close" >/dev/null; then
_NC="$_NC -c -l $ncaddr"
elif echo "$nchelp" | grep "\-N" | grep "Shutdown the network socket after EOF on stdin" >/dev/null; then
_NC="$_NC -N -l $ncaddr"
else
_NC="$_NC -l $ncaddr"
fi
fi
_debug "_NC" "$_NC"
#for centos ncat
if _contains "$nchelp" "nmap.org"; then
_debug "Using ncat: nmap.org"
if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"; then
_exec_err
return 1
fi
if [ "$DEBUG" ]; then
_exec_err
fi
return
fi
# while true ; do
if ! _exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC -p \"$Le_HTTPPort\" >&2"; then
_exec "printf \"%s\r\n\r\n%s\" \"HTTP/1.1 200 OK\" \"$content\" | $_NC \"$Le_HTTPPort\" >&2"
fi
if [ "$?" != "0" ]; then
_err "nc listen error."
_exec_err
exit 1
fi
if [ "$DEBUG" ]; then
_exec_err
fi
# done
#todo listen address
$_NC TCP-LISTEN:$Le_HTTPPort,crlf,reuseaddr,fork SYSTEM:"sleep 0.5; echo HTTP/1.1 200 OK; echo ; echo $content; echo;" &
serverproc="$!"
}
_stopserver() {
......@@ -1478,25 +1997,8 @@ _stopserver() {
return
fi
_debug2 "Le_HTTPPort" "$Le_HTTPPort"
if [ "$Le_HTTPPort" ]; then
if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then
_get "http://localhost:$Le_HTTPPort" "" 1
else
_get "http://localhost:$Le_HTTPPort" "" 1 >/dev/null 2>&1
fi
fi
kill $pid
_debug2 "Le_TLSPort" "$Le_TLSPort"
if [ "$Le_TLSPort" ]; then
if [ "$DEBUG" ] && [ "$DEBUG" -gt "3" ]; then
_get "https://localhost:$Le_TLSPort" "" 1
_get "https://localhost:$Le_TLSPort" "" 1
else
_get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
_get "https://localhost:$Le_TLSPort" "" 1 >/dev/null 2>&1
fi
fi
}
# sleep sec
......@@ -1551,7 +2053,7 @@ _starttlsserver() {
return 1
fi
__S_OPENSSL="$OPENSSL_BIN s_server -cert $TLS_CERT -key $TLS_KEY "
__S_OPENSSL="${ACME_OPENSSL_BIN:-openssl} s_server -www -cert $TLS_CERT -key $TLS_KEY "
if [ "$opaddr" ]; then
__S_OPENSSL="$__S_OPENSSL -accept $opaddr:$port"
else
......@@ -1568,9 +2070,9 @@ _starttlsserver() {
_debug "$__S_OPENSSL"
if [ "$DEBUG" ] && [ "$DEBUG" -ge "2" ]; then
(printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL -tlsextdebug) &
$__S_OPENSSL -tlsextdebug &
else
(printf "%s\r\n\r\n%s" "HTTP/1.1 200 OK" "$content" | $__S_OPENSSL >/dev/null 2>&1) &
$__S_OPENSSL >/dev/null 2>&1 &
fi
serverproc="$!"
......@@ -1582,14 +2084,18 @@ _starttlsserver() {
_readlink() {
_rf="$1"
if ! readlink -f "$_rf" 2>/dev/null; then
if _startswith "$_rf" "\./$PROJECT_ENTRY"; then
printf -- "%s" "$(pwd)/$PROJECT_ENTRY"
if _startswith "$_rf" "/"; then
echo "$_rf"
return 0
fi
readlink "$_rf"
echo "$(pwd)/$_rf" | _conapath
fi
}
_conapath() {
sed "s#/\./#/#g"
}
__initHome() {
if [ -z "$_SCRIPT_HOME" ]; then
if _exists readlink && _exists dirname; then
......@@ -1607,14 +2113,14 @@ __initHome() {
fi
fi
if [ -z "$LE_WORKING_DIR" ]; then
if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then
_debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME"
LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
else
LE_WORKING_DIR="$_SCRIPT_HOME"
fi
fi
# if [ -z "$LE_WORKING_DIR" ]; then
# if [ -f "$DEFAULT_INSTALL_HOME/account.conf" ]; then
# _debug "It seems that $PROJECT_NAME is already installed in $DEFAULT_INSTALL_HOME"
# LE_WORKING_DIR="$DEFAULT_INSTALL_HOME"
# else
# LE_WORKING_DIR="$_SCRIPT_HOME"
# fi
# fi
if [ -z "$LE_WORKING_DIR" ]; then
_debug "Using default home:$DEFAULT_INSTALL_HOME"
......@@ -1622,7 +2128,13 @@ __initHome() {
fi
export LE_WORKING_DIR
_DEFAULT_ACCOUNT_CONF_PATH="$LE_WORKING_DIR/account.conf"
if [ -z "$LE_CONFIG_HOME" ]; then
LE_CONFIG_HOME="$LE_WORKING_DIR"
fi
_debug "Using config home:$LE_CONFIG_HOME"
export LE_CONFIG_HOME
_DEFAULT_ACCOUNT_CONF_PATH="$LE_CONFIG_HOME/account.conf"
if [ -z "$ACCOUNT_CONF_PATH" ]; then
if [ -f "$_DEFAULT_ACCOUNT_CONF_PATH" ]; then
......@@ -1634,16 +2146,73 @@ __initHome() {
ACCOUNT_CONF_PATH="$_DEFAULT_ACCOUNT_CONF_PATH"
fi
DEFAULT_LOG_FILE="$LE_WORKING_DIR/$PROJECT_NAME.log"
DEFAULT_LOG_FILE="$LE_CONFIG_HOME/$PROJECT_NAME.log"
DEFAULT_CA_HOME="$LE_WORKING_DIR/ca"
DEFAULT_CA_HOME="$LE_CONFIG_HOME/ca"
if [ -z "$LE_TEMP_DIR" ]; then
LE_TEMP_DIR="$LE_WORKING_DIR/tmp"
LE_TEMP_DIR="$LE_CONFIG_HOME/tmp"
fi
}
#[domain] [keylength]
#server
_initAPI() {
_api_server="${1:-$ACME_DIRECTORY}"
_debug "_init api for server: $_api_server"
if [ -z "$ACME_NEW_ACCOUNT" ]; then
response=$(_get "$_api_server")
if [ "$?" != "0" ]; then
_debug2 "response" "$response"
_err "Can not init api."
return 1
fi
_debug2 "response" "$response"
ACME_KEY_CHANGE=$(echo "$response" | _egrep_o 'key-change" *: *"[^"]*"' | cut -d '"' -f 3)
export ACME_KEY_CHANGE
ACME_NEW_AUTHZ=$(echo "$response" | _egrep_o 'new-authz" *: *"[^"]*"' | cut -d '"' -f 3)
export ACME_NEW_AUTHZ
ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-cert" *: *"[^"]*"' | cut -d '"' -f 3)
ACME_NEW_ORDER_RES="new-cert"
if [ -z "$ACME_NEW_ORDER" ]; then
ACME_NEW_ORDER=$(echo "$response" | _egrep_o 'new-order" *: *"[^"]*"' | cut -d '"' -f 3)
ACME_NEW_ORDER_RES="new-order"
fi
export ACME_NEW_ORDER
export ACME_NEW_ORDER_RES
ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-reg" *: *"[^"]*"' | cut -d '"' -f 3)
ACME_NEW_ACCOUNT_RES="new-reg"
if [ -z "$ACME_NEW_ACCOUNT" ]; then
ACME_NEW_ACCOUNT=$(echo "$response" | _egrep_o 'new-account" *: *"[^"]*"' | cut -d '"' -f 3)
ACME_NEW_ACCOUNT_RES="new-account"
fi
export ACME_NEW_ACCOUNT
export ACME_NEW_ACCOUNT_RES
ACME_REVOKE_CERT=$(echo "$response" | _egrep_o 'revoke-cert" *: *"[^"]*"' | cut -d '"' -f 3)
export ACME_REVOKE_CERT
ACME_NEW_NONCE=$(echo "$response" | _egrep_o 'new-nonce" *: *"[^"]*"' | cut -d '"' -f 3)
export ACME_NEW_NONCE
ACME_AGREEMENT=$(echo "$response" | _egrep_o 'terms-of-service" *: *"[^"]*"' | cut -d '"' -f 3)
export ACME_AGREEMENT
_debug "ACME_KEY_CHANGE" "$ACME_KEY_CHANGE"
_debug "ACME_NEW_AUTHZ" "$ACME_NEW_AUTHZ"
_debug "ACME_NEW_ORDER" "$ACME_NEW_ORDER"
_debug "ACME_NEW_ACCOUNT" "$ACME_NEW_ACCOUNT"
_debug "ACME_REVOKE_CERT" "$ACME_REVOKE_CERT"
_debug "ACME_AGREEMENT" "$ACME_AGREEMENT"
fi
}
#[domain] [keylength or isEcc flag]
_initpath() {
__initHome
......@@ -1663,23 +2232,27 @@ _initpath() {
CA_HOME="$DEFAULT_CA_HOME"
fi
if [ -z "$API" ]; then
if [ -z "$ACME_DIRECTORY" ]; then
if [ -z "$STAGE" ]; then
API="$DEFAULT_CA"
ACME_DIRECTORY="$DEFAULT_CA"
else
API="$STAGE_CA"
_info "Using stage api:$API"
ACME_DIRECTORY="$STAGE_CA"
_info "Using stage ACME_DIRECTORY: $ACME_DIRECTORY"
fi
fi
_API_HOST="$(echo "$API" | cut -d : -f 2 | tr -d '/')"
CA_DIR="$CA_HOME/$_API_HOST"
_debug2 ACME_DIRECTORY "$ACME_DIRECTORY"
_ACME_SERVER_HOST="$(echo "$ACME_DIRECTORY" | cut -d : -f 2 | tr -s / | cut -d / -f 2)"
_debug2 "_ACME_SERVER_HOST" "$_ACME_SERVER_HOST"
CA_DIR="$CA_HOME/$_ACME_SERVER_HOST"
_DEFAULT_CA_CONF="$CA_DIR/ca.conf"
if [ -z "$CA_CONF" ]; then
CA_CONF="$_DEFAULT_CA_CONF"
fi
_debug3 CA_CONF "$CA_CONF"
if [ -f "$CA_CONF" ]; then
. "$CA_CONF"
......@@ -1690,7 +2263,7 @@ _initpath() {
fi
if [ -z "$APACHE_CONF_BACKUP_DIR" ]; then
APACHE_CONF_BACKUP_DIR="$LE_WORKING_DIR"
APACHE_CONF_BACKUP_DIR="$LE_CONFIG_HOME"
fi
if [ -z "$USER_AGENT" ]; then
......@@ -1698,7 +2271,7 @@ _initpath() {
fi
if [ -z "$HTTP_HEADER" ]; then
HTTP_HEADER="$LE_WORKING_DIR/http.header"
HTTP_HEADER="$LE_CONFIG_HOME/http.header"
fi
_OLD_ACCOUNT_KEY="$LE_WORKING_DIR/account.key"
......@@ -1714,13 +2287,13 @@ _initpath() {
ACCOUNT_JSON_PATH="$_DEFAULT_ACCOUNT_JSON_PATH"
fi
_DEFAULT_CERT_HOME="$LE_WORKING_DIR"
_DEFAULT_CERT_HOME="$LE_CONFIG_HOME"
if [ -z "$CERT_HOME" ]; then
CERT_HOME="$_DEFAULT_CERT_HOME"
fi
if [ -z "$OPENSSL_BIN" ]; then
OPENSSL_BIN="$DEFAULT_OPENSSL_BIN"
if [ -z "$ACME_OPENSSL_BIN" ] || [ ! -f "$ACME_OPENSSL_BIN" ] || [ ! -x "$ACME_OPENSSL_BIN" ]; then
ACME_OPENSSL_BIN="$DEFAULT_OPENSSL_BIN"
fi
if [ -z "$1" ]; then
......@@ -1746,6 +2319,10 @@ _initpath() {
_debug DOMAIN_PATH "$DOMAIN_PATH"
fi
if [ -z "$DOMAIN_BACKUP_PATH" ]; then
DOMAIN_BACKUP_PATH="$DOMAIN_PATH/backup"
fi
if [ -z "$DOMAIN_CONF" ]; then
DOMAIN_CONF="$DOMAIN_PATH/$domain.conf"
fi
......@@ -1772,18 +2349,21 @@ _initpath() {
if [ -z "$CERT_PFX_PATH" ]; then
CERT_PFX_PATH="$DOMAIN_PATH/$domain.pfx"
fi
if [ -z "$CERT_PKCS8_PATH" ]; then
CERT_PKCS8_PATH="$DOMAIN_PATH/$domain.pkcs8"
fi
if [ -z "$TLS_CONF" ]; then
TLS_CONF="$DOMAIN_PATH/tls.valdation.conf"
TLS_CONF="$DOMAIN_PATH/tls.validation.conf"
fi
if [ -z "$TLS_CERT" ]; then
TLS_CERT="$DOMAIN_PATH/tls.valdation.cert"
TLS_CERT="$DOMAIN_PATH/tls.validation.cert"
fi
if [ -z "$TLS_KEY" ]; then
TLS_KEY="$DOMAIN_PATH/tls.valdation.key"
TLS_KEY="$DOMAIN_PATH/tls.validation.key"
fi
if [ -z "$TLS_CSR" ]; then
TLS_CSR="$DOMAIN_PATH/tls.valdation.csr"
TLS_CSR="$DOMAIN_PATH/tls.validation.csr"
fi
}
......@@ -1901,12 +2481,12 @@ _setApache() {
_debug "Backup apache config file" "$httpdconf"
if ! cp "$httpdconf" "$APACHE_CONF_BACKUP_DIR/"; then
_err "Can not backup apache config file, so abort. Don't worry, the apache config is not changed."
_err "This might be a bug of $PROJECT_NAME , pleae report issue: $PROJECT"
_err "This might be a bug of $PROJECT_NAME , please report issue: $PROJECT"
return 1
fi
_info "JFYI, Config file $httpdconf is backuped to $APACHE_CONF_BACKUP_DIR/$httpdconfname"
_info "In case there is an error that can not be restored automatically, you may try restore it yourself."
_info "The backup file will be deleted on sucess, just forget it."
_info "The backup file will be deleted on success, just forget it."
#add alias
......@@ -1960,10 +2540,230 @@ Allow from all
return 0
}
#find the real nginx conf file
#backup
#set the nginx conf
#returns the real nginx conf file
_setNginx() {
_d="$1"
_croot="$2"
_thumbpt="$3"
if ! _exists "nginx"; then
_err "nginx command is not found."
return 1
fi
FOUND_REAL_NGINX_CONF=""
FOUND_REAL_NGINX_CONF_LN=""
BACKUP_NGINX_CONF=""
_debug _croot "$_croot"
_start_f="$(echo "$_croot" | cut -d : -f 2)"
_debug _start_f "$_start_f"
if [ -z "$_start_f" ]; then
_debug "find start conf from nginx command"
if [ -z "$NGINX_CONF" ]; then
NGINX_CONF="$(nginx -V 2>&1 | _egrep_o "--conf-path=[^ ]* " | tr -d " ")"
_debug NGINX_CONF "$NGINX_CONF"
NGINX_CONF="$(echo "$NGINX_CONF" | cut -d = -f 2)"
_debug NGINX_CONF "$NGINX_CONF"
if [ ! -f "$NGINX_CONF" ]; then
_err "'$NGINX_CONF' doesn't exist."
NGINX_CONF=""
return 1
fi
_debug "Found nginx conf file:$NGINX_CONF"
fi
_start_f="$NGINX_CONF"
fi
_debug "Start detect nginx conf for $_d from:$_start_f"
if ! _checkConf "$_d" "$_start_f"; then
_err "Can not find conf file for domain $d"
return 1
fi
_info "Found conf file: $FOUND_REAL_NGINX_CONF"
_ln=$FOUND_REAL_NGINX_CONF_LN
_debug "_ln" "$_ln"
_lnn=$(_math $_ln + 1)
_debug _lnn "$_lnn"
_start_tag="$(sed -n "$_lnn,${_lnn}p" "$FOUND_REAL_NGINX_CONF")"
_debug "_start_tag" "$_start_tag"
if [ "$_start_tag" = "$NGINX_START" ]; then
_info "The domain $_d is already configured, skip"
FOUND_REAL_NGINX_CONF=""
return 0
fi
mkdir -p "$DOMAIN_BACKUP_PATH"
_backup_conf="$DOMAIN_BACKUP_PATH/$_d.nginx.conf"
_debug _backup_conf "$_backup_conf"
BACKUP_NGINX_CONF="$_backup_conf"
_info "Backup $FOUND_REAL_NGINX_CONF to $_backup_conf"
if ! cp "$FOUND_REAL_NGINX_CONF" "$_backup_conf"; then
_err "backup error."
FOUND_REAL_NGINX_CONF=""
return 1
fi
_info "Check the nginx conf before setting up."
if ! _exec "nginx -t" >/dev/null; then
_exec_err
return 1
fi
_info "OK, Set up nginx config file"
if ! sed -n "1,${_ln}p" "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"; then
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
_err "write nginx conf error, but don't worry, the file is restored to the original version."
return 1
fi
echo "$NGINX_START
location ~ \"^/\.well-known/acme-challenge/([-_a-zA-Z0-9]+)\$\" {
default_type text/plain;
return 200 \"\$1.$_thumbpt\";
}
#NGINX_START
" >>"$FOUND_REAL_NGINX_CONF"
if ! sed -n "${_lnn},99999p" "$_backup_conf" >>"$FOUND_REAL_NGINX_CONF"; then
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
_err "write nginx conf error, but don't worry, the file is restored."
return 1
fi
_debug3 "Modified config:$(cat $FOUND_REAL_NGINX_CONF)"
_info "nginx conf is done, let's check it again."
if ! _exec "nginx -t" >/dev/null; then
_exec_err
_err "It seems that nginx conf was broken, let's restore."
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
return 1
fi
_info "Reload nginx"
if ! _exec "nginx -s reload" >/dev/null; then
_exec_err
_err "It seems that nginx reload error, let's restore."
cat "$_backup_conf" >"$FOUND_REAL_NGINX_CONF"
return 1
fi
return 0
}
#d , conf
_checkConf() {
_d="$1"
_c_file="$2"
_debug "Start _checkConf from:$_c_file"
if [ ! -f "$2" ] && ! echo "$2" | grep '*$' >/dev/null && echo "$2" | grep '*' >/dev/null; then
_debug "wildcard"
for _w_f in $2; do
if [ -f "$_w_f" ] && _checkConf "$1" "$_w_f"; then
return 0
fi
done
#not found
return 1
elif [ -f "$2" ]; then
_debug "single"
if _isRealNginxConf "$1" "$2"; then
_debug "$2 is found."
FOUND_REAL_NGINX_CONF="$2"
return 0
fi
if cat "$2" | tr "\t" " " | grep "^ *include *.*;" >/dev/null; then
_debug "Try include files"
for included in $(cat "$2" | tr "\t" " " | grep "^ *include *.*;" | sed "s/include //" | tr -d " ;"); do
_debug "check included $included"
if _checkConf "$1" "$included"; then
return 0
fi
done
fi
return 1
else
_debug "$2 not found."
return 1
fi
return 1
}
#d , conf
_isRealNginxConf() {
_debug "_isRealNginxConf $1 $2"
if [ -f "$2" ]; then
for _fln in $(tr "\t" ' ' <"$2" | grep -n "^ *server_name.* $1" | cut -d : -f 1); do
_debug _fln "$_fln"
if [ "$_fln" ]; then
_start=$(tr "\t" ' ' <"$2" | _head_n "$_fln" | grep -n "^ *server *{" | _tail_n 1)
_debug "_start" "$_start"
_start_n=$(echo "$_start" | cut -d : -f 1)
_start_nn=$(_math $_start_n + 1)
_debug "_start_n" "$_start_n"
_debug "_start_nn" "$_start_nn"
_left="$(sed -n "${_start_nn},99999p" "$2")"
_debug2 _left "$_left"
if echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" >/dev/null; then
_end=$(echo "$_left" | tr "\t" ' ' | grep -n "^ *server *{" | _head_n 1)
_debug "_end" "$_end"
_end_n=$(echo "$_end" | cut -d : -f 1)
_debug "_end_n" "$_end_n"
_seg_n=$(echo "$_left" | sed -n "1,${_end_n}p")
else
_seg_n="$_left"
fi
_debug "_seg_n" "$_seg_n"
if [ "$(echo "$_seg_n" | _egrep_o "^ *ssl *on *;")" ] \
|| [ "$(echo "$_seg_n" | _egrep_o "listen .* ssl[ |;]")" ]; then
_debug "ssl on, skip"
else
FOUND_REAL_NGINX_CONF_LN=$_fln
_debug3 "found FOUND_REAL_NGINX_CONF_LN" "$FOUND_REAL_NGINX_CONF_LN"
return 0
fi
fi
done
fi
return 1
}
#restore all the nginx conf
_restoreNginx() {
if [ -z "$NGINX_RESTORE_VLIST" ]; then
_debug "No need to restore nginx, skip."
return
fi
_debug "_restoreNginx"
_debug "NGINX_RESTORE_VLIST" "$NGINX_RESTORE_VLIST"
for ng_entry in $(echo "$NGINX_RESTORE_VLIST" | tr "$dvsep" ' '); do
_debug "ng_entry" "$ng_entry"
_nd=$(echo "$ng_entry" | cut -d "$sep" -f 1)
_ngconf=$(echo "$ng_entry" | cut -d "$sep" -f 2)
_ngbackupconf=$(echo "$ng_entry" | cut -d "$sep" -f 3)
_info "Restoring from $_ngbackupconf to $_ngconf"
cat "$_ngbackupconf" >"$_ngconf"
done
_info "Reload nginx"
if ! _exec "nginx -s reload" >/dev/null; then
_exec_err
_err "It seems that nginx reload error, please report bug."
return 1
fi
return 0
}
_clearup() {
_stopserver "$serverproc"
serverproc=""
_restoreApache
_restoreNginx
_clearupdns
if [ -z "$DEBUG" ]; then
rm -f "$TLS_CONF"
......@@ -1976,7 +2776,7 @@ _clearup() {
_clearupdns() {
_debug "_clearupdns"
if [ "$dnsadded" != 1 ] || [ -z "$vlist" ]; then
_debug "Dns not added, skip."
_debug "skip dns."
return
fi
......@@ -1986,9 +2786,10 @@ _clearupdns() {
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
_debug txt "$txt"
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
_info "$d is already verified, skip $vtype."
_debug "$d is already verified, skip $vtype."
continue
fi
......@@ -2019,7 +2820,7 @@ _clearupdns() {
txtdomain="_acme-challenge.$d"
if ! $rmcommand "$txtdomain"; then
if ! $rmcommand "$txtdomain" "$txt"; then
_err "Error removing txt for domain:$txtdomain"
return 1
fi
......@@ -2060,23 +2861,39 @@ _clearupwebbroot() {
}
_on_before_issue() {
_chk_web_roots="$1"
_chk_main_domain="$2"
_chk_alt_domains="$3"
_chk_pre_hook="$4"
_chk_local_addr="$5"
_debug _on_before_issue
if _hasfield "$Le_Webroot" "$NO_VALUE"; then
if ! _exists "nc"; then
_err "Please install netcat(nc) tools first."
#run pre hook
if [ "$_chk_pre_hook" ]; then
_info "Run pre hook:'$_chk_pre_hook'"
if ! (
cd "$DOMAIN_PATH" && eval "$_chk_pre_hook"
); then
_err "Error when run pre hook."
return 1
fi
fi
_debug Le_LocalAddress "$Le_LocalAddress"
if _hasfield "$_chk_web_roots" "$NO_VALUE"; then
if ! _exists "socat"; then
_err "Please install socat tools first."
return 1
fi
fi
_debug Le_LocalAddress "$_chk_local_addr"
alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ')
alldomains=$(echo "$_chk_main_domain,$_chk_alt_domains" | tr ',' ' ')
_index=1
_currentRoot=""
_addrIndex=1
for d in $alldomains; do
_debug "Check for domain" "$d"
_currentRoot="$(_getfield "$Le_Webroot" $_index)"
_currentRoot="$(_getfield "$_chk_web_roots" $_index)"
_debug "_currentRoot" "$_currentRoot"
_index=$(_math $_index + 1)
_checkport=""
......@@ -2100,7 +2917,7 @@ _on_before_issue() {
if [ "$_checkport" ]; then
_debug _checkport "$_checkport"
_checkaddr="$(_getfield "$Le_LocalAddress" $_addrIndex)"
_checkaddr="$(_getfield "$_chk_local_addr" $_addrIndex)"
_debug _checkaddr "$_checkaddr"
_addrIndex="$(_math $_addrIndex + 1)"
......@@ -2119,7 +2936,7 @@ _on_before_issue() {
fi
done
if _hasfield "$Le_Webroot" "apache"; then
if _hasfield "$_chk_web_roots" "apache"; then
if ! _setApache; then
_err "set up apache error. Report error to me."
return 1
......@@ -2128,19 +2945,11 @@ _on_before_issue() {
usingApache=""
fi
#run pre hook
if [ "$Le_PreHook" ]; then
_info "Run pre hook:'$Le_PreHook'"
if ! (
cd "$DOMAIN_PATH" && eval "$Le_PreHook"
); then
_err "Error when run pre hook."
return 1
fi
fi
}
_on_issue_err() {
_chk_post_hook="$1"
_chk_vlist="$2"
_debug _on_issue_err
if [ "$LOG_FILE" ]; then
_err "Please check log file for more details: $LOG_FILE"
......@@ -2149,29 +2958,53 @@ _on_issue_err() {
_err "See: $_DEBUG_WIKI"
fi
if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
_debug "$(_dlg_versions)"
fi
#run the post hook
if [ "$Le_PostHook" ]; then
_info "Run post hook:'$Le_PostHook'"
if [ "$_chk_post_hook" ]; then
_info "Run post hook:'$_chk_post_hook'"
if ! (
cd "$DOMAIN_PATH" && eval "$Le_PostHook"
cd "$DOMAIN_PATH" && eval "$_chk_post_hook"
); then
_err "Error when run post hook."
return 1
fi
fi
#trigger the validation to flush the pending authz
_debug2 "_chk_vlist" "$_chk_vlist"
if [ "$_chk_vlist" ]; then
(
_debug2 "start to deactivate authz"
ventries=$(echo "$_chk_vlist" | tr "$dvsep" ' ')
for ventry in $ventries; do
d=$(echo "$ventry" | cut -d "$sep" -f 1)
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
uri=$(echo "$ventry" | cut -d "$sep" -f 3)
vtype=$(echo "$ventry" | cut -d "$sep" -f 4)
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
__trigger_validation "$uri" "$keyauthorization"
done
)
fi
if [ "$IS_RENEW" = "1" ] && _hasfield "$Le_Webroot" "dns"; then
_err "$_DNS_MANUAL_ERR"
fi
if [ "$DEBUG" ] && [ "$DEBUG" -gt "0" ]; then
_debug "$(_dlg_versions)"
fi
}
_on_issue_success() {
_chk_post_hook="$1"
_chk_renew_hook="$2"
_debug _on_issue_success
#run the post hook
if [ "$Le_PostHook" ]; then
_info "Run post hook:'$Le_PostHook'"
if [ "$_chk_post_hook" ]; then
_info "Run post hook:'$_chk_post_hook'"
if ! (
cd "$DOMAIN_PATH" && eval "$Le_PostHook"
cd "$DOMAIN_PATH" && eval "$_chk_post_hook"
); then
_err "Error when run post hook."
return 1
......@@ -2179,16 +3012,20 @@ _on_issue_success() {
fi
#run renew hook
if [ "$IS_RENEW" ] && [ "$Le_RenewHook" ]; then
_info "Run renew hook:'$Le_RenewHook'"
if [ "$IS_RENEW" ] && [ "$_chk_renew_hook" ]; then
_info "Run renew hook:'$_chk_renew_hook'"
if ! (
cd "$DOMAIN_PATH" && eval "$Le_RenewHook"
cd "$DOMAIN_PATH" && eval "$_chk_renew_hook"
); then
_err "Error when run renew hook."
return 1
fi
fi
if _hasfield "$Le_Webroot" "dns"; then
_err "$_DNS_MANUAL_WARN"
fi
}
updateaccount() {
......@@ -2206,11 +3043,16 @@ __calcAccountKeyHash() {
[ -f "$ACCOUNT_KEY_PATH" ] && _digest sha256 <"$ACCOUNT_KEY_PATH"
}
__calc_account_thumbprint() {
printf "%s" "$jwk" | tr -d ' ' | _digest "sha256" | _url_replace
}
#keylength
_regAccount() {
_initpath
_reg_length="$1"
_debug3 _regAccount "$_regAccount"
mkdir -p "$CA_DIR"
if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
_info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
......@@ -2231,72 +3073,109 @@ _regAccount() {
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
return 1
fi
_initAPI
_reg_res="$ACME_NEW_ACCOUNT_RES"
regjson='{"resource": "'$_reg_res'", "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
if [ "$ACCOUNT_EMAIL" ]; then
regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "terms-of-service-agreed": true, "agreement": "'$ACME_AGREEMENT'"}'
fi
_updateTos=""
_reg_res="new-reg"
while true; do
_debug AGREEMENT "$AGREEMENT"
_info "Registering account"
regjson='{"resource": "'$_reg_res'", "agreement": "'$AGREEMENT'"}'
if ! _send_signed_request "${ACME_NEW_ACCOUNT}" "$regjson"; then
_err "Register account Error: $response"
return 1
fi
if [ "$ACCOUNT_EMAIL" ]; then
regjson='{"resource": "'$_reg_res'", "contact": ["mailto: '$ACCOUNT_EMAIL'"], "agreement": "'$AGREEMENT'"}'
if [ "$code" = "" ] || [ "$code" = '201' ]; then
echo "$response" >"$ACCOUNT_JSON_PATH"
_info "Registered"
elif [ "$code" = '409' ]; then
_info "Already registered"
else
_err "Register account Error: $response"
return 1
fi
if [ -z "$_updateTos" ]; then
_info "Registering account"
_accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
_debug "_accUri" "$_accUri"
_savecaconf "ACCOUNT_URL" "$_accUri"
echo "$response" >"$ACCOUNT_JSON_PATH"
CA_KEY_HASH="$(__calcAccountKeyHash)"
_debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
_savecaconf CA_KEY_HASH "$CA_KEY_HASH"
if [ "$code" = '403' ]; then
_err "It seems that the account key is already deactivated, please use a new account key."
return 1
fi
ACCOUNT_THUMBPRINT="$(__calc_account_thumbprint)"
_info "ACCOUNT_THUMBPRINT" "$ACCOUNT_THUMBPRINT"
}
#Implement deactivate account
deactivateaccount() {
_initpath
if [ ! -f "$ACCOUNT_KEY_PATH" ] && [ -f "$_OLD_ACCOUNT_KEY" ]; then
_info "mv $_OLD_ACCOUNT_KEY to $ACCOUNT_KEY_PATH"
mv "$_OLD_ACCOUNT_KEY" "$ACCOUNT_KEY_PATH"
fi
if ! _send_signed_request "$API/acme/new-reg" "$regjson"; then
_err "Register account Error: $response"
return 1
if [ ! -f "$ACCOUNT_JSON_PATH" ] && [ -f "$_OLD_ACCOUNT_JSON" ]; then
_info "mv $_OLD_ACCOUNT_JSON to $ACCOUNT_JSON_PATH"
mv "$_OLD_ACCOUNT_JSON" "$ACCOUNT_JSON_PATH"
fi
if [ "$code" = "" ] || [ "$code" = '201' ]; then
echo "$response" >"$ACCOUNT_JSON_PATH"
_info "Registered"
elif [ "$code" = '409' ]; then
_info "Already registered"
else
_err "Register account Error: $response"
if [ ! -f "$ACCOUNT_KEY_PATH" ]; then
_err "Account key is not found at: $ACCOUNT_KEY_PATH"
return 1
fi
_accUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
_debug "_accUri" "$_accUri"
_accUri=$(_readcaconf "ACCOUNT_URL")
_debug _accUri "$_accUri"
_tos="$(echo "$responseHeaders" | grep "^Link:.*rel=\"terms-of-service\"" | _head_n 1 | _egrep_o "<.*>" | tr -d '<>')"
_debug "_tos" "$_tos"
if [ -z "$_tos" ]; then
_debug "Use default tos: $DEFAULT_AGREEMENT"
_tos="$DEFAULT_AGREEMENT"
if [ -z "$_accUri" ]; then
_err "The account url is empty, please run '--update-account' first to update the account info first,"
_err "Then try again."
return 1
fi
if [ "$_tos" != "$AGREEMENT" ]; then
_updateTos=1
AGREEMENT="$_tos"
_reg_res="reg"
continue
if ! _calcjwk "$ACCOUNT_KEY_PATH"; then
return 1
fi
_initAPI
if _send_signed_request "$_accUri" "{\"resource\": \"reg\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then
_info "Deactivate account success for $_accUri."
_accid=$(echo "$response" | _egrep_o "\"id\" *: *[^,]*," | cut -d : -f 2 | tr -d ' ,')
elif [ "$code" = "403" ]; then
_info "The account is already deactivated."
_accid=$(_getfield "$_accUri" "999" "/")
else
_debug "Update tos: $_tos"
if ! _send_signed_request "$_accUri" "$regjson"; then
_err "Update tos error."
_err "Deactivate: account failed for $_accUri."
return 1
fi
if [ "$code" = '202' ]; then
_info "Update success."
CA_KEY_HASH="$(__calcAccountKeyHash)"
_debug "Calc CA_KEY_HASH" "$CA_KEY_HASH"
_savecaconf CA_KEY_HASH "$CA_KEY_HASH"
_debug "Account id: $_accid"
if [ "$_accid" ]; then
_deactivated_account_path="$CA_DIR/deactivated/$_accid"
_debug _deactivated_account_path "$_deactivated_account_path"
if mkdir -p "$_deactivated_account_path"; then
_info "Moving deactivated account info to $_deactivated_account_path/"
mv "$CA_CONF" "$_deactivated_account_path/"
mv "$ACCOUNT_JSON_PATH" "$_deactivated_account_path/"
mv "$ACCOUNT_KEY_PATH" "$_deactivated_account_path/"
else
_err "Update account error."
return 1
_err "Can not create dir: $_deactivated_account_path, try to remove the deactivated account key."
rm -f "$CA_CONF"
rm -f "$ACCOUNT_JSON_PATH"
rm -f "$ACCOUNT_KEY_PATH"
fi
fi
return 0
done
}
# domain folder file
......@@ -2330,15 +3209,21 @@ _findHook() {
__get_domain_new_authz() {
_gdnd="$1"
_info "Getting new-authz for domain" "$_gdnd"
_initAPI
_Max_new_authz_retry_times=5
_authz_i=0
while [ "$_authz_i" -lt "$_Max_new_authz_retry_times" ]; do
_debug "Try new-authz for the $_authz_i time."
if ! _send_signed_request "$API/acme/new-authz" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then
if ! _send_signed_request "${ACME_NEW_AUTHZ}" "{\"resource\": \"new-authz\", \"identifier\": {\"type\": \"dns\", \"value\": \"$(_idn "$_gdnd")\"}}"; then
_err "Can not get domain new authz."
return 1
fi
if _contains "$response" "No registration exists matching provided key"; then
_err "It seems there is an error, but it's recovered now, please try again."
_err "If you see this message for a second time, please report bug: $(__green "$PROJECT")"
_clearcaconf "CA_KEY_HASH"
break
fi
if ! _contains "$response" "An error occurred while processing your request"; then
_info "The new-authz request is ok."
break
......@@ -2359,43 +3244,64 @@ __get_domain_new_authz() {
}
#uri keyAuthorization
__trigger_validation() {
_debug2 "tigger domain validation."
_t_url="$1"
_debug2 _t_url "$_t_url"
_t_key_authz="$2"
_debug2 _t_key_authz "$_t_key_authz"
_send_signed_request "$_t_url" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$_t_key_authz\"}"
}
#webroot, domain domainlist keylength
issue() {
if [ -z "$2" ]; then
_usage "Usage: $PROJECT_ENTRY --issue -d a.com -w /path/to/webroot/a.com/ "
return 1
fi
Le_Webroot="$1"
Le_Domain="$2"
Le_Alt="$3"
Le_Keylength="$4"
Le_RealCertPath="$5"
Le_RealKeyPath="$6"
Le_RealCACertPath="$7"
Le_ReloadCmd="$8"
Le_RealFullChainPath="$9"
Le_PreHook="${10}"
Le_PostHook="${11}"
Le_RenewHook="${12}"
Le_LocalAddress="${13}"
if [ -z "$1" ]; then
_usage "Please specify at least one validation method: '--webroot', '--standalone', '--apache', '--nginx' or '--dns' etc."
return 1
fi
_web_roots="$1"
_main_domain="$2"
_alt_domains="$3"
if _contains "$_main_domain" ","; then
_main_domain=$(echo "$2,$3" | cut -d , -f 1)
_alt_domains=$(echo "$2,$3" | cut -d , -f 2- | sed "s/,${NO_VALUE}$//")
fi
_key_length="$4"
_real_cert="$5"
_real_key="$6"
_real_ca="$7"
_reload_cmd="$8"
_real_fullchain="$9"
_pre_hook="${10}"
_post_hook="${11}"
_renew_hook="${12}"
_local_addr="${13}"
#remove these later.
if [ "$Le_Webroot" = "dns-cf" ]; then
Le_Webroot="dns_cf"
if [ "$_web_roots" = "dns-cf" ]; then
_web_roots="dns_cf"
fi
if [ "$Le_Webroot" = "dns-dp" ]; then
Le_Webroot="dns_dp"
if [ "$_web_roots" = "dns-dp" ]; then
_web_roots="dns_dp"
fi
if [ "$Le_Webroot" = "dns-cx" ]; then
Le_Webroot="dns_cx"
if [ "$_web_roots" = "dns-cx" ]; then
_web_roots="dns_cx"
fi
_debug "Using api: $API"
if [ ! "$IS_RENEW" ]; then
_initpath "$Le_Domain" "$Le_Keylength"
_initpath "$_main_domain" "$_key_length"
mkdir -p "$DOMAIN_PATH"
fi
_debug "Using ACME_DIRECTORY: $ACME_DIRECTORY"
_initAPI
if [ -f "$DOMAIN_CONF" ]; then
Le_NextRenewTime=$(_readdomainconf Le_NextRenewTime)
_debug Le_NextRenewTime "$Le_NextRenewTime"
......@@ -2404,7 +3310,7 @@ issue() {
_debug _saved_domain "$_saved_domain"
_saved_alt=$(_readdomainconf Le_Alt)
_debug _saved_alt "$_saved_alt"
if [ "$_saved_domain,$_saved_alt" = "$Le_Domain,$Le_Alt" ]; then
if [ "$_saved_domain,$_saved_alt" = "$_main_domain,$_alt_domains" ]; then
_info "Domains not changed."
_info "Skip, Next renewal time is: $(__green "$(_readdomainconf Le_NextRenewTimeStr)")"
_info "Add '$(__red '--force')' to force to renew."
......@@ -2415,32 +3321,32 @@ issue() {
fi
fi
_savedomainconf "Le_Domain" "$Le_Domain"
_savedomainconf "Le_Alt" "$Le_Alt"
_savedomainconf "Le_Webroot" "$Le_Webroot"
_savedomainconf "Le_Domain" "$_main_domain"
_savedomainconf "Le_Alt" "$_alt_domains"
_savedomainconf "Le_Webroot" "$_web_roots"
_savedomainconf "Le_PreHook" "$Le_PreHook"
_savedomainconf "Le_PostHook" "$Le_PostHook"
_savedomainconf "Le_RenewHook" "$Le_RenewHook"
_savedomainconf "Le_PreHook" "$_pre_hook"
_savedomainconf "Le_PostHook" "$_post_hook"
_savedomainconf "Le_RenewHook" "$_renew_hook"
if [ "$Le_LocalAddress" ]; then
_savedomainconf "Le_LocalAddress" "$Le_LocalAddress"
if [ "$_local_addr" ]; then
_savedomainconf "Le_LocalAddress" "$_local_addr"
else
_cleardomainconf "Le_LocalAddress"
fi
Le_API="$API"
Le_API="$ACME_DIRECTORY"
_savedomainconf "Le_API" "$Le_API"
if [ "$Le_Alt" = "$NO_VALUE" ]; then
Le_Alt=""
if [ "$_alt_domains" = "$NO_VALUE" ]; then
_alt_domains=""
fi
if [ "$Le_Keylength" = "$NO_VALUE" ]; then
Le_Keylength=""
if [ "$_key_length" = "$NO_VALUE" ]; then
_key_length=""
fi
if ! _on_before_issue; then
if ! _on_before_issue "$_web_roots" "$_main_domain" "$_alt_domains" "$_pre_hook" "$_local_addr"; then
_err "_on_before_issue."
return 1
fi
......@@ -2450,7 +3356,7 @@ issue() {
if [ -z "$_saved_account_key_hash" ] || [ "$_saved_account_key_hash" != "$(__calcAccountKeyHash)" ]; then
if ! _regAccount "$_accountkeylength"; then
_on_issue_err
_on_issue_err "$_post_hook"
return 1
fi
else
......@@ -2462,37 +3368,38 @@ issue() {
else
_key=$(_readdomainconf Le_Keylength)
_debug "Read key length:$_key"
if [ ! -f "$CERT_KEY_PATH" ] || [ "$Le_Keylength" != "$_key" ]; then
if ! createDomainKey "$Le_Domain" "$Le_Keylength"; then
if [ ! -f "$CERT_KEY_PATH" ] || [ "$_key_length" != "$_key" ] || [ "$Le_ForceNewDomainKey" = "1" ]; then
if ! createDomainKey "$_main_domain" "$_key_length"; then
_err "Create domain key error."
_clearup
_on_issue_err
_on_issue_err "$_post_hook"
return 1
fi
fi
if ! _createcsr "$Le_Domain" "$Le_Alt" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then
if ! _createcsr "$_main_domain" "$_alt_domains" "$CERT_KEY_PATH" "$CSR_PATH" "$DOMAIN_SSL_CONF"; then
_err "Create CSR error."
_clearup
_on_issue_err
_on_issue_err "$_post_hook"
return 1
fi
fi
_savedomainconf "Le_Keylength" "$Le_Keylength"
_savedomainconf "Le_Keylength" "$_key_length"
vlist="$Le_Vlist"
_info "Getting domain auth token for each domain"
sep='#'
dvsep=','
if [ -z "$vlist" ]; then
alldomains=$(echo "$Le_Domain,$Le_Alt" | tr ',' ' ')
alldomains=$(echo "$_main_domain,$_alt_domains" | tr ',' ' ')
_index=1
_currentRoot=""
for d in $alldomains; do
_info "Getting webroot for domain" "$d"
_w="$(echo $Le_Webroot | cut -d , -f $_index)"
_info _w "$_w"
_w="$(echo $_web_roots | cut -d , -f $_index)"
_debug _w "$_w"
if [ "$_w" ]; then
_currentRoot="$_w"
fi
......@@ -2510,13 +3417,12 @@ issue() {
if ! __get_domain_new_authz "$d"; then
_clearup
_on_issue_err
_on_issue_err "$_post_hook"
return 1
fi
if [ -z "$thumbprint" ]; then
accountkey_json=$(printf "%s" "$jwk" | tr -d ' ')
thumbprint=$(printf "%s" "$accountkey_json" | _digest "sha256" | _urlencode)
thumbprint="$(__calc_account_thumbprint)"
fi
entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
......@@ -2524,20 +3430,20 @@ issue() {
if [ -z "$entry" ]; then
_err "Error, can not get domain token $d"
_clearup
_on_issue_err
_on_issue_err "$_post_hook"
return 1
fi
token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
_debug token "$token"
uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d '"' -f 4)"
_debug uri "$uri"
keyauthorization="$token.$thumbprint"
_debug keyauthorization "$keyauthorization"
if printf "%s" "$response" | grep '"status":"valid"' >/dev/null 2>&1; then
_info "$d is already verified, skip."
_debug "$d is already verified, skip."
keyauthorization="$STATE_VERIFIED"
_debug keyauthorization "$keyauthorization"
fi
......@@ -2545,13 +3451,13 @@ issue() {
dvlist="$d$sep$keyauthorization$sep$uri$sep$vtype$sep$_currentRoot"
_debug dvlist "$dvlist"
vlist="$vlist$dvlist,"
vlist="$vlist$dvlist$dvsep"
done
_debug vlist "$vlist"
#add entry
dnsadded=""
ventries=$(echo "$vlist" | tr ',' ' ')
ventries=$(echo "$vlist" | tr "$dvsep" ' ')
for ventry in $ventries; do
d=$(echo "$ventry" | cut -d "$sep" -f 1)
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
......@@ -2559,7 +3465,7 @@ issue() {
_currentRoot=$(echo "$ventry" | cut -d "$sep" -f 5)
if [ "$keyauthorization" = "$STATE_VERIFIED" ]; then
_info "$d is already verified, skip $vtype."
_debug "$d is already verified, skip $vtype."
continue
fi
......@@ -2567,7 +3473,7 @@ issue() {
dnsadded='0'
txtdomain="_acme-challenge.$d"
_debug txtdomain "$txtdomain"
txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _urlencode)"
txt="$(printf "%s" "$keyauthorization" | _digest "sha256" | _url_replace)"
_debug txt "$txt"
d_api="$(_findHook "$d" dnsapi "$_currentRoot")"
......@@ -2577,11 +3483,11 @@ issue() {
if [ "$d_api" ]; then
_info "Found domain api file: $d_api"
else
_err "Add the following TXT record:"
_err "Domain: '$(__green "$txtdomain")'"
_err "TXT value: '$(__green "$txt")'"
_err "Please be aware that you prepend _acme-challenge. before your domain"
_err "so the resulting subdomain will be: $txtdomain"
_info "$(__red "Add the following TXT record:")"
_info "$(__red "Domain: '$(__green "$txtdomain")'")"
_info "$(__red "TXT value: '$(__green "$txt")'")"
_info "$(__red "Please be aware that you prepend _acme-challenge. before your domain")"
_info "$(__red "so the resulting subdomain will be: $txtdomain")"
continue
fi
......@@ -2605,7 +3511,7 @@ issue() {
if [ "$?" != "0" ]; then
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
dnsadded='1'
......@@ -2617,7 +3523,7 @@ issue() {
_debug "Dns record not added yet, so, save to $DOMAIN_CONF and exit."
_err "Please add the TXT records to the domains, and retry again."
_clearup
_on_issue_err
_on_issue_err "$_post_hook"
return 1
fi
......@@ -2634,10 +3540,11 @@ issue() {
_sleep "$Le_DNSSleep"
fi
NGINX_RESTORE_VLIST=""
_debug "ok, let's start to verify"
_ncIndex=1
ventries=$(echo "$vlist" | tr ',' ' ')
ventries=$(echo "$vlist" | tr "$dvsep" ' ')
for ventry in $ventries; do
d=$(echo "$ventry" | cut -d "$sep" -f 1)
keyauthorization=$(echo "$ventry" | cut -d "$sep" -f 2)
......@@ -2662,18 +3569,37 @@ issue() {
if [ "$vtype" = "$VTYPE_HTTP" ]; then
if [ "$_currentRoot" = "$NO_VALUE" ]; then
_info "Standalone mode server"
_ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")"
_ncaddr="$(_getfield "$_local_addr" "$_ncIndex")"
_ncIndex="$(_math $_ncIndex + 1)"
_startserver "$keyauthorization" "$_ncaddr" &
_startserver "$keyauthorization" "$_ncaddr"
if [ "$?" != "0" ]; then
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
serverproc="$!"
sleep 1
_debug serverproc "$serverproc"
elif [ "$_currentRoot" = "$MODE_STATELESS" ]; then
_info "Stateless mode for domain:$d"
_sleep 1
elif _startswith "$_currentRoot" "$NGINX"; then
_info "Nginx mode for domain:$d"
#set up nginx server
FOUND_REAL_NGINX_CONF=""
BACKUP_NGINX_CONF=""
if ! _setNginx "$d" "$_currentRoot" "$thumbprint"; then
_clearup
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
if [ "$FOUND_REAL_NGINX_CONF" ]; then
_realConf="$FOUND_REAL_NGINX_CONF"
_backup="$BACKUP_NGINX_CONF"
_debug _realConf "$_realConf"
NGINX_RESTORE_VLIST="$d$sep$_realConf$sep$_backup$dvsep$NGINX_RESTORE_VLIST"
fi
_sleep 1
else
if [ "$_currentRoot" = "apache" ]; then
wellknown_path="$ACME_DIR"
......@@ -2698,16 +3624,19 @@ issue() {
_err "$d:Can not write token to file : $wellknown_path/$token"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
if [ ! "$usingApache" ]; then
if webroot_owner=$(_stat "$_currentRoot"); then
_debug "Changing owner/group of .well-known to $webroot_owner"
chown -R "$webroot_owner" "$_currentRoot/.well-known"
if ! _exec "chown -R \"$webroot_owner\" \"$_currentRoot/.well-known\""; then
_debug "$(cat "$_EXEC_TEMP_ERR")"
_exec_err >/dev/null 2>&1
fi
else
_debug "not chaning owner/group of webroot"
_debug "not changing owner/group of webroot"
fi
fi
......@@ -2737,22 +3666,22 @@ issue() {
_SAN_B="$_x.$_y.acme.invalid"
_debug2 _SAN_B "$_SAN_B"
_ncaddr="$(_getfield "$Le_LocalAddress" "$_ncIndex")"
_ncaddr="$(_getfield "$_local_addr" "$_ncIndex")"
_ncIndex="$(_math "$_ncIndex" + 1)"
if ! _starttlsserver "$_SAN_B" "$_SAN_A" "$Le_TLSPort" "$keyauthorization" "$_ncaddr"; then
_err "Start tls server error."
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
fi
if ! _send_signed_request "$uri" "{\"resource\": \"challenge\", \"keyAuthorization\": \"$keyauthorization\"}"; then
if ! __trigger_validation "$uri" "$keyauthorization"; then
_err "$d:Can not get challenge: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
......@@ -2760,7 +3689,7 @@ issue() {
_err "$d:Challenge error: $response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
......@@ -2775,7 +3704,7 @@ issue() {
_err "$d:Timeout"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
......@@ -2787,7 +3716,7 @@ issue() {
_err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
_debug2 original "$response"
......@@ -2822,7 +3751,7 @@ issue() {
fi
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
......@@ -2832,7 +3761,7 @@ issue() {
_err "$d:Verify error:$response"
_clearupwebbroot "$_currentRoot" "$removelevel" "$token"
_clearup
_on_issue_err
_on_issue_err "$_post_hook" "$vlist"
return 1
fi
......@@ -2842,16 +3771,17 @@ issue() {
_clearup
_info "Verify finished, start to sign."
der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _urlencode)"
der="$(_getfile "${CSR_PATH}" "${BEGIN_CSR}" "${END_CSR}" | tr -d "\r\n" | _url_replace)"
if ! _send_signed_request "$API/acme/new-cert" "{\"resource\": \"new-cert\", \"csr\": \"$der\"}" "needbase64"; then
if ! _send_signed_request "${ACME_NEW_ORDER}" "{\"resource\": \"$ACME_NEW_ORDER_RES\", \"csr\": \"$der\"}" "needbase64"; then
_err "Sign failed."
_on_issue_err
_on_issue_err "$_post_hook"
return 1
fi
_rcert="$response"
Le_LinkCert="$(grep -i '^Location.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
_debug "Le_LinkCert" "$Le_LinkCert"
_savedomainconf "Le_LinkCert" "$Le_LinkCert"
if [ "$Le_LinkCert" ]; then
......@@ -2888,7 +3818,7 @@ issue() {
if [ -z "$Le_LinkCert" ]; then
response="$(echo "$response" | _dbase64 "multiline" | _normalizeJson)"
_err "Sign failed: $(echo "$response" | _egrep_o '"detail":"[^"]*"')"
_on_issue_err
_on_issue_err "$_post_hook"
return 1
fi
......@@ -2896,18 +3826,37 @@ issue() {
Le_LinkIssuer=$(grep -i '^Link' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | cut -d ';' -f 1 | tr -d '<>')
if ! _contains "$Le_LinkIssuer" ":"; then
Le_LinkIssuer="$API$Le_LinkIssuer"
_info "$(__red "Relative issuer link found.")"
Le_LinkIssuer="$_ACME_SERVER_HOST$Le_LinkIssuer"
fi
_debug Le_LinkIssuer "$Le_LinkIssuer"
_savedomainconf "Le_LinkIssuer" "$Le_LinkIssuer"
if [ "$Le_LinkIssuer" ]; then
_link_issuer_retry=0
_MAX_ISSUER_RETRY=5
while [ "$_link_issuer_retry" -lt "$_MAX_ISSUER_RETRY" ]; do
_debug _link_issuer_retry "$_link_issuer_retry"
if _get "$Le_LinkIssuer" >"$CA_CERT_PATH.der"; then
echo "$BEGIN_CERT" >"$CA_CERT_PATH"
_get "$Le_LinkIssuer" | _base64 "multiline" >>"$CA_CERT_PATH"
_base64 "multiline" <"$CA_CERT_PATH.der" >>"$CA_CERT_PATH"
echo "$END_CERT" >>"$CA_CERT_PATH"
_info "The intermediate CA cert is in $(__green " $CA_CERT_PATH ")"
cat "$CA_CERT_PATH" >>"$CERT_FULLCHAIN_PATH"
_info "And the full chain certs is there: $(__green " $CERT_FULLCHAIN_PATH ")"
rm -f "$CA_CERT_PATH.der"
break
fi
_link_issuer_retry=$(_math $_link_issuer_retry + 1)
_sleep "$_link_issuer_retry"
done
if [ "$_link_issuer_retry" = "$_MAX_ISSUER_RETRY" ]; then
_err "Max retry for issuer ca cert is reached."
fi
else
_debug "No Le_LinkIssuer header found."
fi
Le_CertCreateTime=$(_time)
......@@ -2928,6 +3877,12 @@ issue() {
_clearaccountconf "CA_BUNDLE"
fi
if [ "$CA_PATH" ]; then
_saveaccountconf CA_PATH "$CA_PATH"
else
_clearaccountconf "CA_PATH"
fi
if [ "$HTTPS_INSECURE" ]; then
_saveaccountconf HTTPS_INSECURE "$HTTPS_INSECURE"
else
......@@ -2942,6 +3897,12 @@ issue() {
_cleardomainconf Le_Listen_V4
fi
if [ "$Le_ForceNewDomainKey" = "1" ]; then
_savedomainconf "Le_ForceNewDomainKey" "$Le_ForceNewDomainKey"
else
_cleardomainconf Le_ForceNewDomainKey
fi
Le_NextRenewTime=$(_math "$Le_CertCreateTime" + "$Le_RenewalDays" \* 24 \* 60 \* 60)
Le_NextRenewTimeStr=$(_time2str "$Le_NextRenewTime")
......@@ -2950,10 +3911,18 @@ issue() {
Le_NextRenewTime=$(_math "$Le_NextRenewTime" - 86400)
_savedomainconf "Le_NextRenewTime" "$Le_NextRenewTime"
_on_issue_success
if ! _on_issue_success "$_post_hook" "$_renew_hook"; then
_err "Call hook error."
return 1
fi
if [ "$Le_RealCertPath$Le_RealKeyPath$Le_RealCACertPath$Le_ReloadCmd$Le_RealFullChainPath" ]; then
_installcert
if [ "$_real_cert$_real_key$_real_ca$_reload_cmd$_real_fullchain" ]; then
_savedomainconf "Le_RealCertPath" "$_real_cert"
_savedomainconf "Le_RealCACertPath" "$_real_ca"
_savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd"
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"
fi
}
......@@ -2983,7 +3952,21 @@ renew() {
. "$DOMAIN_CONF"
if [ "$Le_API" ]; then
API="$Le_API"
if [ "$_OLD_CA_HOST" = "$Le_API" ]; then
export Le_API="$DEFAULT_CA"
_savedomainconf Le_API "$Le_API"
fi
if [ "$_OLD_STAGE_CA_HOST" = "$Le_API" ]; then
export Le_API="$STAGE_CA"
_savedomainconf Le_API "$Le_API"
fi
export ACME_DIRECTORY="$Le_API"
#reload ca configs
ACCOUNT_KEY_PATH=""
ACCOUNT_JSON_PATH=""
CA_CONF=""
_debug3 "initpath again."
_initpath "$Le_Domain" "$_isEcc"
fi
if [ -z "$FORCE" ] && [ "$Le_NextRenewTime" ] && [ "$(_time)" -lt "$Le_NextRenewTime" ]; then
......@@ -2992,6 +3975,11 @@ renew() {
return "$RENEW_SKIP"
fi
if [ "$IN_CRON" = "1" ] && [ -z "$Le_CertCreateTime" ]; then
_info "Skip invalid cert for: $Le_Domain"
return 0
fi
IS_RENEW="1"
issue "$Le_Webroot" "$Le_Domain" "$Le_Alt" "$Le_Keylength" "$Le_RealCertPath" "$Le_RealKeyPath" "$Le_RealCACertPath" "$Le_ReloadCmd" "$Le_RealFullChainPath" "$Le_PreHook" "$Le_PostHook" "$Le_RenewHook" "$Le_LocalAddress"
res="$?"
......@@ -3000,7 +3988,7 @@ renew() {
fi
if [ "$Le_DeployHook" ]; then
deploy "$Le_Domain" "$Le_DeployHook" "$Le_Keylength"
_deploy "$Le_Domain" "$Le_DeployHook"
res="$?"
fi
......@@ -3041,7 +4029,7 @@ renewAll() {
return "$rc"
else
_ret="$rc"
_err "Error renew $d, Go ahead to next one."
_err "Error renew $d."
fi
fi
done
......@@ -3065,6 +4053,10 @@ signcsr() {
return 1
fi
_debug _csrsubj "$_csrsubj"
if _contains "$_csrsubj" ' ' || ! _contains "$_csrsubj" '.'; then
_info "It seems that the subject: $_csrsubj is not a valid domain name. Drop it."
_csrsubj=""
fi
_csrdomainlist=$(_readSubjectAltNamesFromCSR "$_csrfile")
if [ "$?" != "0" ]; then
......@@ -3172,45 +4164,32 @@ list() {
}
deploy() {
Le_Domain="$1"
Le_DeployHook="$2"
_isEcc="$3"
if [ -z "$Le_DeployHook" ]; then
_usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] "
return 1
fi
_initpath "$Le_Domain" "$_isEcc"
if [ ! -d "$DOMAIN_PATH" ]; then
_err "Domain is not valid:'$Le_Domain'"
return 1
fi
_deploy() {
_d="$1"
_hooks="$2"
_deployApi="$(_findHook "$Le_Domain" deploy "$Le_DeployHook")"
for _d_api in $(echo "$_hooks" | tr ',' " "); do
_deployApi="$(_findHook "$_d" deploy "$_d_api")"
if [ -z "$_deployApi" ]; then
_err "The deploy hook $Le_DeployHook is not found."
_err "The deploy hook $_d_api is not found."
return 1
fi
_debug _deployApi "$_deployApi"
_savedomainconf Le_DeployHook "$Le_DeployHook"
if ! (
if ! . "$_deployApi"; then
_err "Load file $_deployApi error. Please check your api file and try again."
return 1
fi
d_command="${Le_DeployHook}_deploy"
d_command="${_d_api}_deploy"
if ! _exists "$d_command"; then
_err "It seems that your api file is not correct, it must have a function named: $d_command"
return 1
fi
if ! $d_command "$Le_Domain" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then
_err "Error deploy for domain:$Le_Domain"
_on_issue_err
if ! $d_command "$_d" "$CERT_KEY_PATH" "$CERT_PATH" "$CA_CERT_PATH" "$CERT_FULLCHAIN_PATH"; then
_err "Error deploy for domain:$_d"
return 1
fi
); then
......@@ -3219,100 +4198,142 @@ deploy() {
else
_info "$(__green Success)"
fi
done
}
#domain hooks
deploy() {
_d="$1"
_hooks="$2"
_isEcc="$3"
if [ -z "$_hooks" ]; then
_usage "Usage: $PROJECT_ENTRY --deploy -d domain.com --deploy-hook cpanel [--ecc] "
return 1
fi
_initpath "$_d" "$_isEcc"
if [ ! -d "$DOMAIN_PATH" ]; then
_err "Domain is not valid:'$_d'"
return 1
fi
. "$DOMAIN_CONF"
_savedomainconf Le_DeployHook "$_hooks"
_deploy "$_d" "$_hooks"
}
installcert() {
Le_Domain="$1"
if [ -z "$Le_Domain" ]; then
_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]"
_main_domain="$1"
if [ -z "$_main_domain" ]; then
_usage "Usage: $PROJECT_ENTRY --installcert -d domain.com [--ecc] [--cert-file cert-file-path] [--key-file key-file-path] [--ca-file ca-cert-file-path] [ --reloadCmd reloadCmd] [--fullchain-file fullchain-path]"
return 1
fi
Le_RealCertPath="$2"
Le_RealKeyPath="$3"
Le_RealCACertPath="$4"
Le_ReloadCmd="$5"
Le_RealFullChainPath="$6"
_real_cert="$2"
_real_key="$3"
_real_ca="$4"
_reload_cmd="$5"
_real_fullchain="$6"
_isEcc="$7"
_initpath "$Le_Domain" "$_isEcc"
_initpath "$_main_domain" "$_isEcc"
if [ ! -d "$DOMAIN_PATH" ]; then
_err "Domain is not valid:'$Le_Domain'"
_err "Domain is not valid:'$_main_domain'"
return 1
fi
_installcert
_savedomainconf "Le_RealCertPath" "$_real_cert"
_savedomainconf "Le_RealCACertPath" "$_real_ca"
_savedomainconf "Le_RealKeyPath" "$_real_key"
_savedomainconf "Le_ReloadCmd" "$_reload_cmd"
_savedomainconf "Le_RealFullChainPath" "$_real_fullchain"
_installcert "$_main_domain" "$_real_cert" "$_real_key" "$_real_ca" "$_real_fullchain" "$_reload_cmd"
}
#domain cert key ca fullchain reloadcmd backup-prefix
_installcert() {
_savedomainconf "Le_RealCertPath" "$Le_RealCertPath"
_savedomainconf "Le_RealCACertPath" "$Le_RealCACertPath"
_savedomainconf "Le_RealKeyPath" "$Le_RealKeyPath"
_savedomainconf "Le_ReloadCmd" "$Le_ReloadCmd"
_savedomainconf "Le_RealFullChainPath" "$Le_RealFullChainPath"
_main_domain="$1"
_real_cert="$2"
_real_key="$3"
_real_ca="$4"
_real_fullchain="$5"
_reload_cmd="$6"
_backup_prefix="$7"
if [ "$Le_RealCertPath" = "$NO_VALUE" ]; then
Le_RealCertPath=""
if [ "$_real_cert" = "$NO_VALUE" ]; then
_real_cert=""
fi
if [ "$Le_RealKeyPath" = "$NO_VALUE" ]; then
Le_RealKeyPath=""
if [ "$_real_key" = "$NO_VALUE" ]; then
_real_key=""
fi
if [ "$Le_RealCACertPath" = "$NO_VALUE" ]; then
Le_RealCACertPath=""
if [ "$_real_ca" = "$NO_VALUE" ]; then
_real_ca=""
fi
if [ "$Le_ReloadCmd" = "$NO_VALUE" ]; then
Le_ReloadCmd=""
if [ "$_reload_cmd" = "$NO_VALUE" ]; then
_reload_cmd=""
fi
if [ "$Le_RealFullChainPath" = "$NO_VALUE" ]; then
Le_RealFullChainPath=""
if [ "$_real_fullchain" = "$NO_VALUE" ]; then
_real_fullchain=""
fi
if [ "$Le_RealCertPath" ]; then
_backup_path="$DOMAIN_BACKUP_PATH/$_backup_prefix"
mkdir -p "$_backup_path"
_info "Installing cert to:$Le_RealCertPath"
if [ -f "$Le_RealCertPath" ] && [ ! "$IS_RENEW" ]; then
cp "$Le_RealCertPath" "$Le_RealCertPath".bak
if [ "$_real_cert" ]; then
_info "Installing cert to:$_real_cert"
if [ -f "$_real_cert" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_cert" "$_backup_path/cert.bak"
fi
cat "$CERT_PATH" >"$Le_RealCertPath"
cat "$CERT_PATH" >"$_real_cert"
fi
if [ "$Le_RealCACertPath" ]; then
_info "Installing CA to:$Le_RealCACertPath"
if [ "$Le_RealCACertPath" = "$Le_RealCertPath" ]; then
echo "" >>"$Le_RealCACertPath"
cat "$CA_CERT_PATH" >>"$Le_RealCACertPath"
if [ "$_real_ca" ]; then
_info "Installing CA to:$_real_ca"
if [ "$_real_ca" = "$_real_cert" ]; then
echo "" >>"$_real_ca"
cat "$CA_CERT_PATH" >>"$_real_ca"
else
if [ -f "$Le_RealCACertPath" ] && [ ! "$IS_RENEW" ]; then
cp "$Le_RealCACertPath" "$Le_RealCACertPath".bak
if [ -f "$_real_ca" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_ca" "$_backup_path/ca.bak"
fi
cat "$CA_CERT_PATH" >"$Le_RealCACertPath"
cat "$CA_CERT_PATH" >"$_real_ca"
fi
fi
if [ "$Le_RealKeyPath" ]; then
_info "Installing key to:$Le_RealKeyPath"
if [ -f "$Le_RealKeyPath" ] && [ ! "$IS_RENEW" ]; then
cp "$Le_RealKeyPath" "$Le_RealKeyPath".bak
if [ "$_real_key" ]; then
_info "Installing key to:$_real_key"
if [ -f "$_real_key" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_key" "$_backup_path/key.bak"
fi
if [ -f "$_real_key" ]; then
cat "$CERT_KEY_PATH" >"$_real_key"
else
cat "$CERT_KEY_PATH" >"$_real_key"
chmod 700 "$_real_key"
fi
cat "$CERT_KEY_PATH" >"$Le_RealKeyPath"
fi
if [ "$Le_RealFullChainPath" ]; then
_info "Installing full chain to:$Le_RealFullChainPath"
if [ -f "$Le_RealFullChainPath" ] && [ ! "$IS_RENEW" ]; then
cp "$Le_RealFullChainPath" "$Le_RealFullChainPath".bak
if [ "$_real_fullchain" ]; then
_info "Installing full chain to:$_real_fullchain"
if [ -f "$_real_fullchain" ] && [ ! "$IS_RENEW" ]; then
cp "$_real_fullchain" "$_backup_path/fullchain.bak"
fi
cat "$CERT_FULLCHAIN_PATH" >"$Le_RealFullChainPath"
cat "$CERT_FULLCHAIN_PATH" >"$_real_fullchain"
fi
if [ "$Le_ReloadCmd" ]; then
_info "Run Le_ReloadCmd: $Le_ReloadCmd"
if (cd "$DOMAIN_PATH" && eval "$Le_ReloadCmd"); then
if [ "$_reload_cmd" ]; then
_info "Run reload cmd: $_reload_cmd"
if (
export CERT_PATH
export CERT_KEY_PATH
export CA_CERT_PATH
export CERT_FULLCHAIN_PATH
export Le_Domain
cd "$DOMAIN_PATH" && eval "$_reload_cmd"
); then
_info "$(__green "Reload success")"
else
_err "Reload error for :$Le_Domain"
......@@ -3321,33 +4342,45 @@ _installcert() {
}
#confighome
installcronjob() {
_c_home="$1"
_initpath
if ! _exists "crontab"; then
_err "crontab doesn't exist, so, we can not install cron jobs."
_CRONTAB="crontab"
if ! _exists "$_CRONTAB" && _exists "fcrontab"; then
_CRONTAB="fcrontab"
fi
if ! _exists "$_CRONTAB"; then
_err "crontab/fcrontab doesn't exist, so, we can not install cron jobs."
_err "All your certs will not be renewed automatically."
_err "You must add your own cron job to call '$PROJECT_ENTRY --cron' everyday."
return 1
fi
_info "Installing cron job"
if ! crontab -l | grep "$PROJECT_ENTRY --cron"; then
if ! $_CRONTAB -l | grep "$PROJECT_ENTRY --cron"; then
if [ -f "$LE_WORKING_DIR/$PROJECT_ENTRY" ]; then
lesh="\"$LE_WORKING_DIR\"/$PROJECT_ENTRY"
else
_err "Can not install cronjob, $PROJECT_ENTRY not found."
return 1
fi
if _exists uname && uname -a | grep solaris >/dev/null; then
crontab -l | {
if [ "$_c_home" ]; then
_c_entry="--config-home \"$_c_home\" "
fi
_t=$(_time)
random_minute=$(_math $_t % 60)
if _exists uname && uname -a | grep SunOS >/dev/null; then
$_CRONTAB -l | {
cat
echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
} | crontab --
echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
} | $_CRONTAB --
else
crontab -l | {
$_CRONTAB -l | {
cat
echo "0 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" > /dev/null"
} | crontab -
echo "$random_minute 0 * * * $lesh --cron --home \"$LE_WORKING_DIR\" $_c_entry> /dev/null"
} | $_CRONTAB -
fi
fi
if [ "$?" != "0" ]; then
......@@ -3359,19 +4392,28 @@ installcronjob() {
}
uninstallcronjob() {
if ! _exists "crontab"; then
_CRONTAB="crontab"
if ! _exists "$_CRONTAB" && _exists "fcrontab"; then
_CRONTAB="fcrontab"
fi
if ! _exists "$_CRONTAB"; then
return
fi
_info "Removing cron job"
cr="$(crontab -l | grep "$PROJECT_ENTRY --cron")"
cr="$($_CRONTAB -l | grep "$PROJECT_ENTRY --cron")"
if [ "$cr" ]; then
if _exists uname && uname -a | grep solaris >/dev/null; then
crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab --
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB --
else
crontab -l | sed "/$PROJECT_ENTRY --cron/d" | crontab -
$_CRONTAB -l | sed "/$PROJECT_ENTRY --cron/d" | $_CRONTAB -
fi
LE_WORKING_DIR="$(echo "$cr" | cut -d ' ' -f 9 | tr -d '"')"
_info LE_WORKING_DIR "$LE_WORKING_DIR"
if _contains "$cr" "--config-home"; then
LE_CONFIG_HOME="$(echo "$cr" | cut -d ' ' -f 11 | tr -d '"')"
_debug LE_CONFIG_HOME "$LE_CONFIG_HOME"
fi
fi
_initpath
......@@ -3380,7 +4422,7 @@ uninstallcronjob() {
revoke() {
Le_Domain="$1"
if [ -z "$Le_Domain" ]; then
_usage "Usage: $PROJECT_ENTRY --revoke -d domain.com"
_usage "Usage: $PROJECT_ENTRY --revoke -d domain.com [--ecc]"
return 1
fi
......@@ -3397,15 +4439,17 @@ revoke() {
return 1
fi
cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _urlencode)"
cert="$(_getfile "${CERT_PATH}" "${BEGIN_CERT}" "${END_CERT}" | tr -d "\r\n" | _url_replace)"
if [ -z "$cert" ]; then
_err "Cert for $Le_Domain is empty found, skip."
return 1
fi
_initAPI
data="{\"resource\": \"revoke-cert\", \"certificate\": \"$cert\"}"
uri="$API/acme/revoke-cert"
uri="${ACME_REVOKE_CERT}"
if [ -f "$CERT_KEY_PATH" ]; then
_info "Try domain key first."
......@@ -3438,18 +4482,43 @@ revoke() {
return 1
}
#domain ecc
remove() {
Le_Domain="$1"
if [ -z "$Le_Domain" ]; then
_usage "Usage: $PROJECT_ENTRY --remove -d domain.com [--ecc]"
return 1
fi
_isEcc="$2"
_initpath "$Le_Domain" "$_isEcc"
_removed_conf="$DOMAIN_CONF.removed"
if [ ! -f "$DOMAIN_CONF" ]; then
if [ -f "$_removed_conf" ]; then
_err "$Le_Domain is already removed, You can remove the folder by yourself: $DOMAIN_PATH"
else
_err "$Le_Domain is not a issued domain, skip."
fi
return 1
fi
if mv "$DOMAIN_CONF" "$_removed_conf"; then
_info "$Le_Domain is removed, the key and cert files are in $(__green $DOMAIN_PATH)"
_info "You can remove them by yourself."
return 0
else
_err "Remove $Le_Domain failed."
return 1
fi
}
#domain vtype
_deactivate() {
_d_domain="$1"
_d_type="$2"
_initpath
_d_i=0
_d_max_retry=9
while [ "$_d_i" -lt "$_d_max_retry" ]; do
_info "Deactivate: $_d_domain"
_d_i="$(_math $_d_i + 1)"
if ! __get_domain_new_authz "$_d_domain"; then
_err "Can not get domain new authz token."
return 1
......@@ -3458,12 +4527,43 @@ _deactivate() {
authzUri="$(echo "$responseHeaders" | grep "^Location:" | _head_n 1 | cut -d ' ' -f 2 | tr -d "\r\n")"
_debug "authzUri" "$authzUri"
if [ ! -z "$code" ] && [ ! "$code" = '201' ]; then
if [ "$code" ] && [ ! "$code" = '201' ]; then
_err "new-authz error: $response"
return 1
fi
entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"status":"valid","uri"[^\}]*')"
entries="$(echo "$response" | _egrep_o '{ *"type":"[^"]*", *"status": *"valid", *"uri"[^}]*')"
if [ -z "$entries" ]; then
_info "No valid entries found."
if [ -z "$thumbprint" ]; then
thumbprint="$(__calc_account_thumbprint)"
fi
_debug "Trigger validation."
vtype="$VTYPE_HTTP"
entry="$(printf "%s\n" "$response" | _egrep_o '[^\{]*"type":"'$vtype'"[^\}]*')"
_debug entry "$entry"
if [ -z "$entry" ]; then
_err "Error, can not get domain token $d"
return 1
fi
token="$(printf "%s\n" "$entry" | _egrep_o '"token":"[^"]*' | cut -d : -f 2 | tr -d '"')"
_debug token "$token"
uri="$(printf "%s\n" "$entry" | _egrep_o '"uri":"[^"]*' | cut -d : -f 2,3 | tr -d '"')"
_debug uri "$uri"
keyauthorization="$token.$thumbprint"
_debug keyauthorization "$keyauthorization"
__trigger_validation "$uri" "$keyauthorization"
fi
_d_i=0
_d_max_retry=$(echo "$entries" | wc -l)
while [ "$_d_i" -lt "$_d_max_retry" ]; do
_info "Deactivate: $_d_domain"
_d_i="$(_math $_d_i + 1)"
entry="$(echo "$entries" | sed -n "${_d_i}p")"
_debug entry "$entry"
if [ -z "$entry" ]; then
......@@ -3485,16 +4585,16 @@ _deactivate() {
_info "Deactivate: $_vtype"
if ! _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}"; then
if _send_signed_request "$authzUri" "{\"resource\": \"authz\", \"status\":\"deactivated\"}" && _contains "$response" '"deactivated"'; then
_info "Deactivate: $_vtype success."
else
_err "Can not deactivate $_vtype."
return 1
break
fi
_info "Deactivate: $_vtype success."
done
_debug "$_d_i"
if [ "$_d_i" -lt "$_d_max_retry" ]; then
if [ "$_d_i" -eq "$_d_max_retry" ]; then
_info "Deactivated success!"
else
_err "Deactivate failed."
......@@ -3506,6 +4606,7 @@ deactivate() {
_d_domain_list="$1"
_d_type="$2"
_initpath
_initAPI
_debug _d_domain_list "$_d_domain_list"
if [ -z "$(echo $_d_domain_list | cut -d , -f 1)" ]; then
_usage "Usage: $PROJECT_ENTRY --deactivate -d domain.com [-d domain.com]"
......@@ -3553,83 +4654,20 @@ _detect_profile() {
fi
fi
if [ ! -z "$DETECTED_PROFILE" ]; then
echo "$DETECTED_PROFILE"
fi
}
_initconf() {
_initpath
if [ ! -f "$ACCOUNT_CONF_PATH" ]; then
echo "#ACCOUNT_CONF_PATH=xxxx
#Account configurations:
#Here are the supported macros, uncomment them to make them take effect.
#ACCOUNT_EMAIL=aaa@example.com # the account email used to register account.
#ACCOUNT_KEY_PATH=\"/path/to/account.key\"
#CERT_HOME=\"/path/to/cert/home\"
echo "
#LOG_FILE=\"$DEFAULT_LOG_FILE\"
#LOG_LEVEL=1
#AUTO_UPGRADE=\"1\"
#STAGE=1 # Use the staging api
#FORCE=1 # Force to issue cert
#DEBUG=1 # Debug mode
#OPENSSL_BIN=openssl
#USER_AGENT=\"$USER_AGENT\"
#USER_PATH=
#dns api
#######################
#Cloudflare:
#api key
#CF_Key=\"sdfsdfsdfljlbjkljlkjsdfoiwje\"
#account email
#CF_Email=\"xxxx@sss.com\"
#######################
#Dnspod.cn:
#api key id
#DP_Id=\"1234\"
#api key
#DP_Key=\"sADDsdasdgdsf\"
#######################
#Cloudxns.com:
#CX_Key=\"1234\"
#
#CX_Secret=\"sADDsdasdgdsf\"
#######################
#Godaddy.com:
#GD_Key=\"sdfdsgdgdfdasfds\"
#
#GD_Secret=\"sADDsdasdfsdfdssdgdsf\"
#######################
#nsupdate:
#NSUPDATE_KEY=\"/path/to/update.key\"
#NSUPDATE_SERVER=\"192.168.0.1\"
#######################
#PowerDNS:
#PDNS_Url=\"http://ns.example.com:8081\"
#PDNS_ServerId=\"localhost\"
#PDNS_Token=\"0123456789ABCDEF\"
#PDNS_Ttl=60
#######################
#Amazon Route53:
#AWS_ACCESS_KEY_ID=XXXXXXXXXX
#AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXX
#NO_TIMESTAMP=1
" >"$ACCOUNT_CONF_PATH"
fi
......@@ -3645,7 +4683,7 @@ _precheck() {
fi
if [ -z "$_nocron" ]; then
if ! _exists "crontab"; then
if ! _exists "crontab" && ! _exists "fcrontab"; then
_err "It is recommended to install crontab first. try to install 'cron, crontab, crontabs or vixie-cron'."
_err "We need to set cron job to renew the certs automatically."
_err "Otherwise, your certs will not be able to be renewed automatically."
......@@ -3657,15 +4695,15 @@ _precheck() {
fi
fi
if ! _exists "$OPENSSL_BIN"; then
_err "Please install openssl first."
if ! _exists "${ACME_OPENSSL_BIN:-openssl}"; then
_err "Please install openssl first. ACME_OPENSSL_BIN=$ACME_OPENSSL_BIN"
_err "We need openssl to generate keys."
return 1
fi
if ! _exists "nc"; then
_err "It is recommended to install nc first, try to install 'nc' or 'netcat'."
_err "We use nc for standalone server if you use standalone mode."
if ! _exists "socat"; then
_err "It is recommended to install socat first."
_err "We use socat for standalone server if you use standalone mode."
_err "If you don't use standalone mode, just ignore this warning."
fi
......@@ -3685,7 +4723,9 @@ _setShebang() {
rm -f "$_file.tmp"
}
#confighome
_installalias() {
_c_home="$1"
_initpath
_envfile="$LE_WORKING_DIR/$PROJECT_ENTRY.env"
......@@ -3695,8 +4735,17 @@ _installalias() {
echo "$(cat "$_envfile")" | sed "s|^alias le.sh.*$||" >"$_envfile"
fi
if [ "$_c_home" ]; then
_c_entry=" --config-home '$_c_home'"
fi
_setopt "$_envfile" "export LE_WORKING_DIR" "=" "\"$LE_WORKING_DIR\""
_setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
if [ "$_c_home" ]; then
_setopt "$_envfile" "export LE_CONFIG_HOME" "=" "\"$LE_CONFIG_HOME\""
else
_sed_i "/^export LE_CONFIG_HOME/d" "$_envfile"
fi
_setopt "$_envfile" "alias $PROJECT_ENTRY" "=" "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
_profile="$(_detect_profile)"
if [ "$_profile" ]; then
......@@ -3714,7 +4763,12 @@ _installalias() {
if [ -f "$_csh_profile" ]; then
_info "Installing alias to '$_csh_profile'"
_setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
_setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
if [ "$_c_home" ]; then
_setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\""
else
_sed_i "/^setenv LE_CONFIG_HOME/d" "$_cshfile"
fi
_setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
_setopt "$_csh_profile" "source \"$_cshfile\""
fi
......@@ -3723,13 +4777,16 @@ _installalias() {
if [ -f "$_tcsh_profile" ]; then
_info "Installing alias to '$_tcsh_profile'"
_setopt "$_cshfile" "setenv LE_WORKING_DIR" " " "\"$LE_WORKING_DIR\""
_setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY\""
if [ "$_c_home" ]; then
_setopt "$_cshfile" "setenv LE_CONFIG_HOME" " " "\"$LE_CONFIG_HOME\""
fi
_setopt "$_cshfile" "alias $PROJECT_ENTRY" " " "\"$LE_WORKING_DIR/$PROJECT_ENTRY$_c_entry\""
_setopt "$_tcsh_profile" "source \"$_cshfile\""
fi
}
# nocron
# nocron confighome
install() {
if [ -z "$LE_WORKING_DIR" ]; then
......@@ -3737,6 +4794,7 @@ install() {
fi
_nocron="$1"
_c_home="$2"
if ! _initpath; then
_err "Install failed."
return 1
......@@ -3745,10 +4803,17 @@ install() {
_debug "Skip install cron job"
fi
if [ "$IN_CRON" != "1" ]; then
if ! _precheck "$_nocron"; then
_err "Pre-check failed, can not install."
return 1
fi
fi
if [ -z "$_c_home" ] && [ "$LE_CONFIG_HOME" != "$LE_WORKING_DIR" ]; then
_info "Using config home: $LE_CONFIG_HOME"
_c_home="$LE_CONFIG_HOME"
fi
#convert from le
if [ -d "$HOME/.le" ]; then
......@@ -3768,12 +4833,23 @@ install() {
_info "Installing to $LE_WORKING_DIR"
if [ ! -d "$LE_WORKING_DIR" ]; then
if ! mkdir -p "$LE_WORKING_DIR"; then
_err "Can not create working dir: $LE_WORKING_DIR"
return 1
fi
chmod 700 "$LE_WORKING_DIR"
fi
if [ ! -d "$LE_CONFIG_HOME" ]; then
if ! mkdir -p "$LE_CONFIG_HOME"; then
_err "Can not create config dir: $LE_CONFIG_HOME"
return 1
fi
chmod 700 "$LE_CONFIG_HOME"
fi
cp "$PROJECT_ENTRY" "$LE_WORKING_DIR/" && chmod +x "$LE_WORKING_DIR/$PROJECT_ENTRY"
......@@ -3784,7 +4860,9 @@ install() {
_info "Installed to $LE_WORKING_DIR/$PROJECT_ENTRY"
_installalias
if [ "$IN_CRON" != "1" ]; then
_installalias "$_c_home"
fi
for subf in $_SUB_FOLDERS; do
if [ -d "$subf" ]; then
......@@ -3810,14 +4888,14 @@ install() {
fi
if [ -z "$_nocron" ]; then
installcronjob
installcronjob "$_c_home"
fi
if [ -z "$NO_DETECT_SH" ]; then
#Modify shebang
if _exists bash; then
_info "Good, bash is found, so change the shebang to use bash as prefered."
_shebang='#!/usr/bin/env bash'
_info "Good, bash is found, so change the shebang to use bash as preferred."
_shebang='#!'"$(env bash -c "command -v bash")"
_setShebang "$LE_WORKING_DIR/$PROJECT_ENTRY" "$_shebang"
for subf in $_SUB_FOLDERS; do
if [ -d "$LE_WORKING_DIR/$subf" ]; then
......@@ -3843,7 +4921,7 @@ uninstall() {
_uninstallalias
rm -f "$LE_WORKING_DIR/$PROJECT_ENTRY"
_info "The keys and certs are in $LE_WORKING_DIR, you can remove them by yourself."
_info "The keys and certs are in \"$(__green "$LE_CONFIG_HOME")\", you can remove them by yourself."
}
......@@ -3874,8 +4952,9 @@ _uninstallalias() {
}
cron() {
IN_CRON=1
export IN_CRON=1
_initpath
_info "$(__green "===Starting cron===")"
if [ "$AUTO_UPGRADE" = "1" ]; then
export LE_WORKING_DIR
(
......@@ -3895,6 +4974,7 @@ cron() {
renewAll
_ret="$?"
IN_CRON=""
_info "$(__green "===End cron===")"
exit $_ret
}
......@@ -3912,24 +4992,27 @@ Commands:
--version, -v Show version info.
--install Install $PROJECT_NAME to your system.
--uninstall Uninstall $PROJECT_NAME, and uninstall the cron job.
--upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT .
--upgrade Upgrade $PROJECT_NAME to the latest code from $PROJECT.
--issue Issue a cert.
--signcsr Issue a cert from an existing csr.
--deploy Deploy the cert to your server.
--installcert Install the issued cert to apache/nginx or any other server.
--install-cert Install the issued cert to apache/nginx or any other server.
--renew, -r Renew a cert.
--renewAll Renew all the certs.
--renew-all Renew all the certs.
--revoke Revoke a cert.
--remove Remove the cert from $PROJECT
--list List all the certs.
--showcsr Show the content of a csr.
--installcronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
--uninstallcronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
--install-cronjob Install the cron job to renew certs, you don't need to call this. The 'install' command can automatically install the cron job.
--uninstall-cronjob Uninstall the cron job. The 'uninstall' command can do this automatically.
--cron Run cron job to renew all the certs.
--toPkcs Export the certificate and key to a pfx file.
--updateaccount Update account info.
--registeraccount Register account key.
--createAccountKey, -cak Create an account private key, professional use.
--createDomainKey, -cdk Create an domain private key, professional use.
--toPkcs8 Convert to pkcs8 format.
--update-account Update account info.
--register-account Register account key.
--deactivate-account Deactivate the account.
--create-account-key Create an account private key, professional use.
--create-domain-key Create an domain private key, professional use.
--createCSR, -ccsr Create CSR , professional use.
--deactivate Deactivate the domain authz, professional use.
......@@ -3938,9 +5021,10 @@ Parameters:
--force, -f Used to force to install or force to renew a cert immediately.
--staging, --test Use staging server, just for test.
--debug Output debug info.
--output-insecure Output all the sensitive messages. By default all the credentials/sensitive messages are hidden from the output/debug/log for secure.
--webroot, -w /path/to/webroot Specifies the web root folder for web root mode.
--standalone Use standalone mode.
--stateless Use stateless mode, see: $_STATELESS_WIKI
--tls Use standalone tls mode.
--apache Use apache mode.
--dns [dns_cf|dns_dp|dns_cx|/path/to/api/file] Use dns mode or dns api.
......@@ -3950,19 +5034,22 @@ Parameters:
--accountkeylength, -ak [2048] Specifies the account key length.
--log [/path/to/logfile] Specifies the log file. The default is: \"$DEFAULT_LOG_FILE\" if you don't give a file path here.
--log-level 1|2 Specifies the log level, default is 1.
--syslog [0|3|6|7] Syslog level, 0: disable syslog, 3: error, 6: info, 7: debug.
These parameters are to install the cert to nginx/apache or anyother server after issue/renew a cert:
--certpath /path/to/real/cert/file After issue/renew, the cert will be copied to this path.
--keypath /path/to/real/key/file After issue/renew, the key will be copied to this path.
--capath /path/to/real/ca/file After issue/renew, the intermediate cert will be copied to this path.
--fullchainpath /path/to/fullchain/file After issue/renew, the fullchain cert will be copied to this path.
--cert-file After issue/renew, the cert will be copied to this path.
--key-file After issue/renew, the key will be copied to this path.
--ca-file After issue/renew, the intermediate cert will be copied to this path.
--fullchain-file After issue/renew, the fullchain cert will be copied to this path.
--reloadcmd \"service nginx reload\" After issue/renew, it's used to reload the server.
--server SERVER ACME Directory Resource URI. (default: https://acme-v01.api.letsencrypt.org/directory)
--accountconf Specifies a customized account config file.
--home Specifies the home dir for $PROJECT_NAME .
--certhome Specifies the home dir to save all the certs, only valid for '--install' command.
--cert-home Specifies the home dir to save all the certs, only valid for '--install' command.
--config-home Specifies the home dir to save all the configurations.
--useragent Specifies the user agent string. it will be saved for future use too.
--accountemail Specifies the account email for registering, Only valid for the '--install' command.
--accountkey Specifies the account key path, Only valid for the '--install' command.
......@@ -3971,21 +5058,25 @@ Parameters:
--tlsport Specifies the standalone tls listening port. Only valid if the server is behind a reverse proxy or load balancer.
--local-address Specifies the standalone/tls server listening address, in case you have multiple ip addresses.
--listraw Only used for '--list' command, list the certs in raw format.
--stopRenewOnError, -se Only valid for '--renewall' command. Stop if one cert has error in renewal.
--stopRenewOnError, -se Only valid for '--renew-all' command. Stop if one cert has error in renewal.
--insecure Do not check the server certificate, in some devices, the api server's certificate may not be trusted.
--ca-bundle Specifices the path to the CA certificate bundle to verify api server's certificate.
--ca-bundle Specifies the path to the CA certificate bundle to verify api server's certificate.
--ca-path Specifies directory containing CA certificates in PEM format, used by wget or curl.
--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.
--ecc Specifies to use the ECC cert. Valid for '--installcert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
--no-color Do not output color text.
--ecc Specifies to use the ECC cert. Valid for '--install-cert', '--renew', '--revoke', '--toPkcs' and '--createCSR'
--csr Specifies the input csr.
--pre-hook Command to be run before obtaining any certificates.
--post-hook Command to be run after attempting to obtain/renew certificates. No matter the obain/renew is success or failed.
--post-hook Command to be run after attempting to obtain/renew certificates. No matter the obtain/renew is success or failed.
--renew-hook Command to be run once for each successfully renewed certificate.
--deploy-hook The hook file to deploy cert
--ocsp-must-staple, --ocsp Generate ocsp must Staple extension.
--always-force-new-domain-key Generate new domain key when renewal. Otherwise, the domain key is not changed by default.
--auto-upgrade [0|1] Valid for '--upgrade' command, indicating whether to upgrade automatically in future.
--listen-v4 Force standalone/tls server to listen at ipv4.
--listen-v6 Force standalone/tls server to listen at ipv6.
--openssl-bin Specifies a custom openssl bin location.
--use-wget Force to use wget, if you have both curl and wget installed.
"
}
......@@ -4006,7 +5097,10 @@ _installOnline() {
fi
(
_info "Extracting $localname"
tar xzf $localname
if ! (tar xzf $localname || gtar xzf $localname); then
_err "Extraction error."
exit 1
fi
cd "$PROJECT_NAME-$BRANCH"
chmod +x $PROJECT_ENTRY
......@@ -4050,9 +5144,9 @@ _processAccountConf() {
fi
if [ "$_openssl_bin" ]; then
_saveaccountconf "OPENSSL_BIN" "$_openssl_bin"
elif [ "$OPENSSL_BIN" ] && [ "$OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then
_saveaccountconf "OPENSSL_BIN" "$OPENSSL_BIN"
_saveaccountconf "ACME_OPENSSL_BIN" "$_openssl_bin"
elif [ "$ACME_OPENSSL_BIN" ] && [ "$ACME_OPENSSL_BIN" != "$DEFAULT_OPENSSL_BIN" ]; then
_saveaccountconf "ACME_OPENSSL_BIN" "$ACME_OPENSSL_BIN"
fi
if [ "$_auto_upgrade" ]; then
......@@ -4061,6 +5155,12 @@ _processAccountConf() {
_saveaccountconf "AUTO_UPGRADE" "$AUTO_UPGRADE"
fi
if [ "$_use_wget" ]; then
_saveaccountconf "ACME_USE_WGET" "$_use_wget"
elif [ "$ACME_USE_WGET" ]; then
_saveaccountconf "ACME_USE_WGET" "$ACME_USE_WGET"
fi
}
_process() {
......@@ -4070,10 +5170,10 @@ _process() {
_webroot=""
_keylength=""
_accountkeylength=""
_certpath=""
_keypath=""
_capath=""
_fullchainpath=""
_cert_file=""
_key_file=""
_ca_file=""
_fullchain_file=""
_reloadcmd=""
_password=""
_accountconf=""
......@@ -4081,6 +5181,7 @@ _process() {
_accountemail=""
_accountkey=""
_certhome=""
_confighome=""
_httpport=""
_tlsport=""
_dnssleep=""
......@@ -4088,6 +5189,7 @@ _process() {
_stopRenewOnError=""
#_insecure=""
_ca_bundle=""
_ca_path=""
_nocron=""
_ecc=""
_csr=""
......@@ -4103,6 +5205,9 @@ _process() {
_listen_v4=""
_listen_v6=""
_openssl_bin=""
_syslog=""
_use_wget=""
_server=""
while [ ${#} -gt 0 ]; do
case "${1}" in
......@@ -4135,25 +5240,28 @@ _process() {
--showcsr)
_CMD="showcsr"
;;
--installcert | -i)
--installcert | -i | --install-cert)
_CMD="installcert"
;;
--renew | -r)
_CMD="renew"
;;
--renewAll | --renewall)
--renewAll | --renewall | --renew-all)
_CMD="renewAll"
;;
--revoke)
_CMD="revoke"
;;
--remove)
_CMD="remove"
;;
--list)
_CMD="list"
;;
--installcronjob)
--installcronjob | --install-cronjob)
_CMD="installcronjob"
;;
--uninstallcronjob)
--uninstallcronjob | --uninstall-cronjob)
_CMD="uninstallcronjob"
;;
--cron)
......@@ -4162,10 +5270,13 @@ _process() {
--toPkcs)
_CMD="toPkcs"
;;
--createAccountKey | --createaccountkey | -cak)
--toPkcs8)
_CMD="toPkcs8"
;;
--createAccountKey | --createaccountkey | -cak | --create-account-key)
_CMD="createAccountKey"
;;
--createDomainKey | --createdomainkey | -cdk)
--createDomainKey | --createdomainkey | -cdk | --create-domain-key)
_CMD="createDomainKey"
;;
--createCSR | --createcsr | -ccr)
......@@ -4174,12 +5285,15 @@ _process() {
--deactivate)
_CMD="deactivate"
;;
--updateaccount)
--updateaccount | --update-account)
_CMD="updateaccount"
;;
--registeraccount)
--registeraccount | --register-account)
_CMD="registeraccount"
;;
--deactivate-account)
_CMD="deactivateaccount"
;;
--domain | -d)
_dvalue="$2"
......@@ -4213,14 +5327,23 @@ _process() {
--staging | --test)
STAGE="1"
;;
--server)
ACME_DIRECTORY="$2"
_server="$ACME_DIRECTORY"
export ACME_DIRECTORY
shift
;;
--debug)
if [ -z "$2" ] || _startswith "$2" "-"; then
DEBUG="1"
DEBUG="$DEBUG_LEVEL_DEFAULT"
else
DEBUG="$2"
shift
fi
;;
--output-insecure)
export OUTPUT_INSECURE=1
;;
--webroot | -w)
wvalue="$2"
if [ -z "$_webroot" ]; then
......@@ -4238,6 +5361,14 @@ _process() {
_webroot="$_webroot,$wvalue"
fi
;;
--stateless)
wvalue="$MODE_STATELESS"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--local-address)
lvalue="$2"
_local_address="$_local_address$lvalue,"
......@@ -4251,6 +5382,14 @@ _process() {
_webroot="$_webroot,$wvalue"
fi
;;
--nginx)
wvalue="$NGINX"
if [ -z "$_webroot" ]; then
_webroot="$wvalue"
else
_webroot="$_webroot,$wvalue"
fi
;;
--tls)
wvalue="$W_TLS"
if [ -z "$_webroot" ]; then
......@@ -4261,7 +5400,7 @@ _process() {
;;
--dns)
wvalue="dns"
if ! _startswith "$2" "-"; then
if [ "$2" ] && ! _startswith "$2" "-"; then
wvalue="$2"
shift
fi
......@@ -4286,20 +5425,20 @@ _process() {
shift
;;
--certpath)
_certpath="$2"
--cert-file | --certpath)
_cert_file="$2"
shift
;;
--keypath)
_keypath="$2"
--key-file | --keypath)
_key_file="$2"
shift
;;
--capath)
_capath="$2"
--ca-file | --capath)
_ca_file="$2"
shift
;;
--fullchainpath)
_fullchainpath="$2"
--fullchain-file | --fullchainpath)
_fullchain_file="$2"
shift
;;
--reloadcmd | --reloadCmd)
......@@ -4319,11 +5458,16 @@ _process() {
LE_WORKING_DIR="$2"
shift
;;
--certhome)
--certhome | --cert-home)
_certhome="$2"
CERT_HOME="$_certhome"
shift
;;
--config-home)
_confighome="$2"
LE_CONFIG_HOME="$_confighome"
shift
;;
--useragent)
_useragent="$2"
USER_AGENT="$_useragent"
......@@ -4366,13 +5510,21 @@ _process() {
HTTPS_INSECURE="1"
;;
--ca-bundle)
_ca_bundle="$(readlink -f "$2")"
_ca_bundle="$(_readlink -f "$2")"
CA_BUNDLE="$_ca_bundle"
shift
;;
--ca-path)
_ca_path="$2"
CA_PATH="$_ca_path"
shift
;;
--nocron)
_nocron="1"
;;
--no-color)
export ACME_NO_COLOR=1
;;
--ecc)
_ecc="isEcc"
;;
......@@ -4393,11 +5545,23 @@ _process() {
shift
;;
--deploy-hook)
_deploy_hook="$2"
if [ -z "$2" ] || _startswith "$2" "-"; then
_usage "Please specify a value for '--deploy-hook'"
return 1
fi
_deploy_hook="$_deploy_hook$2,"
shift
;;
--ocsp-must-staple | --ocsp)
Le_OCSP_Stable="1"
Le_OCSP_Staple="1"
;;
--always-force-new-domain-key)
if [ -z "$2" ] || _startswith "$2" "-"; then
Le_ForceNewDomainKey=1
else
Le_ForceNewDomainKey="$2"
shift
fi
;;
--log | --logfile)
_log="1"
......@@ -4417,6 +5581,15 @@ _process() {
LOG_LEVEL="$_log_level"
shift
;;
--syslog)
if ! _startswith "$2" '-'; then
_syslog="$2"
shift
fi
if [ -z "$_syslog" ]; then
_syslog="$SYSLOG_LEVEL_DEFAULT"
fi
;;
--auto-upgrade)
_auto_upgrade="$2"
if [ -z "$_auto_upgrade" ] || _startswith "$_auto_upgrade" '-'; then
......@@ -4436,7 +5609,12 @@ _process() {
;;
--openssl-bin)
_openssl_bin="$2"
OPENSSL_BIN="$_openssl_bin"
ACME_OPENSSL_BIN="$_openssl_bin"
shift
;;
--use-wget)
_use_wget="1"
ACME_USE_WGET="1"
;;
*)
_err "Unknown parameter : $1"
......@@ -4464,6 +5642,21 @@ _process() {
LOG_LEVEL="$_log_level"
fi
if [ "$_syslog" ]; then
if _exists logger; then
if [ "$_syslog" = "0" ]; then
_clearaccountconf "SYS_LOG"
else
_saveaccountconf "SYS_LOG" "$_syslog"
fi
SYS_LOG="$_syslog"
else
_err "The 'logger' command is not found, can not enable syslog."
_clearaccountconf "SYS_LOG"
SYS_LOG=""
fi
fi
_processAccountConf
fi
......@@ -4471,14 +5664,17 @@ _process() {
if [ "$DEBUG" ]; then
version
if [ "$_server" ]; then
_debug "Using server: $_server"
fi
fi
case "${_CMD}" in
install) install "$_nocron" ;;
install) install "$_nocron" "$_confighome" ;;
uninstall) uninstall "$_nocron" ;;
upgrade) upgrade ;;
issue)
issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address"
issue "$_webroot" "$_domain" "$_altdomains" "$_keylength" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_pre_hook" "$_post_hook" "$_renew_hook" "$_local_address"
;;
deploy)
deploy "$_domain" "$_deploy_hook" "$_ecc"
......@@ -4490,7 +5686,7 @@ _process() {
showcsr "$_csr" "$_domain"
;;
installcert)
installcert "$_domain" "$_certpath" "$_keypath" "$_capath" "$_reloadcmd" "$_fullchainpath" "$_ecc"
installcert "$_domain" "$_cert_file" "$_key_file" "$_ca_file" "$_reloadcmd" "$_fullchain_file" "$_ecc"
;;
renew)
renew "$_domain" "$_ecc"
......@@ -4501,6 +5697,9 @@ _process() {
revoke)
revoke "$_domain" "$_ecc"
;;
remove)
remove "$_domain" "$_ecc"
;;
deactivate)
deactivate "$_domain,$_altdomains"
;;
......@@ -4510,15 +5709,21 @@ _process() {
updateaccount)
updateaccount
;;
deactivateaccount)
deactivateaccount
;;
list)
list "$_listraw"
;;
installcronjob) installcronjob ;;
installcronjob) installcronjob "$_confighome" ;;
uninstallcronjob) uninstallcronjob ;;
cron) cron ;;
toPkcs)
toPkcs "$_domain" "$_password" "$_ecc"
;;
toPkcs8)
toPkcs8 "$_domain" "$_ecc"
;;
createAccountKey)
createAccountKey "$_accountkeylength"
;;
......@@ -4530,7 +5735,9 @@ _process() {
;;
*)
if [ "$_CMD" ]; then
_err "Invalid command: $_CMD"
fi
showhelp
return 1
;;
......@@ -4551,6 +5758,21 @@ _process() {
if [ "$_log_level" ]; then
_saveaccountconf "LOG_LEVEL" "$_log_level"
fi
if [ "$_syslog" ]; then
if _exists logger; then
if [ "$_syslog" = "0" ]; then
_clearaccountconf "SYS_LOG"
else
_saveaccountconf "SYS_LOG" "$_syslog"
fi
else
_err "The 'logger' command is not found, can not enable syslog."
_clearaccountconf "SYS_LOG"
SYS_LOG=""
fi
fi
_processAccountConf
fi
......@@ -4558,7 +5780,7 @@ _process() {
if [ "$INSTALLONLINE" ]; then
INSTALLONLINE=""
_installOnline $BRANCH
_installOnline
exit
fi
......
# Using deploy api
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
Here are the scripts to deploy the certs/key to the server/services.
## 1. Deploy the certs to your cpanel host
If you want to deploy using cpanel UAPI see 7.
(cpanel deploy hook is not finished yet, this is just an example.)
Then you can deploy now:
```sh
export DEPLOY_CPANEL_USER=myusername
export DEPLOY_CPANEL_PASSWORD=PASSWORD
acme.sh --deploy -d example.com --deploy-hook cpanel
```
## 2. Deploy ssl cert on kong proxy engine based on api
Before you can deploy your cert, you must [issue the cert first](https://github.com/Neilpang/acme.sh/wiki/How-to-issue-a-cert).
Currently supports Kong-v0.10.x.
```sh
acme.sh --deploy -d ftp.example.com --deploy-hook kong
```
## 3. Deploy the cert to remote server through SSH access
(TODO)
## 4. Deploy the cert to local vsftpd server
```sh
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
```
The default vsftpd conf file is `/etc/vsftpd.conf`, if your vsftpd conf is not in the default location, you can specify one:
```sh
export DEPLOY_VSFTPD_CONF="/etc/vsftpd.conf"
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
```
The default command to restart vsftpd server is `service vsftpd restart`, if it doesn't work, you can specify one:
```sh
export DEPLOY_VSFTPD_RELOAD="/etc/init.d/vsftpd restart"
acme.sh --deploy -d ftp.example.com --deploy-hook vsftpd
```
## 5. Deploy the cert to local exim4 server
```sh
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
```
The default exim4 conf file is `/etc/exim/exim.conf`, if your exim4 conf is not in the default location, you can specify one:
```sh
export DEPLOY_EXIM4_CONF="/etc/exim4/exim4.conf.template"
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
```
The default command to restart exim4 server is `service exim4 restart`, if it doesn't work, you can specify one:
```sh
export DEPLOY_EXIM4_RELOAD="/etc/init.d/exim4 restart"
acme.sh --deploy -d ftp.example.com --deploy-hook exim4
```
## 6. Deploy the cert to OSX Keychain
```sh
acme.sh --deploy -d ftp.example.com --deploy-hook keychain
```
## 7. Deploy to cpanel host using UAPI
This hook is using UAPI and works in cPanel & WHM version 56 or newer.
```
acme.sh --deploy -d example.com --deploy-hook cpanel_uapi
```
DEPLOY_CPANEL_USER is required only if you run the script as root and it should contain cpanel username.
```sh
export DEPLOY_CPANEL_USER=username
acme.sh --deploy -d example.com --deploy-hook cpanel_uapi
```
Please note, that the cpanel_uapi hook will deploy only the first domain when your certificate will automatically renew. Therefore you should issue a separete certificate for each domain.
## 8. Deploy the cert to your FRITZ!Box router
You must specify the credentials that have administrative privileges on the FRITZ!Box in order to deploy the certificate, plus the URL of your FRITZ!Box, through the following environment variables:
```sh
$ export DEPLOY_FRITZBOX_USERNAME=my_username
$ export DEPLOY_FRITZBOX_PASSWORD=the_password
$ export DEPLOY_FRITZBOX_URL=https://fritzbox.example.com
```
After the first deployment, these values will be stored in your $HOME/.acme.sh/account.conf. You may now deploy the certificate like this:
```sh
acme.sh --deploy -d fritzbox.example.com --deploy-hook fritzbox
```
## 9. Deploy the cert to strongswan
```sh
acme.sh --deploy -d ftp.example.com --deploy-hook strongswan
```
#!/usr/bin/env sh
#Here is a script to deploy cert to apache server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
apache_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "Deploy cert to apache server, Not implemented yet"
return 1
}
#!/usr/bin/env sh
# Here is the script to deploy the cert to your cpanel using the cpanel API.
# Uses command line uapi. --user option is needed only if run as root.
# Returns 0 when success.
# Written by Santeri Kannisto <santeri.kannisto@2globalnomads.info>
# Public domain, 2017
#export DEPLOY_CPANEL_USER=myusername
######## Public functions #####################
#domain keyfile certfile cafile fullchain
cpanel_uapi_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
if ! _exists uapi; then
_err "The command uapi is not found."
return 1
fi
if ! _exists php; then
_err "The command php is not found."
return 1
fi
# read cert and key files and urlencode both
_certstr=$(cat "$_ccert")
_keystr=$(cat "$_ckey")
_cert=$(php -r "echo urlencode(\"$_certstr\");")
_key=$(php -r "echo urlencode(\"$_keystr\");")
_debug _cert "$_cert"
_debug _key "$_key"
if [ "$(id -u)" = 0 ]; then
if [ -z "$DEPLOY_CPANEL_USER" ]; then
_err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username"
return 1
fi
_savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
_response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
else
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
fi
error_response="status: 0"
if test "${_response#*$error_response}" != "$_response"; then
_err "Error in deploying certificate:"
_err "$_response"
return 1
fi
_debug response "$_response"
_info "Certificate successfully deployed"
return 0
}
#!/usr/bin/env sh
#Here is a script to deploy cert to dovecot server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
dovecot_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "Not implemented yet"
return 1
}
#!/usr/bin/env sh
#Here is a script to deploy cert to exim4 server.
#returns 0 means success, otherwise error.
#DEPLOY_EXIM4_CONF="/etc/exim/exim.conf"
#DEPLOY_EXIM4_RELOAD="service exim4 restart"
######## Public functions #####################
#domain keyfile certfile cafile fullchain
exim4_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_ssl_path="/etc/acme.sh/exim4"
if ! mkdir -p "$_ssl_path"; then
_err "Can not create folder:$_ssl_path"
return 1
fi
_info "Copying key and cert"
_real_key="$_ssl_path/exim4.key"
if ! cat "$_ckey" >"$_real_key"; then
_err "Error: write key file to: $_real_key"
return 1
fi
_real_fullchain="$_ssl_path/exim4.pem"
if ! cat "$_cfullchain" >"$_real_fullchain"; then
_err "Error: write key file to: $_real_fullchain"
return 1
fi
DEFAULT_EXIM4_RELOAD="service exim4 restart"
_reload="${DEPLOY_EXIM4_RELOAD:-$DEFAULT_EXIM4_RELOAD}"
if [ -z "$IS_RENEW" ]; then
DEFAULT_EXIM4_CONF="/etc/exim/exim.conf"
if [ ! -f "$DEFAULT_EXIM4_CONF" ]; then
DEFAULT_EXIM4_CONF="/etc/exim4/exim4.conf.template"
fi
_exim4_conf="${DEPLOY_EXIM4_CONF:-$DEFAULT_EXIM4_CONF}"
_debug _exim4_conf "$_exim4_conf"
if [ ! -f "$_exim4_conf" ]; then
if [ -z "$DEPLOY_EXIM4_CONF" ]; then
_err "exim4 conf is not found, please define DEPLOY_EXIM4_CONF"
return 1
else
_err "It seems that the specified exim4 conf is not valid, please check."
return 1
fi
fi
if [ ! -w "$_exim4_conf" ]; then
_err "The file $_exim4_conf is not writable, please change the permission."
return 1
fi
_backup_conf="$DOMAIN_BACKUP_PATH/exim4.conf.bak"
_info "Backup $_exim4_conf to $_backup_conf"
cp "$_exim4_conf" "$_backup_conf"
_info "Modify exim4 conf: $_exim4_conf"
if _setopt "$_exim4_conf" "tls_certificate" "=" "$_real_fullchain" \
&& _setopt "$_exim4_conf" "tls_privatekey" "=" "$_real_key"; then
_info "Set config success!"
else
_err "Config exim4 server error, please report bug to us."
_info "Restoring exim4 conf"
if cat "$_backup_conf" >"$_exim4_conf"; then
_info "Restore conf success"
eval "$_reload"
else
_err "Oops, error restore exim4 conf, please report bug to us."
fi
return 1
fi
fi
_info "Run reload: $_reload"
if eval "$_reload"; then
_info "Reload success!"
if [ "$DEPLOY_EXIM4_CONF" ]; then
_savedomainconf DEPLOY_EXIM4_CONF "$DEPLOY_EXIM4_CONF"
else
_cleardomainconf DEPLOY_EXIM4_CONF
fi
if [ "$DEPLOY_EXIM4_RELOAD" ]; then
_savedomainconf DEPLOY_EXIM4_RELOAD "$DEPLOY_EXIM4_RELOAD"
else
_cleardomainconf DEPLOY_EXIM4_RELOAD
fi
return 0
else
_err "Reload error, restoring"
if cat "$_backup_conf" >"$_exim4_conf"; then
_info "Restore conf success"
eval "$_reload"
else
_err "Oops, error restore exim4 conf, please report bug to us."
fi
return 1
fi
return 0
}
#!/usr/bin/env sh
#Here is a script to deploy cert to an AVM FRITZ!Box router.
#returns 0 means success, otherwise error.
#DEPLOY_FRITZBOX_USERNAME="username"
#DEPLOY_FRITZBOX_PASSWORD="password"
#DEPLOY_FRITZBOX_URL="https://fritz.box"
# Kudos to wikrie at Github for his FRITZ!Box update script:
# https://gist.github.com/wikrie/f1d5747a714e0a34d0582981f7cb4cfb
######## Public functions #####################
#domain keyfile certfile cafile fullchain
fritzbox_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
if ! _exists iconv; then
_err "iconv not found"
return 1
fi
_fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}"
_fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}"
_fritzbox_url="${DEPLOY_FRITZBOX_URL}"
_debug _fritzbox_url "$_fritzbox_url"
_debug _fritzbox_username "$_fritzbox_username"
_secure_debug _fritzbox_password "$_fritzbox_password"
if [ -z "$_fritzbox_username" ]; then
_err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME."
return 1
fi
if [ -z "$_fritzbox_password" ]; then
_err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD."
return 1
fi
if [ -z "$_fritzbox_url" ]; then
_err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL."
return 1
fi
_saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}"
_saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}"
_saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}"
# Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate
export HTTPS_INSECURE=1
_info "Log in to the FRITZ!Box"
_fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | md5sum | awk '{print $1}')"
_fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then
_err "Logging in to the FRITZ!Box failed. Please check username, password and URL."
return 1
fi
_info "Generate form POST request"
_post_request="$(_mktemp)"
_post_boundary="---------------------------$(date +%Y%m%d%H%M%S)"
# _CERTPASSWORD_ is unset because Let's Encrypt certificates don't have a password. But if they ever do, here's the place to use it!
_CERTPASSWORD_=
{
printf -- "--"
printf -- "%s\r\n" "${_post_boundary}"
printf "Content-Disposition: form-data; name=\"sid\"\r\n\r\n%s\r\n" "${_fritzbox_sid}"
printf -- "--"
printf -- "%s\r\n" "${_post_boundary}"
printf "Content-Disposition: form-data; name=\"BoxCertPassword\"\r\n\r\n%s\r\n" "${_CERTPASSWORD_}"
printf -- "--"
printf -- "%s\r\n" "${_post_boundary}"
printf "Content-Disposition: form-data; name=\"BoxCertImportFile\"; filename=\"BoxCert.pem\"\r\n"
printf "Content-Type: application/octet-stream\r\n\r\n"
cat "${_ckey}" "${_cfullchain}"
printf "\r\n"
printf -- "--"
printf -- "%s--" "${_post_boundary}"
} >>"${_post_request}"
_info "Upload certificate to the FRITZ!Box"
export _H1="Content-type: multipart/form-data boundary=${_post_boundary}"
_post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL
retval=$?
if [ $retval = 0 ]; then
_info "Upload successful"
else
_err "Upload failed"
fi
rm "${_post_request}"
return $retval
}
#!/usr/bin/env sh
#Here is a script to deploy cert to haproxy server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
haproxy_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to haproxy server, Not implemented yet"
return 1
}
#!/usr/bin/env sh
#Here is a sample custom api script.
#This file name is "myapi.sh"
#So, here must be a method myapi_deploy()
#Which will be called by acme.sh to deploy the cert
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
keychain_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
/usr/bin/security import "$_ckey" -k "/Library/Keychains/System.keychain"
/usr/bin/security import "$_ccert" -k "/Library/Keychains/System.keychain"
/usr/bin/security import "$_cca" -k "/Library/Keychains/System.keychain"
/usr/bin/security import "$_cfullchain" -k "/Library/Keychains/System.keychain"
return 0
}
#!/usr/bin/env sh
# If certificate already exist it will update only cert and key not touching other parameter
# If certificate doesn't exist it will only upload cert and key and not set other parameter
# Note that we deploy full chain
# Written by Geoffroi Genot <ggenot@voxbone.com>
######## Public functions #####################
#domain keyfile certfile cafile fullchain
kong_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_info "Deploying certificate on Kong instance"
if [ -z "$KONG_URL" ]; then
_debug "KONG_URL Not set, using default http://localhost:8001"
KONG_URL="http://localhost:8001"
fi
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
#Get ssl_uuid linked to the domain
ssl_uuid=$(_get "$KONG_URL/certificates/$_cdomain" | _normalizeJson | _egrep_o '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
if [ -z "$ssl_uuid" ]; then
_debug "Unable to get Kong ssl_uuid for domain $_cdomain"
_debug "Make sure that KONG_URL is correctly configured"
_debug "Make sure that a Kong certificate match the sni"
_debug "Kong url: $KONG_URL"
_info "No existing certificate, creating..."
#return 1
fi
#Save kong url if it's succesful (First run case)
_saveaccountconf KONG_URL "$KONG_URL"
#Generate DEIM
delim="-----MultipartDelimiter$(date "+%s%N")"
nl="\015\012"
#Set Header
_H1="Content-Type: multipart/form-data; boundary=$delim"
#Generate data for request (Multipart/form-data with mixed content)
if [ -z "$ssl_uuid" ]; then
#set sni to domain
content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain"
fi
#add key
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
#Add cert
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
#Close multipart
content="$content${nl}--$delim--${nl}"
#Convert CRLF
content=$(printf %b "$content")
#DEBUG
_debug header "$_H1"
_debug content "$content"
#Check if sslcreated (if not => POST else => PATCH)
if [ -z "$ssl_uuid" ]; then
#Post certificate to Kong
response=$(_post "$content" "$KONG_URL/certificates" "" "POST")
else
#patch
response=$(_post "$content" "$KONG_URL/certificates/$ssl_uuid" "" "PATCH")
fi
if ! [ "$(echo "$response" | _egrep_o "created_at")" = "created_at" ]; then
_err "An error occurred with cert upload. Check response:"
_err "$response"
return 1
fi
_debug response "$response"
_info "Certificate successfully deployed"
}
File mode changed from 100644 to 100755
#!/usr/bin/env sh
#Here is a script to deploy cert to mysqld server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
mysqld_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to mysqld server, Not implemented yet"
return 1
}
#!/usr/bin/env sh
#Here is a script to deploy cert to nginx server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
nginx_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to nginx server, Not implemented yet"
return 1
}
#!/usr/bin/env sh
#Here is a script to deploy cert to opensshd server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
opensshd_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to opensshd server, Not implemented yet"
return 1
}
#!/usr/bin/env sh
#Here is a script to deploy cert to pureftpd server.
#returns 0 means success, otherwise error.
######## Public functions #####################
#domain keyfile certfile cafile fullchain
pureftpd_deploy() {
_cdomain="$1"
_ckey="$2"
_ccert="$3"
_cca="$4"
_cfullchain="$5"
_debug _cdomain "$_cdomain"
_debug _ckey "$_ckey"
_debug _ccert "$_ccert"
_debug _cca "$_cca"
_debug _cfullchain "$_cfullchain"
_err "deploy cert to pureftpd server, Not implemented yet"
return 1
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment