added support for requesting preferred-chain instead of default chain

This commit is contained in:
Lukas Schauer
2020-11-13 20:36:51 +01:00
parent 7d3288f428
commit 7dfde364a3
5 changed files with 57 additions and 2 deletions

View File

@@ -6,6 +6,7 @@ This file contains a log of major changes in dehydrated
- Support for external account bindings
- Special support for ZeroSSL
- Support presets for some CAs instead of requiring URLs
- Allow requesting preferred chain (`--preferred-chain`)
## Fixed
- No more silent failures on broken hook-scripts

View File

@@ -57,6 +57,7 @@ Commands:
--cron (-c) Sign/renew non-existent/changed/expiring certificates.
--signcsr (-s) path/to/csr.pem Sign a given CSR, output CRT on stdout (advanced usage)
--revoke (-r) path/to/cert.pem Revoke specified certificate
--deactivate Deactivate account
--cleanup (-gc) Move unused certificate files to archive directory
--help (-h) Show help text
--env (-e) Output configuration variables for use in other scripts
@@ -77,6 +78,7 @@ Parameters:
--privkey (-p) path/to/key.pem Use specified private key instead of account key (useful for revocation)
--config (-f) path/to/config Use specified config file
--hook (-k) path/to/hook.sh Use specified script for hooks
--preferred-chain issuer-cn Use alternative certificate chain identified by issuer CN
--out (-o) certs/directory Output certificates into the specified directory
--alpn alpn-certs/directory Output alpn verification certificates into the specified directory
--challenge (-t) http-01|dns-01 Which challenge should be used? Currently http-01 and dns-01 are supported

View File

@@ -258,6 +258,7 @@ store_configvars() {
__KEYSIZE="${KEYSIZE}"
__CHALLENGETYPE="${CHALLENGETYPE}"
__HOOK="${HOOK}"
__PREFERRED_CHAIN="${PREFERRED_CHAIN}"
__WELLKNOWN="${WELLKNOWN}"
__HOOK_CHAIN="${HOOK_CHAIN}"
__OPENSSL_CNF="${OPENSSL_CNF}"
@@ -272,6 +273,7 @@ reset_configvars() {
KEYSIZE="${__KEYSIZE}"
CHALLENGETYPE="${__CHALLENGETYPE}"
HOOK="${__HOOK}"
PREFERRED_CHAIN="${__PREFERRED_CHAIN}"
WELLKNOWN="${__WELLKNOWN}"
HOOK_CHAIN="${__HOOK_CHAIN}"
OPENSSL_CNF="${__OPENSSL_CNF}"
@@ -336,6 +338,7 @@ load_config() {
DOMAINS_D=
DOMAINS_TXT=
HOOK=
PREFERRED_CHAIN=
HOOK_CHAIN="no"
RENEW_DAYS="30"
KEYSIZE="4096"
@@ -500,6 +503,7 @@ load_config() {
[[ -n "${PARAM_NO_LOCK:-}" ]] && LOCKFILE=""
[[ -n "${PARAM_HOOK:-}" ]] && HOOK="${PARAM_HOOK}"
[[ -n "${PARAM_PREFERRED_CHAIN:-}" ]] && PREFERRED_CHAIN="${PARAM_PREFERRED_CHAIN}"
[[ -n "${PARAM_CERTDIR:-}" ]] && CERTDIR="${PARAM_CERTDIR}"
[[ -n "${PARAM_ALPNCERTDIR:-}" ]] && ALPNCERTDIR="${PARAM_ALPNCERTDIR}"
[[ -n "${PARAM_CHALLENGETYPE:-}" ]] && CHALLENGETYPE="${PARAM_CHALLENGETYPE}"
@@ -924,6 +928,15 @@ extract_altnames() {
fi
}
# Get last subject CN in certificate chain
get_last_cn() {
cn="$("${OPENSSL}" verify -CAfile <(echo "${1}") -show_chain <(echo "${1}") | tail -n 1 | _sed -e 's/.* CN ?= ?([^/,]*).*/\1/')"
if [ -z "${cn}" ]; then
_exiterr "Error while fetching CN from certificate chain"
fi
printf "${cn}"
}
# Create certificate for domain(s) and outputs it FD 3
sign_csr() {
csr="${1}" # the CSR itself (not a file)
@@ -1153,8 +1166,35 @@ sign_csr() {
esac
result="$(signed_request "${order_location}" "" | jsonsh)"
done
resheaders="$(_mktemp)"
certificate="$(echo "${result}" | get_json_string_value certificate)"
crt="$(signed_request "${certificate}" "")"
crt="$(signed_request "${certificate}" "" 4>"${resheaders}")"
if [ -n "${PREFERRED_CHAIN:-}" ]; then
foundaltchain=0
altcn="$(get_last_cn "${crt}")"
if [ "${altcn}" = "${PREFERRED_CHAIN}" ]; then
foundaltchain=1
fi
if [ "${foundaltchain}" = "0" ]; then
while read altcrturl; do
if [ "${foundaltchain}" = "0" ]; then
altcrt="$(signed_request "${altcrturl}" "")"
altcn="$(get_last_cn "${altcrt}")"
if [ "${altcn}" = "${PREFERRED_CHAIN}" ]; then
foundaltchain=1
crt="${altcrt}"
fi
fi
done <<< "$(grep -Ei '^link:' "${resheaders}" | grep -Ei 'rel="alternate"' | cut -d'<' -f2 | cut -d'>' -f1)"
fi
if [ "${foundaltchain}" = "0" ]; then
_exiterr "Alternative chain with CN = ${PREFERRED_CHAIN} not found"
fi
echo " + Using preferred chain with CN = ${altcn}"
fi
rm -f "${resheaders}"
fi
# Try to load the certificate to detect corruption
@@ -1564,7 +1604,7 @@ command_sign_domains() {
config_var="$(echo "${cfgline:1}" | cut -d'=' -f1)"
config_value="$(echo "${cfgline:1}" | cut -d'=' -f2-)"
case "${config_var}" in
KEY_ALGO|OCSP_MUST_STAPLE|PRIVATE_KEY_RENEW|PRIVATE_KEY_ROLLOVER|KEYSIZE|CHALLENGETYPE|HOOK|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS)
KEY_ALGO|OCSP_MUST_STAPLE|PRIVATE_KEY_RENEW|PRIVATE_KEY_ROLLOVER|KEYSIZE|CHALLENGETYPE|HOOK|PREFERRED_CHAIN|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS)
echo " + ${config_var} = ${config_value}"
declare -- "${config_var}=${config_value}"
;;
@@ -2068,6 +2108,14 @@ main() {
PARAM_HOOK="${1}"
;;
# PARAM_Usage: --preferred-chain issuer-cn
# PARAM_Description: Use alternative certificate chain identified by issuer CN
--preferred-chain)
shift 1
check_parameters "${1:-}"
PARAM_PREFERRED_CHAIN="${1}"
;;
# PARAM_Usage: --out (-o) certs/directory
# PARAM_Description: Output certificates into the specified directory
--out|-o)

View File

@@ -127,3 +127,6 @@
# ACME API version (default: auto)
#API=auto
# Preferred issuer chain (default: <unset> -> uses default chain)
#PREFERRED_CHAIN=

View File

@@ -17,6 +17,7 @@ Currently supported options:
- WELLKNOWN
- OPENSSL_CNF
- RENEW_DAYS
- PREFERRED_CHAIN
## DOMAINS_D