Your message dated Sat, 29 Jun 2024 10:46:21 +0000
with message-id <e1snvb3-002bj8...@coccia.debian.org>
and subject line Released with 12.6
has caused the Debian Bug report #1073175,
regarding bookworm-pu: package lacme/0.8.2-1+deb12u1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact ow...@bugs.debian.org
immediately.)


-- 
1073175: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1073175
Debian Bug Tracking System
Contact ow...@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: la...@packages.debian.org
Control: affects -1 + src:lacme
User: release.debian....@packages.debian.org
Usertags: pu

[ Reason ]

Let's Encrypt has recently rotated its intermediate certificates [0].
The previously used intermediate certificates were used as trust anchors
for validation of the issued X.509 certificate before its deployment.

The intermediate rotation means the validation step currently fails with
the default configuration.

[ Impact ]

Post-issuance validation failure (and therefore unusable package) in the
default configuration, see #1072847.

[ Tests ]

lacme has a comprehensive test suite.  It does not run at build time nor
via debci as it requires an open 80/tcp and test hostnames pointing to
it (to reply to ACME challenges), but I succesfully ran in manually.

Moreover the package is already used in production where it indeed
solves the post-issuance validation failure.

[ Risks ]

A quick fix would be to simply replace the old intermediates in the
certificate bundle, but that would cease to work again next time Let's
Encrypt rotate their intermediates.  In fact the new intermediates
expire sooner than the old ones (2 years from now, but of course the
rotation is likely not to happen at the last minute).  This appears to
be deliberate in order to discourage pining them [0].

The validation logic has therefore changed to use arbitrary
intermediate(s) provided during the issuance step as -untrusted (for
chain building).  Only the root certificates are used as trust anchor.
The patch is rather trival:

    diff -Nru -w lacme-0.8.2/lacme lacme-0.8.2/lacme
    --- lacme-0.8.2/lacme       2023-04-25 20:06:22.000000000 +0200
    +++ lacme-0.8.2/lacme       2024-06-14 01:24:36.000000000 +0200
    @@ -822,21 +822,31 @@

The (patch-applied) debdiff is longer as it includes changes to the test
suite made to accomodate Let's Encrypt current staging environment.
These changes could be omitted from debian/patches since the test suite
doesn't run, but I think there is some value in having working manual
tests out of the box.

