--- Begin Message ---
Package: release.debian.org
Severity: normal
X-Debbugs-Cc: dehydra...@packages.debian.org
Control: affects -1 + src:dehydrated
User: release.debian....@packages.debian.org
Usertags: unblock
Please unblock package dehydrated
[ Reason ]
A couple of weeks ago upstream released 0.7.2.
The changes are pretty minimal, and they include stuff that might be
relevant to the trixie release cycle (i.e., the openssl warning coming
from 3.2+ which is in trixie)
Also, the certificate profiles that is part of the updated ACME protocol
(https://letsencrypt.org/2025/01/09/acme-profiles/)
[ Impact ]
Overall, these are pretty much all new features, and nothing would break
if this unblock request is not approved.
[ Tests ]
Nothing manual, but I ran it on a few of my servers to verify everything
that used to work still works.
[ Risks ]
The risks are low if nothing else because the changes are easily
audited.
I attached also a diffoscope of the .deb package, as that shows a more
correct diff, since most of the big changes from this release were
already included in the previous version via patches.
[ Checklist ]
[x] all changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in testing
unblock dehydrated/0.7.2-1
--
regards,
Mattia Rizzolo
GPG Key: 66AE 2B4A FCCF 3F52 DA18 4D18 4B04 3FCD B944 4540 .''`.
More about me: https://mapreri.org : :' :
Launchpad user: https://launchpad.net/~mapreri `. `'`
Debian QA page: https://qa.debian.org/developer.php?login=mattia `-
diffstat for dehydrated-0.7.1 dehydrated-0.7.2
CHANGELOG
| 12
README.md
| 10
debian/changelog
| 10
debian/control
| 2
debian/copyright
| 2
debian/patches/0002-added-note-about-dehydrated-irc-channel.patch
| 26 -
debian/patches/0002-only-validate-existance-of-wellknown-directory-or-ho.patch
| 36 ++
debian/patches/0003-improve-man-page-based-on-feedback-from-debian-l10n-.patch
| 66 ----
debian/patches/0004-Replace-all-escaped-slashes-in-json-strings-closes-8.patch
| 27 -
debian/patches/0004-small-addition-to-0.7.2-changelog.patch
| 24 +
debian/patches/0005-fix-zsh-compatibility-fixes-896.patch
| 25 -
debian/patches/0006-Ignore-output-of-openssl-req-verify.patch
| 27 -
debian/patches/series
| 7
dehydrated
| 136 ++++++++--
docs/examples/config
| 15 -
docs/man/dehydrated.1
| 12
16 files changed, 225 insertions(+), 212 deletions(-)
diff -Nru dehydrated-0.7.1/CHANGELOG dehydrated-0.7.2/CHANGELOG
--- dehydrated-0.7.1/CHANGELOG 2022-10-31 15:12:38.000000000 +0100
+++ dehydrated-0.7.2/CHANGELOG 2025-05-18 01:34:32.000000000 +0200
@@ -1,6 +1,18 @@
# Change Log
This file contains a log of major changes in dehydrated
+## [0.7.2] - 2025-05-18
+## Added
+- Implemented support for certificate profile selection
+- Added a configuration parameter to allow for timeouts during order
processing (`ORDER_TIMEOUT`, defaults to 0 = no timeout)
+- Allowed for automatic deletion of old files (`AUTO_CLEANUP_DELETE`, disabled
by default)
+
+## Changed
+- Renew certificates with 32 days remaining (instead of 30) to avoid issues
with monthly cronjobs (`RENEW_DAYS=32`)
+
+## Fixed
+- Changed behaviour of `openssl req` stdin handling to fix compatibility with
OpenSSL version 3.2+
+
## [0.7.1] - 2022-10-31
## Changed
- `--force` no longer forces domain name revalidation by default, a new
argument `--force-validation` has been added for that
diff -Nru dehydrated-0.7.1/debian/changelog dehydrated-0.7.2/debian/changelog
--- dehydrated-0.7.1/debian/changelog 2024-07-27 08:13:05.000000000 +0200
+++ dehydrated-0.7.2/debian/changelog 2025-06-02 16:50:35.000000000 +0200
@@ -1,3 +1,13 @@
+dehydrated (0.7.2-1) unstable; urgency=medium
+
+ * New upstream release 0.7.2.
+ * Update copyright.
+ * Drop all patches applied upstream.
+ * Add patches from upstream after the 0.7.2 release.
+ * Bump Standards-Version to 4.7.2, no changes needed.
+
+ -- Mattia Rizzolo <mat...@debian.org> Mon, 02 Jun 2025 16:50:35 +0200
+
dehydrated (0.7.1-1) unstable; urgency=medium
* New upstream release 0.7.1. Closes: #1023655
diff -Nru dehydrated-0.7.1/debian/control dehydrated-0.7.2/debian/control
--- dehydrated-0.7.1/debian/control 2024-07-27 08:13:05.000000000 +0200
+++ dehydrated-0.7.2/debian/control 2025-06-02 16:50:35.000000000 +0200
@@ -10,7 +10,7 @@
debhelper-compat (= 13),
dh-apache2,
dh-exec,
-Standards-Version: 4.7.0
+Standards-Version: 4.7.2
Rules-Requires-Root: no
Vcs-Git: https://salsa.debian.org/letsencrypt-team/dehydrated.git
Vcs-Browser: https://salsa.debian.org/letsencrypt-team/dehydrated
diff -Nru dehydrated-0.7.1/debian/copyright dehydrated-0.7.2/debian/copyright
--- dehydrated-0.7.1/debian/copyright 2024-07-27 08:08:39.000000000 +0200
+++ dehydrated-0.7.2/debian/copyright 2025-06-02 16:50:35.000000000 +0200
@@ -9,7 +9,7 @@
Files: debian/*
Copyright: 2016 Daniel Beyer <d...@deb.ymc.ch>
- 2016-2024 Mattia Rizzolo <mat...@debian.org>
+ 2016-2025 Mattia Rizzolo <mat...@debian.org>
License: Expat
License: Expat
diff -Nru
dehydrated-0.7.1/debian/patches/0002-added-note-about-dehydrated-irc-channel.patch
dehydrated-0.7.2/debian/patches/0002-added-note-about-dehydrated-irc-channel.patch
---
dehydrated-0.7.1/debian/patches/0002-added-note-about-dehydrated-irc-channel.patch
2024-07-27 08:11:37.000000000 +0200
+++
dehydrated-0.7.2/debian/patches/0002-added-note-about-dehydrated-irc-channel.patch
1970-01-01 01:00:00.000000000 +0100
@@ -1,26 +0,0 @@
-From 5c4adf6baa9f65d86298d438d53bad308ddd1a60 Mon Sep 17 00:00:00 2001
-From: Lukas Schauer <lu...@schauer.dev>
-Date: Mon, 31 Oct 2022 15:46:28 +0100
-Subject: [PATCH 2/6] added note about dehydrated irc channel
-
----
- README.md | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/README.md b/README.md
-index c03f147..7db9880 100644
---- a/README.md
-+++ b/README.md
-@@ -86,3 +86,9 @@ Parameters:
- --challenge (-t) http-01|dns-01|tls-alpn-01 Which challenge should be used?
Currently http-01, dns-01, and tls-alpn-01 are supported
- --algo (-a) rsa|prime256v1|secp384r1 Which public key algorithm should be
used? Supported: rsa, prime256v1 and secp384r1
- ```
-+
-+## Chat
-+
-+Dehydrated has an official IRC-channel `#dehydrated` on libera.chat that can
be used for general discussion and suggestions.
-+
-+The channel can also be accessed with Matrix using the official libera.chat
bridge at `#dehydrated:libera.chat`.
---
-2.45.2
-
diff -Nru
dehydrated-0.7.1/debian/patches/0002-only-validate-existance-of-wellknown-directory-or-ho.patch
dehydrated-0.7.2/debian/patches/0002-only-validate-existance-of-wellknown-directory-or-ho.patch
---
dehydrated-0.7.1/debian/patches/0002-only-validate-existance-of-wellknown-directory-or-ho.patch
1970-01-01 01:00:00.000000000 +0100
+++
dehydrated-0.7.2/debian/patches/0002-only-validate-existance-of-wellknown-directory-or-ho.patch
2025-06-02 16:50:35.000000000 +0200
@@ -0,0 +1,36 @@
+From 3a71a7ad9472aa625a22d9fba3d89d9dc5ec391c Mon Sep 17 00:00:00 2001
+From: Lukas Schauer <lu...@schauer.dev>
+Date: Sun, 18 May 2025 02:06:53 +0200
+Subject: [PATCH 2/4] only validate existance of wellknown directory or hook
+ script when actually necessary (fixes #965)
+
+---
+ dehydrated | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/dehydrated b/dehydrated
+index 0416cb7..ab25633 100755
+--- a/dehydrated
++++ b/dehydrated
+@@ -326,11 +326,13 @@ hookscript_bricker_hook() {
+ # verify configuration values
+ verify_config() {
+ [[ "${CHALLENGETYPE}" == "http-01" || "${CHALLENGETYPE}" == "dns-01" ||
"${CHALLENGETYPE}" == "tls-alpn-01" ]] || _exiterr "Unknown challenge type
${CHALLENGETYPE}... cannot continue."
+- if [[ "${CHALLENGETYPE}" = "dns-01" ]] && [[ -z "${HOOK}" ]]; then
+- _exiterr "Challenge type dns-01 needs a hook script for deployment...
cannot continue."
+- fi
+- if [[ "${CHALLENGETYPE}" = "http-01" && ! -d "${WELLKNOWN}" && !
"${COMMAND:-}" = "register" ]]; then
+- _exiterr "WELLKNOWN directory doesn't exist, please create ${WELLKNOWN}
and set appropriate permissions."
++ if [[ "${COMMAND:-}" =~ sign_domains|sign_csr ]]; then
++ if [[ "${CHALLENGETYPE}" = "dns-01" ]] && [[ -z "${HOOK}" ]]; then
++ _exiterr "Challenge type dns-01 needs a hook script for deployment...
cannot continue."
++ fi
++ if [[ "${CHALLENGETYPE}" = "http-01" ]] && [[ ! -d "${WELLKNOWN}" ]]; then
++ _exiterr "WELLKNOWN directory doesn't exist, please create ${WELLKNOWN}
and set appropriate permissions."
++ fi
+ fi
+ [[ "${KEY_ALGO}" == "rsa" || "${KEY_ALGO}" == "prime256v1" || "${KEY_ALGO}"
== "secp384r1" || "${KEY_ALGO}" == "secp521r1" ]] || _exiterr "Unknown public
key algorithm ${KEY_ALGO}... cannot continue."
+ if [[ -n "${IP_VERSION}" ]]; then
+--
+2.49.0
+
diff -Nru
dehydrated-0.7.1/debian/patches/0003-improve-man-page-based-on-feedback-from-debian-l10n-.patch
dehydrated-0.7.2/debian/patches/0003-improve-man-page-based-on-feedback-from-debian-l10n-.patch
---
dehydrated-0.7.1/debian/patches/0003-improve-man-page-based-on-feedback-from-debian-l10n-.patch
2024-07-27 08:11:37.000000000 +0200
+++
dehydrated-0.7.2/debian/patches/0003-improve-man-page-based-on-feedback-from-debian-l10n-.patch
1970-01-01 01:00:00.000000000 +0100
@@ -1,66 +0,0 @@
-From fa68ad8b2302e893e2ce9d4b4cd3a87a00021f1c Mon Sep 17 00:00:00 2001
-From: Daniel Molkentin <dan...@molkentin.de>
-Date: Thu, 12 May 2022 11:41:13 +0200
-Subject: [PATCH 3/6] improve man page based on feedback from
- debian-l10n-english (fixes #873, closes #875)
-
-Also propagate changes to dehydrated help and README.md
----
- README.md | 2 +-
- dehydrated | 2 +-
- docs/man/dehydrated.1 | 6 +++---
- 3 files changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/README.md b/README.md
-index 7db9880..c9e532d 100644
---- a/README.md
-+++ b/README.md
-@@ -71,7 +71,7 @@ Parameters:
- --ca url/preset Use specified CA URL or preset
- --alias certalias Use specified name for certificate
directory (and per-certificate config) instead of the primary domain (only used
if --domain is specified)
- --keep-going (-g) Keep going after encountering an error
while creating/renewing multiple certificates in cron mode
-- --force (-x) Force renew of certificate even if it is
longer valid than value in RENEW_DAYS
-+ --force (-x) Force certificate renewal even if it is not
due to expire within RENEW_DAYS
- --force-validation Force revalidation of domain names (used in
combination with --force)
- --no-lock (-n) Don't use lockfile (potentially dangerous!)
- --lock-suffix example.com Suffix lockfile name with a string (useful
for with -d)
-diff --git a/dehydrated b/dehydrated
-index 2befdfb..791fe41 100755
---- a/dehydrated
-+++ b/dehydrated
-@@ -2262,7 +2262,7 @@ main() {
- ;;
-
- # PARAM_Usage: --force (-x)
-- # PARAM_Description: Force renew of certificate even if it is longer
valid than value in RENEW_DAYS
-+ # PARAM_Description: Force certificate renewal even if it is not due to
expire within RENEW_DAYS
- --force|-x)
- PARAM_FORCE="yes"
- ;;
-diff --git a/docs/man/dehydrated.1 b/docs/man/dehydrated.1
-index d866fec..1dadc69 100644
---- a/docs/man/dehydrated.1
-+++ b/docs/man/dehydrated.1
-@@ -20,8 +20,8 @@ Dehydrated will notify if no account is configured. Run with
\fB--register
-
- Next, all domain names must be provided in domains.txt. The format is line
- based: If the file contains two lines "example.com" and "example.net",
--Dehydrated will request two certificate, one for "example.com" and the other
--for "example.net". A single line while "example.com example.net" will request
a
-+dehydrated will request two certificate, one for "example.com" and the other
-+for "example.net". A single line containing "example.com example.net" will
request a
- single certificate valid for both "example.net" and "example.com" through the
\fISubject
- Alternative Name\fR (SAN) field.
-
-@@ -106,7 +106,7 @@ Keep going after encountering an error while
creating/renewing multiple
- certificates in cron mode
- .TP
- .BR \-\-force ", " \-x
--Force renew of certificate even if it is longer valid than value in RENEW_DAYS
-+Force certificate renewal even if it is not due to expire within RENEW_DAYS
- .TP
- .BR \-\-no\-lock ", " \-n
- Don't use lockfile (potentially dangerous!)
---
-2.45.2
-
diff -Nru
dehydrated-0.7.1/debian/patches/0004-Replace-all-escaped-slashes-in-json-strings-closes-8.patch
dehydrated-0.7.2/debian/patches/0004-Replace-all-escaped-slashes-in-json-strings-closes-8.patch
---
dehydrated-0.7.1/debian/patches/0004-Replace-all-escaped-slashes-in-json-strings-closes-8.patch
2024-07-27 08:11:37.000000000 +0200
+++
dehydrated-0.7.2/debian/patches/0004-Replace-all-escaped-slashes-in-json-strings-closes-8.patch
1970-01-01 01:00:00.000000000 +0100
@@ -1,27 +0,0 @@
-From 67b111a7b09374182bbba2bf3feecbbd549c0df2 Mon Sep 17 00:00:00 2001
-From: Alexander Sulfrian <asulfr...@zedat.fu-berlin.de>
-Date: Fri, 4 Feb 2022 20:34:22 +0100
-Subject: [PATCH 4/6] Replace all escaped slashes in json strings (closes #866)
-
-${var/pattern/string} will only replace the first occurence. We should
-use ${var//pattern/string} to replace all escaped slashes.
----
- dehydrated | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/dehydrated b/dehydrated
-index 791fe41..c11d7d0 100755
---- a/dehydrated
-+++ b/dehydrated
-@@ -217,7 +217,7 @@ jsonsh() {
- '[') parse_array "$jpath" ;;
- # At this point, the only valid single-character tokens are digits.
- ''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;;
-- *) value="${token/\\\///}"
-+ *) value="${token//\\\///}"
- # replace solidus ("\/") in json strings with normalized value: "/"
- ;;
- esac
---
-2.45.2
-
diff -Nru
dehydrated-0.7.1/debian/patches/0004-small-addition-to-0.7.2-changelog.patch
dehydrated-0.7.2/debian/patches/0004-small-addition-to-0.7.2-changelog.patch
---
dehydrated-0.7.1/debian/patches/0004-small-addition-to-0.7.2-changelog.patch
1970-01-01 01:00:00.000000000 +0100
+++
dehydrated-0.7.2/debian/patches/0004-small-addition-to-0.7.2-changelog.patch
2025-06-02 16:50:35.000000000 +0200
@@ -0,0 +1,24 @@
+From 9cfcd66f156f75f130a065164b1a27e87e9246c2 Mon Sep 17 00:00:00 2001
+From: Lukas Schauer <lu...@schauer.dev>
+Date: Sun, 18 May 2025 02:28:57 +0200
+Subject: [PATCH 4/4] small addition to 0.7.2 changelog
+
+---
+ CHANGELOG | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index d16be92..4c5e516 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -10,6 +10,7 @@ This file contains a log of major changes in dehydrated
+ - Implemented support for certificate profile selection
+ - Added a configuration parameter to allow for timeouts during order
processing (`ORDER_TIMEOUT`, defaults to 0 = no timeout)
+ - Allowed for automatic deletion of old files (`AUTO_CLEANUP_DELETE`,
disabled by default)
++- Added CA presets for Google Trust Services (prod: google, test: google-test)
+
+ ## Changed
+ - Renew certificates with 32 days remaining (instead of 30) to avoid issues
with monthly cronjobs (`RENEW_DAYS=32`)
+--
+2.49.0
+
diff -Nru
dehydrated-0.7.1/debian/patches/0005-fix-zsh-compatibility-fixes-896.patch
dehydrated-0.7.2/debian/patches/0005-fix-zsh-compatibility-fixes-896.patch
--- dehydrated-0.7.1/debian/patches/0005-fix-zsh-compatibility-fixes-896.patch
2024-07-27 08:11:37.000000000 +0200
+++ dehydrated-0.7.2/debian/patches/0005-fix-zsh-compatibility-fixes-896.patch
1970-01-01 01:00:00.000000000 +0100
@@ -1,25 +0,0 @@
-From e3ef43c816f73d443f32410862d9253d35cf3f99 Mon Sep 17 00:00:00 2001
-From: Lukas Schauer <lu...@schauer.dev>
-Date: Mon, 16 Jan 2023 22:41:05 +0100
-Subject: [PATCH 5/6] fix zsh compatibility (fixes #896)
-
----
- dehydrated | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/dehydrated b/dehydrated
-index c11d7d0..a2bff40 100755
---- a/dehydrated
-+++ b/dehydrated
-@@ -143,7 +143,7 @@ jsonsh() {
-
- # Force zsh to expand $A into multiple words
- local is_wordsplit_disabled
-- is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')"
-+ is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$'
|| true)"
- if [ "${is_wordsplit_disabled}" != "0" ]; then setopt shwordsplit; fi
- $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | grep -Ev "^$SPACE$"
- if [ "${is_wordsplit_disabled}" != "0" ]; then unsetopt shwordsplit; fi
---
-2.45.2
-
diff -Nru
dehydrated-0.7.1/debian/patches/0006-Ignore-output-of-openssl-req-verify.patch
dehydrated-0.7.2/debian/patches/0006-Ignore-output-of-openssl-req-verify.patch
---
dehydrated-0.7.1/debian/patches/0006-Ignore-output-of-openssl-req-verify.patch
2024-07-27 08:11:37.000000000 +0200
+++
dehydrated-0.7.2/debian/patches/0006-Ignore-output-of-openssl-req-verify.patch
1970-01-01 01:00:00.000000000 +0100
@@ -1,27 +0,0 @@
-From 4fd777e87e589652b1127b79ac6688ed7cb151fe Mon Sep 17 00:00:00 2001
-From: Wilfried Teiken <wtei...@teiken.org>
-Date: Sun, 3 Dec 2023 15:07:01 -0500
-Subject: [PATCH 6/6] Ignore output of 'openssl req -verify'.
-
-Newer versions of openssl seem to send the verify outout to stdout instead of
-stderr in the past. Ignore that output when retrieving altnames.
----
- dehydrated | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/dehydrated b/dehydrated
-index a2bff40..a15fb04 100755
---- a/dehydrated
-+++ b/dehydrated
-@@ -1011,7 +1011,7 @@ signed_request() {
- extract_altnames() {
- csr="${1}" # the CSR itself (not a file)
-
-- if ! <<<"${csr}" "${OPENSSL}" req -verify -noout 2>/dev/null; then
-+ if ! <<<"${csr}" "${OPENSSL}" req -verify -noout >/dev/null 2>&1; then
- _exiterr "Certificate signing request isn't valid"
- fi
-
---
-2.45.2
-
diff -Nru dehydrated-0.7.1/debian/patches/series
dehydrated-0.7.2/debian/patches/series
--- dehydrated-0.7.1/debian/patches/series 2024-07-27 08:12:22.000000000
+0200
+++ dehydrated-0.7.2/debian/patches/series 2025-06-02 16:50:35.000000000
+0200
@@ -1,5 +1,2 @@
-0002-added-note-about-dehydrated-irc-channel.patch
-0003-improve-man-page-based-on-feedback-from-debian-l10n-.patch
-0004-Replace-all-escaped-slashes-in-json-strings-closes-8.patch
-0005-fix-zsh-compatibility-fixes-896.patch
-0006-Ignore-output-of-openssl-req-verify.patch
+0002-only-validate-existance-of-wellknown-directory-or-ho.patch
+0004-small-addition-to-0.7.2-changelog.patch
diff -Nru dehydrated-0.7.1/dehydrated dehydrated-0.7.2/dehydrated
--- dehydrated-0.7.1/dehydrated 2022-10-31 15:12:38.000000000 +0100
+++ dehydrated-0.7.2/dehydrated 2025-05-18 01:34:32.000000000 +0200
@@ -17,7 +17,7 @@
exec 3>&-
exec 4>&-
-VERSION="0.7.1"
+VERSION="0.7.2"
# Find directory in which this script is stored by traversing all symbolic
links
SOURCE="${0}"
@@ -143,7 +143,7 @@
# Force zsh to expand $A into multiple words
local is_wordsplit_disabled
- is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')"
+ is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$' ||
true)"
if [ "${is_wordsplit_disabled}" != "0" ]; then setopt shwordsplit; fi
$GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | grep -Ev "^$SPACE$"
if [ "${is_wordsplit_disabled}" != "0" ]; then unsetopt shwordsplit; fi
@@ -217,7 +217,7 @@
'[') parse_array "$jpath" ;;
# At this point, the only valid single-character tokens are digits.
''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;;
- *) value="${token/\\\///}"
+ *) value="${token//\\\///}"
# replace solidus ("\/") in json strings with normalized value: "/"
;;
esac
@@ -291,6 +291,8 @@
__OPENSSL_CNF="${OPENSSL_CNF}"
__RENEW_DAYS="${RENEW_DAYS}"
__IP_VERSION="${IP_VERSION}"
+ __ACME_PROFILE="${ACME_PROFILE}"
+ __ORDER_TIMEOUT=${ORDER_TIMEOUT}
}
reset_configvars() {
@@ -309,6 +311,8 @@
OPENSSL_CNF="${__OPENSSL_CNF}"
RENEW_DAYS="${__RENEW_DAYS}"
IP_VERSION="${__IP_VERSION}"
+ ACME_PROFILE="${__ACME_PROFILE}"
+ ORDER_TIMEOUT=${__ORDER_TIMEOUT}
}
hookscript_bricker_hook() {
@@ -334,6 +338,7 @@
fi
[[ "${API}" == "auto" || "${API}" == "1" || "${API}" == "2" ]] || _exiterr
"Unsupported API version defined in config: ${API}"
[[ "${OCSP_DAYS}" =~ ^[0-9]+$ ]] || _exiterr "OCSP_DAYS must be a number"
+ [[ "${ORDER_TIMEOUT}" =~ ^[0-9]+$ ]] || _exiterr "ORDER_TIMEOUT must be a
number"
}
# Setup default config values, search for and load configuration files
@@ -355,6 +360,8 @@
CA_LETSENCRYPT_TEST="https://acme-staging-v02.api.letsencrypt.org/directory"
CA_BUYPASS="https://api.buypass.com/acme/directory"
CA_BUYPASS_TEST="https://api.test4.buypass.no/acme/directory"
+ CA_GOOGLE="https://dv.acme-v02.api.pki.goog/directory"
+ CA_GOOGLE_TEST="https://dv.acme-v02.test-api.pki.goog/directory"
# Default values
CA="letsencrypt"
@@ -372,7 +379,7 @@
HOOK=
PREFERRED_CHAIN=
HOOK_CHAIN="no"
- RENEW_DAYS="30"
+ RENEW_DAYS="32"
KEYSIZE="4096"
WELLKNOWN=
PRIVATE_KEY_RENEW="yes"
@@ -388,9 +395,12 @@
IP_VERSION=
CHAINCACHE=
AUTO_CLEANUP="no"
+ AUTO_CLEANUP_DELETE="no"
DEHYDRATED_USER=
DEHYDRATED_GROUP=
API="auto"
+ ACME_PROFILE=""
+ ORDER_TIMEOUT=0
if [[ -z "${CONFIG:-}" ]]; then
echo "#" >&2
@@ -481,6 +491,10 @@
CA="${CA_BUYPASS}"
elif [ "${CA}" = "buypass-test" ]; then
CA="${CA_BUYPASS_TEST}"
+ elif [ "${CA}" = "google" ]; then
+ CA="${CA_GOOGLE}"
+ elif [ "${CA}" = "google-test" ]; then
+ CA="${CA_GOOGLE_TEST}"
fi
if [[ -z "${OLDCA}" ]] && [[ "${CA}" =
"https://acme-v02.api.letsencrypt.org/directory" ]]; then
@@ -544,6 +558,8 @@
[[ -n "${PARAM_KEY_ALGO:-}" ]] && KEY_ALGO="${PARAM_KEY_ALGO}"
[[ -n "${PARAM_OCSP_MUST_STAPLE:-}" ]] &&
OCSP_MUST_STAPLE="${PARAM_OCSP_MUST_STAPLE}"
[[ -n "${PARAM_IP_VERSION:-}" ]] && IP_VERSION="${PARAM_IP_VERSION}"
+ [[ -n "${PARAM_ACME_PROFILE:-}" ]] && ACME_PROFILE="${PARAM_ACME_PROFILE}"
+ [[ -n "${PARAM_ORDER_TIMEOUT:-}" ]] && ORDER_TIMEOUT="${PARAM_ORDER_TIMEOUT}"
if [ "${PARAM_FORCE_VALIDATION:-no}" = "yes" ] && [ "${PARAM_FORCE:-no}" =
"no" ]; then
_exiterr "Argument --force-validation can only be used in combination with
--force (-x)"
@@ -587,6 +603,10 @@
_exiterr "Problem retrieving ACME/CA-URLs, check if your configured CA
points to the directory entrypoint."
# Since reg URI is missing from directory we will assume it is the same as
CA_NEW_REG without the new part
CA_REG=${CA_NEW_REG/new-reg/reg}
+
+ if [[ -n "${ACME_PROFILE}" ]]; then
+ _exiterr "ACME profiles are not supported in ACME v1."
+ fi
else
CA_NEW_ORDER="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value
newOrder)" &&
CA_NEW_NONCE="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value
newNonce)" &&
@@ -595,6 +615,35 @@
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."
+
+ # Checking ACME profile
+ if [[ -n "${ACME_PROFILE}" ]]; then
+ # Extract available profiles from CA directory
+ declare -A available_profiles=()
+ while IFS=$'\t' read -r path value; do
+ if [[ "${value}" =~ ^\"([^\"]+)\"$ ]]; then
+ value=${BASH_REMATCH[1]}
+ fi
+ if [[ "${path}" =~ ^\[\"([^\"]+)\"\]$ ]]; then
+ available_profiles[${BASH_REMATCH[1]}]=$value
+ fi
+ done <<< "$(printf "%s" "${CA_DIRECTORY}" | get_json_dict_value -p
'"meta","profiles"' 2>/dev/null)"
+ if [[ ${#available_profiles[@]} -eq 0 ]]; then
+ _exiterr "ACME profile not supported by this CA"
+ fi
+
+ # Check if the requested profile is available
+ found_profile="no"
+ for profile in "${!available_profiles[@]}"; do
+ if [[ "${profile}" == "${ACME_PROFILE}" ]]; then
+ found_profile="yes"
+ break
+ fi
+ done
+ if [[ "${found_profile}" == "no" ]]; then
+ _exiterr "ACME profile '${ACME_PROFILE}' not found, available
profiles:$(for key in "${!available_profiles[@]}"; do printf "\n %s: %s"
"${key}" "${available_profiles[$key]}"; done)"
+ fi
+ fi
fi
# Export some environment variables to be used in hook script
@@ -703,6 +752,14 @@
fi
fi
+ # Google special sauce
+ if [[ "${CA}" = "${CA_GOOGLE}" ]]; then
+ if [[ -z "${CONTACT_EMAIL}" ]] || [[ -z "${EAB_KID:-}" ]] || [[ -z
"${EAB_HMAC_KEY:-}" ]]; then
+ echo "Google requires contact email, EAB_KID and EAB_HMAC_KEY to be
manually configured (see
https://cloud.google.com/certificate-manager/docs/public-ca-tutorial)"
+ FAILED=true
+ fi
+ fi
+
# Check if external account is required
if [[ "${FAILED}" = "false" ]]; then
if [[ "${CA_REQUIRES_EAB}" = "true" ]]; then
@@ -1009,13 +1066,13 @@
# Extracts all subject names from a CSR
# Outputs either the CN, or the SANs, one per line
extract_altnames() {
- csr="${1}" # the CSR itself (not a file)
+ csrfile="${1}" # path to CSR file
- if ! <<<"${csr}" "${OPENSSL}" req -verify -noout 2>/dev/null; then
+ if ! "${OPENSSL}" req -in "${csrfile}" -verify -noout >/dev/null; then
_exiterr "Certificate signing request isn't valid"
fi
- reqtext="$( <<<"${csr}" "${OPENSSL}" req -noout -text )"
+ reqtext="$("${OPENSSL}" req -in "${csrfile}" -noout -text)"
if <<<"${reqtext}" grep -q '^[[:space:]]*X509v3 Subject Alternative
Name:[[:space:]]*$'; then
# SANs used, extract these
altnames="$( <<<"${reqtext}" awk '/X509v3 Subject Alternative
Name:/{print;getline;print;}' | tail -n1 )"
@@ -1043,7 +1100,7 @@
# Create certificate for domain(s) and outputs it FD 3
sign_csr() {
- csr="${1}" # the CSR itself (not a file)
+ csrfile="${1}" # path to CSR file
if { true >&3; } 2>/dev/null; then
: # fd 3 looks OK
@@ -1082,7 +1139,12 @@
challenge_identifiers="[${challenge_identifiers%, }]"
echo " + Requesting new certificate order from CA..."
- order_location="$(signed_request "${CA_NEW_ORDER}" '{"identifiers":
'"${challenge_identifiers}"'}' 4>&1 | grep -i ^Location: | cut -d':' -f2- | tr
-d ' \t\r\n')"
+ local order_payload='{"identifiers": '"${challenge_identifiers}"
+ if [[ -n "${ACME_PROFILE}" ]]; then
+ order_payload="${order_payload}"',"profile":"'"${ACME_PROFILE}"'"'
+ fi
+ order_payload="${order_payload}"'}'
+ order_location="$(signed_request "${CA_NEW_ORDER}" "${order_payload}" 4>&1
| grep -i ^Location: | cut -d':' -f2- | tr -d ' \t\r\n')"
result="$(signed_request "${order_location}" "" | jsonsh)"
order_authorizations="$(echo "${result}" | get_json_array_values
authorizations)"
@@ -1268,25 +1330,30 @@
# Finally request certificate from the acme-server and store it in
cert-${timestamp}.pem and link from cert.pem
echo " + Requesting certificate..."
- csr64="$( <<<"${csr}" "${OPENSSL}" req -config "${OPENSSL_CNF}" -outform DER
| urlbase64)"
+ csr64="$("${OPENSSL}" req -in "${csrfile}" -config "${OPENSSL_CNF}" -outform
DER | urlbase64)"
if [[ ${API} -eq 1 ]]; then
crt64="$(signed_request "${CA_NEW_CERT}" '{"resource": "new-cert", "csr":
"'"${csr64}"'"}' | "${OPENSSL}" base64 -e)"
crt="$( printf -- '-----BEGIN CERTIFICATE-----\n%s\n-----END
CERTIFICATE-----\n' "${crt64}" )"
else
result="$(signed_request "${finalize}" '{"csr": "'"${csr64}"'"}' | jsonsh)"
+ waited=0
while :; do
orderstatus="$(echo "${result}" | get_json_string_value status)"
case "${orderstatus}"
in
"processing" | "pending")
+ if [ ${ORDER_TIMEOUT} -gt 0 ] && [ ${waited} -gt ${ORDER_TIMEOUT} ];
then
+ _exiterr "Timed out waiting for processing of order (still
${orderstatus})"
+ fi
echo " + Order is ${orderstatus}..."
sleep 2;
+ waited=$((waited+2))
;;
"valid")
break;
;;
*)
- _exiterr "Order in status ${orderstatus}"
+ _exiterr "Order has invalid/unknown status: ${orderstatus}"
;;
esac
result="$(signed_request "${order_location}" "" | jsonsh)"
@@ -1510,7 +1577,7 @@
crt_path="${certdir}/cert-${timestamp}.pem"
# shellcheck disable=SC2086
- sign_csr "$(< "${certdir}/cert-${timestamp}.csr")" ${altnames}
3>"${crt_path}"
+ sign_csr "${certdir}/cert-${timestamp}.csr" ${altnames} 3>"${crt_path}"
# Create fullchain.pem
echo " + Creating fullchain.pem..."
@@ -1775,7 +1842,7 @@
# All settings that are allowed here should also be stored and
# restored in store_configvars() and reset_configvars()
case "${config_var}" in
-
KEY_ALGO|OCSP_MUST_STAPLE|OCSP_FETCH|OCSP_DAYS|PRIVATE_KEY_RENEW|PRIVATE_KEY_ROLLOVER|KEYSIZE|CHALLENGETYPE|HOOK|PREFERRED_CHAIN|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS)
+
KEY_ALGO|OCSP_MUST_STAPLE|OCSP_FETCH|OCSP_DAYS|PRIVATE_KEY_RENEW|PRIVATE_KEY_ROLLOVER|KEYSIZE|CHALLENGETYPE|HOOK|PREFERRED_CHAIN|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS|ACME_PROFILE|ORDER_TIMEOUT)
echo " + ${config_var} = ${config_value}"
declare -- "${config_var}=${config_value}"
;;
@@ -1792,16 +1859,18 @@
skip="no"
# Allow for external CSR generation
- local csr=""
+ local csrfile=""
if [[ -n "${HOOK}" ]]; then
csr="$("${HOOK}" "generate_csr" "${domain}" "${certdir}" "${domain}
${morenames}")" || _exiterr 'generate_csr hook returned with non-zero exit code'
if grep -qE "\-----BEGIN (NEW )?CERTIFICATE REQUEST-----" <<< "${csr}";
then
- altnames="$(extract_altnames "${csr}")"
+ csrfile="$(_mktemp)"
+ cat > "${csrfile}" <<< "${csr}"
+ altnames="$(extract_altnames "${csrfile}")"
domain="$(cut -d' ' -f1 <<< "${altnames}")"
morenames="$(cut -s -d' ' -f2- <<< "${altnames}")"
echo " + Using CSR from hook script (real names: ${altnames})"
else
- csr=""
+ csrfile=""
fi
fi
@@ -1851,7 +1920,10 @@
# Sign certificate for this domain
if [[ ! "${skip}" = "yes" ]]; then
update_ocsp="yes"
- [[ -z "${csr}" ]] || printf "%s" "${csr}" >
"${certdir}/cert-${timestamp}.csr"
+ if [[ -n "${csrfile}" ]]; then
+ cat "${csrfile}" > "${certdir}/cert-${timestamp}.csr"
+ rm "${csrfile}"
+ fi
# shellcheck disable=SC2086
if [[ "${PARAM_KEEP_GOING:-}" = "yes" ]]; then
skip_exit_hook=yes
@@ -1895,8 +1967,8 @@
[[ -n "${HOOK}" ]] && ("${HOOK}" "exit_hook" || echo 'exit_hook returned
with non-zero exit code!' >&2)
if [[ "${AUTO_CLEANUP}" == "yes" ]]; then
- echo "+ Running automatic cleanup"
- command_cleanup noinit
+ echo " + Running automatic cleanup"
+ PARAM_CLEANUPDELETE="${AUTO_CLEANUP_DELETE:-no}" command_cleanup noinit |
_sed 's/^/ + /g'
fi
exit "${exit_with_errorcode}"
@@ -1912,19 +1984,18 @@
exec 3>&1 1>&2
# load csr
- csrfile="${1}"
+ local csrfile="${1}"
if [ ! -r "${csrfile}" ]; then
_exiterr "Could not read certificate signing request ${csrfile}"
fi
- csr="$(cat "${csrfile}")"
# extract names
- altnames="$(extract_altnames "${csr}")"
+ altnames="$(extract_altnames "${csrfile}")"
# gen cert
certfile="$(_mktemp)"
# shellcheck disable=SC2086
- sign_csr "${csr}" ${altnames} 3> "${certfile}"
+ sign_csr "${csrfile}" ${altnames} 3> "${certfile}"
# print cert
echo "# CERT #" >&3
@@ -2262,7 +2333,7 @@
;;
# PARAM_Usage: --force (-x)
- # PARAM_Description: Force renew of certificate even if it is longer
valid than value in RENEW_DAYS
+ # PARAM_Description: Force certificate renewal even if it is not due to
expire within RENEW_DAYS
--force|-x)
PARAM_FORCE="yes"
;;
@@ -2364,6 +2435,23 @@
check_parameters "${1:-}"
PARAM_KEY_ALGO="${1}"
;;
+
+ # PARAM_Usage: --acme-profile profile_name
+ # PARAM_Description: Use specified ACME profile
+ --acme-profile)
+ shift 1
+ check_parameters "${1:-}"
+ PARAM_ACME_PROFILE="${1}"
+ ;;
+
+ # PARAM_Usage: --order-timeout seconds
+ # PARAM_Description: Amount of seconds to wait for processing of order
until erroring out
+ --order-timeout)
+ shift 1
+ check_parameters "${1:-}"
+ PARAM_ORDER_TIMEOUT=${1}
+ ;;
+
*)
echo "Unknown parameter detected: ${1}" >&2
echo >&2
diff -Nru dehydrated-0.7.1/docs/examples/config
dehydrated-0.7.2/docs/examples/config
--- dehydrated-0.7.1/docs/examples/config 2022-10-31 15:12:38.000000000
+0100
+++ dehydrated-0.7.2/docs/examples/config 2025-05-18 01:34:32.000000000
+0200
@@ -22,7 +22,7 @@
#IP_VERSION=
# URL to certificate authority or internal preset
-# Presets: letsencrypt, letsencrypt-test, zerossl, buypass, buypass-test
+# Presets: letsencrypt, letsencrypt-test, zerossl, buypass, buypass-test,
google, google-test
# default: letsencrypt
#CA="letsencrypt"
@@ -92,8 +92,8 @@
# Chain clean_challenge|deploy_challenge arguments together into one hook call
per certificate (default: no)
#HOOK_CHAIN="no"
-# Minimum days before expiration to automatically renew certificate (default:
30)
-#RENEW_DAYS="30"
+# Minimum days before expiration to automatically renew certificate (default:
32)
+#RENEW_DAYS="32"
# Regenerate private keys instead of just signing new certificates on renewal
(default: yes)
#PRIVATE_KEY_RENEW="yes"
@@ -125,8 +125,17 @@
# Automatic cleanup (default: no)
#AUTO_CLEANUP="no"
+# Delete files during automatic cleanup instead of moving to archive (default:
no)
+#AUTO_CLEANUP_DELETE="no"
+
# ACME API version (default: auto)
#API=auto
# Preferred issuer chain (default: <unset> -> uses default chain)
#PREFERRED_CHAIN=
+
+# Request certificate with specific profile (default: <unset>)
+#ACME_PROFILE=
+
+# Amount of seconds to wait for processing of order until erroring out
(default: 0 => no timeout)
+#ORDER_TIMEOUT=0
diff -Nru dehydrated-0.7.1/docs/man/dehydrated.1
dehydrated-0.7.2/docs/man/dehydrated.1
--- dehydrated-0.7.1/docs/man/dehydrated.1 2022-10-31 15:12:38.000000000
+0100
+++ dehydrated-0.7.2/docs/man/dehydrated.1 2025-05-18 01:34:32.000000000
+0200
@@ -20,13 +20,13 @@
Next, all domain names must be provided in domains.txt. The format is line
based: If the file contains two lines "example.com" and "example.net",
-Dehydrated will request two certificate, one for "example.com" and the other
-for "example.net". A single line while "example.com example.net" will request a
+dehydrated will request two certificate, one for "example.com" and the other
+for "example.net". A single line containing "example.com example.net" will
request a
single certificate valid for both "example.net" and "example.com" through the
\fISubject
Alternative Name\fR (SAN) field.
For the next step, one way of verifying domain name ownership needs to be
-configured. Dehydrated implements \fIhttp-01\fR and \fIdns-01\fR
verification.
+configured. Dehydrated implements \fIhttp-01\fR and \fIdns-01\fR verification.
The \fIhttp-01\fR verification provides proof of ownership by providing a
challenge token. In order to do that, the directory referenced in the
@@ -106,7 +106,7 @@
certificates in cron mode
.TP
.BR \-\-force ", " \-x
-Force renew of certificate even if it is longer valid than value in RENEW_DAYS
+Force certificate renewal even if it is not due to expire within RENEW_DAYS
.TP
.BR \-\-no\-lock ", " \-n
Don't use lockfile (potentially dangerous!)
@@ -139,7 +139,7 @@
The program exits 0 if everything was fine, 1 if an error occurred.
.SH BUGS
Please report any bugs that you may encounter at the project web site
-.UR https://github.com/lukas2511/dehydrated/issues
+.UR https://github.com/dehydrated-io/dehydrated/issues
.UE .
.SH AUTHOR
Dehydrated was written by Lukas Schauer. This man page was contributed by
@@ -151,5 +151,5 @@
.SH SEE ALSO
Full documentation along with configuration examples are provided in the
\fIdocs\fR
directory of the distribution, or at
-.UR https://github.com/lukas2511/dehydrated/tree/master/docs
+.UR https://github.com/dehydrated-io/dehydrated/tree/master/docs
.UE .
diff -Nru dehydrated-0.7.1/README.md dehydrated-0.7.2/README.md
--- dehydrated-0.7.1/README.md 2022-10-31 15:12:38.000000000 +0100
+++ dehydrated-0.7.2/README.md 2025-05-18 01:34:32.000000000 +0200
@@ -71,7 +71,7 @@
--ca url/preset Use specified CA URL or preset
--alias certalias Use specified name for certificate directory
(and per-certificate config) instead of the primary domain (only used if
--domain is specified)
--keep-going (-g) Keep going after encountering an error while
creating/renewing multiple certificates in cron mode
- --force (-x) Force renew of certificate even if it is
longer valid than value in RENEW_DAYS
+ --force (-x) Force certificate renewal even if it is not
due to expire within RENEW_DAYS
--force-validation Force revalidation of domain names (used in
combination with --force)
--no-lock (-n) Don't use lockfile (potentially dangerous!)
--lock-suffix example.com Suffix lockfile name with a string (useful
for with -d)
@@ -85,4 +85,12 @@
--alpn alpn-certs/directory Output alpn verification certificates into
the specified directory
--challenge (-t) http-01|dns-01|tls-alpn-01 Which challenge should be used?
Currently http-01, dns-01, and tls-alpn-01 are supported
--algo (-a) rsa|prime256v1|secp384r1 Which public key algorithm should be
used? Supported: rsa, prime256v1 and secp384r1
+ --acme-profile profile_name Use specified ACME profile
+ --order-timeout seconds Amount of seconds to wait for processing of
order until erroring out
```
+
+## Chat
+
+Dehydrated has an official IRC-channel `#dehydrated` on libera.chat that can
be used for general discussion and suggestions.
+
+The channel can also be accessed with Matrix using the official libera.chat
bridge at `#dehydrated:libera.chat`.
--- dehydrated_0.7.1-1_all.deb
+++ dehydrated_0.7.2-1_all.deb
├── file list
│ @@ -1,3 +1,3 @@
│ --rw-r--r-- 0 0 0 4 2024-07-27 06:13:05.000000
debian-binary
│ --rw-r--r-- 0 0 0 1420 2024-07-27 06:13:05.000000
control.tar.xz
│ --rw-r--r-- 0 0 0 118924 2024-07-27 06:13:05.000000
data.tar.xz
│ +-rw-r--r-- 0 0 0 4 2025-06-02 14:50:35.000000
debian-binary
│ +-rw-r--r-- 0 0 0 1420 2025-06-02 14:50:35.000000
control.tar.xz
│ +-rw-r--r-- 0 0 0 120076 2025-06-02 14:50:35.000000
data.tar.xz
├── control.tar.xz
│ ├── control.tar
│ │ ├── file list
│ │ │ @@ -1,4 +1,4 @@
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./
│ │ │ --rw-r--r-- 0 root (0) root (0) 23 2024-07-27
06:13:05.000000 ./conffiles
│ │ │ --rw-r--r-- 0 root (0) root (0) 799 2024-07-27
06:13:05.000000 ./control
│ │ │ --rw-r--r-- 0 root (0) root (0) 1666 2024-07-27
06:13:05.000000 ./md5sums
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./
│ │ │ +-rw-r--r-- 0 root (0) root (0) 23 2025-06-02
14:50:35.000000 ./conffiles
│ │ │ +-rw-r--r-- 0 root (0) root (0) 799 2025-06-02
14:50:35.000000 ./control
│ │ │ +-rw-r--r-- 0 root (0) root (0) 1666 2025-06-02
14:50:35.000000 ./md5sums
│ │ ├── ./control
│ │ │ @@ -1,12 +1,12 @@
│ │ │ Package: dehydrated
│ │ │ -Version: 0.7.1-1
│ │ │ +Version: 0.7.2-1
│ │ │ Architecture: all
│ │ │ Maintainer: Debian Let's Encrypt Team
<team+letsencr...@tracker.debian.org>
│ │ │ -Installed-Size: 239
│ │ │ +Installed-Size: 244
│ │ │ Depends: ca-certificates, curl, openssl
│ │ │ Section: misc
│ │ │ Priority: optional
│ │ │ Multi-Arch: foreign
│ │ │ Homepage: https://dehydrated.io
│ │ │ Description: ACME client implemented in Bash
│ │ │ The dehydrated ACME client allows signing certificates with an
│ │ ├── ./md5sums
│ │ │ ├── ./md5sums
│ │ │ │┄ Files differ
├── data.tar.xz
│ ├── data.tar
│ │ ├── file list
│ │ │ @@ -1,41 +1,41 @@
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./etc/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./etc/dehydrated/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./etc/dehydrated/conf.d/
│ │ │ --rw-r--r-- 0 root (0) root (0) 762 2024-07-27
06:13:05.000000 ./etc/dehydrated/config
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/bin/
│ │ │ --rwxr-xr-x 0 root (0) root (0) 88977 2024-07-27
06:13:05.000000 ./usr/bin/dehydrated
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/share/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/share/doc/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/share/doc/dehydrated/
│ │ │ --rw-r--r-- 0 root (0) root (0) 2668 2024-07-27
06:08:25.000000 ./usr/share/doc/dehydrated/README.Debian
│ │ │ --rw-r--r-- 0 root (0) root (0) 2512 2024-07-27
06:13:05.000000 ./usr/share/doc/dehydrated/README.md.gz
│ │ │ --rw-r--r-- 0 root (0) root (0) 907 2024-07-27
06:13:05.000000 ./usr/share/doc/dehydrated/changelog.Debian.gz
│ │ │ --rw-r--r-- 0 root (0) root (0) 2818 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/changelog.gz
│ │ │ --rw-r--r-- 0 root (0) root (0) 1465 2024-07-27
06:08:39.000000 ./usr/share/doc/dehydrated/copyright
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/share/doc/dehydrated/docs/
│ │ │ --rw-r--r-- 0 root (0) root (0) 1709 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/acme-v1.md
│ │ │ --rw-r--r-- 0 root (0) root (0) 1895 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/dns-verification.md
│ │ │ --rw-r--r-- 0 root (0) root (0) 3525 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/domains_txt.md
│ │ │ --rw-r--r-- 0 root (0) root (0) 174 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/ecc.md
│ │ │ --rw-r--r-- 0 root (0) root (0) 2892 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/hook_chain.md
│ │ │ --rw-r--r-- 0 root (0) root (0) 76482 2024-07-27
06:13:05.000000 ./usr/share/doc/dehydrated/docs/logo.png
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/share/doc/dehydrated/docs/man/
│ │ │ --rw-r--r-- 0 root (0) root (0) 2486 2024-07-27
06:13:05.000000 ./usr/share/doc/dehydrated/docs/man/dehydrated.1.gz
│ │ │ --rw-r--r-- 0 root (0) root (0) 744 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/per-certificate-config.md
│ │ │ --rw-r--r-- 0 root (0) root (0) 546 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/staging.md
│ │ │ --rw-r--r-- 0 root (0) root (0) 1850 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/tls-alpn.md.gz
│ │ │ --rw-r--r-- 0 root (0) root (0) 3549 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/troubleshooting.md
│ │ │ --rw-r--r-- 0 root (0) root (0) 2677 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/docs/wellknown.md
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/share/doc/dehydrated/examples/
│ │ │ --rw-r--r-- 0 root (0) root (0) 4770 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/examples/config
│ │ │ --rw-r--r-- 0 root (0) root (0) 1846 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/examples/domains.txt
│ │ │ --rwxr-xr-x 0 root (0) root (0) 7745 2022-10-31
14:12:38.000000 ./usr/share/doc/dehydrated/examples/hook.sh
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/share/man/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./usr/share/man/man1/
│ │ │ --rw-r--r-- 0 root (0) root (0) 2486 2024-07-27
06:13:05.000000 ./usr/share/man/man1/dehydrated.1.gz
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./var/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./var/lib/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./var/lib/dehydrated/
│ │ │ -drwxr-xr-x 0 root (0) root (0) 0 2024-07-27
06:13:05.000000 ./var/lib/dehydrated/acme-challenges/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./etc/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./etc/dehydrated/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./etc/dehydrated/conf.d/
│ │ │ +-rw-r--r-- 0 root (0) root (0) 762 2025-06-02
14:50:35.000000 ./etc/dehydrated/config
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/bin/
│ │ │ +-rwxr-xr-x 0 root (0) root (0) 92503 2025-06-02
14:50:35.000000 ./usr/bin/dehydrated
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/share/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/share/doc/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/
│ │ │ +-rw-r--r-- 0 root (0) root (0) 2668 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/README.Debian
│ │ │ +-rw-r--r-- 0 root (0) root (0) 2578 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/README.md.gz
│ │ │ +-rw-r--r-- 0 root (0) root (0) 942 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/changelog.Debian.gz
│ │ │ +-rw-r--r-- 0 root (0) root (0) 3074 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/changelog.gz
│ │ │ +-rw-r--r-- 0 root (0) root (0) 1465 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/copyright
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/docs/
│ │ │ +-rw-r--r-- 0 root (0) root (0) 1709 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/acme-v1.md
│ │ │ +-rw-r--r-- 0 root (0) root (0) 1895 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/dns-verification.md
│ │ │ +-rw-r--r-- 0 root (0) root (0) 3525 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/domains_txt.md
│ │ │ +-rw-r--r-- 0 root (0) root (0) 174 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/ecc.md
│ │ │ +-rw-r--r-- 0 root (0) root (0) 2892 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/hook_chain.md
│ │ │ +-rw-r--r-- 0 root (0) root (0) 76482 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/docs/logo.png
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/docs/man/
│ │ │ +-rw-r--r-- 0 root (0) root (0) 2482 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/man/dehydrated.1.gz
│ │ │ +-rw-r--r-- 0 root (0) root (0) 744 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/per-certificate-config.md
│ │ │ +-rw-r--r-- 0 root (0) root (0) 546 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/staging.md
│ │ │ +-rw-r--r-- 0 root (0) root (0) 1850 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/tls-alpn.md.gz
│ │ │ +-rw-r--r-- 0 root (0) root (0) 3549 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/troubleshooting.md
│ │ │ +-rw-r--r-- 0 root (0) root (0) 2677 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/docs/wellknown.md
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/share/doc/dehydrated/examples/
│ │ │ +-rw-r--r-- 0 root (0) root (0) 5096 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/examples/config
│ │ │ +-rw-r--r-- 0 root (0) root (0) 1846 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/examples/domains.txt
│ │ │ +-rwxr-xr-x 0 root (0) root (0) 7745 2025-05-17
23:34:32.000000 ./usr/share/doc/dehydrated/examples/hook.sh
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/share/man/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./usr/share/man/man1/
│ │ │ +-rw-r--r-- 0 root (0) root (0) 2482 2025-06-02
14:50:35.000000 ./usr/share/man/man1/dehydrated.1.gz
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./var/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./var/lib/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./var/lib/dehydrated/
│ │ │ +drwxr-xr-x 0 root (0) root (0) 0 2025-06-02
14:50:35.000000 ./var/lib/dehydrated/acme-challenges/
│ │ ├── ./usr/bin/dehydrated
│ │ │ @@ -13,15 +13,15 @@
│ │ │
│ │ │ umask 077 # paranoid umask, we're creating private keys
│ │ │
│ │ │ # Close weird external file descriptors
│ │ │ exec 3>&-
│ │ │ exec 4>&-
│ │ │
│ │ │ -VERSION="0.7.1"
│ │ │ +VERSION="0.7.2"
│ │ │
│ │ │ # Find directory in which this script is stored by traversing all
symbolic links
│ │ │ SOURCE="${0}"
│ │ │ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer
a symlink
│ │ │ DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
│ │ │ SOURCE="$(readlink "$SOURCE")"
│ │ │ [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a
relative symlink, we need to resolve it relative to the path where the symlink
file was located
│ │ │ @@ -287,14 +287,16 @@
│ │ │ __HOOK="${HOOK}"
│ │ │ __PREFERRED_CHAIN="${PREFERRED_CHAIN}"
│ │ │ __WELLKNOWN="${WELLKNOWN}"
│ │ │ __HOOK_CHAIN="${HOOK_CHAIN}"
│ │ │ __OPENSSL_CNF="${OPENSSL_CNF}"
│ │ │ __RENEW_DAYS="${RENEW_DAYS}"
│ │ │ __IP_VERSION="${IP_VERSION}"
│ │ │ + __ACME_PROFILE="${ACME_PROFILE}"
│ │ │ + __ORDER_TIMEOUT=${ORDER_TIMEOUT}
│ │ │ }
│ │ │
│ │ │ reset_configvars() {
│ │ │ KEY_ALGO="${__KEY_ALGO}"
│ │ │ OCSP_MUST_STAPLE="${__OCSP_MUST_STAPLE}"
│ │ │ OCSP_FETCH="${__OCSP_FETCH}"
│ │ │ OCSP_DAYS="${__OCSP_DAYS}"
│ │ │ @@ -305,39 +307,44 @@
│ │ │ HOOK="${__HOOK}"
│ │ │ PREFERRED_CHAIN="${__PREFERRED_CHAIN}"
│ │ │ WELLKNOWN="${__WELLKNOWN}"
│ │ │ HOOK_CHAIN="${__HOOK_CHAIN}"
│ │ │ OPENSSL_CNF="${__OPENSSL_CNF}"
│ │ │ RENEW_DAYS="${__RENEW_DAYS}"
│ │ │ IP_VERSION="${__IP_VERSION}"
│ │ │ + ACME_PROFILE="${__ACME_PROFILE}"
│ │ │ + ORDER_TIMEOUT=${__ORDER_TIMEOUT}
│ │ │ }
│ │ │
│ │ │ hookscript_bricker_hook() {
│ │ │ # Hook scripts should ignore any hooks they don't know.
│ │ │ # Calling a random hook to make this clear to the hook script
authors...
│ │ │ if [[ -n "${HOOK}" ]]; then
│ │ │ "${HOOK}"
"this_hookscript_is_broken__dehydrated_is_working_fine__please_ignore_unknown_hooks_in_your_script"
|| _exiterr "Please check your hook script, it should exit cleanly without
doing anything on unknown/new hooks."
│ │ │ fi
│ │ │ }
│ │ │
│ │ │ # verify configuration values
│ │ │ verify_config() {
│ │ │ [[ "${CHALLENGETYPE}" == "http-01" || "${CHALLENGETYPE}" == "dns-01"
|| "${CHALLENGETYPE}" == "tls-alpn-01" ]] || _exiterr "Unknown challenge type
${CHALLENGETYPE}... cannot continue."
│ │ │ - if [[ "${CHALLENGETYPE}" = "dns-01" ]] && [[ -z "${HOOK}" ]]; then
│ │ │ - _exiterr "Challenge type dns-01 needs a hook script for
deployment... cannot continue."
│ │ │ - fi
│ │ │ - if [[ "${CHALLENGETYPE}" = "http-01" && ! -d "${WELLKNOWN}" && !
"${COMMAND:-}" = "register" ]]; then
│ │ │ - _exiterr "WELLKNOWN directory doesn't exist, please create
${WELLKNOWN} and set appropriate permissions."
│ │ │ + if [[ "${COMMAND:-}" =~ sign_domains|sign_csr ]]; then
│ │ │ + if [[ "${CHALLENGETYPE}" = "dns-01" ]] && [[ -z "${HOOK}" ]]; then
│ │ │ + _exiterr "Challenge type dns-01 needs a hook script for
deployment... cannot continue."
│ │ │ + fi
│ │ │ + if [[ "${CHALLENGETYPE}" = "http-01" ]] && [[ ! -d "${WELLKNOWN}"
]]; then
│ │ │ + _exiterr "WELLKNOWN directory doesn't exist, please create
${WELLKNOWN} and set appropriate permissions."
│ │ │ + fi
│ │ │ fi
│ │ │ [[ "${KEY_ALGO}" == "rsa" || "${KEY_ALGO}" == "prime256v1" ||
"${KEY_ALGO}" == "secp384r1" || "${KEY_ALGO}" == "secp521r1" ]] || _exiterr
"Unknown public key algorithm ${KEY_ALGO}... cannot continue."
│ │ │ if [[ -n "${IP_VERSION}" ]]; then
│ │ │ [[ "${IP_VERSION}" = "4" || "${IP_VERSION}" = "6" ]] || _exiterr
"Unknown IP version ${IP_VERSION}... cannot continue."
│ │ │ fi
│ │ │ [[ "${API}" == "auto" || "${API}" == "1" || "${API}" == "2" ]] ||
_exiterr "Unsupported API version defined in config: ${API}"
│ │ │ [[ "${OCSP_DAYS}" =~ ^[0-9]+$ ]] || _exiterr "OCSP_DAYS must be a
number"
│ │ │ + [[ "${ORDER_TIMEOUT}" =~ ^[0-9]+$ ]] || _exiterr "ORDER_TIMEOUT must
be a number"
│ │ │ }
│ │ │
│ │ │ # Setup default config values, search for and load configuration files
│ │ │ load_config() {
│ │ │ # Check for config in various locations
│ │ │ if [[ -z "${CONFIG:-}" ]]; then
│ │ │ for check_config in "/etc/dehydrated" "/usr/local/etc/dehydrated"
"${PWD}" "${SCRIPTDIR}"; do
│ │ │ @@ -351,14 +358,16 @@
│ │ │
│ │ │ # Preset
│ │ │ CA_ZEROSSL="https://acme.zerossl.com/v2/DV90"
│ │ │ CA_LETSENCRYPT="https://acme-v02.api.letsencrypt.org/directory"
│ │ │
CA_LETSENCRYPT_TEST="https://acme-staging-v02.api.letsencrypt.org/directory"
│ │ │ CA_BUYPASS="https://api.buypass.com/acme/directory"
│ │ │ CA_BUYPASS_TEST="https://api.test4.buypass.no/acme/directory"
│ │ │ + CA_GOOGLE="https://dv.acme-v02.api.pki.goog/directory"
│ │ │ + CA_GOOGLE_TEST="https://dv.acme-v02.test-api.pki.goog/directory"
│ │ │
│ │ │ # Default values
│ │ │ CA="letsencrypt"
│ │ │ OLDCA=
│ │ │ CERTDIR=
│ │ │ ALPNCERTDIR=
│ │ │ ACCOUNTDIR=
│ │ │ @@ -368,15 +377,15 @@
│ │ │ CONFIG_D=
│ │ │ CURL_OPTS=
│ │ │ DOMAINS_D=
│ │ │ DOMAINS_TXT=
│ │ │ HOOK=
│ │ │ PREFERRED_CHAIN=
│ │ │ HOOK_CHAIN="no"
│ │ │ - RENEW_DAYS="30"
│ │ │ + RENEW_DAYS="32"
│ │ │ KEYSIZE="4096"
│ │ │ WELLKNOWN=
│ │ │ PRIVATE_KEY_RENEW="yes"
│ │ │ PRIVATE_KEY_ROLLOVER="no"
│ │ │ KEY_ALGO=secp384r1
│ │ │ OPENSSL=openssl
│ │ │ OPENSSL_CNF=
│ │ │ @@ -384,17 +393,20 @@
│ │ │ LOCKFILE=
│ │ │ OCSP_MUST_STAPLE="no"
│ │ │ OCSP_FETCH="no"
│ │ │ OCSP_DAYS=5
│ │ │ IP_VERSION=
│ │ │ CHAINCACHE=
│ │ │ AUTO_CLEANUP="no"
│ │ │ + AUTO_CLEANUP_DELETE="no"
│ │ │ DEHYDRATED_USER=
│ │ │ DEHYDRATED_GROUP=
│ │ │ API="auto"
│ │ │ + ACME_PROFILE=""
│ │ │ + ORDER_TIMEOUT=0
│ │ │
│ │ │ if [[ -z "${CONFIG:-}" ]]; then
│ │ │ echo "#" >&2
│ │ │ echo "# !! WARNING !! No main config file found, using default
config!" >&2
│ │ │ echo "#" >&2
│ │ │ elif [[ -f "${CONFIG}" ]]; then
│ │ │ echo "# INFO: Using main config file ${CONFIG}"
│ │ │ @@ -477,14 +489,18 @@
│ │ │ CA="${CA_LETSENCRYPT_TEST}"
│ │ │ elif [ "${CA}" = "zerossl" ]; then
│ │ │ CA="${CA_ZEROSSL}"
│ │ │ elif [ "${CA}" = "buypass" ]; then
│ │ │ CA="${CA_BUYPASS}"
│ │ │ elif [ "${CA}" = "buypass-test" ]; then
│ │ │ CA="${CA_BUYPASS_TEST}"
│ │ │ + elif [ "${CA}" = "google" ]; then
│ │ │ + CA="${CA_GOOGLE}"
│ │ │ + elif [ "${CA}" = "google-test" ]; then
│ │ │ + CA="${CA_GOOGLE_TEST}"
│ │ │ fi
│ │ │
│ │ │ if [[ -z "${OLDCA}" ]] && [[ "${CA}" =
"https://acme-v02.api.letsencrypt.org/directory" ]]; then
│ │ │ OLDCA="https://acme-v01.api.letsencrypt.org/directory"
│ │ │ fi
│ │ │
│ │ │ # Create new account directory or symlink to account directory from
old CA
│ │ │ @@ -540,14 +556,16 @@
│ │ │ [[ -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}"
│ │ │ [[ -n "${PARAM_KEY_ALGO:-}" ]] && KEY_ALGO="${PARAM_KEY_ALGO}"
│ │ │ [[ -n "${PARAM_OCSP_MUST_STAPLE:-}" ]] &&
OCSP_MUST_STAPLE="${PARAM_OCSP_MUST_STAPLE}"
│ │ │ [[ -n "${PARAM_IP_VERSION:-}" ]] && IP_VERSION="${PARAM_IP_VERSION}"
│ │ │ + [[ -n "${PARAM_ACME_PROFILE:-}" ]] &&
ACME_PROFILE="${PARAM_ACME_PROFILE}"
│ │ │ + [[ -n "${PARAM_ORDER_TIMEOUT:-}" ]] &&
ORDER_TIMEOUT="${PARAM_ORDER_TIMEOUT}"
│ │ │
│ │ │ if [ "${PARAM_FORCE_VALIDATION:-no}" = "yes" ] && [
"${PARAM_FORCE:-no}" = "no" ]; then
│ │ │ _exiterr "Argument --force-validation can only be used in
combination with --force (-x)"
│ │ │ fi
│ │ │
│ │ │ if [ ! "${1:-}" = "noverify" ]; then
│ │ │ verify_config
│ │ │ @@ -583,22 +601,55 @@
│ │ │ CA_NEW_REG="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value
new-reg)" &&
│ │ │ CA_TERMS="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value
terms-of-service)" &&
│ │ │ CA_REQUIRES_EAB="false" &&
│ │ │ CA_REVOKE_CERT="$(printf "%s" "${CA_DIRECTORY}" |
get_json_string_value revoke-cert)" ||
│ │ │ _exiterr "Problem retrieving ACME/CA-URLs, check if your configured
CA points to the directory entrypoint."
│ │ │ # Since reg URI is missing from directory we will assume it is the
same as CA_NEW_REG without the new part
│ │ │ CA_REG=${CA_NEW_REG/new-reg/reg}
│ │ │ +
│ │ │ + if [[ -n "${ACME_PROFILE}" ]]; then
│ │ │ + _exiterr "ACME profiles are not supported in ACME v1."
│ │ │ + fi
│ │ │ else
│ │ │ 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 -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."
│ │ │ +
│ │ │ + # Checking ACME profile
│ │ │ + if [[ -n "${ACME_PROFILE}" ]]; then
│ │ │ + # Extract available profiles from CA directory
│ │ │ + declare -A available_profiles=()
│ │ │ + while IFS=$'\t' read -r path value; do
│ │ │ + if [[ "${value}" =~ ^\"([^\"]+)\"$ ]]; then
│ │ │ + value=${BASH_REMATCH[1]}
│ │ │ + fi
│ │ │ + if [[ "${path}" =~ ^\[\"([^\"]+)\"\]$ ]]; then
│ │ │ + available_profiles[${BASH_REMATCH[1]}]=$value
│ │ │ + fi
│ │ │ + done <<< "$(printf "%s" "${CA_DIRECTORY}" | get_json_dict_value -p
'"meta","profiles"' 2>/dev/null)"
│ │ │ + if [[ ${#available_profiles[@]} -eq 0 ]]; then
│ │ │ + _exiterr "ACME profile not supported by this CA"
│ │ │ + fi
│ │ │ +
│ │ │ + # Check if the requested profile is available
│ │ │ + found_profile="no"
│ │ │ + for profile in "${!available_profiles[@]}"; do
│ │ │ + if [[ "${profile}" == "${ACME_PROFILE}" ]]; then
│ │ │ + found_profile="yes"
│ │ │ + break
│ │ │ + fi
│ │ │ + done
│ │ │ + if [[ "${found_profile}" == "no" ]]; then
│ │ │ + _exiterr "ACME profile '${ACME_PROFILE}' not found, available
profiles:$(for key in "${!available_profiles[@]}"; do printf "\n %s: %s"
"${key}" "${available_profiles[$key]}"; done)"
│ │ │ + fi
│ │ │ + fi
│ │ │ fi
│ │ │
│ │ │ # Export some environment variables to be used in hook script
│ │ │ export WELLKNOWN BASEDIR CERTDIR ALPNCERTDIR CONFIG COMMAND
│ │ │
│ │ │ # Checking for private key ...
│ │ │ register_new_key="no"
│ │ │ @@ -699,14 +750,22 @@
│ │ │ echo "${zeroapi}"
│ │ │ FAILED=true
│ │ │ fi
│ │ │ fi
│ │ │ fi
│ │ │ fi
│ │ │
│ │ │ + # Google special sauce
│ │ │ + if [[ "${CA}" = "${CA_GOOGLE}" ]]; then
│ │ │ + if [[ -z "${CONTACT_EMAIL}" ]] || [[ -z "${EAB_KID:-}" ]] || [[ -z
"${EAB_HMAC_KEY:-}" ]]; then
│ │ │ + echo "Google requires contact email, EAB_KID and EAB_HMAC_KEY
to be manually configured (see
https://cloud.google.com/certificate-manager/docs/public-ca-tutorial)"
│ │ │ + FAILED=true
│ │ │ + 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
│ │ │ @@ -1005,21 +1064,21 @@
│ │ │ printf "%s" "${output}"
│ │ │ fi
│ │ │ }
│ │ │
│ │ │ # Extracts all subject names from a CSR
│ │ │ # Outputs either the CN, or the SANs, one per line
│ │ │ extract_altnames() {
│ │ │ - csr="${1}" # the CSR itself (not a file)
│ │ │ + csrfile="${1}" # path to CSR file
│ │ │
│ │ │ - if ! <<<"${csr}" "${OPENSSL}" req -verify -noout >/dev/null 2>&1; then
│ │ │ + if ! "${OPENSSL}" req -in "${csrfile}" -verify -noout >/dev/null; then
│ │ │ _exiterr "Certificate signing request isn't valid"
│ │ │ fi
│ │ │
│ │ │ - reqtext="$( <<<"${csr}" "${OPENSSL}" req -noout -text )"
│ │ │ + reqtext="$("${OPENSSL}" req -in "${csrfile}" -noout -text)"
│ │ │ if <<<"${reqtext}" grep -q '^[[:space:]]*X509v3 Subject Alternative
Name:[[:space:]]*$'; then
│ │ │ # SANs used, extract these
│ │ │ altnames="$( <<<"${reqtext}" awk '/X509v3 Subject Alternative
Name:/{print;getline;print;}' | tail -n1 )"
│ │ │ # split to one per line:
│ │ │ # shellcheck disable=SC1003
│ │ │ altnames="$( <<<"${altnames}" _sed -e 's/^[[:space:]]*//; s/,
/\'$'\n''/g' )"
│ │ │ # we can only get DNS/IP: ones signed
│ │ │ @@ -1039,15 +1098,15 @@
│ │ │ # Get last issuer CN in certificate chain
│ │ │ get_last_cn() {
│ │ │ <<<"${1}" _sed 'H;/-----BEGIN CERTIFICATE-----/h;$!d;x' | "${OPENSSL}"
x509 -noout -issuer | head -n1 | _sed -e 's/.*[ /]CN ?= ?([^/,]*).*/\1/'
│ │ │ }
│ │ │
│ │ │ # Create certificate for domain(s) and outputs it FD 3
│ │ │ sign_csr() {
│ │ │ - csr="${1}" # the CSR itself (not a file)
│ │ │ + csrfile="${1}" # path to CSR file
│ │ │
│ │ │ if { true >&3; } 2>/dev/null; then
│ │ │ : # fd 3 looks OK
│ │ │ else
│ │ │ _exiterr "sign_csr: FD 3 not open"
│ │ │ fi
│ │ │
│ │ │ @@ -1078,15 +1137,20 @@
│ │ │ else
│ │ │ challenge_identifiers+="$(printf '{"type": "dns", "value": "%s"},
' "${altname}")"
│ │ │ fi
│ │ │ done
│ │ │ challenge_identifiers="[${challenge_identifiers%, }]"
│ │ │
│ │ │ echo " + Requesting new certificate order from CA..."
│ │ │ - order_location="$(signed_request "${CA_NEW_ORDER}" '{"identifiers":
'"${challenge_identifiers}"'}' 4>&1 | grep -i ^Location: | cut -d':' -f2- | tr
-d ' \t\r\n')"
│ │ │ + local order_payload='{"identifiers": '"${challenge_identifiers}"
│ │ │ + if [[ -n "${ACME_PROFILE}" ]]; then
│ │ │ + order_payload="${order_payload}"',"profile":"'"${ACME_PROFILE}"'"'
│ │ │ + fi
│ │ │ + order_payload="${order_payload}"'}'
│ │ │ + order_location="$(signed_request "${CA_NEW_ORDER}"
"${order_payload}" 4>&1 | grep -i ^Location: | cut -d':' -f2- | tr -d '
\t\r\n')"
│ │ │ result="$(signed_request "${order_location}" "" | jsonsh)"
│ │ │
│ │ │ order_authorizations="$(echo "${result}" | get_json_array_values
authorizations)"
│ │ │ finalize="$(echo "${result}" | get_json_string_value finalize)"
│ │ │
│ │ │ local idx=0
│ │ │ for uri in ${order_authorizations}; do
│ │ │ @@ -1264,33 +1328,38 @@
│ │ │ echo " + Challenge validation has failed :("
│ │ │ _exiterr "Challenge is invalid! (returned: ${reqstatus}) (result:
${result})"
│ │ │ fi
│ │ │ fi
│ │ │
│ │ │ # Finally request certificate from the acme-server and store it in
cert-${timestamp}.pem and link from cert.pem
│ │ │ echo " + Requesting certificate..."
│ │ │ - csr64="$( <<<"${csr}" "${OPENSSL}" req -config "${OPENSSL_CNF}"
-outform DER | urlbase64)"
│ │ │ + csr64="$("${OPENSSL}" req -in "${csrfile}" -config "${OPENSSL_CNF}"
-outform DER | urlbase64)"
│ │ │ if [[ ${API} -eq 1 ]]; then
│ │ │ crt64="$(signed_request "${CA_NEW_CERT}" '{"resource": "new-cert",
"csr": "'"${csr64}"'"}' | "${OPENSSL}" base64 -e)"
│ │ │ crt="$( printf -- '-----BEGIN CERTIFICATE-----\n%s\n-----END
CERTIFICATE-----\n' "${crt64}" )"
│ │ │ else
│ │ │ result="$(signed_request "${finalize}" '{"csr": "'"${csr64}"'"}' |
jsonsh)"
│ │ │ + waited=0
│ │ │ while :; do
│ │ │ orderstatus="$(echo "${result}" | get_json_string_value status)"
│ │ │ case "${orderstatus}"
│ │ │ in
│ │ │ "processing" | "pending")
│ │ │ + if [ ${ORDER_TIMEOUT} -gt 0 ] && [ ${waited} -gt
${ORDER_TIMEOUT} ]; then
│ │ │ + _exiterr "Timed out waiting for processing of order (still
${orderstatus})"
│ │ │ + fi
│ │ │ echo " + Order is ${orderstatus}..."
│ │ │ sleep 2;
│ │ │ + waited=$((waited+2))
│ │ │ ;;
│ │ │ "valid")
│ │ │ break;
│ │ │ ;;
│ │ │ *)
│ │ │ - _exiterr "Order in status ${orderstatus}"
│ │ │ + _exiterr "Order has invalid/unknown status: ${orderstatus}"
│ │ │ ;;
│ │ │ esac
│ │ │ result="$(signed_request "${order_location}" "" | jsonsh)"
│ │ │ done
│ │ │
│ │ │ resheaders="$(_mktemp)"
│ │ │ certificate="$(echo "${result}" | get_json_string_value certificate)"
│ │ │ @@ -1506,15 +1575,15 @@
│ │ │ fi
│ │ │ "${OPENSSL}" req -new -sha256 -key "${certdir}/${privkey}" -out
"${certdir}/cert-${timestamp}.csr" -subj "${SUBJ}" -reqexts SAN -config
"${tmp_openssl_cnf}"
│ │ │ rm -f "${tmp_openssl_cnf}"
│ │ │ fi
│ │ │
│ │ │ crt_path="${certdir}/cert-${timestamp}.pem"
│ │ │ # shellcheck disable=SC2086
│ │ │ - sign_csr "$(< "${certdir}/cert-${timestamp}.csr")" ${altnames}
3>"${crt_path}"
│ │ │ + sign_csr "${certdir}/cert-${timestamp}.csr" ${altnames} 3>"${crt_path}"
│ │ │
│ │ │ # Create fullchain.pem
│ │ │ echo " + Creating fullchain.pem..."
│ │ │ if [[ ${API} -eq 1 ]]; then
│ │ │ cat "${crt_path}" > "${certdir}/fullchain-${timestamp}.pem"
│ │ │ local issuer_hash
│ │ │ issuer_hash="$(get_issuer_hash "${crt_path}")"
│ │ │ @@ -1771,15 +1840,15 @@
│ │ │ rm "${aftervars}"
│ │ │ ); do
│ │ │ config_var="$(echo "${cfgline:1}" | cut -d'=' -f1)"
│ │ │ config_value="$(echo "${cfgline:1}" | cut -d'=' -f2- | tr -d
"'")"
│ │ │ # All settings that are allowed here should also be stored and
│ │ │ # restored in store_configvars() and reset_configvars()
│ │ │ case "${config_var}" in
│ │ │ -
KEY_ALGO|OCSP_MUST_STAPLE|OCSP_FETCH|OCSP_DAYS|PRIVATE_KEY_RENEW|PRIVATE_KEY_ROLLOVER|KEYSIZE|CHALLENGETYPE|HOOK|PREFERRED_CHAIN|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS)
│ │ │ +
KEY_ALGO|OCSP_MUST_STAPLE|OCSP_FETCH|OCSP_DAYS|PRIVATE_KEY_RENEW|PRIVATE_KEY_ROLLOVER|KEYSIZE|CHALLENGETYPE|HOOK|PREFERRED_CHAIN|WELLKNOWN|HOOK_CHAIN|OPENSSL_CNF|RENEW_DAYS|ACME_PROFILE|ORDER_TIMEOUT)
│ │ │ echo " + ${config_var} = ${config_value}"
│ │ │ declare -- "${config_var}=${config_value}"
│ │ │ ;;
│ │ │ _) ;;
│ │ │ *) echo " ! Setting ${config_var} on a per-certificate base
is not (yet) supported" >&2
│ │ │ esac
│ │ │ done
│ │ │ @@ -1788,24 +1857,26 @@
│ │ │ verify_config
│ │ │ hookscript_bricker_hook
│ │ │ export WELLKNOWN CHALLENGETYPE KEY_ALGO PRIVATE_KEY_ROLLOVER
│ │ │
│ │ │ skip="no"
│ │ │
│ │ │ # Allow for external CSR generation
│ │ │ - local csr=""
│ │ │ + local csrfile=""
│ │ │ if [[ -n "${HOOK}" ]]; then
│ │ │ csr="$("${HOOK}" "generate_csr" "${domain}" "${certdir}"
"${domain} ${morenames}")" || _exiterr 'generate_csr hook returned with
non-zero exit code'
│ │ │ if grep -qE "\-----BEGIN (NEW )?CERTIFICATE REQUEST-----" <<<
"${csr}"; then
│ │ │ - altnames="$(extract_altnames "${csr}")"
│ │ │ + csrfile="$(_mktemp)"
│ │ │ + cat > "${csrfile}" <<< "${csr}"
│ │ │ + altnames="$(extract_altnames "${csrfile}")"
│ │ │ domain="$(cut -d' ' -f1 <<< "${altnames}")"
│ │ │ morenames="$(cut -s -d' ' -f2- <<< "${altnames}")"
│ │ │ echo " + Using CSR from hook script (real names: ${altnames})"
│ │ │ else
│ │ │ - csr=""
│ │ │ + csrfile=""
│ │ │ fi
│ │ │ fi
│ │ │
│ │ │ # Check domain names of existing certificate
│ │ │ if [[ -e "${cert}" && "${force_renew}" = "no" ]]; then
│ │ │ printf " + Checking domain name(s) of existing cert..."
│ │ │
│ │ │ @@ -1847,15 +1918,18 @@
│ │ │
│ │ │ local update_ocsp
│ │ │ update_ocsp="no"
│ │ │
│ │ │ # Sign certificate for this domain
│ │ │ if [[ ! "${skip}" = "yes" ]]; then
│ │ │ update_ocsp="yes"
│ │ │ - [[ -z "${csr}" ]] || printf "%s" "${csr}" >
"${certdir}/cert-${timestamp}.csr"
│ │ │ + if [[ -n "${csrfile}" ]]; then
│ │ │ + cat "${csrfile}" > "${certdir}/cert-${timestamp}.csr"
│ │ │ + rm "${csrfile}"
│ │ │ + fi
│ │ │ # shellcheck disable=SC2086
│ │ │ if [[ "${PARAM_KEEP_GOING:-}" = "yes" ]]; then
│ │ │ skip_exit_hook=yes
│ │ │ sign_domain "${certdir}" "${timestamp}" "${domain}" ${morenames}
&
│ │ │ wait $! || exit_with_errorcode=1
│ │ │ skip_exit_hook=no
│ │ │ else
│ │ │ @@ -1891,16 +1965,16 @@
│ │ │ reset_configvars
│ │ │
│ │ │ # remove temporary domains.txt file if used
│ │ │ [[ -n "${PARAM_DOMAIN:-}" ]] && rm -f "${DOMAINS_TXT}"
│ │ │
│ │ │ [[ -n "${HOOK}" ]] && ("${HOOK}" "exit_hook" || echo 'exit_hook
returned with non-zero exit code!' >&2)
│ │ │ if [[ "${AUTO_CLEANUP}" == "yes" ]]; then
│ │ │ - echo "+ Running automatic cleanup"
│ │ │ - command_cleanup noinit
│ │ │ + echo " + Running automatic cleanup"
│ │ │ + PARAM_CLEANUPDELETE="${AUTO_CLEANUP_DELETE:-no}" command_cleanup
noinit | _sed 's/^/ + /g'
│ │ │ fi
│ │ │
│ │ │ exit "${exit_with_errorcode}"
│ │ │ }
│ │ │
│ │ │ # Usage: --signcsr (-s) path/to/csr.pem
│ │ │ # Description: Sign a given CSR, output CRT on stdout (advanced usage)
│ │ │ @@ -1908,27 +1982,26 @@
│ │ │ init_system
│ │ │
│ │ │ # redirect stdout to stderr
│ │ │ # leave stdout over at fd 3 to output the cert
│ │ │ exec 3>&1 1>&2
│ │ │
│ │ │ # load csr
│ │ │ - csrfile="${1}"
│ │ │ + local csrfile="${1}"
│ │ │ if [ ! -r "${csrfile}" ]; then
│ │ │ _exiterr "Could not read certificate signing request ${csrfile}"
│ │ │ fi
│ │ │ - csr="$(cat "${csrfile}")"
│ │ │
│ │ │ # extract names
│ │ │ - altnames="$(extract_altnames "${csr}")"
│ │ │ + altnames="$(extract_altnames "${csrfile}")"
│ │ │
│ │ │ # gen cert
│ │ │ certfile="$(_mktemp)"
│ │ │ # shellcheck disable=SC2086
│ │ │ - sign_csr "${csr}" ${altnames} 3> "${certfile}"
│ │ │ + sign_csr "${csrfile}" ${altnames} 3> "${certfile}"
│ │ │
│ │ │ # print cert
│ │ │ echo "# CERT #" >&3
│ │ │ cat "${certfile}" >&3
│ │ │ echo >&3
│ │ │
│ │ │ # print chain
│ │ │ @@ -2360,14 +2433,31 @@
│ │ │ # PARAM_Usage: --algo (-a) rsa|prime256v1|secp384r1
│ │ │ # PARAM_Description: Which public key algorithm should be used?
Supported: rsa, prime256v1 and secp384r1
│ │ │ --algo|-a)
│ │ │ shift 1
│ │ │ check_parameters "${1:-}"
│ │ │ PARAM_KEY_ALGO="${1}"
│ │ │ ;;
│ │ │ +
│ │ │ + # PARAM_Usage: --acme-profile profile_name
│ │ │ + # PARAM_Description: Use specified ACME profile
│ │ │ + --acme-profile)
│ │ │ + shift 1
│ │ │ + check_parameters "${1:-}"
│ │ │ + PARAM_ACME_PROFILE="${1}"
│ │ │ + ;;
│ │ │ +
│ │ │ + # PARAM_Usage: --order-timeout seconds
│ │ │ + # PARAM_Description: Amount of seconds to wait for processing of
order until erroring out
│ │ │ + --order-timeout)
│ │ │ + shift 1
│ │ │ + check_parameters "${1:-}"
│ │ │ + PARAM_ORDER_TIMEOUT=${1}
│ │ │ + ;;
│ │ │ +
│ │ │ *)
│ │ │ echo "Unknown parameter detected: ${1}" >&2
│ │ │ echo >&2
│ │ │ command_help >&2
│ │ │ exit 1
│ │ │ ;;
│ │ │ esac
│ │ ├── ./usr/share/doc/dehydrated/README.md.gz
│ │ │ ├── README.md
│ │ │ │ @@ -81,14 +81,16 @@
│ │ │ │ --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|tls-alpn-01 Which challenge should be
used? Currently http-01, dns-01, and tls-alpn-01 are supported
│ │ │ │ --algo (-a) rsa|prime256v1|secp384r1 Which public key algorithm
should be used? Supported: rsa, prime256v1 and secp384r1
│ │ │ │ + --acme-profile profile_name Use specified ACME profile
│ │ │ │ + --order-timeout seconds Amount of seconds to wait for
processing of order until erroring out
│ │ │ │ ```
│ │ │ │
│ │ │ │ ## Chat
│ │ │ │
│ │ │ │ Dehydrated has an official IRC-channel `#dehydrated` on libera.chat
that can be used for general discussion and suggestions.
│ │ │ │
│ │ │ │ The channel can also be accessed with Matrix using the official
libera.chat bridge at `#dehydrated:libera.chat`.
│ │ ├── ./usr/share/doc/dehydrated/changelog.Debian.gz
│ │ │ ├── changelog.Debian
│ │ │ │ @@ -1,7 +1,17 @@
│ │ │ │ +dehydrated (0.7.2-1) unstable; urgency=medium
│ │ │ │ +
│ │ │ │ + * New upstream release 0.7.2.
│ │ │ │ + * Update copyright.
│ │ │ │ + * Drop all patches applied upstream.
│ │ │ │ + * Add patches from upstream after the 0.7.2 release.
│ │ │ │ + * Bump Standards-Version to 4.7.2, no changes needed.
│ │ │ │ +
│ │ │ │ + -- Mattia Rizzolo <mat...@debian.org> Mon, 02 Jun 2025 16:50:35 +0200
│ │ │ │ +
│ │ │ │ dehydrated (0.7.1-1) unstable; urgency=medium
│ │ │ │
│ │ │ │ * New upstream release 0.7.1. Closes: #1023655
│ │ │ │ * Update watch file.
│ │ │ │ Thanks to Beat Bolli <me+...@drbeat.li> for the patch
│ │ │ │ * Update copyright.
│ │ │ │ * Remove all patches applied upstream.
│ │ ├── ./usr/share/doc/dehydrated/changelog.gz
│ │ │ ├── changelog
│ │ │ │ @@ -1,10 +1,23 @@
│ │ │ │ # Change Log
│ │ │ │ This file contains a log of major changes in dehydrated
│ │ │ │
│ │ │ │ +## [0.7.2] - 2025-05-18
│ │ │ │ +## Added
│ │ │ │ +- Implemented support for certificate profile selection
│ │ │ │ +- Added a configuration parameter to allow for timeouts during order
processing (`ORDER_TIMEOUT`, defaults to 0 = no timeout)
│ │ │ │ +- Allowed for automatic deletion of old files (`AUTO_CLEANUP_DELETE`,
disabled by default)
│ │ │ │ +- Added CA presets for Google Trust Services (prod: google, test:
google-test)
│ │ │ │ +
│ │ │ │ +## Changed
│ │ │ │ +- Renew certificates with 32 days remaining (instead of 30) to avoid
issues with monthly cronjobs (`RENEW_DAYS=32`)
│ │ │ │ +
│ │ │ │ +## Fixed
│ │ │ │ +- Changed behaviour of `openssl req` stdin handling to fix
compatibility with OpenSSL version 3.2+
│ │ │ │ +
│ │ │ │ ## [0.7.1] - 2022-10-31
│ │ │ │ ## Changed
│ │ │ │ - `--force` no longer forces domain name revalidation by default, a
new argument `--force-validation` has been added for that
│ │ │ │ - Added support for EC secp521r1 algorithm (works with e.g. zerossl)
│ │ │ │ - `EC PARAMETERS` are no longer written to privkey.pem (didn't seem
necessary and was causing issues with various software)
│ │ │ │
│ │ │ │ ## Fixed
│ │ ├── ./usr/share/doc/dehydrated/copyright
│ │ │ @@ -5,15 +5,15 @@
│ │ │
│ │ │ Files: *
│ │ │ Copyright: 2015-2021 Lukas Schauer
│ │ │ License: Expat
│ │ │
│ │ │ Files: debian/*
│ │ │ Copyright: 2016 Daniel Beyer <d...@deb.ymc.ch>
│ │ │ - 2016-2024 Mattia Rizzolo <mat...@debian.org>
│ │ │ + 2016-2025 Mattia Rizzolo <mat...@debian.org>
│ │ │ License: Expat
│ │ │
│ │ │ License: Expat
│ │ │ Permission is hereby granted, free of charge, to any person obtaining a
copy
│ │ │ of this software and associated documentation files (the "Software"),
to deal
│ │ │ in the Software without restriction, including without limitation the
rights
│ │ │ to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell
│ │ ├── ./usr/share/doc/dehydrated/docs/logo.png
│ │ │ ├── sng
│ │ │ │ @@ -16,37 +16,37 @@
│ │ │ │ }
│ │ │ │ bKGD {red: 255; green: 255; blue: 255;}
│ │ │ │ pHYs {xpixels: 5487; ypixels: 5487; per: meter;} # (139 dpi)
│ │ │ │ private orNT {
│ │ │ │ base64 1;
│ │ │ │ }
│ │ │ │ tIME {
│ │ │ │ - # 27 Jul 2024 06:13:05 GMT
│ │ │ │ - year: 2024
│ │ │ │ - month: 7
│ │ │ │ - day: 27
│ │ │ │ - hour: 6
│ │ │ │ - minute: 13
│ │ │ │ - second: 5
│ │ │ │ + # 2 Jun 2025 14:50:35 GMT
│ │ │ │ + year: 2025
│ │ │ │ + month: 6
│ │ │ │ + day: 2
│ │ │ │ + hour: 14
│ │ │ │ + minute: 50
│ │ │ │ + second: 35
│ │ │ │ }
│ │ │ │ zTXt {
│ │ │ │ keyword: "Raw profile type icc";
│ │ │ │ text: "\nicc\n
672\n000002a06c636d73043000006d6e74725247422058595a2007e5000b0001001200080025\n616373704150504c0000000000000000000000000000000000000000000000000000f6d6\n000100000000d32d6c636d73000000000000000000000000000000000000000000000000\n00000000000000000000000000000000000000000000000d646573630000012000000040\n63707274000001600000003677747074000001980000001463686164000001ac0000002c\n7258595a000001d8000000146258595a000001ec000000146758595a0000020000000014\n725452430000021400000020675452430000021400000020625452430000021400000020\n6368726d0000023400000024646d6e640000025800000024646d64640000027c00000024\n6d6c756300000000000000010000000c656e5553000000240000001c00470049004d0050\n0020006200750069006c0074002d0069006e002000730052004700426d6c756300000000\n000000010000000c656e55530000001a0000001c005000750062006c0069006300200044\n006f006d00610069006e000058595a20000000000000f6d6000100000000d32d73663332\n0000000000010c42000005defffff325000007930000fd90fffffba1fffffda2000003dc\n0000c06e58595a200000000000006fa0000038f50000039058595a20000000000000249f\n00000f840000b6c458595a2000000000000062970000b787000018d97061726100000000\n00030000000266660000f2a700000d59000013d000000a5b6368726d0000000000030000\n0000a3d70000547c00004ccd0000999a0000266700000f5c6d6c75630000000000000001\n0000000c656e5553000000080000001c00470049004d00506d6c75630000000000000001\n0000000c656e5553000000080000001c0073005200470042\n";
│ │ │ │ }
│ │ │ │ zTXt {
│ │ │ │ keyword: "Raw profile type xmp";
│ │ │ │ text: "\nxmp\n
3332\n3c3f787061636b657420626567696e3d22efbbbf222069643d2257354d304d7043656869\n487a7265537a4e54637a6b633964223f3e0a3c783a786d706d65746120786d6c6e733a78\n3d2261646f62653a6e733a6d6574612f2220783a786d70746b3d22584d5020436f726520\n342e342e302d4578697632223e0a203c7264663a52444620786d6c6e733a7264663d2268\n7474703a2f2f7777772e77332e6f72672f313939392f30322f32322d7264662d73796e74\n61782d6e7323223e0a20203c7264663a4465736372697074696f6e207264663a61626f75\n743d22220a20202020786d6c6e733a786d704d4d3d22687474703a2f2f6e732e61646f62\n652e636f6d2f7861702f312e302f6d6d2f220a20202020786d6c6e733a73744576743d22\n687474703a2f2f6e732e61646f62652e636f6d2f7861702f312e302f73547970652f5265\n736f757263654576656e7423220a20202020786d6c6e733a64633d22687474703a2f2f70\n75726c2e6f72672f64632f656c656d656e74732f312e312f220a20202020786d6c6e733a\n47494d503d22687474703a2f2f7777772e67696d702e6f72672f786d702f220a20202020\n786d6c6e733a746966663d22687474703a2f2f6e732e61646f62652e636f6d2f74696666\n2f312e302f220a20202020786d6c6e733a786d703d22687474703a2f2f6e732e61646f62\n652e636f6d2f7861702f312e302f220a202020786d704d4d3a446f63756d656e7449443d\n2267696d703a646f6369643a67696d703a30643137303065362d653962652d346238302d\n613733642d646563313266373034613536220a202020786d704d4d3a496e7374616e6365\n49443d22786d702e6969643a33643638633035372d333334612d343361642d616438362d\n363965623030303830646162220a202020786d704d4d3a4f726967696e616c446f63756d\n656e7449443d22786d702e6469643a64343637313964362d343264302d343534322d3931\n30342d303362616638313161376533220a20202064633a466f726d61743d22696d616765\n2f706e67220a20202047494d503a4150493d22322e30220a20202047494d503a506c6174\n666f726d3d224c696e7578220a20202047494d503a54696d655374616d703d2231363335\n373930323333313237323434220a20202047494d503a56657273696f6e3d22322e31302e\n3238220a202020746966663a4f7269656e746174696f6e3d2231220a202020786d703a43\n726561746f72546f6f6c3d2247494d5020322e3130223e0a2020203c786d704d4d3a4869\n73746f72793e0a202020203c7264663a5365713e0a20202020203c7264663a6c690a2020\n2020202073744576743a616374696f6e3d227361766564220a2020202020207374457674\n3a6368616e6765643d222f220a20202020202073744576743a696e7374616e636549443d\n22786d702e6969643a61643862333566332d333134332d346239312d383631372d346138\n396162633864376662220a20202020202073744576743a736f6674776172654167656e74\n3d2247696d7020322e313020284c696e757829220a20202020202073744576743a776865\n6e3d22323032312d31312d30315431393a31303a33332b30313a3030222f3e0a20202020\n3c2f7264663a5365713e0a2020203c2f786d704d4d3a486973746f72793e0a20203c2f72\n64663a4465736372697074696f6e3e0a203c2f7264663a5244463e0a3c2f783a786d706d\n6574613e0a20202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n2020202020202020202020202020202020202020202020202020202020202020200a2020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n20202020202020202020202020202020202020202020202020200a202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020200a20202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n2020202020202020202020200a2020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n20202020200a202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020200a20\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n2020202020202020202020202020202020202020202020202020200a2020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n20202020202020202020202020202020202020200a202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020200a20202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n2020202020200a2020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n20202020202020202020202020202020202020202020202020202020202020202020200a\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020200a20202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n2020202020202020202020202020202020202020200a2020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n20202020202020202020202020200a202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020200a20202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n0a2020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n20202020202020202020202020202020202020202020202020202020200a202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020200a20202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n2020202020202020202020202020200a2020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n202020202020202020202020202020202020202020202020202020202020202020202020\n20202020202020200a202020202020202020202020202020202020202020202020202020\n0a3c3f787061636b657420656e643d2277223f3e\n";
│ │ │ │ }
│ │ │ │ tEXt {
│ │ │ │ keyword: "date:create";
│ │ │ │ - text: "2024-07-27T06:13:05-00:00";
│ │ │ │ + text: "2025-06-02T14:50:35-00:00";
│ │ │ │ }
│ │ │ │ tEXt {
│ │ │ │ keyword: "date:modify";
│ │ │ │ - text: "2024-07-27T06:13:05-00:00";
│ │ │ │ + text: "2025-06-02T14:50:35-00:00";
│ │ │ │ }
│ │ │ │ tEXt {
│ │ │ │ keyword: "exif:BitsPerSample";
│ │ │ │ text: "8, 8, 8";
│ │ │ │ }
│ │ │ │ tEXt {
│ │ │ │ keyword: "exif:ColorSpace";
│ │ ├── ./usr/share/doc/dehydrated/docs/man/dehydrated.1.gz
│ │ │ ├── dehydrated.1
│ │ │ │ @@ -22,15 +22,15 @@
│ │ │ │ based: If the file contains two lines "example.com" and "example.net",
│ │ │ │ dehydrated will request two certificate, one for "example.com" and the
other
│ │ │ │ for "example.net". A single line containing "example.com example.net"
will request a
│ │ │ │ single certificate valid for both "example.net" and "example.com"
through the \fISubject
│ │ │ │ Alternative Name\fR (SAN) field.
│ │ │ │
│ │ │ │ For the next step, one way of verifying domain name ownership needs to
be
│ │ │ │ -configured. Dehydrated implements \fIhttp-01\fR and \fIdns-01\fR
verification.
│ │ │ │ +configured. Dehydrated implements \fIhttp-01\fR and \fIdns-01\fR
verification.
│ │ │ │
│ │ │ │ The \fIhttp-01\fR verification provides proof of ownership by
providing a
│ │ │ │ challenge token. In order to do that, the directory referenced in the
│ │ │ │ \fIWELLKNOWN\fR config variable needs to be exposed at
│ │ │ │ \fIhttp://{domain}/.well-known/acme-challenge/\fR, where {domain} is
every
│ │ │ │ domain name specified in \fIdomains.txt\fR. Dehydrated does not
provide its
│ │ │ │ own challenge responder, but relies on an existing web server to
provide the
│ │ │ │ @@ -135,21 +135,21 @@
│ │ │ │ .BR \-\-algo ", " \-a " " \fI[rsa|prime256v1|secp384r1]\fR
│ │ │ │ Which public key algorithm should be used? Supported: rsa, prime256v1
and
│ │ │ │ secp384r1
│ │ │ │ .SH DIAGNOSTICS
│ │ │ │ The program exits 0 if everything was fine, 1 if an error occurred.
│ │ │ │ .SH BUGS
│ │ │ │ Please report any bugs that you may encounter at the project web site
│ │ │ │ -.UR https://github.com/lukas2511/dehydrated/issues
│ │ │ │ +.UR https://github.com/dehydrated-io/dehydrated/issues
│ │ │ │ .UE .
│ │ │ │ .SH AUTHOR
│ │ │ │ Dehydrated was written by Lukas Schauer. This man page was contributed
by
│ │ │ │ Daniel Molkentin.
│ │ │ │ .SH COPYRIGHT
│ │ │ │ Copyright 2015-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
│ │ │ │ Full documentation along with configuration examples are provided in
the \fIdocs\fR
│ │ │ │ directory of the distribution, or at
│ │ │ │ -.UR https://github.com/lukas2511/dehydrated/tree/master/docs
│ │ │ │ +.UR https://github.com/dehydrated-io/dehydrated/tree/master/docs
│ │ │ │ .UE .
│ │ ├── ./usr/share/doc/dehydrated/examples/config
│ │ │ @@ -18,15 +18,15 @@
│ │ │
│ │ │ # Resolve names to addresses of IP version only. (curl)
│ │ │ # supported values: 4, 6
│ │ │ # default: <unset>
│ │ │ #IP_VERSION=
│ │ │
│ │ │ # URL to certificate authority or internal preset
│ │ │ -# Presets: letsencrypt, letsencrypt-test, zerossl, buypass, buypass-test
│ │ │ +# Presets: letsencrypt, letsencrypt-test, zerossl, buypass,
buypass-test, google, google-test
│ │ │ # default: letsencrypt
│ │ │ #CA="letsencrypt"
│ │ │
│ │ │ # 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.
│ │ │ @@ -88,16 +88,16 @@
│ │ │ # BASEDIR and WELLKNOWN variables are exported and can be used in an
external program
│ │ │ # default: <unset>
│ │ │ #HOOK=
│ │ │
│ │ │ # Chain clean_challenge|deploy_challenge arguments together into one
hook call per certificate (default: no)
│ │ │ #HOOK_CHAIN="no"
│ │ │
│ │ │ -# Minimum days before expiration to automatically renew certificate
(default: 30)
│ │ │ -#RENEW_DAYS="30"
│ │ │ +# Minimum days before expiration to automatically renew certificate
(default: 32)
│ │ │ +#RENEW_DAYS="32"
│ │ │
│ │ │ # Regenerate private keys instead of just signing new certificates on
renewal (default: yes)
│ │ │ #PRIVATE_KEY_RENEW="yes"
│ │ │
│ │ │ # Create an extra private key for rollover (default: no)
│ │ │ #PRIVATE_KEY_ROLLOVER="no"
│ │ │
│ │ │ @@ -121,12 +121,21 @@
│ │ │
│ │ │ # Issuer chain cache directory (default: $BASEDIR/chains)
│ │ │ #CHAINCACHE="${BASEDIR}/chains"
│ │ │
│ │ │ # Automatic cleanup (default: no)
│ │ │ #AUTO_CLEANUP="no"
│ │ │
│ │ │ +# Delete files during automatic cleanup instead of moving to archive
(default: no)
│ │ │ +#AUTO_CLEANUP_DELETE="no"
│ │ │ +
│ │ │ # ACME API version (default: auto)
│ │ │ #API=auto
│ │ │
│ │ │ # Preferred issuer chain (default: <unset> -> uses default chain)
│ │ │ #PREFERRED_CHAIN=
│ │ │ +
│ │ │ +# Request certificate with specific profile (default: <unset>)
│ │ │ +#ACME_PROFILE=
│ │ │ +
│ │ │ +# Amount of seconds to wait for processing of order until erroring out
(default: 0 => no timeout)
│ │ │ +#ORDER_TIMEOUT=0
│ │ ├── ./usr/share/man/man1/dehydrated.1.gz
│ │ │ ├── dehydrated.1
│ │ │ │ @@ -22,15 +22,15 @@
│ │ │ │ based: If the file contains two lines "example.com" and "example.net",
│ │ │ │ dehydrated will request two certificate, one for "example.com" and the
other
│ │ │ │ for "example.net". A single line containing "example.com example.net"
will request a
│ │ │ │ single certificate valid for both "example.net" and "example.com"
through the \fISubject
│ │ │ │ Alternative Name\fR (SAN) field.
│ │ │ │
│ │ │ │ For the next step, one way of verifying domain name ownership needs to
be
│ │ │ │ -configured. Dehydrated implements \fIhttp-01\fR and \fIdns-01\fR
verification.
│ │ │ │ +configured. Dehydrated implements \fIhttp-01\fR and \fIdns-01\fR
verification.
│ │ │ │
│ │ │ │ The \fIhttp-01\fR verification provides proof of ownership by
providing a
│ │ │ │ challenge token. In order to do that, the directory referenced in the
│ │ │ │ \fIWELLKNOWN\fR config variable needs to be exposed at
│ │ │ │ \fIhttp://{domain}/.well-known/acme-challenge/\fR, where {domain} is
every
│ │ │ │ domain name specified in \fIdomains.txt\fR. Dehydrated does not
provide its
│ │ │ │ own challenge responder, but relies on an existing web server to
provide the
│ │ │ │ @@ -135,21 +135,21 @@
│ │ │ │ .BR \-\-algo ", " \-a " " \fI[rsa|prime256v1|secp384r1]\fR
│ │ │ │ Which public key algorithm should be used? Supported: rsa, prime256v1
and
│ │ │ │ secp384r1
│ │ │ │ .SH DIAGNOSTICS
│ │ │ │ The program exits 0 if everything was fine, 1 if an error occurred.
│ │ │ │ .SH BUGS
│ │ │ │ Please report any bugs that you may encounter at the project web site
│ │ │ │ -.UR https://github.com/lukas2511/dehydrated/issues
│ │ │ │ +.UR https://github.com/dehydrated-io/dehydrated/issues
│ │ │ │ .UE .
│ │ │ │ .SH AUTHOR
│ │ │ │ Dehydrated was written by Lukas Schauer. This man page was contributed
by
│ │ │ │ Daniel Molkentin.
│ │ │ │ .SH COPYRIGHT
│ │ │ │ Copyright 2015-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
│ │ │ │ Full documentation along with configuration examples are provided in
the \fIdocs\fR
│ │ │ │ directory of the distribution, or at
│ │ │ │ -.UR https://github.com/lukas2511/dehydrated/tree/master/docs
│ │ │ │ +.UR https://github.com/dehydrated-io/dehydrated/tree/master/docs
│ │ │ │ .UE .
signature.asc
Description: PGP signature
--- End Message ---