#1100734 debian-keyring: Many SHA-1 issues found by «sq cert lint»

#1100734#5
Date:
2025-03-18 01:20:26 UTC
From:
To:
Hi!

The current keyrings generate many SHA-1 issues when running them through
the Sequoia-PGP certificate linter. This means that tools that are
starting to use Sequoia commands as OpenPGP backends, or possibly other
implementations via the SOP CLI, might fail. For example dscverify,
dpkg-source or dupload, or even when using things like sq directly.

Running the linter over the current keyrings in the package gives the
following summary:

  $ sq cert lint </usr/share/keyrings/debian-keyring.gpg
  […]
  Examined 924 certificates.
    0 certificates are invalid and were not linted. (GOOD)
    924 certificates were linted.
    181 of the 924 certificates (19%) have at least one issue. (BAD)
  0 of the linted certificates were revoked.
    0 of the 0 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
  90 of the linted certificates were expired.
  834 of the non-revoked linted certificates have at least one non-revoked User ID:
    143 have at least one User ID protected by SHA-1. (BAD)
    81 have all User IDs protected by SHA-1. (BAD)
  792 of the non-revoked linted certificates have at least one non-revoked, live subkey:
    145 have at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
  214 of the non-revoked linted certificates have at least one non-revoked, live, signing-capable subkey:
    12 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (BAD)

  $ sq cert lint </usr/share/keyrings/debian-maintainers.gpg
  […]
  Examined 247 certificates.
    0 certificates are invalid and were not linted. (GOOD)
    247 certificates were linted.
    40 of the 247 certificates (16%) have at least one issue. (BAD)
  0 of the linted certificates were revoked.
    0 of the 0 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
  42 of the linted certificates were expired.
  205 of the non-revoked linted certificates have at least one non-revoked User ID:
    31 have at least one User ID protected by SHA-1. (BAD)
    19 have all User IDs protected by SHA-1. (BAD)
  194 of the non-revoked linted certificates have at least one non-revoked, live subkey:
    31 have at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
  53 of the non-revoked linted certificates have at least one non-revoked, live, signing-capable subkey:
    3 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (BAD)

  $ sq cert lint </usr/share/keyrings/debian-nonupload.gpg
  […]
  Examined 40 certificates.
    0 certificates are invalid and were not linted. (GOOD)
    40 certificates were linted.
    8 of the 40 certificates (20%) have at least one issue. (BAD)
  0 of the linted certificates were revoked.
    0 of the 0 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
  2 of the linted certificates were expired.
  38 of the non-revoked linted certificates have at least one non-revoked User ID:
    5 have at least one User ID protected by SHA-1. (BAD)
    3 have all User IDs protected by SHA-1. (BAD)
  35 of the non-revoked linted certificates have at least one non-revoked, live subkey:
    7 have at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
  4 of the non-revoked linted certificates have at least one non-revoked, live, signing-capable subkey:
    0 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (GOOD)

The debian-role-keys.gpg is all good.

Checking the git repo, gives similar results, where for some things
the git repo is worse and for others it's better.

It would be nice to stop accepting new updates that regress on this
front. And ideally to start a new campaign like had been done in the
past for other issues about weak keys/certificates.

(I think you might already know, but in any case «sq cert lint» provides
a --fix mode that should be able to fix these issues for the owner of
the keys.)

Thanks,
Guillem

#1100734#10
Date:
2025-03-18 01:26:50 UTC
From:
To:
Hi!

And an additional nice documentation resource for reference, or to
point people to could be:

https://book.sequoia-pgp.org/lint.html

Thanks,
Guillem

#1100734#15
Date:
2025-03-18 08:43:33 UTC
From:
To:
Hello,

Something like this might implement the "stop accepting new updates"
part. It's a bit more strict than suggested because it refuses all
updates if the new key is broken.

