Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package dehydrated for openSUSE:Factory 
checked in at 2022-11-01 13:42:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/dehydrated (Old)
 and      /work/SRC/openSUSE:Factory/.dehydrated.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "dehydrated"

Tue Nov  1 13:42:48 2022 rev:25 rq:1032541 version:0.7.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/dehydrated/dehydrated.changes    2022-09-08 
14:23:53.974702926 +0200
+++ /work/SRC/openSUSE:Factory/.dehydrated.new.2275/dehydrated.changes  
2022-11-01 13:42:50.191981722 +0100
@@ -1,0 +2,7 @@
+Sat Oct 29 05:03:26 UTC 2022 - Daniel Molkentin <dan...@molkentin.de>
+
+- Update to 0.7.1
+  * See https://github.com/dehydrated-io/dehydrated/releases/tag/v0.7.1 
+  * Removes more-examples.patch
+
+-------------------------------------------------------------------

Old:
----
  dehydrated-0.7.0.tar.gz
  dehydrated-0.7.0.tar.gz.asc
  more-examples.patch

New:
----
  dehydrated-0.7.1.tar.gz
  dehydrated-0.7.1.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ dehydrated.spec ++++++
--- /var/tmp/diff_new_pack.iceFQx/_old  2022-11-01 13:42:51.739989957 +0100
+++ /var/tmp/diff_new_pack.iceFQx/_new  2022-11-01 13:42:51.783990191 +0100
@@ -53,7 +53,7 @@
 %endif
 
 Name:           dehydrated
-Version:        0.7.0
+Version:        0.7.1
 Release:        0
 Summary:        A client for signing certificates with an ACME server
 License:        MIT
@@ -77,7 +77,6 @@
 Source18:       dehydrated-postrun-hooks.service
 Source19:       dehydrated-postrun-hooks@.service
 Source20:       README.postrun-hooks
-Patch:          more-examples.patch
 BuildRequires:  %{_apache}
 Requires:       coreutils
 Requires:       curl
@@ -172,7 +171,6 @@
 
 %prep
 %setup -q
-%patch -p1
 cp %{SOURCE9} .
 cp %{SOURCE10} .
 cp %{SOURCE20} .
@@ -206,10 +204,12 @@
 #!/bin/sh
 systemctl reload apache2.service
 EOF
+%if %{with nginx}
 cat > %{buildroot}%{_sysconfdir}/dehydrated/postrun-hooks.d/reload-nginx.sh << 
EOF
 #!/bin/sh
 systemctl reload nginx.service
 EOF
+%endif
 
 %if %{with nginx}
 install -m 0755 -d %{buildroot}%{_sysconfdir}/nginx
