mirror of
https://github.com/dehydrated-io/dehydrated.git
synced 2026-03-13 05:35:16 +01:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70d261a729 | ||
|
|
947dbb9e29 | ||
|
|
8a414e55bc | ||
|
|
fd3fc8af62 | ||
|
|
6e802ddc19 | ||
|
|
0211d24577 | ||
|
|
68274646bb | ||
|
|
c0bcf91410 | ||
|
|
a91074b707 | ||
|
|
a6a07779ad | ||
|
|
a6e6aa7445 | ||
|
|
dcdb2940fb | ||
|
|
0ade30cc74 | ||
|
|
bc34f3aa86 | ||
|
|
5940c55e18 | ||
|
|
2eedd69ee9 | ||
|
|
be252c7db9 | ||
|
|
9ebab3e026 | ||
|
|
ad291207d0 | ||
|
|
a7b2af2b92 | ||
|
|
082ed17a0a | ||
|
|
dec5ad5840 | ||
|
|
da67297288 | ||
|
|
83bf2664b0 | ||
|
|
63854b752b | ||
|
|
901f9f76e2 | ||
|
|
b5de2e26eb | ||
|
|
73a116e879 | ||
|
|
9c35fce61e | ||
|
|
87194f6596 | ||
|
|
62d37c9b3d | ||
|
|
b53cb6643b | ||
|
|
fb41783885 | ||
|
|
0bc0bd13d6 | ||
|
|
6d02bfdb42 | ||
|
|
727443483d | ||
|
|
7a0e71c6c2 | ||
|
|
45f5c17260 | ||
|
|
61083cf522 | ||
|
|
afba7c694c | ||
|
|
471899b4d8 | ||
|
|
ec5dbcc816 | ||
|
|
0f69481e2b | ||
|
|
6f3fed496d | ||
|
|
5fd93ea874 | ||
|
|
656af8cadc | ||
|
|
3e521e1c01 | ||
|
|
68cb1e0661 | ||
|
|
35a9f31643 |
14
.travis.yml
14
.travis.yml
@@ -1,14 +0,0 @@
|
||||
sudo: false
|
||||
language: shell
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- ngrok
|
||||
|
||||
script:
|
||||
- export CI="true"
|
||||
- ./test.sh
|
||||
14
CHANGELOG
14
CHANGELOG
@@ -1,6 +1,20 @@
|
||||
# Change Log
|
||||
This file contains a log of major changes in dehydrated
|
||||
|
||||
## [0.6.1] - 2018-03-13
|
||||
## Changed
|
||||
- Use new ACME v2 endpoint by default
|
||||
|
||||
## [0.6.0] - 2018-03-11
|
||||
## Changed
|
||||
- Challenge validation loop has been modified to loop over authorization identifiers instead of altnames (ACMEv2 + wildcard support)
|
||||
- Removed LICENSE parameter from config (terms of service is now acquired directly from the CA directory)
|
||||
|
||||
## Added
|
||||
- Support for ACME v02 (including wildcard certificates!)
|
||||
- New hook: generate_csr (see example hook script for more information)
|
||||
- Calling random hook on startup to make it clear to hook script authors that unknown hooks should just be ignored...
|
||||
|
||||
## [0.5.0] - 2018-01-13
|
||||
## Changed
|
||||
- Certificate chain is now cached (CHAINCACHE)
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2017 Lukas Schauer
|
||||
Copyright (c) 2015-2018 Lukas Schauer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
42
README.md
42
README.md
@@ -1,8 +1,9 @@
|
||||
# dehydrated
|
||||
# dehydrated [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=23P9DSJBTY7C8)
|
||||
|
||||

