Oh, this is a mess.
https://community.letsencrypt.org/t/openssl-client-compatibility-changes-for-let-s-encrypt-certificates/143816
Old versions of Android don't recognize the new Let's Encrypt issuer.
So LE deployed a kludge: their certificate chains include a reference to
their old issuer, which /is/ recognized by old Android versions. But
there's a problem: this issuer /expired/ yesterday, and old versions of
OpenSSL and GnuTLS reject certificate bundles involving expired issuers,
even if (a) the expired certificate is in the cert store, not provided
by the server, and (b) there's a perfectly fine trust path which doesn't
involve the duff certificate.
Introduce a new script `fix-cert-chain' to generally tidy up certificate
chains by (a) deleting duplicate certificates and (b) removing
certificates from `bad' issuers.
--- /dev/null
+#! /bin/sh -e
+
+bad_issuers="
+O = Digital Signature Trust Co., CN = DST Root CA X3
+"
+
+case $# in
+ 1) certs=$1 ;;
+ *) echo >&2 "usage: $0 CERTLIST-FILE"; exit 2 ;;
+esac
+
+nl="
+"
+mode=skip all=
+while IFS= read -r line; do
+ case $line,$mode in
+ "-----BEGIN CERTIFICATE-----",skip)
+ mode=keep
+ buf="$line$nl"
+ ;;
+ "-----END CERTIFICATE-----",keep)
+ mode=skip
+ buf="$buf$line"
+ keep=t
+ case "$nl$nl$all$nl$nl" in
+ *"$nl$nl$buf$nl$nl"*) keep=nil ;;
+ esac
+ case $keep in
+ t)
+ issuer=$(echo "$buf" | openssl x509 -noout -issuer)
+ case $bad_issuers in $"$nl$issuer$nl"*) keep=nil ;; esac
+ ;;
+ esac
+ case $keep in t) all="${all:+$all$nl$nl}$buf" ;; esac
+ ;;
+ *,keep) buf="$buf$line$nl" ;;
+ esac
+done <"$certs"
+
+case $all in "") echo >&2 "$0: no certificates found"; exit 127 ;; esac
+echo "$all"
cert=$home/cert/$tag
cd $cert
dehydrated -f $HOME/dehydrated-config.sh -fc -s req >full-chain.new
-mv full-chain.new full-chain
+fix-cert-chain full-chain.new >full-chain.fixed
+mv full-chain.fixed full-chain
+rm full-chain.new