@@ -280,7 +280,7 @@
 %{_bindir}/dehydrated
 %attr(-,%{_user},root) %dir %{_localstatedir}/lib/acme-challenge
 %{_mandir}/man1/*
-%doc LICENSE README.md docs/*.md docs/*.jpg
+%doc LICENSE README.md docs/*.md
 %doc README.maintainer
 %if %{defined redhat}
 %doc README.Fedora

++++++ dehydrated-0.7.0.tar.gz -> dehydrated-0.7.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/CHANGELOG 
new/dehydrated-0.7.1/CHANGELOG
--- old/dehydrated-0.7.0/CHANGELOG      2020-12-10 16:54:26.000000000 +0100
+++ new/dehydrated-0.7.1/CHANGELOG      2022-10-31 15:12:38.000000000 +0100
@@ -1,6 +1,21 @@
 # Change Log
 This file contains a log of major changes in dehydrated
 
+## [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
+- Requests resulting in `badNonce` errors are now automatically retried (fixes 
operation with LE staging servers)
+- Deprecated `egrep` usage has been removed
+
+## Added
+- Implemented EC for account keys
+- Domain list now also read from domains.txt.d subdirectory (behaviour might 
change, see docs)
+- Implemented RFC 8738 (validating/signing certificates for IP addresses 
instead of domain names) support (this will not work with most public CAs, if 
any!)
+
 ## [0.7.0] - 2020-12-10
 ## Added
 - Support for external account bindings
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/LICENSE new/dehydrated-0.7.1/LICENSE
--- old/dehydrated-0.7.0/LICENSE        2020-12-10 16:54:26.000000000 +0100
+++ new/dehydrated-0.7.1/LICENSE        2022-10-31 15:12:38.000000000 +0100
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2015-2018 Lukas Schauer
+Copyright (c) 2015-2021 Lukas Schauer
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/README.md 
new/dehydrated-0.7.1/README.md
--- old/dehydrated-0.7.0/README.md      2020-12-10 16:54:26.000000000 +0100
+++ new/dehydrated-0.7.1/README.md      2022-10-31 15:12:38.000000000 +0100
@@ -1,9 +1,6 @@
 # dehydrated 
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=23P9DSJBTY7C8)
 
-Quick note: dehydrated moved, the license will NOT change, and I will still 
take care of the project.
-See https://lukas.im/2020/01/30/selling-dehydrated/index.html for more details.
-
-![](docs/logo.jpg)
+![](docs/logo.png)
 
 Dehydrated is a client for signing certificates with an ACME-server (e.g. 
Let's Encrypt) implemented as a relatively simple (zsh-compatible) bash-script.
 This client supports both ACME v1 and the new ACME v2 including support for 
wildcard certificates!
@@ -17,6 +14,7 @@
 - Signing of a custom CSR (either standalone or completely automated using 
hooks!)
 - Renewal if a certificate is about to expire or defined set of domains changed
 - Certificate revocation
+- and lots more..
 
 Please keep in mind that this software, the ACME-protocol and all supported CA 
servers out there are relatively young and there might be a few issues. Feel 
free to report any issues you find with this script or contribute by submitting 
a pull request,
 but please check for duplicates first (feel free to comment on those to get 
things rolling).
@@ -74,6 +72,7 @@
  --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-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)
  --ocsp                           Sets option in CSR indicating OCSP stapling 
to be mandatory
@@ -84,28 +83,6 @@
  --preferred-chain issuer-cn      Use alternative certificate chain identified 
by issuer CN
  --out (-o) certs/directory       Output certificates into the specified 
directory
  --alpn alpn-certs/directory      Output alpn verification certificates into 
the specified directory
- --challenge (-t) http-01|dns-01  Which challenge should be used? Currently 
http-01 and dns-01 are supported
+ --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
 ```
-
-## Donate
-
-I'm a student hacker with a few (unfortunately) quite expensive hobbies 
(self-hosting, virtualization clusters, routing,
-high-speed networking, embedded hardware, etc.).
-I'm really having fun playing around with hard- and software and I'm steadily 
learning new things.
-Without those hobbies I probably would never have started working on 
dehydrated to begin with :)
-
-I'd really appreciate if you could [donate a bit of 
money](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=23P9DSJBTY7C8)
-so I can buy cool stuff (while still being able to afford food :D).  
-
-If you have hardware laying around that you think I'd enjoy playing with (e.g. 
decommissioned but still modern-ish servers,
-10G networking hardware, enterprise grade routers or APs, interesting ARM/MIPS 
boards, etc.) and that you would be willing
-to ship to me please contact me at `donati...@dehydrated.io` or on Twitter 
[@lukas2511](https://twitter.com/lukas2511).
-
-If you want your name to be added to the [donations 
list](https://dehydrated.io/donations.html) please add a note or send me an
-email `donati...@dehydrated.io`. I respect your privacy and won't publish your 
name without permission.
-
-Other ways of donating:
- - [My Amazon Wishlist](http://www.amazon.de/registry/wishlist/1TUCFJK35IO4Q)
- - Monero: 
4Kkf4tF4r9DakxLj37HDXLJgmpVfQoFhT7JLDvXwtUZZMTbsK9spsAPXivWPAFcDUj6jHhY8hJSHX8Cb8ndMhKeQHPSkBZZiK89Fx8NTHk
- - Bitcoin: 12487bHxcrREffTGwUDnoxF1uYxCA7ztKK
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/dehydrated 
new/dehydrated-0.7.1/dehydrated
--- old/dehydrated-0.7.0/dehydrated     2020-12-10 16:54:26.000000000 +0100
+++ new/dehydrated-0.7.1/dehydrated     2022-10-31 15:12:38.000000000 +0100
@@ -17,7 +17,7 @@
 exec 3>&-
 exec 4>&-
 
-VERSION="0.7.0"
+VERSION="0.7.1"
 
 # Find directory in which this script is stored by traversing all symbolic 
links
 SOURCE="${0}"
@@ -31,6 +31,22 @@
 BASEDIR="${SCRIPTDIR}"
 ORIGARGS=("${@}")
 
+noglob_set() {
+  if [[ -n "${ZSH_VERSION:-}" ]]; then
+    set +o noglob
+  else
+    set +f
+  fi
+}
+
+noglob_clear() {
+  if [[ -n "${ZSH_VERSION:-}" ]]; then
+    set -o noglob
+  else
+    set -f
+  fi
+}
+
 # Generate json.sh path matching string
 json_path() {
        if [ ! "${1}" = "-p" ]; then
@@ -55,7 +71,6 @@
 # Get sub-dictionary from json
 get_json_dict_value() {
   local filter
-       echo "$(json_path "${1:-}" "${2:-}")"
   filter="$(printf 's/.*\[%s\][[:space:]]*\(.*\)/\\1/p' "$(json_path "${1:-}" 
"${2:-}")")"
   sed -n "${filter}" | jsonsh
 }
@@ -88,7 +103,7 @@
   awk_egrep () {
     local pattern_string=$1
 
-    gawk '{
+    awk '{
       while ($0) {
         start=match($0, pattern);
         token=substr($0, start, RLENGTH);
@@ -103,14 +118,15 @@
     local ESCAPE
     local CHAR
 
-    if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1
+    if echo "test string" | grep -Eao --color=never "test" >/dev/null 2>&1
     then
-      GREP='egrep -ao --color=never'
+      GREP='grep -Eao --color=never'
     else
-      GREP='egrep -ao'
+      GREP='grep -Eao'
     fi
 
-    if echo "test string" | egrep -o "test" >/dev/null 2>&1
+    # shellcheck disable=SC2196
+    if echo "test string" | grep -Eao "test" >/dev/null 2>&1
     then
       ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
       CHAR='[^[:cntrl:]"\\]'
@@ -126,10 +142,11 @@
     local SPACE='[[:space:]]+'
 
     # Force zsh to expand $A into multiple words
-    local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c 
'^shwordsplit$')
-    if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi
-    $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"
-    if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi
+    local is_wordsplit_disabled
+    is_wordsplit_disabled="$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')"
+    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
   }
 
   parse_array () {
@@ -194,17 +211,14 @@
   }
 
   parse_value () {
-    local jpath="${1:+$1,}${2:-}" isleaf=0 isempty=0 print=0
+    local jpath="${1:+$1,}${2:-}"
     case "$token" in
       '{') parse_object "$jpath" ;;
       '[') 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: "/"
-         value=$(echo "$value" | sed 's#\\/#/#g')
-         isleaf=1
-         [ "$value" = '""' ] && isempty=1
          ;;
     esac
     [ "$value" = '' ] && return
@@ -227,16 +241,26 @@
   tokenize | parse
 }
 
+# Convert IP addresses to their reverse dns variants.
+# Used for ALPN certs as validation for IPs uses this in SNI since IPs aren't 
allowed there.
+ip_to_ptr() {
+  ip="$(cat)"
+  if [[ "${ip}" =~ : ]]; then
+    printf "%sip6.arpa" "$(printf "%s" "${ip}" | awk -F: 'BEGIN {OFS=""; 
}{addCount = 9 - NF; for(i=1; i<=NF;i++){if(length($i) == 0){ 
for(j=1;j<=addCount;j++){$i = ($i "0000");} } else { $i = substr(("0000" $i), 
length($i)+5-4);}}; print}' | rev | sed -e "s/./&./g")"
+  else
+    printf "%s.in-addr.arpa" "$(printf "%s" "${ip}" | awk -F. '{print 
$4"."$3"." $2"."$1}')"
+  fi
+}
+
 # Create (identifiable) temporary files
 _mktemp() {
-  # shellcheck disable=SC2068
-  mktemp ${@:-} "${TMPDIR:-/tmp}/dehydrated-XXXXXX"
+  mktemp "${TMPDIR:-/tmp}/dehydrated-XXXXXX"
 }
 
 # Check for script dependencies
 check_dependencies() {
   # look for required binaries
-  for binary in grep mktemp diff sed awk curl cut; do
+  for binary in grep mktemp diff sed awk curl cut head tail hexdump; do
     bin_path="$(command -v "${binary}" 2>/dev/null)" || _exiterr "This script 
requires ${binary}."
     [[ -x "${bin_path}" ]] || _exiterr "${binary} found in PATH but it's not 
executable"
   done
@@ -254,7 +278,10 @@
 store_configvars() {
   __KEY_ALGO="${KEY_ALGO}"
   __OCSP_MUST_STAPLE="${OCSP_MUST_STAPLE}"
+  __OCSP_FETCH="${OCSP_FETCH}"
+  __OCSP_DAYS="${OCSP_DAYS}"
   __PRIVATE_KEY_RENEW="${PRIVATE_KEY_RENEW}"
+  __PRIVATE_KEY_ROLLOVER="${PRIVATE_KEY_ROLLOVER}"
   __KEYSIZE="${KEYSIZE}"
   __CHALLENGETYPE="${CHALLENGETYPE}"
   __HOOK="${HOOK}"
@@ -269,7 +296,10 @@
 reset_configvars() {
   KEY_ALGO="${__KEY_ALGO}"
   OCSP_MUST_STAPLE="${__OCSP_MUST_STAPLE}"
+  OCSP_FETCH="${__OCSP_FETCH}"
+  OCSP_DAYS="${__OCSP_DAYS}"
   PRIVATE_KEY_RENEW="${__PRIVATE_KEY_RENEW}"
+  PRIVATE_KEY_ROLLOVER="${__PRIVATE_KEY_ROLLOVER}"
   KEYSIZE="${__KEYSIZE}"
   CHALLENGETYPE="${__CHALLENGETYPE}"
   HOOK="${__HOOK}"
@@ -298,7 +328,7 @@
   if [[ "${CHALLENGETYPE}" = "http-01" && ! -d "${WELLKNOWN}" && ! 
"${COMMAND:-}" = "register" ]]; then
     _exiterr "WELLKNOWN directory doesn't exist, please create ${WELLKNOWN} 
and set appropriate permissions."
   fi
-  [[ "${KEY_ALGO}" == "rsa" || "${KEY_ALGO}" == "prime256v1" || "${KEY_ALGO}" 
== "secp384r1" ]] || _exiterr "Unknown public key algorithm ${KEY_ALGO}... 
cannot continue."
+  [[ "${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
@@ -332,6 +362,8 @@
   CERTDIR=
   ALPNCERTDIR=
   ACCOUNTDIR=
+  ACCOUNT_KEYSIZE="4096"
+  ACCOUNT_KEY_ALGO=rsa
   CHALLENGETYPE="http-01"
   CONFIG_D=
   CURL_OPTS=
@@ -379,7 +411,7 @@
     fi
 
     # Allow globbing
-    [[ -n "${ZSH_VERSION:-}" ]] && set +o noglob || set +f
+    noglob_set
 
     for check_config_d in "${CONFIG_D}"/*.sh; do
       if [[ -f "${check_config_d}" ]] && [[ -r "${check_config_d}" ]]; then
@@ -392,7 +424,7 @@
     done
 
     # Disable globbing
-    [[ -n "${ZSH_VERSION:-}" ]] && set -o noglob || set -f
+    noglob_clear
   fi
 
   # Check for missing dependencies
@@ -473,6 +505,7 @@
     fi
   fi
 
+  # shellcheck disable=SC1090
   [[ -f "${ACCOUNTDIR}/${CAHASH}/config" ]] && . 
"${ACCOUNTDIR}/${CAHASH}/config"
   ACCOUNT_KEY="${ACCOUNTDIR}/${CAHASH}/account_key.pem"
   ACCOUNT_KEY_JSON="${ACCOUNTDIR}/${CAHASH}/registration_info.json"
@@ -512,6 +545,10 @@
   [[ -n "${PARAM_OCSP_MUST_STAPLE:-}" ]] && 
OCSP_MUST_STAPLE="${PARAM_OCSP_MUST_STAPLE}"
   [[ -n "${PARAM_IP_VERSION:-}" ]] && IP_VERSION="${PARAM_IP_VERSION}"
 
+  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
   fi
@@ -539,8 +576,8 @@
     grep -q newOrder <<< "${CA_DIRECTORY}" && API=2 || API=1
   fi
 
-  if [[ ${API} -eq 1 ]]; then
-    # shellcheck disable=SC2015
+  # shellcheck disable=SC2015
+  if [[ "${API}" = "1" ]]; then
     CA_NEW_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value 
new-cert)" &&
     CA_NEW_AUTHZ="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value 
new-authz)" &&
     CA_NEW_REG="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value 
new-reg)" &&
@@ -551,7 +588,6 @@
     # 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}
   else
-    # shellcheck disable=SC2015
     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)" &&
@@ -559,8 +595,6 @@
     CA_REQUIRES_EAB="$(printf "%s" "${CA_DIRECTORY}" | get_json_bool_value -p 
'"meta","externalAccountRequired"' || echo false)" &&
     CA_REVOKE_CERT="$(printf "%s" "${CA_DIRECTORY}" | get_json_string_value 
revokeCert)" ||
     _exiterr "Problem retrieving ACME/CA-URLs, check if your configured CA 
points to the directory entrypoint."
-    # Since acct URI is missing from directory we will assume it is the same 
as CA_NEW_ACCOUNT without the new part
-    CA_ACCOUNT=${CA_NEW_ACCOUNT/new-acct/acct}
   fi
 
   # Export some environment variables to be used in hook script
@@ -582,26 +616,63 @@
       if [[ ! "${PARAM_ACCEPT_TERMS:-}" = "yes" ]]; then
         printf '\n' >&2
         printf 'To use dehydrated with this certificate authority you have to 
agree to their terms of service which you can find here: %s\n\n' "${CA_TERMS}" 
>&2
-        printf 'To accept these terms of service run `%s --register 
--accept-terms`.\n' "${0}" >&2
+        printf 'To accept these terms of service run "%s --register 
--accept-terms".\n' "${0}" >&2
         exit 1
       fi
 
       echo "+ Generating account key..."
       generated="true"
-      local tmp_account_key="$(_mktemp)"
-      _openssl genrsa -out "${tmp_account_key}" "${KEYSIZE}"
+      local tmp_account_key
+      tmp_account_key="$(_mktemp)"
+      if [[ ${API} -eq 1 && ! "${ACCOUNT_KEY_ALGO}" = "rsa" ]]; then
+        _exiterr "ACME API version 1 does not support EC account keys"
+      fi
+      case "${ACCOUNT_KEY_ALGO}" in
+        rsa) _openssl genrsa -out "${tmp_account_key}" "${ACCOUNT_KEYSIZE}";;
+        prime256v1|secp384r1|secp521r1) _openssl ecparam -genkey -name 
"${ACCOUNT_KEY_ALGO}" -out "${tmp_account_key}" -noout;;
+      esac
       cat "${tmp_account_key}" > "${ACCOUNT_KEY}"
       rm "${tmp_account_key}"
       register_new_key="yes"
     fi
   fi
-  "${OPENSSL}" rsa -in "${ACCOUNT_KEY}" -check 2>/dev/null > /dev/null || 
_exiterr "Account key is not valid, cannot continue."
 
-  # Get public components from private key and calculate thumbprint
-  pubExponent64="$(printf '%x' "$("${OPENSSL}" rsa -in "${ACCOUNT_KEY}" -noout 
-text | awk '/publicExponent/ {print $2}')" | hex2bin | urlbase64)"
-  pubMod64="$("${OPENSSL}" rsa -in "${ACCOUNT_KEY}" -noout -modulus | cut 
-d'=' -f2 | hex2bin | urlbase64)"
+  if ("${OPENSSL}" rsa -in "${ACCOUNT_KEY}" -check 2>/dev/null > /dev/null); 
then
+    # Get public components from private key and calculate thumbprint
+    pubExponent64="$(printf '%x' "$("${OPENSSL}" rsa -in "${ACCOUNT_KEY}" 
-noout -text | awk '/publicExponent/ {print $2}')" | hex2bin | urlbase64)"
+    pubMod64="$("${OPENSSL}" rsa -in "${ACCOUNT_KEY}" -noout -modulus | cut 
-d'=' -f2 | hex2bin | urlbase64)"
+
+    account_key_info="$(printf '{"e":"%s","kty":"RSA","n":"%s"}' 
"${pubExponent64}" "${pubMod64}")"
+    account_key_sigalgo=RS256
+  elif ("${OPENSSL}" ec -in "${ACCOUNT_KEY}" -check 2>/dev/null > /dev/null); 
then
+    curve="$("${OPENSSL}" ec -in "${ACCOUNT_KEY}" -noout -text 2>/dev/null | 
grep 'NIST CURVE' | cut -d':' -f2 | tr -d ' ')"
+    pubkey="$("${OPENSSL}" ec -in "${ACCOUNT_KEY}" -noout -text 2>/dev/null | 
tr -d '\n ' | grep -Eo 'pub:.*ASN1' | _sed -e 's/^pub://' -e 's/ASN1$//' | tr 
-d ':')"
+
+    if [ "${curve}" = "P-256" ]; then
+      account_key_sigalgo="ES256"
+    elif [ "${curve}" = "P-384" ]; then
+      account_key_sigalgo="ES384"
+    elif [ "${curve}" = "P-521" ]; then
+      account_key_sigalgo="ES512"
+    else
+      _exiterr "Unknown account key curve: ${curve}"
+    fi
+
+    ec_x_offset=2
+    ec_x_len=$((${#pubkey}/2 - 1))
+    ec_x="${pubkey:$ec_x_offset:$ec_x_len}"
+    ec_x64="$(printf "%s" "${ec_x}" | hex2bin | urlbase64)"
+
+    ec_y_offset=$((ec_x_offset+ec_x_len))
+    ec_y_len=$((${#pubkey}-ec_y_offset))
+    ec_y="${pubkey:$ec_y_offset:$ec_y_len}"
+    ec_y64="$(printf "%s" "${ec_y}" | hex2bin | urlbase64)"
 
-  thumbprint="$(printf '{"e":"%s","kty":"RSA","n":"%s"}' "${pubExponent64}" 
"${pubMod64}" | "${OPENSSL}" dgst -sha256 -binary | urlbase64)"
+    account_key_info="$(printf '{"crv":"%s","kty":"EC","x":"%s","y":"%s"}' 
"${curve}" "${ec_x64}" "${ec_y64}")"
+  else
+    _exiterr "Account key is not valid, cannot continue."
+  fi
+  thumbprint="$(printf '%s' "${account_key_info}" | "${OPENSSL}" dgst -sha256 
-binary | urlbase64)"
 
   # If we generated a new private key in the step above we have to register it 
with the acme-server
   if [[ "${register_new_key}" = "yes" ]]; then
@@ -654,7 +725,7 @@
         if [[ -n "${EAB_KID:-}" ]] && [[ -n "${EAB_HMAC_KEY:-}" ]]; then
           eab_url="${CA_NEW_ACCOUNT}"
           eab_protected64="$(printf '{"alg":"HS256","kid":"%s","url":"%s"}' 
"${EAB_KID}" "${eab_url}" | urlbase64)"
-          eab_payload64="$(printf "%s" '{"e": "'"${pubExponent64}"'", "kty": 
"RSA", "n": "'"${pubMod64}"'"}' | urlbase64)"
+          eab_payload64="$(printf "%s" "${account_key_info}" | urlbase64)"
           eab_key="$(printf "%s" "${EAB_HMAC_KEY}" | deurlbase64 | bin2hex)"
           eab_signed64="$(printf '%s' "${eab_protected64}.${eab_payload64}" | 
"${OPENSSL}" dgst -binary -sha256 -mac HMAC -macopt "hexkey:${eab_key}" | 
urlbase64)"
 
@@ -692,16 +763,16 @@
   # Read account information or request from CA if missing
   if [[ -e "${ACCOUNT_KEY_JSON}" ]]; then
     if [[ ${API} -eq 1 ]]; then
-      ACCOUNT_ID="$(cat "${ACCOUNT_KEY_JSON}" | jsonsh | get_json_int_value 
id)"
+      ACCOUNT_ID="$(jsonsh < "${ACCOUNT_KEY_JSON}" | get_json_int_value id)"
       ACCOUNT_URL="${CA_REG}/${ACCOUNT_ID}"
     else
       if [[ -e "${ACCOUNT_ID_JSON}" ]]; then
-        ACCOUNT_URL="$(cat "${ACCOUNT_ID_JSON}" | jsonsh | 
get_json_string_value url)"
+        ACCOUNT_URL="$(jsonsh < "${ACCOUNT_ID_JSON}" | get_json_string_value 
url)"
       fi
       # if account URL is not storred, fetch it from the CA
       if [[ -z "${ACCOUNT_URL:-}" ]]; then
         echo "+ Fetching account URL..."
-        ACCOUNT_URL="$(signed_request "${CA_NEW_ACCOUNT}" 
'{"onlyReturnExisting": true}' 4>&1 | grep -i ^Location: | awk '{print $2}' | 
tr -d '\r\n')"
+        ACCOUNT_URL="$(signed_request "${CA_NEW_ACCOUNT}" 
'{"onlyReturnExisting": true}' 4>&1 | grep -i ^Location: | cut -d':' -f2- | tr 
-d ' \t\r\n')"
         if [[ -z "${ACCOUNT_URL}" ]]; then
           _exiterr "Unknown error on fetching account information"
         fi
@@ -713,7 +784,7 @@
     if [[ ${API} -eq 1 ]]; then
       _exiterr "This is not implemented for ACMEv1! Consider switching to 
ACMEv2 :)"
     else
-      ACCOUNT_URL="$(signed_request "${CA_NEW_ACCOUNT}" 
'{"onlyReturnExisting": true}' 4>&1 | grep -i ^Location: | awk '{print $2}' | 
tr -d '\r\n')"
+      ACCOUNT_URL="$(signed_request "${CA_NEW_ACCOUNT}" 
'{"onlyReturnExisting": true}' 4>&1 | grep -i ^Location: | cut -d':' -f2- | tr 
-d ' \t\r\n')"
       ACCOUNT_INFO="$(signed_request "${ACCOUNT_URL}" '{}')"
     fi
     echo "${ACCOUNT_INFO}" > "${ACCOUNT_KEY_JSON}"
@@ -734,7 +805,7 @@
   if [ -n "${1:-}" ]; then
     echo "ERROR: ${1}" >&2
   fi
-  [[ "${skip_exit_hook:-no}" = "no" ]] && [[ -n "${HOOK:-}" ]] && ("${HOOK}" 
"exit_hook" "${1}" || echo 'exit_hook returned with non-zero exit code!' >&2)
+  [[ "${skip_exit_hook:-no}" = "no" ]] && [[ -n "${HOOK:-}" ]] && ("${HOOK}" 
"exit_hook" "${1:-}" || echo 'exit_hook returned with non-zero exit code!' >&2)
   exit 1
 }
 
@@ -762,12 +833,13 @@
 # Convert hex string to binary data
 hex2bin() {
   # Remove spaces, add leading zero, escape as hex string and parse with printf
-  printf -- "$(cat | _sed -e 's/[[:space:]]//g' -e 's/^(.(.{2})*)$/0\1/' -e 
's/(.{2})/\\x\1/g')"
+  # shellcheck disable=SC2059
+  printf "%b" "$(cat | _sed -e 's/[[:space:]]//g' -e 's/^(.(.{2})*)$/0\1/' -e 
's/(.{2})/\\x\1/g')"
 }
 
 # Convert binary data to hex string
 bin2hex() {
-  hexdump -e '16/1 "%02x"'
+  hexdump -v -e '/1 "%02x"'
 }
 
 # OpenSSL writes to stderr/stdout even when there are no errors. So just
@@ -797,6 +869,7 @@
   fi
 
   set +e
+  # shellcheck disable=SC2086
   if [[ "${1}" = "head" ]]; then
     statuscode="$(curl ${ip_version:-} ${CURL_OPTS} -A "dehydrated/${VERSION} 
curl/${CURL_VERSION}" -s -w "%{http_code}" -o "${tempcont}" "${2}" -I)"
     curlret="${?}"
@@ -826,6 +899,10 @@
     elif [[ -n "${CA_REVOKE_CERT:-}" ]] && [[ "${2}" = "${CA_REVOKE_CERT:-}" 
]] && [[ "${statuscode}" = "409" ]]; then
       grep -q "Certificate already revoked" "${tempcont}" && return
     else
+      if grep -q "urn:ietf:params:acme:error:badNonce" "${tempcont}"; then
+        printf "badnonce %s" "$(grep -Eoi "^replay-nonce:.*$" "${tempheaders}" 
| sed 's/ //' | cut -d: -f2)"
+        return 0
+      fi
       echo "  + ERROR: An error occurred while sending ${1}-request to ${2} 
(Status ${statuscode})" >&2
       echo >&2
       echo "Details:" >&2
@@ -836,8 +913,8 @@
 
       # An exclusive hook for the {1}-request error might be useful (e.g., for 
sending an e-mail to admins)
       if [[ -n "${HOOK}" ]]; then
-        errtxt="$(cat ${tempcont})"
-        errheaders="$(cat ${tempheaders})"
+        errtxt="$(cat "${tempcont}")"
+        errheaders="$(cat "${tempheaders}")"
         "${HOOK}" "request_failure" "${statuscode}" "${errtxt}" "${1}" 
"${errheaders}" || _exiterr 'request_failure hook returned with non-zero exit 
code'
       fi
 
@@ -863,16 +940,17 @@
   # Encode payload as urlbase64
   payload64="$(printf '%s' "${2}" | urlbase64)"
 
-  # Retrieve nonce from acme-server
-  if [[ ${API} -eq 1 ]]; then
-    nonce="$(http_request head "${CA}" | grep -i ^Replay-Nonce: | awk -F ': ' 
'{print $2}' | tr -d '\n\r')"
+  if [ -n "${3:-}" ]; then
+    nonce="$(printf "%s" "${3}" | tr -d ' \t\n\r')"
   else
-    nonce="$(http_request head "${CA_NEW_NONCE}" | grep -i ^Replay-Nonce: | 
awk -F ': ' '{print $2}' | tr -d '\n\r')"
+    # Retrieve nonce from acme-server
+    if [[ ${API} -eq 1 ]]; then
+      nonce="$(http_request head "${CA}" | grep -i ^Replay-Nonce: | cut -d':' 
-f2- | tr -d ' \t\n\r')"
+    else
+      nonce="$(http_request head "${CA_NEW_NONCE}" | grep -i ^Replay-Nonce: | 
cut -d':' -f2- | tr -d ' \t\n\r')"
+    fi
   fi
 
-  # Build header with just our public key and algorithm information
-  header='{"alg": "RS256", "jwk": {"e": "'"${pubExponent64}"'", "kty": "RSA", 
"n": "'"${pubMod64}"'"}}'
-
   if [[ ${API} -eq 1 ]]; then
     # Build another header which also contains the previously received nonce 
and encode it as urlbase64
     protected='{"alg": "RS256", "jwk": {"e": "'"${pubExponent64}"'", "kty": 
"RSA", "n": "'"${pubMod64}"'"}, "nonce": "'"${nonce}"'"}'
@@ -880,17 +958,37 @@
   else
     # Build another header which also contains the previously received nonce 
and url and encode it as urlbase64
     if [[ -n "${ACCOUNT_URL:-}" ]]; then
-      protected='{"alg": "RS256", "kid": "'"${ACCOUNT_URL}"'", "url": 
"'"${1}"'", "nonce": "'"${nonce}"'"}'
+      protected='{"alg": "'"${account_key_sigalgo}"'", "kid": 
"'"${ACCOUNT_URL}"'", "url": "'"${1}"'", "nonce": "'"${nonce}"'"}'
     else
-      protected='{"alg": "RS256", "jwk": {"e": "'"${pubExponent64}"'", "kty": 
"RSA", "n": "'"${pubMod64}"'"}, "url": "'"${1}"'", "nonce": "'"${nonce}"'"}'
+      protected='{"alg": "'"${account_key_sigalgo}"'", "jwk": 
'"${account_key_info}"', "url": "'"${1}"'", "nonce": "'"${nonce}"'"}'
     fi
     protected64="$(printf '%s' "${protected}" | urlbase64)"
   fi
 
   # Sign header with nonce and our payload with our private key and encode 
signature as urlbase64
-  signed64="$(printf '%s' "${protected64}.${payload64}" | "${OPENSSL}" dgst 
-sha256 -sign "${ACCOUNT_KEY}" | urlbase64)"
+  if [[ "${account_key_sigalgo}" = "RS256" ]]; then
+    signed64="$(printf '%s' "${protected64}.${payload64}" | "${OPENSSL}" dgst 
-sha256 -sign "${ACCOUNT_KEY}" | urlbase64)"
+  else
+    dgstparams="$(printf '%s' "${protected64}.${payload64}" | "${OPENSSL}" 
dgst -sha${account_key_sigalgo:2} -sign "${ACCOUNT_KEY}" | "${OPENSSL}" 
asn1parse -inform DER)"
+    dgst_parm_1="$(echo "$dgstparams" | head -n 2 | tail -n 1 | cut -d':' -f4)"
+    dgst_parm_2="$(echo "$dgstparams" | head -n 3 | tail -n 1 | cut -d':' -f4)"
+
+    # zero-padding (doesn't seem to be necessary, but other clients are doing 
this as well...
+    case "${account_key_sigalgo}" in
+      "ES256") siglen=64;;
+      "ES384") siglen=96;;
+      "ES512") siglen=132;;
+    esac
+    while [[ ${#dgst_parm_1} -lt $siglen ]]; do dgst_parm_1="0${dgst_parm_1}"; 
done
+    while [[ ${#dgst_parm_2} -lt $siglen ]]; do dgst_parm_2="0${dgst_parm_2}"; 
done
+
+    signed64="$(printf "%s%s" "${dgst_parm_1}" "${dgst_parm_2}" | hex2bin | 
urlbase64)"
+  fi
 
   if [[ ${API} -eq 1 ]]; then
+    # Build header with just our public key and algorithm information
+    header='{"alg": "RS256", "jwk": {"e": "'"${pubExponent64}"'", "kty": 
"RSA", "n": "'"${pubMod64}"'"}}'
+
     # Send header + extended header + payload + signature to the acme-server
     data='{"header": '"${header}"', "protected": "'"${protected64}"'", 
"payload": "'"${payload64}"'", "signature": "'"${signed64}"'"}'
   else
@@ -898,7 +996,14 @@
     data='{"protected": "'"${protected64}"'", "payload": "'"${payload64}"'", 
"signature": "'"${signed64}"'"}'
   fi
 
-  http_request post "${1}" "${data}"
+  output="$(http_request post "${1}" "${data}")"
+
+  if grep -qE "^badnonce " <<< "${output}"; then
+    echo " ! Request failed (badNonce), retrying request..." >&2
+    signed_request "${1:-}" "${2:-}" "$(printf "%s" "${output}" | cut -d' ' 
-f2)"
+  else
+    printf "%s" "${output}"
+  fi
 }
 
 # Extracts all subject names from a CSR
@@ -917,23 +1022,23 @@
     # split to one per line:
     # shellcheck disable=SC1003
     altnames="$( <<<"${altnames}" _sed -e 's/^[[:space:]]*//; s/, /\'$'\n''/g' 
)"
-    # we can only get DNS: ones signed
-    if grep -qEv '^(DNS|othername):' <<<"${altnames}"; then
-      _exiterr "Certificate signing request contains non-DNS Subject 
Alternative Names"
+    # we can only get DNS/IP: ones signed
+    if grep -qEv '^(DNS|IP( Address)*|othername):' <<<"${altnames}"; then
+      _exiterr "Certificate signing request contains non-DNS/IP Subject 
Alternative Names"
     fi