diff --git a/scripts/add-key b/scripts/add-key
index 313719fe1d48..d38437016728 100755
--- a/scripts/add-key
+++ b/scripts/add-key
@@ -61,6 +61,10 @@ else
 	gpg --quiet --keyserver keyserver.ubuntu.com --recv-key $1 || true
 	gpg --quiet --keyserver the.earth.li --send-key $1
 fi
+
+echo "Inspect new key with Sequoia:"
+sq cert lint --cert=$keyid
+
 gpg --keyring output/keyrings/debian-keyring.gpg \
         --keyring output/keyrings/debian-nonupload.gpg --check-sigs \
         --with-fingerprint --keyid-format 0xlong 0x$keyid | \
diff --git a/scripts/replace-key b/scripts/replace-key
index caad4990b20e..d93ab21d977d 100755
--- a/scripts/replace-key
+++ b/scripts/replace-key
@@ -39,6 +39,8 @@ gpg --no-auto-check-trustdb --options /dev/null \
 	--export-options export-clean,no-export-attributes \
 	--export "$newkey" > $newkeytemp

+sq cert lint ----cert-file="$newkeytemp"
+
 # strip leading 0x from fingerprints
 oldkey=${oldkey##0x}
 newkey=${newkey##0x}
diff --git a/scripts/update-key b/scripts/update-key
index 769a0805ef4d..45f3847d0cac 100755
--- a/scripts/update-key
+++ b/scripts/update-key
@@ -82,6 +82,7 @@ while [ "x$n" = "xa" -o "x$n" = "xA" ]; do
 	echo $summary
 	echo
 	scripts/gpg-diff $keydir/0x$keyid $GNUPGHOME/0x$keyid
+	sq cert lint --cert-file="$GNUPGHOME/0x$keyid"
     ) | sensible-pager

     echo "Are you sure you want to update this key? (y/n/a: Yes/No/Again)"

Best regards
Uwe

#1100734#20
Date:
2025-03-18 08:43:33 UTC
From:
To:
Hello,

Something like this might implement the "stop accepting new updates"
part. It's a bit more strict than suggested because it refuses all
updates if the new key is broken.

diff --git a/scripts/add-key b/scripts/add-key
index 313719fe1d48..d38437016728 100755
--- a/scripts/add-key
+++ b/scripts/add-key
@@ -61,6 +61,10 @@ else
 	gpg --quiet --keyserver keyserver.ubuntu.com --recv-key $1 || true
 	gpg --quiet --keyserver the.earth.li --send-key $1
 fi
+
+echo "Inspect new key with Sequoia:"
+sq cert lint --cert=$keyid
+
 gpg --keyring output/keyrings/debian-keyring.gpg \
         --keyring output/keyrings/debian-nonupload.gpg --check-sigs \
         --with-fingerprint --keyid-format 0xlong 0x$keyid | \
diff --git a/scripts/replace-key b/scripts/replace-key
index caad4990b20e..d93ab21d977d 100755
--- a/scripts/replace-key
+++ b/scripts/replace-key
@@ -39,6 +39,8 @@ gpg --no-auto-check-trustdb --options /dev/null \
 	--export-options export-clean,no-export-attributes \
 	--export "$newkey" > $newkeytemp

+sq cert lint ----cert-file="$newkeytemp"
+
 # strip leading 0x from fingerprints
 oldkey=${oldkey##0x}
 newkey=${newkey##0x}
diff --git a/scripts/update-key b/scripts/update-key
index 769a0805ef4d..45f3847d0cac 100755
--- a/scripts/update-key
+++ b/scripts/update-key
@@ -82,6 +82,7 @@ while [ "x$n" = "xa" -o "x$n" = "xA" ]; do
 	echo $summary
 	echo
 	scripts/gpg-diff $keydir/0x$keyid $GNUPGHOME/0x$keyid
+	sq cert lint --cert-file="$GNUPGHOME/0x$keyid"
     ) | sensible-pager

     echo "Are you sure you want to update this key? (y/n/a: Yes/No/Again)"

Best regards
Uwe

#1100734#25
Date:
2025-03-20 08:44:21 UTC
From:
To:
The other problem is that "sq cert" is not available in bookworm. We
have a requirement that we can build the keyring under a machine running
stable. Recent versions of sequoia can't even be built on bookworm
machine (they want a newer Rust compiler), so unfortunately we're not
going to be able to build that sort of check into our pipelines until
trixie is released and deployed in the right places.

I see Guillem has already taken this to -devel. While I agree we want to
get rid of SHA-1 self-signatures on keys, I'm not clear on exactly what
problem this is causing with new dpkg, given that I'd expect the
signatures it cares about are from the unaffected role keys?

J.

#1100734#30
Date:
2025-03-20 09:55:38 UTC
From:
To:
Hi!

I think passing «--weak-digest SHA1 --weak-digest RIPEMD160» to the
relevant gpg invocations might effectively do the same (?). This has
been in effect in Dpkg::* Perl modules, and thus dpkg-source for some
time now as well as on things like dscverify (AFAIR), and recently on
dupload as well.

Otherwise in bookworm the Sequoia certificate linter was available in
the form of the sq-keyring-linter package and command.

dpkg (the project) and surrounding tools are more concerned about the
non-role keys than the role or archive keys, as those tools deal with
signatures on .dsc, .changes and similar artifacts, signed directly
by developers.

I brought it up there after receiving #1100867, and realizing that an
earlier report I had been pointed at (see from
https://bugs.debian.org/1076223#54 onwards) was affected by the same
issues, to try to mitigate similar confused reactions from developers.

Thanks,
Guillem

#1100734#35
Date:
2025-03-23 22:46:37 UTC
From:
To:
Guillem Jover wrote:

I'm not sure this analysis is completely correct. As far as I can tell,
you've flagged my key on the basis of "sq cert lint" reporting the
following output:

    $ sq cert lint --keyring /usr/share/keyrings/debian-keyring.gpg --cert 01817AB0AAF6CDAE
    Certificate 01817AB0AAF6CDAE, key 292C9BB54A4D3CBA uses a SHA-1-protected binding signature.
    Examined 1 certificate.
      0 certificates are invalid and were not linted. (GOOD)
      1 certificate was linted.
      1 of the 1 certificates (100%) has at least one issue. (BAD)
    0 of the linted certificates were revoked.
      0 of the 0 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
    0 of the linted certificates were expired.
    1 of the non-revoked linted certificate has at least one non-revoked User ID:
      0 have at least one User ID protected by SHA-1. (GOOD)
      0 have all User IDs protected by SHA-1. (GOOD)
    1 of the non-revoked linted certificates has at least one non-revoked, live subkey:
      1 has at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
    0 of the non-revoked linted certificates have at least one non-revoked, live, signing-capable subkey:
      0 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (GOOD)

      Error: 1 certificate have at least one issue

Now, key 292C9BB54A4D3CBA is my encryption subkey, not the main key
01817AB0AAF6CDAE that is used for signing and certifying:

    sec  rsa4096/01817AB0AAF6CDAE
         created: 2013-10-03  expires: never       usage: SC
         card-no: 0005 00003A89
         trust: ultimate      validity: ultimate
    ssb  rsa4096/292C9BB54A4D3CBA
         created: 2013-10-03  expires: never       usage: E
         card-no: 0005 00003A89

Since only the encryption subkey is affected, I do not believe this
problem can affect the signatures on my signed .dsc or .changes files.

Here are the raw PGP packets, from a clean sid chroot with gpg and
debian-keyring installed:

    root@7311057f397a:/# gpg --keyring=/usr/share/keyrings/debian-keyring.gpg --export-options export-minimal --export 01817AB0AAF6CDAE | gpg --list-packets
    # off=0 ctb=99 tag=6 hlen=3 plen=525
    :public key packet:
    	version 4, algo 1, created 1380802569, expires 0
    	pkey[0]: [4096 bits]
    	pkey[1]: [17 bits]
    	keyid: 01817AB0AAF6CDAE
    # off=528 ctb=b4 tag=13 hlen=2 plen=31
    :user ID packet: "Robert Edmonds <edmonds@fsi.io>"
    # off=561 ctb=89 tag=2 hlen=3 plen=543
    :signature packet: algo 1, keyid 01817AB0AAF6CDAE
    	version 4, created 1470513048, md5len 0, sigclass 0x30
    	digest algo 8, begin of digest fb a2
    	hashed subpkt 2 len 4 (sig created 2016-08-06)
    	hashed subpkt 29 len 1 (revocation reason 0x20 ())
    	subpkt 16 len 8 (issuer key ID 01817AB0AAF6CDAE)
    	data: [4095 bits]
    # off=1107 ctb=b4 tag=13 hlen=2 plen=33
    :user ID packet: "Robert Edmonds <edmonds@mycre.ws>"
    # off=1142 ctb=89 tag=2 hlen=3 plen=570
    :signature packet: algo 1, keyid 01817AB0AAF6CDAE
    	version 4, created 1408125108, md5len 0, sigclass 0x13
    	digest algo 8, begin of digest 5e 8d
    	hashed subpkt 27 len 1 (key flags: 03)
    	hashed subpkt 30 len 1 (features: 01)
    	hashed subpkt 23 len 1 (keyserver preferences: 80)
    	hashed subpkt 25 len 1 (primary user ID)
    	hashed subpkt 2 len 4 (sig created 2014-08-15)
    	hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 3)
    	hashed subpkt 21 len 4 (pref-hash-algos: 10 9 8 11)
    	hashed subpkt 22 len 4 (pref-zip-algos: 2 3 1 0)
    	subpkt 16 len 8 (issuer key ID 01817AB0AAF6CDAE)
    	data: [4096 bits]
    # off=1715 ctb=b4 tag=13 hlen=2 plen=35
    :user ID packet: "Robert Edmonds <edmonds@debian.org>"
    # off=1752 ctb=89 tag=2 hlen=3 plen=567
    :signature packet: algo 1, keyid 01817AB0AAF6CDAE
    	version 4, created 1408125126, md5len 0, sigclass 0x13
    	digest algo 8, begin of digest cc 62
    	hashed subpkt 27 len 1 (key flags: 03)
    	hashed subpkt 30 len 1 (features: 01)
    	hashed subpkt 23 len 1 (keyserver preferences: 80)
    	hashed subpkt 2 len 4 (sig created 2014-08-15)
    	hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 3)
    	hashed subpkt 21 len 4 (pref-hash-algos: 10 9 8 11)
    	hashed subpkt 22 len 4 (pref-zip-algos: 2 3 1 0)
    	subpkt 16 len 8 (issuer key ID 01817AB0AAF6CDAE)
    	data: [4095 bits]
    # off=2322 ctb=b9 tag=14 hlen=3 plen=525
    :public sub key packet:
    	version 4, algo 1, created 1380802569, expires 0
    	pkey[0]: [4096 bits]
    	pkey[1]: [17 bits]
    	keyid: 292C9BB54A4D3CBA
    # off=2850 ctb=89 tag=2 hlen=3 plen=543
    :signature packet: algo 1, keyid 01817AB0AAF6CDAE
    	version 4, created 1380802569, md5len 0, sigclass 0x18
    	digest algo 2, begin of digest 1e e4
    	hashed subpkt 2 len 4 (sig created 2013-10-03)
    	hashed subpkt 27 len 1 (key flags: 0C)
    	subpkt 16 len 8 (issuer key ID 01817AB0AAF6CDAE)
    	data: [4095 bits]

If I understand correctly, the last packet is the only one with "digest
algo 2" (SHA-1), which is the self-signature on the encryption subkey
(292C9BB54A4D3CBA). All the other signatures are "digest algo 8"
(SHA-256).

By the way, the hash algorithm numbers are registered here:
https://www.iana.org/assignments/openpgp/openpgp.xhtml#openpgp-hash-algorithms.

I do not see any of the verification failures that you demonstrated
downthread on debian-devel when I try to verify a recent upload of mine:

    $ apt source --download-only protobuf-c
    NOTICE: 'protobuf-c' packaging is maintained in the 'Git' version control system at:
https://salsa.debian.org/edmonds/protobuf-c.git
    Please use:
    git clone https://salsa.debian.org/edmonds/protobuf-c.git
    to retrieve the latest (possibly unreleased) updates to the package.
    Need to get 538 kB of source archives.
    Get:1 http://deb.debian.org/debian sid/main protobuf-c 1.5.1-1 (dsc) [2,060 B]
    Get:2 http://deb.debian.org/debian sid/main protobuf-c 1.5.1-1 (tar) [532 kB]
    Get:3 http://deb.debian.org/debian sid/main protobuf-c 1.5.1-1 (diff) [4,576 B]
    Fetched 538 kB in 0s (8,641 kB/s)
    Download complete and in download only mode

    $ gpgv-sq --keyring /usr/share/keyrings/debian-keyring.gpg protobuf-c_1.5.1-1.dsc 1>/dev/null
    gpgv: Signature made Sun Feb  2 00:10:24 2025 -05:00
    gpgv:                using RSA key DF3D96EEB3827820F302665C01817AB0AAF6CDAE
    gpgv: Good signature from "Robert Edmonds <edmonds@mycre.ws>"
    gpgv:                     "Robert Edmonds <edmonds@debian.org>"

    $ dscverify --verbose --no-default-keyrings --keyring /usr/share/keyrings/debian-keyring.gpg protobuf-c_1.5.1-1.dsc
    protobuf-c_1.5.1-1.dsc:
    gpg: Signature made Sun 02 Feb 2025 12:10:24 AM EST
    gpg:                using RSA key DF3D96EEB3827820F302665C01817AB0AAF6CDAE
    gpg: Good signature from "Robert Edmonds <edmonds@mycre.ws>" [unknown]
    gpg:                 aka "Robert Edmonds <edmonds@debian.org>" [unknown]
    gpg: WARNING: Using untrusted key!
          Good signature found
       validating protobuf-c_1.5.1.orig.tar.gz
       validating protobuf-c_1.5.1-1.debian.tar.xz
    All files validated successfully.

That makes sense, since only my encryption subkey is affected.

The "gpg --edit-key" instructions on the lore.kernel.org page you
linked did not work for me. (I use an OpenPGP hardware card and have not
investigated Sequoia's support for hardware keys.)

I did find this blog post:

https://blog.bmarwell.de/2020/11/21/fixing-old-sha1-infested-openpgp-keys.html

And the command "gpg --quick-set-expire <key-fingerprint> 0 '*'" listed
on that page worked to replace the self-signature on the encryption
subkey. Now I have the following signature packet with "digest algo 10"
(SHA-512) rather than "digest algo 2" (SHA-1):

    # off=2850 ctb=89 tag=2 hlen=3 plen=566
    :signature packet: algo 1, keyid 01817AB0AAF6CDAE
    	version 4, created 1742767476, md5len 0, sigclass 0x18
    	digest algo 10, begin of digest 93 60
    	hashed subpkt 27 len 1 (key flags: 0C)
    	hashed subpkt 33 len 21 (issuer fpr v4 DF3D96EEB3827820F302665C01817AB0AAF6CDAE)
    	hashed subpkt 2 len 4 (sig created 2025-03-23)
    	subpkt 16 len 8 (issuer key ID 01817AB0AAF6CDAE)
    	data: [4095 bits]

With this new signature, the "sq cert lint" command does not print any
red text to the terminal now.

But, again, this is a self-signature on an encryption subkey and I do
not see how that should affect the verification of signatures made from
the signing key on .dsc, .changes, etc. files.