mirror of
https://github.com/dehydrated-io/dehydrated.git
synced 2026-05-07 07:33:26 +02:00
EAB + ZeroSSL support
This commit is contained in:
93
dehydrated
93
dehydrated
@@ -236,7 +236,7 @@ _mktemp() {
|
||||
# Check for script dependencies
|
||||
check_dependencies() {
|
||||
# look for required binaries
|
||||
for binary in grep mktemp diff sed awk curl cut; do
|
||||
for binary in grep mktemp diff sed awk curl cut; do
|
||||
bin_path="$(command -v "${binary}" 2>/dev/null)" || _exiterr "This script requires ${binary}."
|
||||
[[ -x "${bin_path}" ]] || _exiterr "${binary} found in PATH but it's not executable"
|
||||
done
|
||||
@@ -318,7 +318,7 @@ load_config() {
|
||||
fi
|
||||
|
||||
# Preset
|
||||
CA_ZEROSSL=""
|
||||
CA_ZEROSSL="https://acme.zerossl.com/v2/DV90"
|
||||
CA_LETSENCRYPT="https://acme-v02.api.letsencrypt.org/directory"
|
||||
|
||||
# Default values
|
||||
@@ -424,6 +424,11 @@ load_config() {
|
||||
# Check BASEDIR and set default variables
|
||||
[[ -d "${BASEDIR}" ]] || _exiterr "BASEDIR does not exist: ${BASEDIR}"
|
||||
|
||||
# Check for ca cli parameter
|
||||
if [ -n "${PARAM_CA:-}" ]; then
|
||||
CA="${PARAM_CA}"
|
||||
fi
|
||||
|
||||
# Preset CAs
|
||||
if [ "${CA}" = "letsencrypt" ]; then
|
||||
CA="{$CA_LETSENCRYPT}"
|
||||
@@ -527,7 +532,8 @@ init_system() {
|
||||
CA_NEW_ORDER="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newOrder)" &&
|
||||
CA_NEW_NONCE="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newNonce)" &&
|
||||
CA_NEW_ACCOUNT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value newAccount)" &&
|
||||
CA_TERMS="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value termsOfService)" &&
|
||||
CA_TERMS="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value -p '"meta","termsOfService"')" &&
|
||||
CA_REQUIRES_EAB="$(printf "%s" "${CA_DIRECTORY}" | get_json_bool_value -p '"meta","externalAccountRequired"' || echo false)" &&
|
||||
CA_REVOKE_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value revokeCert)" ||
|
||||
_exiterr "Problem retrieving ACME/CA-URLs, check if your configured CA points to the directory entrypoint."
|
||||
# Since acct URI is missing from directory we will assume it is the same as CA_NEW_ACCOUNT without the new part
|
||||
@@ -539,6 +545,7 @@ init_system() {
|
||||
|
||||
# Checking for private key ...
|
||||
register_new_key="no"
|
||||
generated="false"
|
||||
if [[ -n "${PARAM_ACCOUNT_KEY:-}" ]]; then
|
||||
# a private key was specified from the command line so use it for this run
|
||||
echo "Using private key ${PARAM_ACCOUNT_KEY} instead of account key"
|
||||
@@ -557,6 +564,7 @@ init_system() {
|
||||
fi
|
||||
|
||||
echo "+ Generating account key..."
|
||||
generated="true"
|
||||
local tmp_account_key="$(_mktemp)"
|
||||
_openssl genrsa -out "${tmp_account_key}" "${KEYSIZE}"
|
||||
cat "${tmp_account_key}" > "${ACCOUNT_KEY}"
|
||||
@@ -582,6 +590,35 @@ init_system() {
|
||||
FAILED=true
|
||||
fi
|
||||
|
||||
# ZeroSSL special sauce
|
||||
if [[ "${CA}" = "${CA_ZEROSSL}" ]]; then
|
||||
if [[ -z "${EAB_KID:-}" ]] || [[ -z "${EAB_HMAC_KEY:-}" ]]; then
|
||||
if [[ -z "${CONTACT_EMAIL}" ]]; then
|
||||
echo "ZeroSSL requires contact email to be set or EAB_KID/EAB_HMAC_KEY to be manually configured"
|
||||
FAILED=true
|
||||
else
|
||||
zeroapi="$(curl -s "https://api.zerossl.com/acme/eab-credentials-email" -d "email=${CONTACT_EMAIL}" | jsonsh)"
|
||||
EAB_KID="$(printf "%s" "${zeroapi}" | get_json_string_value eab_kid)"
|
||||
EAB_HMAC_KEY="$(printf "%s" "${zeroapi}" | get_json_string_value eab_hmac_key)"
|
||||
if [[ -z "${EAB_KID:-}" ]] || [[ -z "${EAB_HMAC_KEY:-}" ]]; then
|
||||
echo "Unknown error retrieving ZeroSSL API credentials"
|
||||
echo "${zeroapi}"
|
||||
FAILED=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if external account is required
|
||||
if [[ "${FAILED}" = "false" ]]; then
|
||||
if [[ "${CA_REQUIRES_EAB}" = "true" ]]; then
|
||||
if [[ -z "${EAB_KID:-}" ]] || [[ -z "${EAB_HMAC_KEY:-}" ]]; then
|
||||
FAILED=true
|
||||
echo "This CA requires an external account but no EAB_KID/EAB_HMAC_KEY has been configured"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# If an email for the contact has been provided then adding it to the registration request
|
||||
if [[ "${FAILED}" = "false" ]]; then
|
||||
if [[ ${API} -eq 1 ]]; then
|
||||
@@ -591,11 +628,26 @@ init_system() {
|
||||
(signed_request "${CA_NEW_REG}" '{"resource": "new-reg", "agreement": "'"${CA_TERMS}"'"}' > "${ACCOUNT_KEY_JSON}") || FAILED=true
|
||||
fi
|
||||
else
|
||||
if [[ -n "${CONTACT_EMAIL}" ]]; then
|
||||
(signed_request "${CA_NEW_ACCOUNT}" '{"contact":["mailto:'"${CONTACT_EMAIL}"'"], "termsOfServiceAgreed": true}' > "${ACCOUNT_KEY_JSON}") || FAILED=true
|
||||
if [[ -n "${EAB_KID:-}" ]] && [[ -n "${EAB_HMAC_KEY:-}" ]]; then
|
||||
eab_url="${CA_NEW_ACCOUNT}"
|
||||
eab_protected64="$(printf '{"alg":"HS256","kid":"%s","url":"%s"}' "${EAB_KID}" "${eab_url}" | urlbase64)"
|
||||
eab_payload64="$(printf "%s" '{"e": "'"${pubExponent64}"'", "kty": "RSA", "n": "'"${pubMod64}"'"}' | urlbase64)"
|
||||
eab_key="$(printf "%s" "${EAB_HMAC_KEY}" | deurlbase64)"
|
||||
eab_signed64="$(printf '%s' "${eab_protected64}.${eab_payload64}" | "${OPENSSL}" dgst -binary -sha256 -hmac "${eab_key}" | urlbase64)"
|
||||
|
||||
if [[ -n "${CONTACT_EMAIL}" ]]; then
|
||||
regjson='{"contact":["mailto:'"${CONTACT_EMAIL}"'"], "termsOfServiceAgreed": true, "externalAccountBinding": {"protected": "'"${eab_protected64}"'", "payload": "'"${eab_payload64}"'", "signature": "'"${eab_signed64}"'"}}'
|
||||
else
|
||||
regjson='{"termsOfServiceAgreed": true, "externalAccountBinding": {"protected": "'"${eab_protected64}"'", "payload": "'"${eab_payload64}"'", "signature": "'"${eab_signed64}"'"}}'
|
||||
fi
|
||||
else
|
||||
(signed_request "${CA_NEW_ACCOUNT}" '{"termsOfServiceAgreed": true}' > "${ACCOUNT_KEY_JSON}") || FAILED=true
|
||||
if [[ -n "${CONTACT_EMAIL}" ]]; then
|
||||
regjson='{"contact":["mailto:'"${CONTACT_EMAIL}"'"], "termsOfServiceAgreed": true}'
|
||||
else
|
||||
regjson='{"termsOfServiceAgreed": true}'
|
||||
fi
|
||||
fi
|
||||
(signed_request "${CA_NEW_ACCOUNT}" "${regjson}" > "${ACCOUNT_KEY_JSON}") || FAILED=true
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -603,7 +655,10 @@ init_system() {
|
||||
echo >&2
|
||||
echo >&2
|
||||
echo "Error registering account key. See message above for more information." >&2
|
||||
rm "${ACCOUNT_KEY}" "${ACCOUNT_KEY_JSON}"
|
||||
if [[ "${generated}" = "true" ]]; then
|
||||
rm "${ACCOUNT_KEY}"
|
||||
fi
|
||||
rm -f "${ACCOUNT_KEY_JSON}"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "${COMMAND:-}" = "register" ]]; then
|
||||
@@ -669,12 +724,27 @@ urlbase64() {
|
||||
"${OPENSSL}" base64 -e | tr -d '\n\r' | _sed -e 's:=*$::g' -e 'y:+/:-_:'
|
||||
}
|
||||
|
||||
# Decode data from url-safe formatted base64
|
||||
deurlbase64() {
|
||||
data="$(cat | tr -d ' \n\r')"
|
||||
modlen=$((${#data} % 4))
|
||||
padding=""
|
||||
if [[ "${modlen}" = "2" ]]; then padding="==";
|
||||
elif [[ "${modlen}" = "3" ]]; then padding="="; fi
|
||||
printf "%s%s" "${data}" "${padding}" | tr -d '\n\r' | _sed -e 'y:-_:+/:' | "${OPENSSL}" base64 -d -A
|
||||
}
|
||||
|
||||
# Convert hex string to binary data
|
||||
hex2bin() {
|
||||
# Remove spaces, add leading zero, escape as hex string and parse with printf
|
||||
printf -- "$(cat | _sed -e 's/[[:space:]]//g' -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')"
|
||||
}
|
||||
|
||||
# Convert binary data to hex string
|
||||
bin2hex() {
|
||||
hexdump | _sed 's/^[^ ]*//' | tr -d ' \n\r'
|
||||
}
|
||||
|
||||
# OpenSSL writes to stderr/stdout even when there are no errors. So just
|
||||
# display the output if the exit code was != 0 to simplify debugging.
|
||||
_openssl() {
|
||||
@@ -1873,6 +1943,15 @@ main() {
|
||||
fi
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --ca url/preset
|
||||
# PARAM_Description: Use specified CA URL or preset
|
||||
--ca)
|
||||
shift 1
|
||||
check_parameters "${1:-}"
|
||||
[[ -n "${PARAM_CA:-}" ]] && _exiterr "CA can only be specified once!"
|
||||
PARAM_CA="${1}"
|
||||
;;
|
||||
|
||||
# PARAM_Usage: --alias certalias
|
||||
# PARAM_Description: Use specified name for certificate directory (and per-certificate config) instead of the primary domain (only used if --domain is specified)
|
||||
--alias)
|
||||
|
||||
Reference in New Issue
Block a user