-    # strip away the DNS: prefix
-    altnames="$( <<<"${altnames}" _sed -e 
's/^(DNS:|othername:<unsupported>)//' )"
+    # strip away the DNS/IP: prefix
+    altnames="$( <<<"${altnames}" _sed -e 's/^(DNS:|IP( 
Address)*:|othername:<unsupported>)//' )"
     printf "%s" "${altnames}" | tr '\n' ' '
   else
     # No SANs, extract CN
-    altnames="$( <<<"${reqtext}" grep '^[[:space:]]*Subject:' | _sed -e 's/.* 
CN ?= ?([^ /,]*).*/\1/' )"
+    altnames="$( <<<"${reqtext}" grep '^[[:space:]]*Subject:' | _sed -e 's/.*[ 
/]CN ?= ?([^ /,]*).*/\1/' )"
     printf "%s" "${altnames}"
   fi
 }
 
 # 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/'
+  <<<"${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
@@ -968,12 +1073,16 @@
     # Request new order and store authorization URIs
     local challenge_identifiers=""
     for altname in ${altnames}; do
-      challenge_identifiers+="$(printf '{"type": "dns", "value": "%s"}, ' 
"${altname}")"
+    if [[ "${altname}" =~ ^ip: ]]; then
+      challenge_identifiers+="$(printf '{"type": "ip", "value": "%s"}, ' 
"${altname:3}")"
+    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: | awk '{print $2}' | 
tr -d '\r\n')"
+    order_location="$(signed_request "${CA_NEW_ORDER}" '{"identifiers": 
'"${challenge_identifiers}"'}' 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)"
@@ -1001,6 +1110,7 @@
       # Receive authorization ($authorization is authz uri)
       response="$(signed_request "$(echo "${authorization}" | _sed -e 
's/\"(.*)".*/\1/')" "" | jsonsh)"
       identifier="$(echo "${response}" | get_json_string_value -p 