[ 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 stable
  [x] the issue is verified as fixed in unstable

[ Changes ]

  * Backport upstream patch to fix post-issuance validation logic.
    Avoid pining the intermediate certificates in the bundle and instead
    validate the leaf certificate with intermediate(s) supplied during
    issuance as untrusted (used for chain building only).  Only the root
    certificates are used as trust anchor.
    Not pining intermediate certificates is in line with Let's Encrypt's
    latest recommendations.
    Closes: #1072847
  * Adjust test suite against current Let's Encrypt staging environment.
  * d/gbp.conf: Set 'debian-branch = debian/bookworm'.

-- 
Guilhem.

[0] https://letsencrypt.org/2024/03/19/new-intermediate-certificates
diffstat for lacme-0.8.2 lacme-0.8.2

 Makefile                        |    8 ---
 debian/changelog                |   14 ++++++
 debian/gbp.conf                 |    2 
 debian/patches/series           |    2 
 lacme                           |   26 ++++++++++--
 tests/account-encrypted-gpg     |    2 
 tests/account-encrypted-openssl |    1 
 tests/cert-install              |   84 +++++++++++++++++++++++++---------------
 tests/cert-verify               |   22 ++--------
 tests/old-lacme                 |    9 ++--
 10 files changed, 106 insertions(+), 64 deletions(-)

diff -Nru lacme-0.8.2/debian/changelog lacme-0.8.2/debian/changelog
--- lacme-0.8.2/debian/changelog        2023-04-25 20:08:21.000000000 +0200
+++ lacme-0.8.2/debian/changelog        2024-06-14 01:20:13.000000000 +0200
@@ -1,3 +1,17 @@
+lacme (0.8.2-1+deb12u1) bookworm; urgency=medium
+
+  * Backport upstream patches to fix post-issuance validation logic.
+    We avoid pining the intermediate certificates in the bundle and instead
+    validate the leaf certificate with intermediates supplied during issuance
+    as untrusted (used for chain building only).  Only the root certificates
+    are used as trust anchor.  Not pining intermediate certificates is in line
+    with Let's Encrypt's latest recommendations.
+    Closes: #1072847
+  * Adjust test suite against current Let's Encrypt staging environment.
+  * d/gbp.conf: Set 'debian-branch = debian/bookworm'.
+
+ -- Guilhem Moulin <guil...@debian.org>  Fri, 14 Jun 2024 01:20:13 +0200
+
 lacme (0.8.2-1) unstable; urgency=medium
 
   * New upstream bugfix release.
diff -Nru lacme-0.8.2/debian/gbp.conf lacme-0.8.2/debian/gbp.conf
--- lacme-0.8.2/debian/gbp.conf 2023-04-25 20:08:21.000000000 +0200
+++ lacme-0.8.2/debian/gbp.conf 2024-06-14 01:20:13.000000000 +0200
@@ -1,6 +1,6 @@
 [DEFAULT]
 upstream-branch = upstream
-debian-branch = debian/latest
+debian-branch = debian/bookworm
 upstream-tag = v%(version)s
 debian-tag = debian/%(version)s
 pristine-tar = False
diff -Nru lacme-0.8.2/debian/patches/series lacme-0.8.2/debian/patches/series
--- lacme-0.8.2/debian/patches/series   2023-04-25 20:08:21.000000000 +0200
+++ lacme-0.8.2/debian/patches/series   2024-06-14 01:20:13.000000000 +0200
@@ -1 +1,3 @@
 Mention-the-Debian-BTS-in-the-manpages.patch
+Fix-post-issuance-validation-logic.patch
+Adjust-test-suite-against-current-Let-s-Encrypt-staging-e.patch
diff -Nru lacme-0.8.2/lacme lacme-0.8.2/lacme
--- lacme-0.8.2/lacme   2023-04-25 20:06:22.000000000 +0200
+++ lacme-0.8.2/lacme   2024-06-14 01:46:27.000000000 +0200
@@ -822,21 +822,31 @@
             next;
         }
 
-        my $cert;
+        my @chain;
         eval {
             my $mem = Net::SSLeay::BIO_s_mem() or die;
             my $bio = Net::SSLeay::BIO_new($mem) or die;
             die "incomplete write" unless
                 Net::SSLeay::BIO_write($bio, $chain) == length($chain);
-            my $x509 = Net::SSLeay::PEM_read_bio_X509($bio);
-            $cert = Net::SSLeay::PEM_get_string_X509($x509);
+
+            my $sk_x509_info = Net::SSLeay::PEM_X509_INFO_read_bio($bio);
+
+            my $n = Net::SSLeay::sk_X509_INFO_num($sk_x509_info);
+            for (my $i = 0; $i < $n; $i++) {
+                my $x509_info = Net::SSLeay::sk_X509_INFO_value($sk_x509_info, 
$i);
+                my $x509 = Net::SSLeay::P_X509_INFO_get_x509($x509_info);
+                my $cert = Net::SSLeay::PEM_get_string_X509($x509);
+                push @chain, $cert;
+            }
+
             Net::SSLeay::BIO_free($bio) or die;
         };
