Page MenuHome GnuPG

Primary Key Binding Signature not updated when updating Subkey Binding Signature
Open, NormalPublic

Description

While examining the Debian Keyring, I discovered many uses of SHA1. One use stuck out, however: there are several signing-capable subkeys that use SHA256 or SHA512 for the subkey binding signature, but SHA1 for the primary key binding signature (the backsig). This appears to be because gpg reuses any existing backsig when updating the subkey binding signature (e.g., when extending the subkey's expiration time). As far as I know there is no way to force gpg to update the backsig (please correct me if I am wrong). To make it less painful for users when SHA1 is bad listed, it would be helpful if the primary key binding signature were also updated when the subkey binding signature is updated (if the signing key's secret key material is available as is usually the case).

I created the following test data (attached):

$ export GNUPGHOME=$(mktemp -d)
$ gpg1 --gen-key
...
pub   1024R/0F66162A 2020-10-23
      Key fingerprint = 29B2 8740 3105 1C66 718E  C51E A23C 9525 0F66 162A
uid                  SHA1 Test <sha1@example.org>
sub   1024R/3AB6951D 2020-10-23
$ gpg1 --edit-key sha1@example.org
...
gpg> addkey
This key is not protected.
Please select what kind of key you want:
   (3) DSA (sign only)
   (4) RSA (sign only)
   (5) Elgamal (encrypt only)
   (6) RSA (encrypt only)
Your selection? 4
...
pub  1024R/0F66162A  created: 2020-10-23  expires: never       usage: SC  
                     trust: ultimate      validity: ultimate
sub  1024R/3AB6951D  created: 2020-10-23  expires: never       usage: E   
sub  1024R/F07D9EC7  created: 2020-10-23  expires: never       usage: S   
[ultimate] (1). SHA1 Test <sha1@example.org>
...
$ gpg --export-secret-key sha1@example.org >/tmp/sha1-key.pgp
...
$ gpg --edit-key sha1@example.org
...
gpg> key 2

sec  rsa1024/A23C95250F66162A
     created: 2020-10-23  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa1024/5F7E2C5F3AB6951D
     created: 2020-10-23  expires: never       usage: E   
ssb* rsa1024/88DEBBA1F07D9EC7
     created: 2020-10-23  expires: never       usage: S   
[ultimate] (1). SHA1 Test <sha1@example.org>
...
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) 3y
Key expires at Mon 23 Oct 2023 09:36:15 AM CEST
Is this correct? (y/N) y

sec  rsa1024/A23C95250F66162A
     created: 2020-10-23  expires: never       usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa1024/5F7E2C5F3AB6951D
     created: 2020-10-23  expires: never       usage: E   
ssb* rsa1024/88DEBBA1F07D9EC7
     created: 2020-10-23  expires: 2023-10-23  usage: S   
[ultimate] (1). SHA1 Test <sha1@example.org>

gpg> save
$ gpg --export-secret-key sha1@example.org >/tmp/sha1-key2.pgp
$ gpg --version
gpg: WARNING: unsafe permissions on homedir '/tmp/tmp.J0eBv81zH9'
gpg (GnuPG) 2.2.20
libgcrypt 1.8.4
...

Examing the first variant of the key, we see that the signing subkey's binding signature uses SHA1 as does its primary key binding signature:

$ pgpdump /tmp/sha1-key.pgp
Old: Secret Subkey Packet(tag 7)(472 bytes)
	Ver 4 - new
	Public key creation time - Fri Oct 23 09:31:05 CEST 2020
	Pub alg - RSA Encrypt or Sign(pub 1)
	RSA n(1024 bits) - ...
	RSA e(17 bits) - ...
	RSA d(1021 bits) - ...
	RSA p(512 bits) - ...
	RSA q(512 bits) - ...
	RSA u(512 bits) - ...
	Checksum - a2 60 
Old: Signature Packet(tag 2)(317 bytes)
	Ver 4 - new
	Sig type - Subkey Binding Signature(0x18).
	Pub alg - RSA Encrypt or Sign(pub 1)