'"identifier","value"')"
+      identifier_type="$(echo "${response}" | get_json_string_value -p 
'"identifier","type"')"
       echo " + Handling authorization for ${identifier}"
     else
       # Request new authorization ($authorization is altname)
@@ -1010,9 +1120,13 @@
     fi
 
     # Check if authorization has already been validated
-    if [ "$(echo "${response}" | _sed 's/"challenges": \[\{.*\}\]//' | 
get_json_string_value status)" = "valid" ] && [ ! "${PARAM_FORCE:-no}" = "yes" 
]; then
-      echo " + Found valid authorization for ${identifier}"
-      continue
+    if [ "$(echo "${response}" | get_json_string_value status)" = "valid" ]; 
then
+      if [ "${PARAM_FORCE_VALIDATION:-no}" = "yes" ]; then
+        echo " + A valid authorization has been found but will be ignored"
+      else
+        echo " + Found valid authorization for ${identifier}"
+        continue
+      fi
     fi
 
     # Find challenge in authorization
@@ -1025,7 +1139,11 @@
     challenge="$(echo "${response}" | get_json_dict_value -p 
'"challenges",'"${challengeindex}")"
 
     # Gather challenge information
-    challenge_names[${idx}]="${identifier}"
+    if [ "${identifier_type:-}" = "ip" ] && [ "${CHALLENGETYPE}" = 
"tls-alpn-01" ] ; then
+      challenge_names[${idx}]="$(echo "${identifier}" | ip_to_ptr)"
+    else
+      challenge_names[${idx}]="${identifier}"
+    fi
     challenge_tokens[${idx}]="$(echo "${challenge}" | get_json_string_value 
token)"
 
     if [[ ${API} -eq 2 ]]; then
