bin/make-cert, bin/fix-cert-chain: Hack certificate chains for compatiblity. master
authorMark Wooding <mdw@distorted.org.uk>
Sat, 2 Oct 2021 10:39:05 +0000 (11:39 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 2 Oct 2021 10:39:05 +0000 (11:39 +0100)
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.

bin/fix-cert-chain [new file with mode: 0755]
bin/make-cert

diff --git a/bin/fix-cert-chain b/bin/fix-cert-chain
new file mode 100755 (executable)
index 0000000..dc9a313
--- /dev/null
@@ -0,0 +1,41 @@
+#! /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"
index 9dcf15b..a094a53 100755 (executable)
@@ -22,4 +22,6 @@ unset http_proxy
 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