Key expiration time ignored for zero creation date keys
Open, NormalPublic

Description

GnuPG usually ignores the key expiration date when the key's creation date is set to zero (e.g. 1970-01-01) and treats the key as if it doesn't expire. For example, here is a key with such a date that expired June 2019:

-----BEGIN PGP PUBLIC KEY BLOCK-----

xjMEAAAAABYJKwYBBAHaRw8BAQdAKTUvEQJiYcC9ODhvNWkMfdCLPm8IjFgq9V08
6sPqFQXNB0V4YW1wbGXCZwQTFggAGQUCAAAAAAkQA3p8nXsU19ICGwMFCV2UTIAA
AKYRAP90FrOK7jPVldQSDbHRtKLieCBGwHxQybRntR7Rw19qIAD/WvzblYv9aU/R
Bm0Hxy2tlS8Sj60stKn24Ix1oc/yDAo=
=UBbd
-----END PGP PUBLIC KEY BLOCK-----

The --list-packets command shows the key expiration time subpacket corresponding to June 2019 (reminder: "expires 0" is only because this is a version 4 key packet):

$ gpg --list-packets example.asc
:public key packet:
        version 4, algo 22, created 0, expires 0
...
        hashed subpkt 9 len 4 (key expires after 49y170d13h20m)
...

However, with --show-key and for any uses of the key that I've tried, this expiration date is ignored. For example, here's a cleartext signed document with that key, example.txt:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

hello
-----BEGIN PGP SIGNATURE-----

wnUEARYIACcFAl1HYnUJEAN6fJ17FNfSFiEEF+GNHkxnebcbPb6lA3p8nXsU19IA
AAPqAP4ucCyrQnoexJanZMJGrKIXs9Y+b77+353ef3bECY2WXAD/YMOKkIb3CzTD
ort76CYkg/i8O2Y4qFcurD2p052QCAw=
=mZaN
-----END PGP SIGNATURE-----

The --verify command ignores that it has expired:

$ gpg --import example.asc 
gpg: key 037A7C9D7B14D7D2: public key "Example" imported
gpg: Total number processed: 1
gpg:               imported: 1

$ gpg --verify example.txt
gpg: Signature made Sun Aug  4 22:55:49 2019 UTC
gpg:                using EDDSA key 17E18D1E4C6779B71B3DBEA5037A7C9D7B14D7D2
gpg: Good signature from "Example" [uncertain]
Primary key fingerprint: 17E1 8D1E 4C67 79B7 1B3D  BEA5 037A 7C9D 7B14 D7D2

However, if I nudge the creation date forward by 1 second, leaving everything else the same (including the key material):

-----BEGIN PGP PUBLIC KEY BLOCK-----

xjMEAAAAARYJKwYBBAHaRw8BAQdAKTUvEQJiYcC9ODhvNWkMfdCLPm8IjFgq9V08
6sPqFQXNB0V4YW1wbGXCZwQTFggAGQUCAAAAAQkQSVb+epD++gcCGwMFCVz7tf8A
AIhsAQCptZtpe0Ue7wlhlzK5SM2QaXhfLHxU4b/42fta4MoBmQD6Aj9KJJXFzM3G
wLCZhzDMMUrr5cgptpdwQvGMOn2shg8=
=sWiM
-----END PGP PUBLIC KEY BLOCK-----

Suddenly GnuPG sees the expiration date:

gnupg/bin/gpg --show-key example1.asc 
pub   ed25519 1970-01-01 [SC] [expired: 2019-06-08]
      384B5CE1F3BD763810F0C97B4956FE7A90FEFA07
uid                      Example

Signed document using this key, :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

hello
-----BEGIN PGP SIGNATURE-----

wnUEARYIACcFAl1HZEoJEElW/nqQ/voHFiEEOEtc4fO9djgQ8Ml7SVb+epD++gcA
AF4kAQDku0vZiyKvp9+oLNtXhL9wP2zvF51jBAjVfgL+A/WgdAEA9l0z6qBjYEFq
eBsZSNB/xTefiqTsJ7qyBzoXQhm2pAU=
=Zvgz
-----END PGP SIGNATURE-----

And in GnuPG:

$ gpg --import example1.asc 
gpg: key 4956FE7A90FEFA07: public key "Example" imported
gpg: Total number processed: 1
gpg:               imported: 1

$ gpg --verify example1.txt
gpg: Signature made Sun Aug  4 23:03:38 2019 UTC
gpg:                using EDDSA key 384B5CE1F3BD763810F0C97B4956FE7A90FEFA07
gpg: Good signature from "Example" [expired]
gpg: Note: This key has expired!

As far as I can tell, this bug only affects keys with a creation date of zero, but I haven't checked thoroughly.

Details

Version
2.2.17
skeeto created this task.Aug 5 2019, 1:18 AM
werner triaged this task as Normal priority.Aug 5 2019, 10:00 AM
werner added a project: gnupg (gpg22).
gniibe added a subscriber: gniibe.Aug 13 2019, 6:27 AM

I think that I located the cause of this bug:

diff --git a/g10/getkey.c b/g10/getkey.c
index 57617a0a9..b47b6c5e4 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -2753,7 +2753,9 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
 	    {
 	      PKT_user_id *uid = k->pkt->pkt.user_id;
 
-	      if (uid->help_key_usage && uid->created > uiddate)
+	      if (uid->help_key_usage
+                  && (uid->created > uiddate
+                      || (uid->created == 0 && uiddate == 0)))
 		{
 		  key_usage = uid->help_key_usage;
 		  uiddate = uid->created;
@@ -2790,7 +2792,9 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
 	  if (k->pkt->pkttype == PKT_USER_ID)
 	    {
 	      PKT_user_id *uid = k->pkt->pkt.user_id;
-	      if (uid->help_key_expire && uid->created > uiddate)
+	      if (uid->help_key_expire
+                  && (uid->created > uiddate
+                      || (uid->created == 0 && uiddate == 0)))
 		{
 		  key_expire = uid->help_key_expire;
 		  uiddate = uid->created;

... where we use 0 as exceptional value.