-->	Hash alg - SHA1(hash 2)
	Hashed Sub: signature creation time(sub 2)(4 bytes)
		Time - Fri Oct 23 09:31:05 CEST 2020
	Hashed Sub: key flags(sub 27)(1 bytes)
		Flag - This key may be used to sign data
	Sub: issuer key ID(sub 16)(8 bytes)
		Key ID - 0xA23C95250F66162A
	Sub: embedded signature(sub 32)(156 bytes)
	Ver 4 - new
	Sig type - Primary Key Binding Signature(0x19).
	Pub alg - RSA Encrypt or Sign(pub 1)
-->	Hash alg - SHA1(hash 2)
	Hashed Sub: signature creation time(sub 2)(4 bytes)
		Time - Fri Oct 23 09:31:05 CEST 2020
	Sub: issuer key ID(sub 16)(8 bytes)
		Key ID - 0x88DEBBA1F07D9EC7
-->	Hash left 2 bytes - 18 9d 
	RSA m^d mod n(1022 bits) - ...
		-> PKCS-1
	Hash left 2 bytes - 15 54 
	RSA m^d mod n(1024 bits) - ...
		-> PKCS-1
$ pgpdump /tmp/sha1-key2.pgp
...
Old: Secret Subkey Packet(tag 7)(472 bytes)
	Ver 4 - new
	Public key creation time - Fri Oct 23 09:31:05 CEST 2020
	Pub alg - RSA Encrypt or Sign(pub 1)
	RSA n(1024 bits) - ...
	RSA e(17 bits) - ...
	RSA d(1021 bits) - ...
	RSA p(512 bits) - ...
	RSA q(512 bits) - ...
	RSA u(512 bits) - ...
	Checksum - a2 60 
Old: Signature Packet(tag 2)(346 bytes)
	Ver 4 - new
	Sig type - Subkey Binding Signature(0x18).
	Pub alg - RSA Encrypt or Sign(pub 1)
-->	Hash alg - SHA512(hash 10)
	Hashed Sub: key flags(sub 27)(1 bytes)
		Flag - This key may be used to sign data
	Hashed Sub: issuer fingerprint(sub 33)(21 bytes)
	 v4 -	Fingerprint - 29 b2 87 40 31 05 1c 66 71 8e c5 1e a2 3c 95 25 0f 66 16 2a 
	Hashed Sub: signature creation time(sub 2)(4 bytes)
		Time - Fri Oct 23 09:36:17 CEST 2020
	Hashed Sub: key expiration time(sub 9)(4 bytes)
		Time - Mon Oct 23 09:36:17 CEST 2023
	Sub: embedded signature(sub 32)(156 bytes)
	Ver 4 - new
	Sig type - Primary Key Binding Signature(0x19).
	Pub alg - RSA Encrypt or Sign(pub 1)
-->	Hash alg - SHA1(hash 2)
	Hashed Sub: signature creation time(sub 2)(4 bytes)
		Time - Fri Oct 23 09:31:05 CEST 2020
	Sub: issuer key ID(sub 16)(8 bytes)
		Key ID - 0x88DEBBA1F07D9EC7
-->	Hash left 2 bytes - 18 9d 
	RSA m^d mod n(1022 bits) - ...
		-> PKCS-1
	Sub: issuer key ID(sub 16)(8 bytes)
		Key ID - 0xA23C95250F66162A
	Hash left 2 bytes - e9 34 
	RSA m^d mod n(1024 bits) - ...
		-> PKCS-1

In short, I created a key using gpg1 and added a signing subkey to it that uses SHA1. Then, I set the signing subkey to expire using GnuPG 2.2.20 from Debian Testing. Using pgpdump, we see that the new subkey binding signature uses SHA512, but the primary key binding signature uses SHA1. Looking at the primary key binding signature's creation time, and the hash prefix ("hash left 2 bytes"), it appears that the embedded signature is just a copy of the original primary key binding signature.