Subject: Re: [openpgp] v5 sample key

From: Heiko Stamer <[email-masked]>
Date: Mon, 22 Apr 2019 08:55:20 +0200

Hi Werner,

during implementation of V5 keys and signatures in LibTMCG I discovered
a minor issue with RFC 4880bis. Section 5.2.4 says at third paragraph:

  "When a signature is made over a key, the hash data starts with the
   octet 0x99, followed by a two-octet length of the key, and then body
   of the key packet."

There is no distinction between V3, V4, and V5 signatures resp. keys.
However, GnuPG computes the hash in function hash_public_key() for V5
keys in a different way: starting with octet 0x9a and a four-octet
length is given before the body of key packet is hashed.

Thus, either this part should be specified in RFC 4880bis with more
detail or GnuPG has to change its hash computation for signatures.
Best regards,
Heiko.

PS. Taking the above issue into account the given V5 sample key is
recognized by LibTMCG as required:

PrivateKeyBlockParse(emma_armored, 3, "", emma)
INFO: PacketDecode() = 5 version = 5
INFO: encdatalen = 0
INFO: skalgo = 0
INFO: aeadalgo = 0
INFO: s2kconv = 0
INFO: s2k_type = 0 s2k_hashalgo = 0 s2k_count = 0
INFO: key ID of private primary key: 19 34 7b c9 87 24 64 2
INFO: PacketDecode() = 13 version = 0
INFO: signature subpacket type = 33 found
INFO: signature subpacket type = 2 found
INFO: signature subpacket type = 27 found
INFO: signature subpacket type = 11 found
INFO: signature subpacket type = 34 found
INFO: signature subpacket type = 21 found
INFO: signature subpacket type = 22 found
INFO: signature subpacket type = 30 found
INFO: signature subpacket type = 23 found
INFO: PacketDecode() = 2 version = 5
INFO: EdDSA rbits = 254 sbits = 255
INFO: PacketDecode() = 7 version = 5
INFO: encdatalen = 0
INFO: skalgo = 0
INFO: aeadalgo = 0
INFO: s2kconv = 0
INFO: s2k_type = 0 s2k_hashalgo = 0 s2k_count = 0
INFO: key ID of private subkey: e4 55 7c 2b 2 ff bf 4b
INFO: signature subpacket type = 33 found
INFO: signature subpacket type = 2 found
INFO: signature subpacket type = 27 found
INFO: PacketDecode() = 2 version = 5
INFO: EdDSA rbits = 256 sbits = 256
CheckSelfSignatures()
INFO: key ID of primary key: 19 34 7b c9 87 24 64 2
INFO: fingerprint of primary key: 19 34 7b c9 87 24 64 2 5f 99 df 3e c2
e0 0 e d9 88 48 92 e1 f7 b3 ea 4c 94 0 91 59 56 9b 54
INFO: number of selfsigs = 0
INFO: number of keyrevsigs = 0
INFO: number of certrevsigs = 0
INFO: number of userids = 1
INFO: number of userattributes = 0
INFO: number of subkeys = 1
INFO: number of revkeys = 0
INFO: userid = "[email-masked]"
INFO: number of selfsigs = 1
INFO: number of revsigs = 0
INFO: number of certsigs = 0
INFO: sig type = 0x13 pkalgo = 22 hashalgo = 8 revocable = true
exportable = true version = 5 creationtime = 1553069284 expirationtime =
0 keyexpirationtime = 0 revcode = 0 packet.size() = 152 hspd.size() = 72
issuer = 19 34 7b c9 87 24 64 2  issuerfpr = 19 34 7b c9 87 24 64 2 5f
99 df 3e c2 e0 0 e d9 88 48 92 e1 f7 b3 ea 4c 94 0 91 59 56 9b 54
keyflags = 3  revkeys.size() = 0
INFO: left = f5 c0
INFO: user ID is valid
INFO: primary key update expirationtime to 0
INFO: primary key update flags to 3
INFO: primary key update features to 7
INFO: primary key update psa to 9 8 7 2
INFO: primary key update pha to 10 9 8 11 2
INFO: primary key update pca to 2 3 1
INFO: primary key update paa to 2 1
INFO: primary key update revkeys with added
INFO: key flags on primary key are CS
CheckSubkeys()
INFO: key ID of subkey: e4 55 7c 2b 2 ff bf 4b
INFO: fingerprint of subkey: e4 55 7c 2b 2 ff bf 4b 4 f8 74 1 ec 33 6a
f7 13 3d f 85 be 7f d0 9b ae fd 9c ae b8 c9 39 65
INFO: number of selfsigs = 0
INFO: number of bindsigs = 1
INFO: number of pbindsigs = 0
INFO: number of keyrevsigs = 0
INFO: number of certrevsigs = 0
INFO: number of revkeys = 0
INFO: sig type = 0x18 pkalgo = 22 hashalgo = 8 revocable = true
exportable = true version = 5 creationtime = 1553069284 expirationtime =
0 keyexpirationtime = 0 revcode = 0 packet.size() = 124 hspd.size() = 44
issuer = 19 34 7b c9 87 24 64 2  issuerfpr = 19 34 7b c9 87 24 64 2 5f
99 df 3e c2 e0 0 e d9 88 48 92 e1 f7 b3 ea 4c 94 0 91 59 56 9b 54
keyflags = c  revkeys.size() = 0
INFO: left = 39 24
INFO: subkey update expirationtime to 0
INFO: subkey update flags to c
INFO: subkey update features to
INFO: subkey update psa to
INFO: subkey update pha to
INFO: subkey update pca to
INFO: subkey update paa to
INFO: subkey update revkeys with added
INFO: subkey is valid
INFO: key flags on subkey are Ee
!primary->Weak()
INFO: EdDSA with curve "Ed25519" and 256 bits