@@ -1052,13 +1170,17 @@
         keyauth_hook="$(printf '%s' "${keyauth}" | "${OPENSSL}" dgst -sha256 
-binary | urlbase64)"
         ;;
       "tls-alpn-01")
-        keyauth_hook="$(printf '%s' "${keyauth}" | "${OPENSSL}" dgst -sha256 
-c -hex | awk '{print $2}')"
-        generate_alpn_certificate "${identifier}" "${keyauth_hook}"
+        keyauth_hook="$(printf '%s' "${keyauth}" | "${OPENSSL}" dgst -sha256 
-c -hex | awk '{print $NF}')"
+        generate_alpn_certificate "${identifier}" "${identifier_type}" 
"${keyauth_hook}"
         ;;
     esac
 
     keyauths[${idx}]="${keyauth}"
-    deploy_args[${idx}]="${identifier} ${challenge_tokens[${idx}]} 
${keyauth_hook}"
+    if [ "${identifier_type:-}" = "ip" ] && [ "${CHALLENGETYPE}" = 
"tls-alpn-01" ]; then
+      deploy_args[${idx}]="$(echo "${identifier}" | ip_to_ptr) 
${challenge_tokens[${idx}]} ${keyauth_hook}"
+    else
+      deploy_args[${idx}]="${identifier} ${challenge_tokens[${idx}]} 
${keyauth_hook}"
+    fi
 
     idx=$((idx+1))
   done
@@ -1069,11 +1191,13 @@
   if [[ ${num_pending_challenges} -ne 0 ]]; then
     echo " + Deploying challenge tokens..."
     if [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]]; then
+      # shellcheck disable=SC2068
       "${HOOK}" "deploy_challenge" ${deploy_args[@]} || _exiterr 
'deploy_challenge hook returned with non-zero exit code'
     elif [[ -n "${HOOK}" ]]; then
       # Run hook script to deploy the challenge token
       local idx=0
       while [ ${idx} -lt ${num_pending_challenges} ]; do
+        # shellcheck disable=SC2086
         "${HOOK}" "deploy_challenge" ${deploy_args[${idx}]} || _exiterr 
'deploy_challenge hook returned with non-zero exit code'
         idx=$((idx+1))
       done
@@ -1120,6 +1244,7 @@
     echo " + Cleaning challenge tokens..."
 
     # Clean challenge tokens using chained hook
+    # shellcheck disable=SC2068
     [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" = "yes" ]] && ("${HOOK}" 
"clean_challenge" ${deploy_args[@]} || _exiterr 'clean_challenge hook returned 
with non-zero exit code')
 
     # Clean remaining challenge tokens if validation has failed
@@ -1130,6 +1255,7 @@
       # Delete alpn verification certificates
       [[ "${CHALLENGETYPE}" = "tls-alpn-01" ]] && rm -f 
"${ALPNCERTDIR}/${challenge_names[${idx}]}.crt.pem" 
"${ALPNCERTDIR}/${challenge_names[${idx}]}.key.pem"
       # Clean challenge token using non-chained hook
+      # shellcheck disable=SC2086
       [[ -n "${HOOK}" ]] && [[ "${HOOK_CHAIN}" != "yes" ]] && ("${HOOK}" 
"clean_challenge" ${deploy_args[${idx}]} || _exiterr 'clean_challenge hook 
returned with non-zero exit code')
       idx=$((idx+1))
     done
@@ -1177,8 +1303,8 @@
       if [ "${altcn}" = "${PREFERRED_CHAIN}" ]; then
         foundaltchain=1
       fi
-      if [ "${foundaltchain}" = "0" ]; then
-        while read altcrturl; do
+      if [ "${foundaltchain}" = "0" ] && (grep -Ei '^link:' "${resheaders}" | 
grep -q -Ei 'rel="alternate"'); then
+        while read -r altcrturl; do
           if [ "${foundaltchain}" = "0" ]; then
             altcrt="$(signed_request "${altcrturl}" "")"
             altcn="$(get_last_cn "${altcrt}")"
@@ -1266,7 +1392,8 @@
 # Generate ALPN verification certificate
 generate_alpn_certificate() {
   local altname="${1}"
-  local acmevalidation="${2}"
+  local identifier_type="${2}"
+  local acmevalidation="${3}"
 
   local alpncertdir="${ALPNCERTDIR}"
   if [[ ! -e "${alpncertdir}" ]]; then
@@ -1277,10 +1404,17 @@
   echo " + Generating ALPN certificate and key for ${1}..."
   tmp_openssl_cnf="$(_mktemp)"
   cat "${OPENSSL_CNF}" > "${tmp_openssl_cnf}"
-  printf "[SAN]\nsubjectAltName=DNS:%s\n" "${altname}" >> "${tmp_openssl_cnf}"
-  printf "1.3.6.1.5.5.7.1.31=critical,DER:04:20:${acmevalidation}\n" >> 
"${tmp_openssl_cnf}"
+  if [[ "${identifier_type}" = "ip" ]]; then
+    printf "\n[SAN]\nsubjectAltName=IP:%s\n" "${altname}" >> 
"${tmp_openssl_cnf}"
+  else
+    printf "\n[SAN]\nsubjectAltName=DNS:%s\n" "${altname}" >> 
"${tmp_openssl_cnf}"
+  fi
+  printf "1.3.6.1.5.5.7.1.31=critical,DER:04:20:%s\n" "${acmevalidation}" >> 
"${tmp_openssl_cnf}"
   SUBJ="/CN=${altname}/"
   [[ "${OSTYPE:0:5}" = "MINGW" ]] && SUBJ="/${SUBJ}"
+  if [[ "${identifier_type}" = "ip" ]]; then
+    altname="$(echo "${altname}" | ip_to_ptr)"
+  fi
   _openssl req -x509 -new -sha256 -nodes -newkey rsa:2048 -keyout 
"${alpncertdir}/${altname}.key.pem" -out "${alpncertdir}/${altname}.crt.pem" 
-subj "${SUBJ}" -extensions SAN -config "${tmp_openssl_cnf}"
   chmod g+r "${alpncertdir}/${altname}.key.pem" 
"${alpncertdir}/${altname}.crt.pem"
   rm -f "${tmp_openssl_cnf}"
@@ -1312,10 +1446,11 @@
     if [[ ! -r "${certdir}/privkey.pem" ]] || [[ "${PRIVATE_KEY_RENEW}" = 
"yes" ]]; then
       echo " + Generating private key..."
       privkey="privkey-${timestamp}.pem"
-      local tmp_privkey="$(_mktemp)"
+      local tmp_privkey
+      tmp_privkey="$(_mktemp)"
       case "${KEY_ALGO}" in
         rsa) _openssl genrsa -out "${tmp_privkey}" "${KEYSIZE}";;
-        prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" 
-out "${tmp_privkey}";;
+        prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" 
-out "${tmp_privkey}" -noout;;
       esac
       cat "${tmp_privkey}" > "${certdir}/privkey-${timestamp}.pem"
       rm "${tmp_privkey}"
@@ -1332,7 +1467,7 @@
       echo " + Generating private rollover key..."
       case "${KEY_ALGO}" in
         rsa) _openssl genrsa -out "${certdir}/privkey.roll.pem" "${KEYSIZE}";;
-        prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" 
-out "${certdir}/privkey.roll.pem";;
+        prime256v1|secp384r1) _openssl ecparam -genkey -name "${KEY_ALGO}" 
-out "${certdir}/privkey.roll.pem" -noout;;
       esac
     fi
     # delete rolloverkeys if disabled
@@ -1345,17 +1480,25 @@
     echo " + Generating signing request..."
     SAN=""
     for altname in ${altnames}; do
-      SAN="${SAN}DNS:${altname}, "
+      if [[ "${altname}" =~ ^ip: ]]; then
+        SAN="${SAN}IP:${altname:3}, "
+      else
+        SAN="${SAN}DNS:${altname}, "
+      fi
     done
+    if [[ "${domain}" =~ ^ip: ]]; then
+      SUBJ="/CN=${domain:3}/"
+    else
+      SUBJ="/CN=${domain}/"
+    fi
     SAN="${SAN%%, }"
     local tmp_openssl_cnf
     tmp_openssl_cnf="$(_mktemp)"
     cat "${OPENSSL_CNF}" > "${tmp_openssl_cnf}"
-    printf "[SAN]\nsubjectAltName=%s" "${SAN}" >> "${tmp_openssl_cnf}"
+    printf "\n[SAN]\nsubjectAltName=%s" "${SAN}" >> "${tmp_openssl_cnf}"
     if [ "${OCSP_MUST_STAPLE}" = "yes" ]; then
       printf "\n1.3.6.1.5.5.7.1.24=DER:30:03:02:01:05" >> "${tmp_openssl_cnf}"
     fi
-    SUBJ="/CN=${domain}/"
     if [[ "${OSTYPE:0:5}" = "MINGW" ]]; then
       # The subject starts with a /, so MSYS will assume it's a path and 
convert
       # it unless we escape it with another one:
@@ -1426,20 +1569,21 @@
   revision="$(cd "${SCRIPTDIR}"; git rev-parse HEAD 2>/dev/null || echo 
"unknown")"
   echo "GIT-Revision: ${revision}"
   echo ""
-  if [[ "${OSTYPE}" =~ "BSD" ]]; then
+  # shellcheck disable=SC1091
+  if [[ "${OSTYPE}" =~ (BSD|Darwin) ]]; then
     echo "OS: $(uname -sr)"
   elif [[ -e /etc/os-release ]]; then
     ( . /etc/os-release && echo "OS: $PRETTY_NAME" )
   elif [[ -e /usr/lib/os-release ]]; then
     ( . /usr/lib/os-release && echo "OS: $PRETTY_NAME" )
   else