|
||||
|
||||
This is a client for signing certificates with an ACME-server (currently only provided by Let's Encrypt) implemented as a relatively simple bash-script.
|
||||
Dehydrated supports both ACME v1 and the new ACME v2 including support for wildcard certificates!
|
||||
|
||||
It uses the `openssl` utility for everything related to actually handling keys and certificates, so you need to have that installed.
|
||||
|
||||
@@ -78,31 +79,22 @@ Parameters:
|
||||
|
||||
## Donate
|
||||
|
||||
I'm having fun developing dehydrated, but it takes time, and time is money, at least that's what I've been told.
|
||||
I'm a student hacker with a few (unfortunately) quite expensive hobbies (self-hosting, virtualization clusters, routing,
|
||||
high-speed networking, embedded hardware, etc.).
|
||||
I'm really having fun playing around with hard- and software and I'm steadily learning new things.
|
||||
Without those hobbies I probably would never have started working on dehydrated to begin with :)
|
||||
|
||||
I will definitively continue developing dehydrated for free, but if you want to support me you can do so using the following ways:
|
||||
I'd really appreciate if you could [donate a bit of money](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=23P9DSJBTY7C8)
|
||||
so I can buy cool stuff (while still being able to afford food :D).
|
||||
|
||||
### PayPal
|
||||
If you have hardware laying around that you think I'd enjoy playing with (e.g. decomissioned but still modern-ish servers,
|
||||
10G networking hardware, enterprise grade routers or APs, interesting ARM/MIPS boards, etc.) and that you would be willing
|
||||
to ship to me please contact me at `donations@dehydrated.de` or on Twitter [@lukas2511](https://twitter.com/lukas2511).
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=23P9DSJBTY7C8)
|
||||
|
||||
### BitCoin
|
||||
|
||||
Send bitcoins to 12487bHxcrREffTGwUDnoxF1uYxCA7ztKK
|
||||
|
||||
### Server
|
||||
|
||||
I'm still planning on building a bigger testing-suite for dehydrated, it would be really cool to have a big(ish) server running
|
||||
in a datacenter somewhere without having to pay for it... If you are a server provider and can offer me a (dedicated!) machine,
|
||||
please contact me at `donations@dehydrated.de`.
|
||||
|
||||
### Other ways
|
||||
|
||||
I always like to play around with modern(ish) network and computer gear, 10G switches and stuff, modern ARM boards
|
||||
(but please not that Raspberry Pi rubbish), tiny PCs for routing, etc.
|
||||
|
||||
If you have something that seems of value and that you don't need anymore feel free to contact me at
|
||||
`donations@dehydrated.de`.
|
||||
|
||||
Also here is my [Amazon Wishlist](http://www.amazon.de/registry/wishlist/1TUCFJK35IO4Q) :)
|
||||
If you want your name to be added to the [donations list](https://dehydrated.de/donations.html) please add a note or send me an
|
||||
email `donations@dehydrated.de`. I respect your privacy and won't publish your name without permission.
|
||||
|
||||
Other ways of donating:
|
||||
- [My Amazon Wishlist](http://www.amazon.de/registry/wishlist/1TUCFJK35IO4Q)
|
||||
- Monero: 4Kkf4tF4r9DakxLj37HDXLJgmpVfQoFhT7JLDvXwtUZZMTbsK9spsAPXivWPAFcDUj6jHhY8hJSHX8Cb8ndMhKeQHPSkBZZiK89Fx8NTHk
|
||||
- Bitcoin: 12487bHxcrREffTGwUDnoxF1uYxCA7ztKK
|
||||
|
||||
680
dehydrated
680
dehydrated
File diff suppressed because it is too large
Load Diff
@@ -17,3 +17,6 @@ You can define an alias for your certificate which will (instead of the primary
|
||||
used as directory name under your certdir and for a per-certificate lookup.
|
||||
This allows multiple certificates with identical sets of domains but different configuration
|
||||
to exist.
|
||||
|
||||
Certificates with a wildcard domain as first (or only) name require an alias to be set.
|
||||
Aliases can't start with `*.`.
|
||||
|
||||
@@ -24,11 +24,12 @@
|
||||
# Path to certificate authority (default: https://acme-v01.api.letsencrypt.org/directory)
|
||||
#CA="https://acme-v01.api.letsencrypt.org/directory"
|
||||
|
||||
# Path to certificate authority license terms redirect (default: https://acme-v01.api.letsencrypt.org/terms)
|
||||
#CA_TERMS="https://acme-v01.api.letsencrypt.org/terms"
|
||||
|
||||
# Path to license agreement (default: <unset>)
|
||||
#LICENSE=""
|
||||
# Path to old certificate authority
|
||||
# Set this value to your old CA value when upgrading from ACMEv1 to ACMEv2 under a different endpoint.
|
||||
# If dehydrated detects an account-key for the old CA it will automatically reuse that key
|
||||
# instead of registering a new one.
|
||||
# default: <unset>
|
||||
#OLDCA=
|
||||
|
||||
# Which challenge should be used? Currently http-01 and dns-01 are supported
|
||||
#CHALLENGETYPE="http-01"
|
||||
@@ -110,3 +111,6 @@
|
||||
|
||||
# Automatic cleanup (default: no)
|
||||
#AUTO_CLEANUP="no"
|
||||
|
||||
# ACME API version (default: auto)
|
||||
#API=auto
|
||||
|
||||
@@ -19,6 +19,9 @@ deploy_challenge() {
|
||||
# validation, this is what you want to put in the _acme-challenge
|
||||
# TXT record. For HTTP validation it is the value that is expected
|
||||
# be found in the $TOKEN_FILENAME file.
|
||||
|
||||
# Simple example: Use nsupdate with local named
|
||||
# printf 'server 127.0.0.1\nupdate add _acme-challenge.%s 300 IN TXT "%s"\nsend\n' "${DOMAIN}" "${TOKEN_VALUE}" | nsupdate -k /var/run/named/session.key
|
||||
}
|
||||
|
||||
clean_challenge() {
|
||||
@@ -29,6 +32,9 @@ clean_challenge() {
|
||||
# files or DNS records that are no longer needed.
|
||||
#
|
||||
# The parameters are the same as for deploy_challenge.
|
||||
|
||||
# Simple example: Use nsupdate with local named
|
||||
# printf 'server 127.0.0.1\nupdate delete _acme-challenge.%s TXT "%s"\nsend\n' "${DOMAIN}" "${TOKEN_VALUE}" | nsupdate -k /var/run/named/session.key
|
||||
}
|
||||
|
||||
deploy_cert() {
|
||||
@@ -52,6 +58,10 @@ deploy_cert() {
|
||||
# The path of the file containing the intermediate certificate(s).
|
||||
# - TIMESTAMP
|
||||
# Timestamp when the specified certificate was created.
|
||||
|
||||
# Simple example: Copy file to nginx config
|
||||
# cp "${KEYFILE}" "${FULLCHAINFILE}" /etc/nginx/ssl/; chown -R nginx: /etc/nginx/ssl
|
||||
# systemctl reload nginx
|
||||
}
|
||||
|
||||
unchanged_cert() {
|
||||
@@ -86,10 +96,13 @@ invalid_challenge() {
|
||||
# name (CN).
|
||||
# - RESPONSE
|
||||
# The response that the verification server returned
|
||||
|
||||
# Simple example: Send mail to root
|
||||
# printf "Subject: Validation of ${DOMAIN} failed!\n\nOh noez!" | sendmail root
|
||||
}
|
||||
|
||||
request_failure() {
|
||||
local STATUSCODE="${1}" REASON="${2}" REQTYPE="${3}"
|
||||
local STATUSCODE="${1}" REASON="${2}" REQTYPE="${3}" HEADERS="${4}"
|
||||
|
||||
# This hook is called when an HTTP request fails (e.g., when the ACME
|
||||
# server is busy, returns an error, etc). It will be called upon any
|
||||
@@ -103,6 +116,34 @@ request_failure() {
|
||||
# The specified reason for the error.
|
||||
# - REQTYPE
|
||||
# The kind of request that was made (GET, POST...)
|
||||
|
||||
# Simple example: Send mail to root
|
||||
# printf "Subject: HTTP request failed failed!\n\nA http request failed with status ${STATUSCODE}!" | sendmail root
|
||||
}
|
||||
|
||||
generate_csr() {
|
||||
local DOMAIN="${1}" CERTDIR="${2}" ALTNAMES="${3}"
|
||||
|
||||
# This hook is called before any certificate signing operation takes place.
|
||||
# It can be used to generate or fetch a certificate signing request with external
|
||||
# tools.
|
||||
# The output should be just the cerificate signing request formatted as PEM.
|
||||
#
|
||||
# Parameters:
|
||||
# - DOMAIN
|
||||
# The primary domain as specified in domains.txt. This does not need to
|
||||
# match with the domains in the CSR, it's basically just the directory name.
|
||||
# - CERTDIR
|
||||
# Certificate output directory for this particular certificate. Can be used
|
||||
# for storing additional files.
|
||||
# - ALTNAMES
|
||||
# All domain names for the current certificate as specified in domains.txt.
|
||||
# Again, this doesn't need to match with the CSR, it's just there for convenience.
|
||||
|
||||
# Simple example: Look for pre-generated CSRs
|
||||
# if [ -e "${CERTDIR}/pre-generated.csr" ]; then
|
||||
# cat "${CERTDIR}/pre-generated.csr"
|
||||
# fi
|
||||
}
|
||||
|
||||
startup_hook() {
|
||||
@@ -120,6 +161,6 @@ exit_hook() {
|
||||
}
|
||||
|
||||
HANDLER="$1"; shift
|
||||
if [[ "${HANDLER}" =~ ^(deploy_challenge|clean_challenge|deploy_cert|unchanged_cert|invalid_challenge|request_failure|startup_hook|exit_hook)$ ]]; then
|
||||
if [[ "${HANDLER}" =~ ^(deploy_challenge|clean_challenge|deploy_cert|unchanged_cert|invalid_challenge|request_failure|generate_csr|startup_hook|exit_hook)$ ]]; then
|
||||
"$HANDLER" "$@"
|
||||
fi
|
||||
|
||||
@@ -60,4 +60,3 @@ HOOK: clean_challenge lukas.im blablabla blablabla.supersecure www.lukas.im blub
|
||||
HOOK: deploy_cert lukas.im /etc/dehydrated/certs/lukas.im/privkey.pem /etc/dehydrated/certs/lukas.im/cert.pem /etc/dehydrated/certs/lukas.im/fullchain.pem /etc/dehydrated/certs/lukas.im/chain.pem 1460152408
|
||||
+ Done!
|
||||
```
|
||||
|
||||
|
||||
BIN
docs/logo.jpg
BIN
docs/logo.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 42 KiB |
@@ -1,4 +1,4 @@
|
||||
.TH DEHYDRATED 1 2017-09-20 "Dehydrated ACME Client"
|
||||
.TH DEHYDRATED 1 2018-01-13 "Dehydrated ACME Client"
|
||||
.SH NAME
|
||||
dehydrated \- ACME client implemented as a shell-script
|
||||
.SH SYNOPSIS
|
||||
@@ -7,8 +7,8 @@ dehydrated \- ACME client implemented as a shell-script
|
||||
[\fBargument\fR [\fBargument\fR]]
|
||||
.IR ...
|
||||
.SH DESCRIPTION
|
||||
A client for ACME-based Certificate Authorities, such as LetsEncrypt. It
|
||||
allows to request and obtain TLS certificates from an ACME-based
|
||||
A client for ACME-based Certificate Authorities, such as LetsEncrypt. It can
|
||||
be used to request and obtain TLS certificates from an ACME-based
|
||||
certificate authority.
|
||||
|
||||
Before any certificates can be requested, Dehydrated needs
|
||||
@@ -145,7 +145,7 @@ Please report any bugs that you may encounter at the project web site
|
||||
Dehydrated was written by Lukas Schauer. This man page was contributed by
|
||||
Daniel Molkentin.
|
||||
.SH COPYRIGHT
|
||||
Copyright 20015-2017 by Lukas Schauer and the respective contributors.
|
||||
Copyright 20015-2018 by Lukas Schauer and the respective contributors.
|
||||
Provided under the MIT License. See the LICENSE file that accompanies the
|
||||
distribution for licensing information.
|
||||
.SH SEE ALSO
|
||||
@@ -9,5 +9,9 @@ To avoid this, please set the CA property to the Let’s Encrypt staging server
|
||||
|
||||
```bash
|
||||
CA="https://acme-staging.api.letsencrypt.org/directory"
|
||||
CA_TERMS="https://acme-staging.api.letsencrypt.org/terms"
|
||||
```
|
||||
|
||||
# ACMEv2 staging
|
||||
|
||||
You can use `CA="https://acme-staging-v02.api.letsencrypt.org/directory"` to test dehydrated with
|
||||
the ACMEv2 staging endpoint.
|
||||
|
||||
@@ -11,12 +11,6 @@ the current workaround is to move `private_key.pem` (and, if you care, `private_
|
||||
|
||||
This will hopefully be fixed in the future.
|
||||
|
||||
## "Provided agreement URL [LICENSE1] does not match current agreement URL [LICENSE2]"
|
||||
|
||||
Set LICENSE in your config to the value in place of "LICENSE2".
|
||||
|
||||
LICENSE1 and LICENSE2 are just placeholders for the real values in this troubleshooting document!
|
||||
|
||||
## "Error creating new cert :: Too many certificates already issued for: [...]"
|
||||
|
||||
This is not an issue with dehydrated but an API limit with boulder (the ACME server).
|
||||
|
||||
@@ -24,7 +24,7 @@ With Nginx you'll need to add this to any of your `server`/VHost config blocks:
|
||||
```nginx
|
||||
server {
|
||||
[...]
|
||||
location /.well-known/acme-challenge {
|
||||
location ^~ /.well-known/acme-challenge {
|
||||
alias /var/www/dehydrated;
|
||||
}
|
||||
[...]
|
||||
|
||||
266
test.sh
266
test.sh
@@ -1,266 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Fail early
|
||||
set -eu -o pipefail
|
||||
|
||||
# Check if running in CI environment
|
||||
if [[ ! "${CI:-false}" == "true" ]]; then
|
||||
echo "ERROR: Not running in CI environment!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_TEST() {
|
||||
echo
|
||||
echo "${1} "
|
||||
}
|
||||
_SUBTEST() {
|
||||
echo -n " + ${1} "
|
||||
}
|
||||
_PASS() {
|
||||
echo -e "[\u001B[32mPASS\u001B[0m]"
|
||||
}
|
||||
_FAIL() {
|
||||
echo -e "[\u001B[31mFAIL\u001B[0m]"
|
||||
echo
|
||||
echo "Problem: ${@}"
|
||||
echo
|
||||
echo "STDOUT:"
|
||||
cat tmplog
|
||||
echo
|
||||
echo "STDERR:"
|
||||
cat errorlog
|
||||
exit 1
|
||||
}
|
||||
_CHECK_FILE() {
|
||||
_SUBTEST "Checking if file '${1}' exists..."
|
||||
if [[ -e "${1}" ]]; then
|
||||
_PASS
|
||||
else
|
||||
_FAIL "Missing file: ${1}"
|
||||
fi
|
||||
}
|
||||
_CHECK_LOG() {
|
||||
_SUBTEST "Checking if log contains '${1}'..."
|
||||
if grep -- "${1}" tmplog > /dev/null; then
|
||||
_PASS
|
||||
else
|
||||
_FAIL "Missing in log: ${1}"
|
||||
fi
|
||||
}
|
||||
_CHECK_NOT_LOG() {
|
||||
_SUBTEST "Checking if log doesn't contain '${1}'..."
|
||||
if grep -- "${1}" tmplog > /dev/null; then
|
||||
_FAIL "Found in log: ${1}"
|
||||
else
|
||||
_PASS
|
||||
fi
|
||||
}
|
||||
_CHECK_ERRORLOG() {
|
||||
_SUBTEST "Checking if errorlog is empty..."
|
||||
if [[ -z "$(cat errorlog)" ]]; then
|
||||
_PASS
|
||||
else
|
||||
_FAIL "Non-empty errorlog"
|
||||
fi
|
||||
}
|
||||
|
||||
# If not found (should be cached in travis) download ngrok
|
||||
if [[ ! -e "ngrok/ngrok" ]]; then
|
||||
(
|
||||
mkdir -p ngrok
|
||||
cd ngrok
|
||||
if [ "${TRAVIS_OS_NAME}" = "linux" ]; then
|
||||
wget -O ngrok.zip https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
|
||||
elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then
|
||||
wget -O ngrok.zip https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip
|
||||
else
|
||||
echo "No ngrok for ${TRAVIS_OS_NAME}"
|
||||
exit 1
|
||||
fi
|
||||
unzip ngrok.zip ngrok
|
||||
chmod +x ngrok
|
||||
)
|
||||
fi
|
||||
|
||||
# Run ngrok and grab temporary url from logfile
|
||||
ngrok/ngrok http 8080 --log stdout --log-format logfmt --log-level debug > tmp.log &
|
||||
ngrok/ngrok http 8080 --log stdout --log-format logfmt --log-level debug > tmp2.log &
|
||||
ngrok/ngrok http 8080 --log stdout --log-format logfmt --log-level debug > tmp3.log &
|
||||
sleep 2
|
||||
TMP_URL="$(grep -Eo "Hostname:[a-z0-9]+.ngrok.io" tmp.log | head -1 | cut -d':' -f2)"
|
||||
TMP2_URL="$(grep -Eo "Hostname:[a-z0-9]+.ngrok.io" tmp2.log | head -1 | cut -d':' -f2)"
|
||||
TMP3_URL="$(grep -Eo "Hostname:[a-z0-9]+.ngrok.io" tmp3.log | head -1 | cut -d':' -f2)"
|
||||
if [[ -z "${TMP_URL}" ]] || [[ -z "${TMP2_URL}" ]] || [[ -z "${TMP3_URL}" ]]; then
|
||||
echo "Couldn't get an url from ngrok, not a dehydrated bug, tests can't continue."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run python webserver in .acme-challenges directory to serve challenge responses
|
||||
mkdir -p .acme-challenges/.well-known/acme-challenge
|
||||
(
|
||||
cd .acme-challenges
|
||||
python -m SimpleHTTPServer 8080 > /dev/null 2> /dev/null
|
||||
) &
|
||||
|
||||
# Generate config and create empty domains.txt
|
||||
echo 'CA="https://testca.kurz.pw/directory"' > config
|
||||
echo 'CA_TERMS="https://testca.kurz.pw/terms"' >> config
|
||||
echo 'WELLKNOWN=".acme-challenges/.well-known/acme-challenge"' >> config
|
||||
echo 'RENEW_DAYS="14"' >> config
|
||||
touch domains.txt
|
||||
|
||||
# Check if help command is working
|
||||
_TEST "Checking if help command is working..."
|
||||
./dehydrated --help > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Default command: help"
|
||||
_CHECK_LOG "--help (-h)"
|
||||
_CHECK_LOG "--domain (-d) domain.tld"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Register account key without LICENSE set
|
||||
_TEST "Register account key without LICENSE set"
|
||||
./dehydrated --register > tmplog 2> errorlog && _FAIL "Script execution failed"
|
||||
_CHECK_LOG "To accept these terms"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Register account key and agreeing to terms
|
||||
_TEST "Register account key without LICENSE set"
|
||||
./dehydrated --register --accept-terms > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Registering account key"
|
||||
_CHECK_FILE accounts/*/account_key.pem
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Delete accounts and add LICENSE to config for normal operation
|
||||
rm -rf accounts
|
||||
echo 'LICENSE="https://testca.kurz.pw/terms/v1"' >> config
|
||||
|
||||
# Run in cron mode with empty domains.txt (should only generate private key and exit)
|
||||
_TEST "First run in cron mode, checking if private key is generated and registered"
|
||||
./dehydrated --cron > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Registering account key"
|
||||
_CHECK_FILE accounts/*/account_key.pem
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Temporarily move config out of the way and try signing certificate by using temporary config location
|
||||
_TEST "Try signing using temporary config location and with domain as command line parameter"
|
||||
mv config tmp_config
|
||||
./dehydrated --cron --domain "${TMP_URL}" --domain "${TMP2_URL}" --accept-terms -f tmp_config > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_NOT_LOG "Checking domain name(s) of existing cert"
|
||||
_CHECK_LOG "Generating private key"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP_URL}"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP2_URL}"
|
||||
_CHECK_LOG "Challenge is valid!"
|
||||
_CHECK_LOG "Creating fullchain.pem"
|
||||
_CHECK_LOG "Done!"
|
||||
_CHECK_ERRORLOG
|
||||
mv tmp_config config
|
||||
|
||||
# Add third domain to command-lime, should force renewal.
|
||||
_TEST "Run in cron mode again, this time adding third domain, should force renewal."
|
||||
./dehydrated --cron --domain "${TMP_URL}" --domain "${TMP2_URL}" --domain "${TMP3_URL}" > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Domain name(s) are not matching!"
|
||||
_CHECK_LOG "Forcing renew."
|
||||
_CHECK_LOG "Generating private key"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP_URL}"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP2_URL}"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP3_URL}"
|
||||
_CHECK_LOG "Challenge is valid!"
|
||||
_CHECK_LOG "Creating fullchain.pem"
|
||||
_CHECK_LOG "Done!"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Prepare domains.txt
|
||||
# Modify TMP3_URL to be uppercase to check for upper-lower-case mismatch bugs
|
||||
echo "${TMP_URL} ${TMP2_URL} $(tr 'a-z' 'A-Z' <<<"${TMP3_URL}")" >> domains.txt
|
||||
|
||||
# Run in cron mode again (should find a non-expiring certificate and do nothing)
|
||||
_TEST "Run in cron mode again, this time with domain in domains.txt, should find non-expiring certificate"
|
||||
./dehydrated --cron > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Checking domain name(s) of existing cert... unchanged."
|
||||
_CHECK_LOG "Skipping renew"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Disable private key renew
|
||||
echo 'PRIVATE_KEY_RENEW="no"' >> config
|
||||
|
||||
# Run in cron mode one last time, with domain in domains.txt and force-resign (should find certificate, resign anyway, and not generate private key)
|
||||
_TEST "Run in cron mode one last time, with domain in domains.txt and force-resign"
|
||||
./dehydrated --cron --force > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Checking domain name(s) of existing cert... unchanged."
|
||||
_CHECK_LOG "Ignoring because renew was forced!"
|
||||
_CHECK_NOT_LOG "Generating private key"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP_URL}"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP2_URL}"
|
||||
_CHECK_LOG "Requesting challenge for ${TMP3_URL}"
|
||||
_CHECK_LOG "Already validated!"
|
||||
_CHECK_LOG "Creating fullchain.pem"
|
||||
_CHECK_LOG "Done!"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Check if signcsr command is working
|
||||
_TEST "Running signcsr command"
|
||||
./dehydrated --signcsr certs/${TMP_URL}/cert.csr > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "BEGIN CERTIFICATE"
|
||||
_CHECK_LOG "END CERTIFICATE"
|
||||
_CHECK_NOT_LOG "ERROR"
|
||||
|
||||
# Check if renewal works
|
||||
_TEST "Run in cron mode again, to check if renewal works"
|
||||
echo 'RENEW_DAYS="300"' >> config
|
||||
./dehydrated --cron > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Checking domain name(s) of existing cert... unchanged."
|
||||
_CHECK_LOG "Renewing!"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Check if certificate is valid in various ways
|
||||
_TEST "Verifying certificate..."
|
||||
_SUBTEST "Verifying certificate on its own..."
|
||||
openssl x509 -in "certs/${TMP_URL}/cert.pem" -noout -text > tmplog 2> errorlog && _PASS || _FAIL
|
||||
_CHECK_LOG "CN=${TMP_URL}"
|
||||
_CHECK_LOG "${TMP2_URL}"
|
||||
_SUBTEST "Verifying file with full chain..."
|
||||
openssl x509 -in "certs/${TMP_URL}/fullchain.pem" -noout -text > /dev/null 2>> errorlog && _PASS || _FAIL
|
||||
_SUBTEST "Verifying certificate against CA certificate..."
|
||||
curl -s https://testca.kurz.pw/acme/issuer-cert | openssl x509 -inform DER -outform PEM > ca.pem
|
||||
(openssl verify -verbose -CAfile "ca.pem" -purpose sslserver "certs/${TMP_URL}/fullchain.pem" 2>&1 || true) | (grep -v ': OK$' || true) >> errorlog 2>> errorlog && _PASS || _FAIL
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Revoke certificate using certificate key
|
||||
_TEST "Revoking certificate..."
|
||||
./dehydrated --revoke "certs/${TMP_URL}/cert.pem" --privkey "certs/${TMP_URL}/privkey.pem" > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
REAL_CERT="$(readlink -n "certs/${TMP_URL}/cert.pem")"
|
||||
_CHECK_LOG "Revoking certs/${TMP_URL}/${REAL_CERT}"
|
||||
_CHECK_LOG "Done."
|
||||
_CHECK_FILE "certs/${TMP_URL}/${REAL_CERT}-revoked"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Enable private key renew
|
||||
echo 'PRIVATE_KEY_RENEW="yes"' >> config
|
||||
echo 'PRIVATE_KEY_ROLLOVER="yes"' >> config
|
||||
|
||||
# Check if Rolloverkey creation works
|
||||
_TEST "Testing Rolloverkeys..."
|
||||
_SUBTEST "First Run: Creating rolloverkey"
|
||||
./dehydrated --cron --domain "${TMP2_URL}" > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
CERT_ROLL_HASH=$(openssl rsa -in certs/${TMP2_URL}/privkey.roll.pem -outform DER -pubout 2>/dev/null | openssl sha -sha256)
|
||||
_CHECK_LOG "Generating private key"
|
||||
_CHECK_LOG "Generating private rollover key"
|
||||
_SUBTEST "Second Run: Force Renew, Use rolloverkey"
|
||||
./dehydrated --cron --force --domain "${TMP2_URL}" > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
CERT_NEW_HASH=$(openssl rsa -in certs/${TMP2_URL}/privkey.pem -outform DER -pubout 2>/dev/null | openssl sha -sha256)
|
||||
_CHECK_LOG "Generating private key"
|
||||
_CHECK_LOG "Moving Rolloverkey into position"
|
||||
_SUBTEST "Verifying Hash Rolloverkey and private key second run"
|
||||
[[ "${CERT_ROLL_HASH}" = "${CERT_NEW_HASH}" ]] && _PASS || _FAIL
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# Test cleanup command
|
||||
_TEST "Cleaning up certificates"
|
||||
./dehydrated --cleanup > tmplog 2> errorlog || _FAIL "Script execution failed"
|
||||
_CHECK_LOG "Moving unused file to archive directory: ${TMP_URL}/cert-"
|
||||
_CHECK_LOG "Moving unused file to archive directory: ${TMP_URL}/chain-"
|
||||
_CHECK_LOG "Moving unused file to archive directory: ${TMP_URL}/fullchain-"
|
||||
_CHECK_ERRORLOG
|
||||
|
||||
# All done
|
||||
exit 0
|
||||
Reference in New Issue
Block a user