-        if ($@) {
+        if ($@ or !@chain) {
             print STDERR "[$s] Error: Received bogus X.509 certificate from 
ACME server!\n";
             $rv = 1;
             next;
         }
+        my $cert = shift @chain; # leave only the intermediate in @chain
 
         # extract pubkeys from CSR and cert, and ensure they match
         # XXX would be nice to use X509_get_X509_PUBKEY and 
X509_REQ_get_X509_PUBKEY here,
@@ -852,9 +862,15 @@
 
         # verify certificate validity against the CA bundle
         if ((my $CAfile = $conf->{CAfile} // 
'@@datadir@@/lacme/ca-certificates.crt') ne '') {
+            my $chain_tmp = File::Temp::->new(SUFFIX => '.crt', TMPDIR => 1) 
// die;
+            $chain_tmp->say($_) foreach @chain;
+            $chain_tmp->flush();
+
             my %args = (in => $cert);
             $args{out} = \*STDERR if $OPTS{debug};
-            my @options = ('-trusted', $CAfile, '-purpose', 'sslserver', 
'-x509_strict');
+            my @options = ('-trusted', $CAfile);
+            push @options, '-untrusted', $chain_tmp->filename() if @chain;
+            push @options, ('-purpose', 'sslserver', '-x509_strict');
             push @options, '-show_chain' if $OPTS{debug};
             if (spawn(\%args, 'openssl', 'verify', @options)) {
                 print STDERR "[$s] Error: Received invalid X.509 certificate 
from ACME server!\n";
diff -Nru lacme-0.8.2/Makefile lacme-0.8.2/Makefile
--- lacme-0.8.2/Makefile        2023-04-25 20:06:22.000000000 +0200
+++ lacme-0.8.2/Makefile        2024-06-14 01:46:27.000000000 +0200
@@ -16,17 +16,13 @@
 # used for validation, see https://letsencrypt.org/certificates/
 $(BUILDDIR)/certs/ca-certificates.crt: \
         certs/isrgrootx1.pem \
-        certs/isrg-root-x2.pem \
-        certs/lets-encrypt-r[34].pem \
-        certs/lets-encrypt-e[12].pem
+        certs/isrg-root-x2.pem
        mkdir -pv -- $(@D)
        cat -- $^ >$@
 
 # Staging Environment for tests, see 
https://letsencrypt.org/docs/staging-environment/
 $(BUILDDIR)/certs-staging/ca-certificates.crt: \
-        certs-staging/letsencrypt-stg-root-x[12].pem \
-        certs-staging/letsencrypt-stg-int-r[34].pem \
-        certs-staging/letsencrypt-stg-int-e[12].pem
+        certs-staging/letsencrypt-stg-root-x[12].pem
        mkdir -pv -- $(@D)
        cat -- $^ >$@
 
diff -Nru lacme-0.8.2/tests/account-encrypted-gpg 
lacme-0.8.2/tests/account-encrypted-gpg
--- lacme-0.8.2/tests/account-encrypted-gpg     2023-04-25 20:06:22.000000000 
+0200
+++ lacme-0.8.2/tests/account-encrypted-gpg     2024-06-14 01:46:27.000000000 
+0200
@@ -9,7 +9,7 @@
 gpg --encrypt -r "$keyid" /etc/lacme/account.key
 sed -ri '0,\|^#?privkey\s*=.*| {s||privkey = gpg:/etc/lacme/account.key.gpg|}' 
/etc/lacme/lacme-accountd.conf
 
-export GPG_TTY="$(tty)"
+export GPG_TTY="$(tty)" TERM="linux"
 lacme account
 
 # vim: set filetype=sh :
diff -Nru lacme-0.8.2/tests/account-encrypted-openssl 
lacme-0.8.2/tests/account-encrypted-openssl
--- lacme-0.8.2/tests/account-encrypted-openssl 2023-04-25 20:06:22.000000000 
+0200
+++ lacme-0.8.2/tests/account-encrypted-openssl 2024-06-14 01:46:27.000000000 
+0200
@@ -5,6 +5,7 @@
 openssl rsa -aes128 -passout pass:"$PASSPHRASE" </etc/lacme/account.key 
>/etc/lacme/account.enc.key
 sed -ri '0,\|^#?privkey\s*=.*| {s||privkey = 
file:/etc/lacme/account.enc.key|}' /etc/lacme/lacme-accountd.conf
 
+export TERM="linux"
 lacme account
 
 # vim: set filetype=sh :
diff -Nru lacme-0.8.2/tests/cert-install lacme-0.8.2/tests/cert-install
--- lacme-0.8.2/tests/cert-install      2023-04-25 20:06:22.000000000 +0200
+++ lacme-0.8.2/tests/cert-install      2024-06-14 01:46:27.000000000 +0200
@@ -28,9 +28,58 @@
 grepstderr -Fxq "[bad3] Warning: Couldn't generate CSR, skipping"
 
 
+check_spki() {
+    local p1="$1" p2="$2" s1 s2
+    s1="$(openssl x509 -in "$p1" -noout -pubkey \
+        | openssl pkey -pubin -outform DER \
+        | openssl dgst -sha256 \
+        | sed 's/.*=\s*//')"
+    s2="$(openssl pkey -in "$p2" -pubout -outform DER \
+        | openssl dgst -sha256 \
+        | sed 's/.*=\s*//')"
+    if [ -n "$s1" ] && [ "$s1" = "$s2" ]; then
+        return 0
+    else
+        printf "%s != %s\\n" "$s1" "$s2" >&2
+        return 1
+    fi
+}
+check_chain() {
+    local priv="$1" chain="$2" leaf="${3-}" pem0
+
+    csplit -f "${chain%.crt}.chain.pem" "$chain" \
+        "/-----BEGIN CERTIFICATE-----/" "{*}"
+
+    pem0="${chain%.crt}.chain.pem00"
+    if [ ! -s "$pem0" ]; then
+        # 00 is empty, leaf cert is at 01
+        rm -f -- "$pem0"
+        pem0="${chain%.crt}.chain.pem01"
+    fi
+    test -s "$pem0" || return 1
+    check_spki "$pem0" "$priv"
+
+    if [ -n "$leaf" ]; then
+        diff --ignore-blank-lines --unified "$pem0" "$leaf" || return 1
+    fi
+
+    leaf="${chain%.crt}.leaf.pem"
+    mv -T -- "$pem0" "$leaf"
+
+    intermediates="${chain%.crt}.intermediates.pem"
+    sed "/^$/d" "${chain%.crt}.chain.pem"[0-9]* >"$intermediates"
+    test -s "$intermediates" || return 1 # ensure there is at least one 
intermediate
+
+    openssl verify -trusted /usr/share/lacme/ca-certificates.crt \
+        -untrusted "$intermediates" \
+        -purpose sslserver -x509_strict \
+        -show_chain \
+        -- "$leaf" || return 1
+}
+
 # 'certificate' installs only the leaf certificate
 openssl genpkey -algorithm RSA -out /etc/lacme/test1.key
-subject="/CN=$(head -c10 /dev/urandom | base32 -w0).$DOMAINNAME"
+subject="/CN=$(head -c10 /dev/urandom | base32 -w0 | tr "A-Z" 
"a-z").$DOMAINNAME"
 cat >"/etc/lacme/lacme-certs.conf.d/test1.conf" <<- EOF
        [test1]
        certificate-key = /etc/lacme/test1.key
@@ -42,23 +91,9 @@
 test /etc/lacme/test1.crt -nt /etc/lacme/test1.key
 sed -n "0,/^-----END CERTIFICATE-----$/ p" /etc/lacme/test1.crt 
>/etc/lacme/test1.pem
 diff --unified /etc/lacme/test1.crt /etc/lacme/test1.pem
+check_spki /etc/lacme/test1.crt /etc/lacme/test1.key
 
 
-check_hash() {
-    local p1="$1" p2 s1 s2
-    s1="$(openssl x509 -noout -hash <"$p1")"
-    for p2 in /usr/share/lacme/ca-certificates.pem.*; do
-        s2="$(openssl x509 -noout -hash <"$p2")"
-        if [ "$s1" = "$s2" ]; then
-            return 0
-        fi
-    done
-    return 1
-}
-csplit -f /usr/share/lacme/ca-certificates.pem. 
/usr/share/lacme/ca-certificates.crt \
-    "/-----BEGIN CERTIFICATE-----/" "{*}"
-rm -f /usr/share/lacme/ca-certificates.pem.00
-
 # 'certificate-chain' appends the chain of trust
 openssl genpkey -algorithm RSA -out /etc/lacme/test2.key
 cat >"/etc/lacme/lacme-certs.conf.d/test2.conf" <<- EOF
@@ -70,16 +105,7 @@
 
 lacme newOrder test2 2>"$STDERR" || fail newOrder test2
 test /etc/lacme/test2.crt -nt /etc/lacme/test2.key
-csplit -f /etc/lacme/test2.chain.pem /etc/lacme/test2.crt \
-    "/-----BEGIN CERTIFICATE-----/" "{*}"
-test -s /etc/lacme/test2.chain.pem01 # leaf cert (00 is empty)
-rm -f /etc/lacme/test2.chain.pem0[01]
-test -s /etc/lacme/test2.chain.pem02 # depth 1
-
-# all certificates at depth >=1 must be in our CA bundle
-for p in /etc/lacme/test2.chain.pem*; do
-    check_hash "$p"
-done
+check_chain /etc/lacme/test2.key /etc/lacme/test2.crt
 
 # 'certificate' + 'certificate-chain'
 openssl genpkey -algorithm RSA -out /etc/lacme/test3.key
@@ -94,10 +120,8 @@
 lacme newOrder test3 2>"$STDERR" || fail newOrder test3
 test /etc/lacme/test3.pem -nt /etc/lacme/test3.key
 test /etc/lacme/test3.crt -nt /etc/lacme/test3.key
-csplit -f /etc/lacme/test3.chain.pem /etc/lacme/test3.crt \
-    "/-----BEGIN CERTIFICATE-----/" "{*}"
-sed -i "/^$/d" /etc/lacme/test3.chain.pem*
-diff -q /etc/lacme/test3.chain.pem01 /etc/lacme/test3.pem
+check_chain /etc/lacme/test3.key /etc/lacme/test3.crt /etc/lacme/test3.pem
+
 st="$(stat -c "%U:%G %#a" /etc/lacme/test3.pem)"
 [ "$st" = "root:root 0644" ]
 st="$(stat -c "%U:%G %#a" /etc/lacme/test3.crt)"
diff -Nru lacme-0.8.2/tests/cert-verify lacme-0.8.2/tests/cert-verify
--- lacme-0.8.2/tests/cert-verify       2023-04-25 20:06:22.000000000 +0200
+++ lacme-0.8.2/tests/cert-verify       2024-06-14 01:46:27.000000000 +0200
@@ -8,31 +8,19 @@
 done
 update-ca-certificates
 
-# test (modified) trust store for intermediate certificates
-openssl verify -no-CAfile -CApath /etc/ssl/certs                     
-show_chain /usr/share/lacme/letsencrypt-stg-int-*.pem
-openssl verify -no-CApath -CAfile /etc/ssl/certs/ca-certificates.crt 
-show_chain /usr/share/lacme/letsencrypt-stg-int-*.pem
+# test (modified) trust store
+openssl verify -no-CAfile -CApath /etc/ssl/certs                     
-show_chain /usr/share/lacme/letsencrypt-stg-root-x1.pem
+openssl verify -no-CApath -CAfile /etc/ssl/certs/ca-certificates.crt 
-show_chain /usr/share/lacme/letsencrypt-stg-root-x1.pem
 
 mv /usr/share/lacme/ca-certificates.crt 
/usr/share/lacme/ca-certificates.crt.back
 ! lacme newOrder 2>"$STDERR" || fail
-grepstderr -Fxq "Could not open file or uri for loading certs of trusted 
certificates from /usr/share/lacme/ca-certificates.crt"
+grepstderr -Fq  " certs of trusted certificates from 
/usr/share/lacme/ca-certificates.crt"
 grepstderr -Fxq "[simpletest-rsa] Error: Received invalid X.509 certificate 
from ACME server!"
 
 # verification error for unrelated CA bundle
 cat /etc/ssl/certs/ssl-cert-snakeoil.pem >/usr/share/lacme/ca-certificates.crt
 ! lacme newOrder 2>"$STDERR" || fail
-grepstderr -Fxq "error 20 at 0 depth lookup: unable to get local issuer 
certificate"
-grepstderr -Fxq "[simpletest-rsa] Error: Received invalid X.509 certificate 
from ACME server!"
-
-# verification error when the CA bundle contains only the root certificates
-cat /usr/share/lacme/letsencrypt-stg-root-*.pem 
>/usr/share/lacme/ca-certificates.crt
-! lacme newOrder 2>"$STDERR" || fail
-grepstderr -Fxq "error 20 at 0 depth lookup: unable to get local issuer 
certificate"
-grepstderr -Fxq "[simpletest-rsa] Error: Received invalid X.509 certificate 
from ACME server!"
-
-# verification error when the CA bundle contains only the intermediate 
certificates
-cat /usr/share/lacme/letsencrypt-stg-int-*.pem 
>/usr/share/lacme/ca-certificates.crt
-! lacme newOrder 2>"$STDERR" || fail
-grepstderr -Fxq "error 2 at 1 depth lookup: unable to get issuer certificate"
+grepstderr -Fxq "error 20 at 1 depth lookup: unable to get local issuer 
certificate"
 grepstderr -Fxq "[simpletest-rsa] Error: Received invalid X.509 certificate 
from ACME server!"
 
 # use saved bundle as custom CAfile
diff -Nru lacme-0.8.2/tests/old-lacme lacme-0.8.2/tests/old-lacme
--- lacme-0.8.2/tests/old-lacme 2023-04-25 20:06:22.000000000 +0200
+++ lacme-0.8.2/tests/old-lacme 2024-06-14 01:46:27.000000000 +0200
@@ -1,5 +1,6 @@
-# IPC test between recent lacme-accountd(1) and ancient lacme(8) 0.5 from 
Debian buster
-# (we don't try earlier versions as we need v2 support of the ACME API)
+# IPC test between recent lacme-accountd(1) and ancient lacme(8) 0.8 from 
Debian Bullseye
+# (we don't try earlier versions as we need v2 support of the ACME API
+# and non-pinned intermediates)
 
 adduser --disabled-password \
        --home /home/lacme-account \
@@ -14,12 +15,12 @@
        privkey = file:/etc/lacme/account.key
 EOF
 
-echo "deb http://deb.debian.org/debian buster main" >>/etc/apt/sources.list
+echo "deb http://deb.debian.org/debian bullseye main" >>/etc/apt/sources.list
 DEBIAN_FRONTEND="noninteractive" apt update
 DEBIAN_FRONTEND="noninteractive" apt install -y --no-install-recommends \
     --reinstall --allow-downgrades \
     -oDPkg::Options::="--force-confdef" -oDPkg::Options::="--force-overwrite" \
-    lacme/buster
+    lacme/bullseye
 
 # restore staging environment
 mv -f /usr/share/lacme/ca-certificates.crt.back 
/usr/share/lacme/ca-certificates.crt

Attachment: signature.asc
Description: PGP signature


--- End Message ---
--- Begin Message ---
Version: 12.6

The upload requested in this bug has been released as part of 12.6.

--- End Message ---

Reply via email to