-    echo "OS: $(cat /etc/issue | grep -v ^$ | head -n1 | _sed 's/\\(r|n|l) 
.*//g')"
+    echo "OS: $(grep -v '^$' /etc/issue | head -n1 | _sed 's/\\(r|n|l) .*//g')"
   fi
   echo "Used software:"
   [[ -n "${BASH_VERSION:-}" ]] && echo " bash: ${BASH_VERSION}"
   [[ -n "${ZSH_VERSION:-}" ]] && echo " zsh: ${ZSH_VERSION}"
   echo " curl: ${CURL_VERSION}"
-  if [[ "${OSTYPE}" =~ "BSD" ]]; then
+  if [[ "${OSTYPE}" =~ (BSD|Darwin) ]]; then
     echo " awk, sed, mktemp, grep, diff: BSD base system versions"
   else
     echo " awk: $(awk -W version 2>&1 | head -n1)"
@@ -1518,6 +1662,20 @@
   exit 0
 }
 
+# Parse contents of domains.txt and domains.txt.d
+parse_domains_txt() {
+  # Allow globbing temporarily
+  noglob_set
+  local inputs=("${DOMAINS_TXT}" "${DOMAINS_TXT}.d"/*.txt)
+  noglob_clear
+
+  cat "${inputs[@]}" |
+    tr -d '\r' |
+    awk '{print tolower($0)}' |
+    _sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e 's/[[:space:]]+/ 
/g' -e 's/([^ ])>/\1 >/g' -e 's/> />/g' |
+    (grep -vE '^(#|$)' || true)
+}
+
 # Usage: --cron (-c)
 # Description: Sign/renew non-existent/changed/expiring certificates.
 command_sign_domains() {
@@ -1535,9 +1693,9 @@
   if [[ -n "${PARAM_DOMAIN:-}" ]]; then
     DOMAINS_TXT="$(_mktemp)"
     if [[ -n "${PARAM_ALIAS:-}" ]]; then
-      printf -- "${PARAM_DOMAIN} > ${PARAM_ALIAS}" > "${DOMAINS_TXT}"
+      printf "%s > %s" "${PARAM_DOMAIN}" "${PARAM_ALIAS}" > "${DOMAINS_TXT}"
     else
-      printf -- "${PARAM_DOMAIN}" > "${DOMAINS_TXT}"
+      printf "%s" "${PARAM_DOMAIN}" > "${DOMAINS_TXT}"
     fi
   elif [[ -e "${DOMAINS_TXT}" ]]; then
     if [[ ! -r "${DOMAINS_TXT}" ]]; then
@@ -1550,17 +1708,17 @@
   # Generate certificates for all domains found in domains.txt. Check if 
existing certificate are about to expire
   ORIGIFS="${IFS}"
   IFS=$'\n'
-  for line in $(<"${DOMAINS_TXT}" tr -d '\r' | awk '{print tolower($0)}' | 
_sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e 's/[[:space:]]+/ /g' -e 
's/([^ ])>/\1 >/g' -e 's/> />/g' | (grep -vE '^(#|$)' || true)); do
+  for line in $(parse_domains_txt); do
     reset_configvars
     IFS="${ORIGIFS}"
     alias="$(grep -Eo '>[^ ]+' <<< "${line}" || true)"
     line="$(_sed -e 's/>[^ ]+[ ]*//g' <<< "${line}")"
     aliascount="$(grep -Eo '>' <<< "${alias}" | awk 'END {print NR}' || true )"
-    [ ${aliascount} -gt 1 ] && _exiterr "Only one alias per line is allowed in 
domains.txt!"
+    [ "${aliascount}" -gt 1 ] && _exiterr "Only one alias per line is allowed 
in domains.txt!"
 
     domain="$(printf '%s\n' "${line}" | cut -d' ' -f1)"
     morenames="$(printf '%s\n' "${line}" | cut -s -d' ' -f2-)"
-    [ ${aliascount} -lt 1 ] && alias="${domain}" || alias="${alias#>}"
+    [ "${aliascount}" -lt 1 ] && alias="${domain}" || alias="${alias#>}"
     export alias
 
     if [[ -z "${morenames}" ]];then
@@ -1614,6 +1772,8 @@
       ); 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)
             echo "   + ${config_var} = ${config_value}"
@@ -1646,12 +1806,12 @@
     fi
 
     # Check domain names of existing certificate
-    if [[ -e "${cert}" ]]; then
+    if [[ -e "${cert}" && "${force_renew}" = "no" ]]; then
       printf " + Checking domain name(s) of existing cert..."
 
-      certnames="$("${OPENSSL}" x509 -in "${cert}" -text -noout | grep DNS: | 
_sed 's/DNS://g' | tr -d ' ' | tr ',' '\n' | sort -u | tr '\n' ' ' | _sed 's/ 
$//')"
-      givennames="$(echo "${domain}" "${morenames}"| tr ' ' '\n' | sort -u | 
tr '\n' ' ' | _sed 's/ $//' | _sed 's/^ //')"
-
+      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
@@ -1692,13 +1852,14 @@
     if [[ ! "${skip}" = "yes" ]]; then
       update_ocsp="yes"
       [[ -z "${csr}" ]] || printf "%s" "${csr}" > 
"${certdir}/cert-${timestamp}.csr"
+      # shellcheck disable=SC2086
       if [[ "${PARAM_KEEP_GOING:-}" = "yes" ]]; then
         skip_exit_hook=yes
-        sign_domain "${certdir}" ${timestamp} ${domain} ${morenames} &
+        sign_domain "${certdir}" "${timestamp}" "${domain}" ${morenames} &
         wait $! || exit_with_errorcode=1
         skip_exit_hook=no
       else
-        sign_domain "${certdir}" ${timestamp} ${domain} ${morenames}
+        sign_domain "${certdir}" "${timestamp}" "${domain}" ${morenames}
       fi
     fi
 
@@ -1744,12 +1905,12 @@
 # Usage: --signcsr (-s) path/to/csr.pem
 # Description: Sign a given CSR, output CRT on stdout (advanced usage)
 command_sign_csr() {
+  init_system
+
   # redirect stdout to stderr
   # leave stdout over at fd 3 to output the cert
   exec 3>&1 1>&2
 
-  init_system
-
   # load csr
   csrfile="${1}"
   if [ ! -r "${csrfile}" ]; then
@@ -1762,6 +1923,7 @@
 
   # gen cert
   certfile="$(_mktemp)"
+  # shellcheck disable=SC2086
   sign_csr "${csr}" ${altnames} 3> "${certfile}"
 
   # print cert
@@ -1866,7 +2028,7 @@
   fi
 
   # Allow globbing
-  [[ -n "${ZSH_VERSION:-}" ]] && set +o noglob || set +f
+  noglob_set
 
   # Loop over all certificate directories
   for certdir in "${CERTDIR}/"*; do
@@ -1907,7 +2069,6 @@
         # Check if current file is in use, if unused move to archive directory
         filename="$(basename "${file}")"
         if [[ ! "${filename}" = "${current}" ]] && [[ -f 
"${certdir}/${filename}" ]]; then
-          echo "${filename}"
           if [[ "${PARAM_CLEANUPDELETE:-}" = "yes" ]]; then
             echo "Deleting unused file: ${certname}/${filename}"
             rm "${certdir}/${filename}"
@@ -1980,8 +2141,7 @@
     fi
   }
 
-  # shellcheck disable=SC2199
-  [[ -z "${@}" ]] && eval set -- "--help"
+  [[ -z "${*}" ]] && eval set -- "--help"
 
   while (( ${#} )); do
     case "${1}" in
@@ -2107,6 +2267,12 @@
         PARAM_FORCE="yes"
         ;;
 
+      # PARAM_Usage: --force-validation
+      # PARAM_Description: Force revalidation of domain names (used in 
combination with --force)
+      --force-validation)
+        PARAM_FORCE_VALIDATION="yes"
+        ;;
+
       # PARAM_Usage: --no-lock (-n)
       # PARAM_Description: Don't use lockfile (potentially dangerous!)
       --no-lock|-n)
@@ -2183,8 +2349,8 @@
         PARAM_ALPNCERTDIR="${1}"
         ;;
 
-      # PARAM_Usage: --challenge (-t) http-01|dns-01
-      # PARAM_Description: Which challenge should be used? Currently http-01 
and dns-01 are supported
+      # PARAM_Usage: --challenge (-t) http-01|dns-01|tls-alpn-01
+      # PARAM_Description: Which challenge should be used? Currently http-01, 
dns-01, and tls-alpn-01 are supported
       --challenge|-t)
         shift 1
         check_parameters "${1:-}"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/docs/domains_txt.md 