---

From: Werner Koch <[email-masked]>
Date: Tue, 23 Apr 2019 10:28:26 +0200

Hi!

> length is given before the body of key packet is hashed.

That is because 12.2 (Key IDS and Fingerprints) has

   A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99,
   followed by the two-octet packet length, followed by the entire
   [...]
   A V5 fingerprint is the 256-bit SHA2-256 hash of the octet 0x9A,
   followed by the four-octet packet length, followed by the entire

I think it makes sense to keep the signature computation in sync with
the fingerprint computation.  Using the four-octet length and thus 0x9a
is important because it remove ambiguities if the key material is larger
than 2^16.

> Thus, either this part should be specified in RFC 4880bis with more

I would prefer to fix this flaw in rfc4880bis 5.2.4 (Computing
Signatures):

-When a signature is made over a key, the hash data starts with the
+When a V4 signature is made over a key, the hash data starts with the
 octet 0x99, followed by a two-octet length of the key, and then body
-of the key packet. (Note that this is an old-style packet header for a
-key packet with two-octet length.) A subkey binding signature (type
-0x18) or primary key binding signature (type 0x19) then hashes the
-subkey using the same format as the main key (also using 0x99 as the
-first octet).  Primary key revocation signatures (type 0x20) hash only
-the key being revoked.  Subkey revocation signature (type 0x28) hash
-first the primary key and then the subkey being revoked.
+of the key packet; when a V5 signature is made over a key, the hash
+data starts with the octet 0x9a, followed by a four-octet length of
+the key, and then body of the key packet.  A subkey binding signature
+(type 0x18) or primary key binding signature (type 0x19) then hashes
+the subkey using the same format as the main key (also using 0x99 or
+0x9a as the first octet).  Primary key revocation signatures (type
+0x20) hash only the key being revoked.  Subkey revocation signature
+(type 0x28) hash first the primary key and then the subkey being
+revoked.

> recognized by LibTMCG as required:

Thanks for testing.

Shalom-Salam,

   Werner

-- 
Die Gedanken sind frei.  Ausnahmen regelt ein Bundesgesetz.

---

From: Heiko Stamer <[email-masked]>
Date: Tue, 23 Apr 2019 20:58:29 +0200

On 23 Apr 2019 10:28, Werner Koch wrote:

> +the key, and then body of the key packet.

This change seems to be reasonable. But how V3 signatures are computed?

--
Heiko.

---

From: Jonathan McDowell <[email-masked]>
Date: Thu, 25 Apr 2019 10:11:33 +0100

> is important because it remove ambiguities if the key material is larger

A move to easily enable key material > 2^16 bytes seems to be in
conflict with dkg's work on trying to reinvigorate the usefulness of key
servers + the suggestion to limit key material packets to < 8383 bytes.

J.

-- 
I have seen the future - the future is Channel 3.
This .sig brought to you by the letter S and the number 38
Product of the Republic of HuggieTag

---

From: Heiko Stamer <[email-masked]>
Date: Tue, 30 Apr 2019 23:28:43 +0200

> Thanks for testing.

I've attached a detached v5 signature of this key for testing purposes.

HTH,
Heiko.