Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion dehydrated
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ 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_RENEWAL_INFO="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value renewalInfo || true)" &&
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)" ||
Expand Down Expand Up @@ -800,6 +801,15 @@ _sed() {
fi
}

# Different date versions act very differently.
rfc3339date2unix() {
if [[ "${OSTYPE}" = "Linux" || "${OSTYPE:0:5}" = "MINGW" ]]; then
date -d "$1" "+%s"
else
date -j -f "%Y-%m-%dT%H:%M:%S%z" "${1/%Z/+0000}" "+%s"
fi
}

# Print error message and exit with error
_exiterr() {
if [ -n "${1:-}" ]; then
Expand Down Expand Up @@ -1811,7 +1821,7 @@ command_sign_domains() {

certnames="$("${OPENSSL}" x509 -in "${cert}" -text -noout | grep -E '(DNS|IP( Address*)):' | _sed 's/(DNS|IP( Address)*)://g' | tr -d ' ' | tr ',' '\n' | sort -u | tr '\n' ' ' | _sed 's/ $//')"
givennames="$(echo "${domain}" "${morenames}"| tr ' ' '\n' | sort -u | tr '\n' ' ' | _sed 's/ip://g' | _sed 's/ $//' | _sed 's/^ //')"

if [[ "${certnames}" = "${givennames}" ]]; then
echo " unchanged."
else
Expand All @@ -1824,6 +1834,42 @@ command_sign_domains() {
fi
fi

if [[ -e "${cert}" && "${force_renew}" = "no" && -n "${CA_RENEWAL_INFO}" ]]; then
printf " + Checking renewal info for existing cert..."

authkeyid="$("${OPENSSL}" x509 -in "${cert}" -text -noout | grep -A1 "X509v3 Authority Key Identifier:" | tail -n1 | tr -d '[:space:]:' | hex2bin | urlbase64)"
serial="$("${OPENSSL}" x509 -in "${cert}" -noout -serial | cut -d= -f2)"
encserial="$("${OPENSSL}" asn1parse -genstr "INT:0x${serial}" -noout -out - | tail -c +3 | urlbase64)"
Comment on lines +1841 to +1842
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reaseon for the roundtrip through asn1parse?

AIUI,

encserial="$("${OPENSSL}" x509 -in "${cert}" -noout -serial | cut -d= -f2 | hex2bin | urlbase64)"

does the same thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's implemented in line with https://letsencrypt.org/2024/04/25/guide-to-integrating-ari-into-existing-acme-clients/
Which does the same round-trip, just in go-code.
It reads to me like it's done to "ensure the serial is a positive integer". Why it does that, I'm not sure myself.
If for example the serial starts with 0x87... like in that example, piping it through asn1 like that would result in a leading zero-byte being added, which LE apparently expects:

$ openssl asn1parse -genstr "INT:0x87123456789A" -noout -out - | tail -c +3 | hexdump -v -e '/1 "%02x"'; echo
0087123456789a

Now if the ID does not start with a 1 bit, the extra 00 is not added:

$ openssl asn1parse -genstr "INT:0x57123456789A" -noout -out - | tail -c +3 | hexdump -v -e '/1 "%02x"'; echo
57123456789a

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, I remember reading about the positive integer stuff. Makes sense.


ari_response="$(http_request get "${CA_RENEWAL_INFO}/${authkeyid}.${encserial}" | jsonsh)"
window_start="$(printf "%s" "${ari_response}" | get_json_string_value -p '"suggestedWindow","start"')"
window_end="$(printf "%s" "${ari_response}" | get_json_string_value -p '"suggestedWindow","end"')"
expl_url="$(printf "%s" "${ari_response}" | get_json_string_value explanationURL)"

if [[ -n "${window_start}" && -n "${window_end}" ]]; then
window_start_unix="$(rfc3339date2unix "${window_start}")"
window_end_unix="$(rfc3339date2unix "${window_end}")"

# Assume we run once a day, so substract one day as per ari rfc.
# Add 1 second to window size to avoid possible div by zero.
renewal_datetime_unix="$(( ((RANDOM<<15)|RANDOM) % (${window_end_unix} - ${window_start_unix} + 1) + ${window_start_unix} - 86400 ))"

if [[ "${renewal_datetime_unix}" -le "$(date "+%s")" ]]; then
echo " renewal requested!"
force_renew="yes"
else
echo " no renewal requested."
fi
echo " + Renewal window: ${window_start} to ${window_end}"
else
echo " unknown."
fi

if [[ -n "${expl_url}" ]]; then
echo " + See also: ${expl_url}"
fi
fi

# Check expire date of existing certificate
if [[ -e "${cert}" ]]; then
echo " + Checking expire date of existing cert..."
Expand Down