new/dehydrated-0.7.1/docs/domains_txt.md
--- old/dehydrated-0.7.0/docs/domains_txt.md    2020-12-10 16:54:26.000000000 
+0100
+++ new/dehydrated-0.7.1/docs/domains_txt.md    2022-10-31 15:12:38.000000000 
+0100
@@ -34,6 +34,30 @@
 example.net www.example.net wiki.example.net > certalias
 ```
 
+This allows to set per certificates options. The options you can change are
+explained in [Per Certificate Config](per-certificate-config.md).
+
+If you want to create different certificate types for the same domain
+you can use:
+
+```text
+*.service.example.org service.example.org  > star_service_example_org_rsa
+*.service.example.org service.example.org  > star_service_example_org_ecdsa
+```
+
+Then add a config file `certs/star_service_example_org_rsa/config` with
+the value
+
+```
+KEY_ALGO="rsa"
+```
+
+or respectively
+
+```
+KEY_ALGO="ecdsa"
+```
+
 ### Wildcards
 
 Support for wildcards was added by the ACME v2 protocol.
@@ -70,3 +94,14 @@
 **Note:** The first certificate is valid for both `service.example.com` and for
 `*.service.example.com` which can be a useful way to create wildcard
 certificates.
+
+### Drop-in directory
+
+If a directory named `domains.txt.d` exists in the same location as
+`domains.txt`, the contents of `*.txt` files in that directory are appended to
+the list of domains, in alphabetical order of the filenames. This is useful for
+automation, as it doesn't require editing an existing file to add new domains.
+
+Warning: Behaviour of this might change as the naming between `domains.txt.d`
+and the `DOMAINS_D` config variable (which is used for per-certificate
+configuration) is a bit confusing.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/docs/examples/domains.txt 
new/dehydrated-0.7.1/docs/examples/domains.txt
--- old/dehydrated-0.7.0/docs/examples/domains.txt      2020-12-10 
16:54:26.000000000 +0100
+++ new/dehydrated-0.7.1/docs/examples/domains.txt      2022-10-31 
15:12:38.000000000 +0100
@@ -24,6 +24,15 @@
 # NOTE: It is a certificate for 'service.example.org'
 *.service.example.org service.example.org  > star_service_example_org
 
+# Optionally you can also append the certificate algorithm here to create
+# multiple certificate types for the same domain.
+#
+# This allows to set per certificates options. How to do this is
+# explained in [domains.txt documentation](domains_txt.md).
+#
+*.service.example.org service.example.org  > star_service_example_org_rsa
+*.service.example.org service.example.org  > star_service_example_org_ecdsa
+
 # Create a certificate for 'service.example.net' with an alternative name of
 # '*.service.example.net' (which is a wildcard domain) and store it in the
 # directory ${CERTDIR}/service.example.net
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/docs/examples/hook.sh 
new/dehydrated-0.7.1/docs/examples/hook.sh
--- old/dehydrated-0.7.0/docs/examples/hook.sh  2020-12-10 16:54:26.000000000 
+0100
+++ new/dehydrated-0.7.1/docs/examples/hook.sh  2022-10-31 15:12:38.000000000 
+0100
@@ -1,199 +1,199 @@
 #!/usr/bin/env bash
 
 deploy_challenge() {
-    local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
+  local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
 
-    # This hook is called once for every domain that needs to be
-    # validated, including any alternative names you may have listed.
-    #
-    # Parameters:
-    # - DOMAIN
-    #   The domain name (CN or subject alternative name) being
-    #   validated.
-    # - TOKEN_FILENAME
-    #   The name of the file containing the token to be served for HTTP
-    #   validation. Should be served by your web server as
-    #   /.well-known/acme-challenge/${TOKEN_FILENAME}.
-    # - TOKEN_VALUE
-    #   The token value that needs to be served for validation. For DNS
-    #   validation, this is what you want to put in the _acme-challenge
-    #   TXT record. For HTTP validation it is the value that is expected
-    #   be found in the $TOKEN_FILENAME file.
+  # This hook is called once for every domain that needs to be
+  # validated, including any alternative names you may have listed.
+  #
+  # Parameters:
+  # - DOMAIN
+  #   The domain name (CN or subject alternative name) being
+  #   validated.
+  # - TOKEN_FILENAME
+  #   The name of the file containing the token to be served for HTTP
+  #   validation. Should be served by your web server as
+  #   /.well-known/acme-challenge/${TOKEN_FILENAME}.
+  # - TOKEN_VALUE
+  #   The token value that needs to be served for validation. For DNS
+  #   validation, this is what you want to put in the _acme-challenge
+  #   TXT record. For HTTP validation it is the value that is expected
+  #   be found in the $TOKEN_FILENAME file.
 
-    # Simple example: Use nsupdate with local named
-    # printf 'server 127.0.0.1\nupdate add _acme-challenge.%s 300 IN TXT 
"%s"\nsend\n' "${DOMAIN}" "${TOKEN_VALUE}" | nsupdate -k 
/var/run/named/session.key
+  # Simple example: Use nsupdate with local named
+  # printf 'server 127.0.0.1\nupdate add _acme-challenge.%s 300 IN TXT 
"%s"\nsend\n' "${DOMAIN}" "${TOKEN_VALUE}" | nsupdate -k 
/var/run/named/session.key
 }
 
 clean_challenge() {
-    local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
+  local DOMAIN="${1}" TOKEN_FILENAME="${2}" TOKEN_VALUE="${3}"
 
-    # This hook is called after attempting to validate each domain,
-    # whether or not validation was successful. Here you can delete
-    # files or DNS records that are no longer needed.
-    #
-    # The parameters are the same as for deploy_challenge.
+  # This hook is called after attempting to validate each domain,
+  # whether or not validation was successful. Here you can delete
+  # files or DNS records that are no longer needed.
+  #
+  # The parameters are the same as for deploy_challenge.
 
-    # Simple example: Use nsupdate with local named
-    # printf 'server 127.0.0.1\nupdate delete _acme-challenge.%s TXT 
"%s"\nsend\n' "${DOMAIN}" "${TOKEN_VALUE}" | nsupdate -k 
/var/run/named/session.key
+  # Simple example: Use nsupdate with local named
+  # printf 'server 127.0.0.1\nupdate delete _acme-challenge.%s TXT 
"%s"\nsend\n' "${DOMAIN}" "${TOKEN_VALUE}" | nsupdate -k 
/var/run/named/session.key
 }
 
 sync_cert() {
-    local KEYFILE="${1}" CERTFILE="${2}" FULLCHAINFILE="${3}" CHAINFILE="${4}" 
REQUESTFILE="${5}"
+  local KEYFILE="${1}" CERTFILE="${2}" FULLCHAINFILE="${3}" CHAINFILE="${4}" 
REQUESTFILE="${5}"
 
-    # This hook is called after the certificates have been created but before
-    # they are symlinked. This allows you to sync the files to disk to prevent
-    # creating a symlink to empty files on unexpected system crashes.
-    #
-    # This hook is not intended to be used for further processing of 
certificate
-    # files, see deploy_cert for that.
-    #
-    # Parameters:
-    # - KEYFILE
-    #   The path of the file containing the private key.
-    # - CERTFILE
-    #   The path of the file containing the signed certificate.
-    # - FULLCHAINFILE
-    #   The path of the file containing the full certificate chain.
-    # - CHAINFILE
-    #   The path of the file containing the intermediate certificate(s).
-    # - REQUESTFILE
-    #   The path of the file containing the certificate signing request.
+  # This hook is called after the certificates have been created but before
+  # they are symlinked. This allows you to sync the files to disk to prevent
+  # creating a symlink to empty files on unexpected system crashes.
+  #
+  # This hook is not intended to be used for further processing of certificate
+  # files, see deploy_cert for that.
+  #
+  # Parameters:
+  # - KEYFILE
+  #   The path of the file containing the private key.
+  # - CERTFILE
+  #   The path of the file containing the signed certificate.
+  # - FULLCHAINFILE
+  #   The path of the file containing the full certificate chain.
+  # - CHAINFILE
+  #   The path of the file containing the intermediate certificate(s).
+  # - REQUESTFILE
+  #   The path of the file containing the certificate signing request.
 
-    # Simple example: sync the files before symlinking them
-    # sync "${KEYFILE}" "${CERTFILE}" "${FULLCHAINFILE}" "${CHAINFILE}" 
"${REQUESTFILE}"
+  # Simple example: sync the files before symlinking them
+  # sync "${KEYFILE}" "${CERTFILE}" "${FULLCHAINFILE}" "${CHAINFILE}" 
"${REQUESTFILE}"
 }
 
 deploy_cert() {
-    local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" 
CHAINFILE="${5}" TIMESTAMP="${6}"
+  local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" 
CHAINFILE="${5}" TIMESTAMP="${6}"
 
-    # This hook is called once for each certificate that has been
-    # produced. Here you might, for instance, copy your new certificates
-    # to service-specific locations and reload the service.
-    #
-    # Parameters:
-    # - DOMAIN
-    #   The primary domain name, i.e. the certificate common
-    #   name (CN).
-    # - KEYFILE
-    #   The path of the file containing the private key.
-    # - CERTFILE
-    #   The path of the file containing the signed certificate.
-    # - FULLCHAINFILE
-    #   The path of the file containing the full certificate chain.
-    # - CHAINFILE
-    #   The path of the file containing the intermediate certificate(s).
-    # - TIMESTAMP
-    #   Timestamp when the specified certificate was created.
-
-    # Simple example: Copy file to nginx config
-    # cp "${KEYFILE}" "${FULLCHAINFILE}" /etc/nginx/ssl/; chown -R nginx: 
/etc/nginx/ssl
-    # systemctl reload nginx
+  # This hook is called once for each certificate that has been
+  # produced. Here you might, for instance, copy your new certificates
+  # to service-specific locations and reload the service.
+  #
+  # Parameters:
+  # - DOMAIN
+  #   The primary domain name, i.e. the certificate common
+  #   name (CN).
+  # - KEYFILE
+  #   The path of the file containing the private key.
+  # - CERTFILE
+  #   The path of the file containing the signed certificate.
+  # - FULLCHAINFILE
+  #   The path of the file containing the full certificate chain.
+  # - CHAINFILE
+  #   The path of the file containing the intermediate certificate(s).
+  # - TIMESTAMP
+  #   Timestamp when the specified certificate was created.
+
+  # Simple example: Copy file to nginx config
+  # cp "${KEYFILE}" "${FULLCHAINFILE}" /etc/nginx/ssl/; chown -R nginx: 
/etc/nginx/ssl
+  # systemctl reload nginx
 }
 
 deploy_ocsp() {
-    local DOMAIN="${1}" OCSPFILE="${2}" TIMESTAMP="${3}"
+  local DOMAIN="${1}" OCSPFILE="${2}" TIMESTAMP="${3}"
 
-    # This hook is called once for each updated ocsp stapling file that has
-    # been produced. Here you might, for instance, copy your new ocsp stapling
-    # files to service-specific locations and reload the service.
-    #
-    # Parameters:
-    # - DOMAIN
-    #   The primary domain name, i.e. the certificate common
-    #   name (CN).
-    # - OCSPFILE
-    #   The path of the ocsp stapling file
-    # - TIMESTAMP
-    #   Timestamp when the specified ocsp stapling file was created.
-
-    # Simple example: Copy file to nginx config
-    # cp "${OCSPFILE}" /etc/nginx/ssl/; chown -R nginx: /etc/nginx/ssl
-    # systemctl reload nginx
+  # This hook is called once for each updated ocsp stapling file that has
+  # been produced. Here you might, for instance, copy your new ocsp stapling
+  # files to service-specific locations and reload the service.
+  #
+  # Parameters:
+  # - DOMAIN
+  #   The primary domain name, i.e. the certificate common
+  #   name (CN).
+  # - OCSPFILE
+  #   The path of the ocsp stapling file
+  # - TIMESTAMP
+  #   Timestamp when the specified ocsp stapling file was created.
+
+  # Simple example: Copy file to nginx config
+  # cp "${OCSPFILE}" /etc/nginx/ssl/; chown -R nginx: /etc/nginx/ssl
+  # systemctl reload nginx
 }
 
 
 unchanged_cert() {
-    local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" 
CHAINFILE="${5}"
+  local DOMAIN="${1}" KEYFILE="${2}" CERTFILE="${3}" FULLCHAINFILE="${4}" 
CHAINFILE="${5}"
 
-    # This hook is called once for each certificate that is still
-    # valid and therefore wasn't reissued.
-    #
-    # Parameters:
-    # - DOMAIN
-    #   The primary domain name, i.e. the certificate common
-    #   name (CN).
-    # - KEYFILE
-    #   The path of the file containing the private key.
-    # - CERTFILE
-    #   The path of the file containing the signed certificate.
-    # - FULLCHAINFILE
-    #   The path of the file containing the full certificate chain.
-    # - CHAINFILE
-    #   The path of the file containing the intermediate certificate(s).
+  # This hook is called once for each certificate that is still
+  # valid and therefore wasn't reissued.
+  #
+  # Parameters:
+  # - DOMAIN
+  #   The primary domain name, i.e. the certificate common
+  #   name (CN).
+  # - KEYFILE
+  #   The path of the file containing the private key.
+  # - CERTFILE
+  #   The path of the file containing the signed certificate.
+  # - FULLCHAINFILE
+  #   The path of the file containing the full certificate chain.
+  # - CHAINFILE
+  #   The path of the file containing the intermediate certificate(s).
 }
 
 invalid_challenge() {
-    local DOMAIN="${1}" RESPONSE="${2}"
+  local DOMAIN="${1}" RESPONSE="${2}"
 
-    # This hook is called if the challenge response has failed, so domain
-    # owners can be aware and act accordingly.
-    #
-    # Parameters:
-    # - DOMAIN
-    #   The primary domain name, i.e. the certificate common
-    #   name (CN).
-    # - RESPONSE
-    #   The response that the verification server returned
+  # This hook is called if the challenge response has failed, so domain
+  # owners can be aware and act accordingly.
+  #
+  # Parameters:
+  # - DOMAIN
+  #   The primary domain name, i.e. the certificate common
+  #   name (CN).
+  # - RESPONSE
+  #   The response that the verification server returned
 
-    # Simple example: Send mail to root
-    # printf "Subject: Validation of ${DOMAIN} failed!\n\nOh noez!" | sendmail 
root
+  # Simple example: Send mail to root
+  # printf "Subject: Validation of ${DOMAIN} failed!\n\nOh noez!" | sendmail 
root
 }
 
 request_failure() {
-    local STATUSCODE="${1}" REASON="${2}" REQTYPE="${3}" HEADERS="${4}"
+  local STATUSCODE="${1}" REASON="${2}" REQTYPE="${3}" HEADERS="${4}"
 
-    # This hook is called when an HTTP request fails (e.g., when the ACME
-    # server is busy, returns an error, etc). It will be called upon any
-    # response code that does not start with '2'. Useful to alert admins
-    # about problems with requests.
-    #
-    # Parameters:
-    # - STATUSCODE
-    #   The HTML status code that originated the error.
-    # - REASON
-    #   The specified reason for the error.
-    # - REQTYPE
-    #   The kind of request that was made (GET, POST...)
-    # - HEADERS
-    #   HTTP headers returned by the CA
+  # This hook is called when an HTTP request fails (e.g., when the ACME
+  # server is busy, returns an error, etc). It will be called upon any
+  # response code that does not start with '2'. Useful to alert admins
+  # about problems with requests.
+  #
+  # Parameters:
+  # - STATUSCODE
+  #   The HTML status code that originated the error.
+  # - REASON
+  #   The specified reason for the error.
+  # - REQTYPE
+  #   The kind of request that was made (GET, POST...)
+  # - HEADERS
+  #   HTTP headers returned by the CA
 
-    # Simple example: Send mail to root
-    # printf "Subject: HTTP request failed failed!\n\nA http request failed 
with status ${STATUSCODE}!" | sendmail root
+  # Simple example: Send mail to root
+  # printf "Subject: HTTP request failed failed!\n\nA http request failed with 
status ${STATUSCODE}!" | sendmail root
 }
 
 generate_csr() {
-    local DOMAIN="${1}" CERTDIR="${2}" ALTNAMES="${3}"
+  local DOMAIN="${1}" CERTDIR="${2}" ALTNAMES="${3}"
 
-    # This hook is called before any certificate signing operation takes place.
-    # It can be used to generate or fetch a certificate signing request with 
external
-    # tools.
-    # The output should be just the certificate signing request formatted as 
PEM.
-    #
-    # Parameters:
-    # - DOMAIN
-    #   The primary domain as specified in domains.txt. This does not need to
-    #   match with the domains in the CSR, it's basically just the directory 
name.
-    # - CERTDIR
-    #   Certificate output directory for this particular certificate. Can be 
used
-    #   for storing additional files.
-    # - ALTNAMES
-    #   All domain names for the current certificate as specified in 
domains.txt.
-    #   Again, this doesn't need to match with the CSR, it's just there for 
convenience.
-
-    # Simple example: Look for pre-generated CSRs
-    # if [ -e "${CERTDIR}/pre-generated.csr" ]; then
-    #   cat "${CERTDIR}/pre-generated.csr"
-    # fi
+  # This hook is called before any certificate signing operation takes place.
+  # It can be used to generate or fetch a certificate signing request with 
external
+  # tools.
+  # The output should be just the certificate signing request formatted as PEM.
+  #
+  # Parameters:
+  # - DOMAIN
+  #   The primary domain as specified in domains.txt. This does not need to
+  #   match with the domains in the CSR, it's basically just the directory 
name.
+  # - CERTDIR
+  #   Certificate output directory for this particular certificate. Can be used
+  #   for storing additional files.
+  # - ALTNAMES
+  #   All domain names for the current certificate as specified in domains.txt.
+  #   Again, this doesn't need to match with the CSR, it's just there for 
convenience.
+
+  # Simple example: Look for pre-generated CSRs
+  # if [ -e "${CERTDIR}/pre-generated.csr" ]; then
+  #   cat "${CERTDIR}/pre-generated.csr"
+  # fi
 }
 
 startup_hook() {
Binary files old/dehydrated-0.7.0/docs/logo.jpg and 
new/dehydrated-0.7.1/docs/logo.jpg differ
Binary files old/dehydrated-0.7.0/docs/logo.png and 
new/dehydrated-0.7.1/docs/logo.png differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/docs/per-certificate-config.md 
new/dehydrated-0.7.1/docs/per-certificate-config.md
--- old/dehydrated-0.7.0/docs/per-certificate-config.md 2020-12-10 
16:54:26.000000000 +0100
+++ new/dehydrated-0.7.1/docs/per-certificate-config.md 2022-10-31 
15:12:38.000000000 +0100
@@ -11,6 +11,8 @@
 - KEY_ALGO
 - KEYSIZE
 - OCSP_MUST_STAPLE
+- OCSP_FETCH
+- OCSP_DAYS
 - CHALLENGETYPE
 - HOOK
 - HOOK_CHAIN
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/docs/staging.md 
new/dehydrated-0.7.1/docs/staging.md
--- old/dehydrated-0.7.0/docs/staging.md        2020-12-10 16:54:26.000000000 
+0100
+++ new/dehydrated-0.7.1/docs/staging.md        2022-10-31 15:12:38.000000000 
+0100
@@ -8,10 +8,7 @@
 To avoid this, please set the CA property to the Let???s Encrypt staging 
server URL in your config file:
 
 ```bash
