fixing SHA-1 key and uid bindings [Was: Keys using SHA-1 in the kernel keyring]

Uwe Kleine-König <[email protected]> Sun, 23 Feb 2025 14:17:25 +0100
Newsgroups org.kernel.linux.keys
Message-ID <fxotnlhsyl2frp54xtguy7ryrucuwselanazixeax3motyyoo3@7vf7ip6gxyvx>
Hello,

On Fri, Feb 07, 2025 at 06:09:40PM +0100, Uwe Kleine-König wrote:
> sequoia (one of the alternative OpenPGP implementations) has a key
> linter tool that analyses key material for "issues".
> 
> When applied to the keys stored in the kernel pgpkeys.git it reports:
> 
> 	cat keys/* | sq cert lint --cert-file=-
> 	...
> 	Examined 643 certificates.
> 	  0 certificates are invalid and were not linted. (GOOD)
> 	  643 certificates were linted.
> 	  305 of the 643 certificates (47%) have at least one issue. (BAD)
> 	1 of the linted certificates was revoked.
> 	  0 of the 1 certificates has revocation certificates that are weaker than the certificate and should be recreated. (GOOD)
> 	51 of the linted certificates were expired.
> 	591 of the non-revoked linted certificates have at least one non-revoked User ID:
> 	  284 have at least one User ID protected by SHA-1. (BAD)
> 	  209 have all User IDs protected by SHA-1. (BAD)
> 	563 of the non-revoked linted certificates have at least one non-revoked, live
> 	subkey:
> 	  267 have at least one non-revoked, live subkey with a binding signature that uses SHA-1. (BAD)
> 	228 of the non-revoked linted certificates have at least one non-revoked, live,
> 	signing-capable subkey:
> 	  10 certificates have at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (BAD)
> 
> 	  Error: 305 certificates have at least one issue

I spend a while now to work out how to fix keys with both Sequoia and
GnuPG. I'll show that with two keys I found in the Sequoia sq test
directory (thanks to Neal for pointing me to those):

The key 7AAAE2F9A20EE786 has a strong binding signature, but a backsig that uses SHA-1:

	test@taurus:~$ sq cert lint --cert=F80F0DAA80C881408AB4B8257AAAE2F9A20EE786
	Certificate 7AAAE2F9A20EE786, key A15FEA88CB94EFC6 uses a SHA512-protected binding signature, but a SHA-1-protected backsig
	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:
	  0 have at least one non-revoked, live subkey with a binding signature that uses SHA-1. (GOOD)
	1 of the non-revoked linted certificates has at least one non-revoked, live, signing-capable subkey:
	  1 certificate has at least one non-revoked, live, signing-capable subkey with a strong binding signature, but a backsig that uses SHA-1. (BAD)

	  Error: 1 certificate have at least one issue

To fix this with Sequoia just do:

	$ sq cert lint --fix --output - --cert 7AAAE2F9A20EE786 | gpg --import

This works for me with Sequoia sq 1.2.0, earlier versions might not work.

With gnupg it's a *tad* more complicated (or I'm unaware of an easier
way). I'm using gpg (GnuPG) 2.2.45. You have to drop the subkey and
readd it, taking care to use the same meta data to get the same keyid
again.

This works as follows (if you follow this with your key, backup your ~/.gnupg
beforehand in case something breaks):

	$ gpg --list-key --with-colons --with-keygrip F80F0DAA80C881408AB4B8257AAAE2F9A20EE786
	tru::1:1740247384:0:3:1:5
	pub:-:2048:1:7AAAE2F9A20EE786:1604498771:::-:::scESC::::::23::0:
	fpr:::::::::F80F0DAA80C881408AB4B8257AAAE2F9A20EE786:
	grp:::::::::728B335833FD26A94E0D4E138612FFC4BF6C6C54:
	uid:-::::1604498771::B54A5427E86E5C1403595B4F2832A22830465C57::SHA1 Signing Subkey <[email protected]>::::::::::0:
	sub:-:2048:1:E311678FFC76B5C3:1604498771::::::e::::::23:
	fpr:::::::::049FE6B6E73AADAE3DC45721E311678FFC76B5C3:
	grp:::::::::C63D43150EB6E5C37B95FDF66E9DBF74D6C1FCB2:
	sub:-:2048:1:A15FEA88CB94EFC6:1604498790:2613650939:::::s::::::23:
	fpr:::::::::566697A84501E920CD8F509DA15FEA88CB94EFC6:
	grp:::::::::656C1C47DEA278D6C87F58ED17F7CC26EBDB4F84:

It's the second subkey that has the broken backsig (see output of `sq cert
lint` above)

The key expiry date is in 7th field in the respective sub line. We need that in
a iso-8601-like format in a moment:

	$ date --utc +%Y%m%dT%H%M%SZ -d @2613650939
	20521027T140859Z

Now start gpg --edit-key freezing it at the creation date (6th field in the sub
line above; note the exclamation mark):

	$ gpg --edit-key --expert --faked-system-time 1604498790! 7AAAE2F9A20EE786
	...
	sec  rsa2048/7AAAE2F9A20EE786
	     created: 2020-11-04  expires: never       usage: SC  
	     trust: unknown       validity: unknown
	ssb  rsa2048/E311678FFC76B5C3
	     created: 2020-11-04  expires: never       usage: E   
	ssb  rsa2048/A15FEA88CB94EFC6
	     created: 2020-11-04  expires: 2052-10-27  usage: S   
	[ unknown] (1). SHA1 Signing Subkey <[email protected]>

Select the second subkey:

	gpg> key 2

	sec  rsa2048/7AAAE2F9A20EE786
	     created: 2020-11-04  expires: never       usage: SC  
	     trust: unknown       validity: unknown
	ssb  rsa2048/E311678FFC76B5C3
	     created: 2020-11-04  expires: never       usage: E   
	ssb* rsa2048/A15FEA88CB94EFC6
	     created: 2020-11-04  expires: 2052-10-27  usage: S   
	[ unknown] (1). SHA1 Signing Subkey <[email protected]>

Note the key A15FEA88CB94EFC6 is marked with a * now.

	gpg> delkey
	Do you really want to delete this key? (y/N) y

	sec  rsa2048/7AAAE2F9A20EE786
	     created: 2020-11-04  expires: never       usage: SC  
	     trust: unknown       validity: unknown
	ssb  rsa2048/E311678FFC76B5C3
	     created: 2020-11-04  expires: never       usage: E   
	[ unknown] (1). SHA1 Signing Subkey <[email protected]>

Readd the key:

	gpg> addkey
	Please select what kind of key you want:
	   (3) DSA (sign only)
	   (4) RSA (sign only)
	   (5) Elgamal (encrypt only)
	   (6) RSA (encrypt only)
	   (7) DSA (set your own capabilities)
	   (8) RSA (set your own capabilities)
	  (10) ECC (sign only)
	  (11) ECC (set your own capabilities)
	  (12) ECC (encrypt only)
	  (13) Existing key
	  (14) Existing key from card
	Your selection? 13
	Enter the keygrip: 656C1C47DEA278D6C87F58ED17F7CC26EBDB4F84

	Possible actions for a RSA key: Sign Encrypt Authenticate 
	Current allowed actions: Sign Encrypt 

	   (S) Toggle the sign capability
	   (E) Toggle the encrypt capability
	   (A) Toggle the authenticate capability
	   (Q) Finished

The suggestion is to use this key as Sign and Encrypt. To match the previous
usage (important!) make it a signing key only (matching the 's' in the
--list-key output above), so toggle encrypt capability:

	Your selection? e

	Possible actions for a RSA key: Sign Encrypt Authenticate 
	Current allowed actions: Sign 

	   (S) Toggle the sign capability
	   (E) Toggle the encrypt capability
	   (A) Toggle the authenticate capability
	   (Q) Finished

	Your selection? q

Take care to restore the previous expiration date.

	Please specify how long the key should be valid.
		 0 = key does not expire
	      <n>  = key expires in n days
	      <n>w = key expires in n weeks
	      <n>m = key expires in n months
	      <n>y = key expires in n years
	Key is valid for? (0) 20521027T140859Z

	Key expires at Sun 27 Oct 2052 03:08:59 PM CET
	Is this correct? (y/N) y
	Really create? (y/N) y

	sec  rsa2048/7AAAE2F9A20EE786
	     created: 2020-11-04  expires: never       usage: SC  
	     trust: unknown       validity: unknown
	ssb  rsa2048/E311678FFC76B5C3
	     created: 2020-11-04  expires: never       usage: E   
	ssb  rsa2048/A15FEA88CB94EFC6
	     created: 2020-11-04  expires: 2052-10-27  usage: S   
	[ unknown] (1). SHA1 Signing Subkey <[email protected]>

	gpg> save

OK, the key is restored now. Now modify the expiry a bit to make the new
binding newer than the previous one; otherwise for others getting your updated
key gpg will not import it. You have to restart gpg without the
faked-system-time for that to work:

	$ gpg --edit-key 7AAAE2F9A20EE786
	...
	gpg> key 2
	...
	gpg> expire
	Changing expiration time for a subkey.
	Please specify how long the key should be valid.
		 0 = key does not expire
	      <n>  = key expires in n days
	      <n>w = key expires in n weeks
	      <n>m = key expires in n months
	      <n>y = key expires in n years
	Key is valid for? (0) 20521027T140900Z
	Key expires at Sun 27 Oct 2052 03:09:00 PM CET
	Is this correct? (y/N) y

	...

	gpg> save

That's already it.

The same procedure is needed to fix a key suffering from "live subkey with a
binding signature that uses SHA-1."

If your key suffers from "User ID protected by SHA-1", the procedure
with Sequoia is the same as above (i.e.

	$ sq cert lint --fix --output - --cert 7AAAE2F9A20EE786 | gpg --import

), with GnuPG it's again a bit more complicated, but considerably better
than above. You only have to resign the affected uid:

	$ gpg --edit-key --expert A8AC5ACC2FB87104
	gpg (GnuPG) 2.2.45; Copyright (C) 2024 g10 Code GmbH
	This is free software: you are free to change and redistribute it.
	There is NO WARRANTY, to the extent permitted by law.

	Secret key is available.

	sec  rsa2048/A8AC5ACC2FB87104
	     created: 2020-11-04  expires: never       usage: SC  
	     trust: unknown       validity: unknown
	ssb  rsa2048/666981FAEF87076A
	     created: 2020-11-04  expires: never       usage: E   
	[ unknown] (1). SHA1 User ID <[email protected]>
	[ unknown] (2)  SHA256 User ID <[email protected]>

	gpg> uid 1

	sec  rsa2048/A8AC5ACC2FB87104
	     created: 2020-11-04  expires: never       usage: SC
	     trust: unknown       validity: unknown
	ssb  rsa2048/666981FAEF87076A
	     created: 2020-11-04  expires: never       usage: E
	[ unknown] (1)* SHA1 User ID <[email protected]>
	[ unknown] (2)  SHA256 User ID <[email protected]>

	gpg> sign
	"SHA1 User ID <[email protected]>" was already signed by key A8AC5ACC2FB87104
	Do you want to sign it again anyway? (y/N) y

	sec  rsa2048/A8AC5ACC2FB87104
	     created: 2020-11-04  expires: never       usage: SC
	     trust: unknown       validity: unknown
	 Primary key fingerprint: 94F1 9D3C B565 6E0B C397  7C09 A8AC 5ACC 2FB8 7104

	     SHA1 User ID <[email protected]>

	Are you sure that you want to sign this key with your
	key "SHA1 User ID <[email protected]>" (A8AC5ACC2FB87104)

	This will be a self-signature.

	Really sign? (y/N) y

	gpg> save

If you have problems following any of this for you key (or if it worked
fine for you!), I'm happy to hear from you. If you report a problem,
please include what you did and the versions of Sequoia and/or GnuPG
involved.

I guess many of the affected people will miss this mail. I intend to
contact a few of them in private pointing them to this mail to get some
feedback if it works. Once the procedure is proven to work on a few
keys, I'd widen the audience.

Best regards
Uwe
signature.asc (application/pgp-signature, 488 B)
-----BEGIN PGP SIGNATURE-----

iQEzBAABCgAdFiEEP4GsaTp6HlmJrf7Tj4D7WH0S/k4FAme7H+MACgkQj4D7WH0S
/k4o3gf+MerY+TbILlDQzf32oYUaVqwiHsl2JSBZ+YkF4DX2tnEqsudY1K3iTVBj
YH5MLbmYOD8KWlXNOi2czgL6LE/laA/Jf1FpJZKwL4+911lxtjw3cvP6tpkMe7Ti
m5Rn8QDLzYd3HYEQSQCBNfyTJ76jaHcLnZiL4MJI+qo6DLUNDZvD1Q0fsdapZpZw
pmS5h3CQ2TWnadbKd3/3hLaCb6eckJP7OQ8WPV7zYbPxHjNTRBQCqGT/uSRT6s6Q
3qv8CKIgrd2hhi+75Yt3BL2ob4JovAkNzdKBOzNr0fZYESEEhwTOfo6qi2nTKiai
SoIGq7aigzpOls01KPl/O47lW1sIHA==
=Mcz1
-----END PGP SIGNATURE-----