-CA="https://acme-staging.api.letsencrypt.org/directory";
+CA="https://acme-staging-v02.api.letsencrypt.org/directory";
 ```
 
-# ACMEv2 staging
-
-You can use `CA="https://acme-staging-v02.api.letsencrypt.org/directory"` to 
test dehydrated with
-the ACMEv2 staging endpoint.
+Alternatively you can define the CA using the CLI argument `--ca 
letsencrypt-test` (`letsencrypt-test` is an integrated preset-CA corresponding 
to the URL above).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/dehydrated-0.7.0/docs/tls-alpn.md 
new/dehydrated-0.7.1/docs/tls-alpn.md
--- old/dehydrated-0.7.0/docs/tls-alpn.md       2020-12-10 16:54:26.000000000 
+0100
+++ new/dehydrated-0.7.1/docs/tls-alpn.md       2022-10-31 15:12:38.000000000 
+0100
@@ -6,6 +6,26 @@
 
 Dehydrated generates the required verification certificates, but the delivery 
is out of its scope.
 
+### Example lighttpd config
+
+lighttpd can be configured to recognize ALPN `acme-tls/1` and to respond to 
such
+requests using the specially crafted TLS certificates generated by dehydrated.
+Configure lighttpd and dehydrated to use the same path for these certificates.
+(Be sure to allow read access to the user account under which the lighttpd
+server is running.) `mkdir -p /etc/dehydrated/alpn-certs`
+
+lighttpd.conf:
+```
+ssl.acme-tls-1 = "/etc/dehydrated/alpn-certs"
+```
+
+When renewing certificates, specify `-t tls-alpn-01` and `--alpn 
/etc/dehydrated/alpn-certs` to dehydrated, e.g.
+```
+dehydrated -t tls-alpn-01 --alpn /etc/dehydrated/alpn-certs -c --out 
/etc/lighttpd/certs -d www.example.com
+# gracefully reload lighttpd to use the new certificates by sending lighttpd 
pid SIGUSR1
+systemctl reload lighttpd
+```
+
 ### Example nginx config
 
 On an nginx tcp load-balancer you can use the `ssl_preread` module to map a 
different port for acme-tls

Reply via email to