#1013288 gnupg: Doesn't show uid expiry

Package:
gnupg
Source:
gnupg2
Submitter:
Uwe Kleine-König
Date:
2022-06-30 21:57:05 UTC
Severity:
normal
#1013288#5
Date:
2022-06-20 21:37:13 UTC
From:
To:
Hello,

	uwe@taurus:~$ export GNUPGHOME=$(mktemp -d)
	uwe@taurus:~$ curl -s https://git.kernel.org/pub/scm/docs/kernel/pgpkeys.git/plain/keys/6637D326999B862C.asc | gpg --import
	gpg: keybox '/tmp/tmp.S4Xeh1pmja/pubring.kbx' created
	gpg: key 6637D326999B862C: 3 signatures not checked due to missing keys
	gpg: /tmp/tmp.S4Xeh1pmja/trustdb.gpg: trustdb created
	gpg: key 6637D326999B862C: public key "Philipp Zabel <pzabel@gmx.de>" imported
	gpg: Total number processed: 1
	gpg:               imported: 1
	gpg: no ultimately trusted keys found
	uwe@taurus:~$ gpg --with-colons --check-sigs 6637D326999B862C
	tru::1:1655760525:0:3:1:5
	pub:-:4096:1:6637D326999B862C:1402826245:1664799531::-:::scESC::::::23::0:
	fpr:::::::::27C6398DC5B132E22A8D2B516637D326999B862C:
	uid:-::::1633263532::645CAC3041C5B2B3F7D7169DC0216C1B2ACB8711::Philipp Zabel <pzabel@gmx.de>::::::::::0:
	sig:?::1:0BE9E3157A1E2C64:1403019369:::::10x:::::2:
	sig:!::1:6637D326999B862C:1633263532::::Philipp Zabel <pzabel@gmx.de>:13x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:
	uid:-::::1599034236::834E8111DE69C80CC6C776EEBD2DD3BB50DCD452::Philipp Zabel <p.zabel@pengutronix.de>::::::::::0:
	sig:?::1:0BE9E3157A1E2C64:1403019369:::::10x:::::2:
	sig:!::1:6637D326999B862C:1599034236::::Philipp Zabel <pzabel@gmx.de>:13x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:
	uid:-::::1633263531::46A0A420CBEFD71A9CE3EFCCDC59B187D056C137::Philipp Zabel <philipp.zabel@gmail.com>::::::::::0:
	sig:?::1:0BE9E3157A1E2C64:1403019369:::::10x:::::2:
	sig:!::1:6637D326999B862C:1633263531::::Philipp Zabel <pzabel@gmx.de>:13x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:
	sub:-:4096:1:8FCC408DE8F7F370:1402826245:1664799540:::::e::::::23:
	fpr:::::::::40ACEFA243542A5ADBFA706C8FCC408DE8F7F370:
	sig:!::1:6637D326999B862C:1633263540::::Philipp Zabel <pzabel@gmx.de>:18x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:
	sub:-:4096:1:50C2881C709E60EB:1402828631:1664799540:::::s::::::23:
	fpr:::::::::06C071855D4568AC17B8238150C2881C709E60EB:
	sig:!::1:6637D326999B862C:1633263540::::Philipp Zabel <pzabel@gmx.de>:18x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:
	sub:-:255:22:D585A725183762C0:1526278694:1664799540:::::s:::::ed25519::
	fpr:::::::::513BA17A59DA47D51D2F1A26D585A725183762C0:
	sig:!::1:6637D326999B862C:1633263540::::Philipp Zabel <pzabel@gmx.de>:18x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:

so the key seems to have three valid uids. However the pengutronix.de
uid isn't valid any more according to hokey (marked with an arrow):

	uwe@taurus:~$ gpg --export 6637D326999B862C | hokey lint
	hokey (hopenpgp-tools) 0.23.6
	Copyright (C) 2012-2021  Clint Adams
	hokey comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions.

	Key has potential validity: good
	Key has fingerprint: 27C6 398D C5B1 32E2 2A8D  2B51 6637 D326 999B 862C
	Checking to see if key is OpenPGPv4: V4
	Checking the strength of your primary asymmetric key: RSA 4096
	Checking user-ID- and user-attribute-related items:
	  Philipp Zabel <p.zabel@pengutronix.de>:
	    Self-sig hash algorithms: [SHA-256]
	    Preferred hash algorithms: [SHA-512, SHA-384, SHA-256, SHA-224]
  -->	    Key expiration times: [7y2m18d25991s = Thu Sep  2 08:10:36 UTC 2021]
	    Key usage flags: [[sign-data, certify-keys]]
	  Philipp Zabel <pzabel@gmx.de>:
	    Self-sig hash algorithms: [SHA-256]
	    Preferred hash algorithms: [SHA-512, SHA-384, SHA-256, SHA-224]
	    Key expiration times: [8y3m18d67886s = Mon Oct  3 12:18:51 UTC 2022]
	    Key usage flags: [[sign-data, certify-keys]]
	  Philipp Zabel <philipp.zabel@gmail.com>:
	    Self-sig hash algorithms: [SHA-256]
	    Preferred hash algorithms: [SHA-512, SHA-384, SHA-256, SHA-224]
	    Key expiration times: [8y3m18d67886s = Mon Oct  3 12:18:51 UTC 2022]
	    Key usage flags: [[sign-data, certify-keys]]
	Checking subkeys:
	  one of the subkeys is encryption-capable: True
	  fpr: 40AC EFA2 4354 2A5A DBFA  706C 8FCC 408D E8F7 F370
	    version: v4
	    timestamp: 20140615-095725
	    algo/size: RSA 4096
	    binding sig hash algorithms: [SHA-256]
	    usage flags: [[encrypt-storage, encrypt-communications]]
	    embedded cross-cert: False
	    cross-cert hash algorithms: [SHA-256]
	  fpr: 06C0 7185 5D45 68AC 17B8  2381 50C2 881C 709E 60EB
	    version: v4
	    timestamp: 20140615-103711
	    algo/size: RSA 4096
	    binding sig hash algorithms: [SHA-256]
	    usage flags: [[sign-data]]
	    embedded cross-cert: True
	    cross-cert hash algorithms: [SHA-256]
	  fpr: 513B A17A 59DA 47D5 1D2F  1A26 D585 A725 1837 62C0
	    version: v4
	    timestamp: 20180514-061814
	    algo/size: EdDSA 256
	    binding sig hash algorithms: [SHA-256]
	    usage flags: [[sign-data]]
	    embedded cross-cert: True
	    cross-cert hash algorithms: [SHA-256]

If I export the key with only the pengutronix uid, then reimport that
cleanly, gpg also notices that there is a problem:

	uwe@taurus:~$ gpg --export --export-filter keep-uid="uid =~ @pengutronix.de" 6637D326999B862C > k
	uwe@taurus:~$ gpg --delete-keys 6637D326999B862C
	gpg (GnuPG) 2.2.35; Copyright (C) 2022 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.


	pub  rsa4096/6637D326999B862C 2014-06-15 Philipp Zabel <pzabel@gmx.de>

	Delete this key from the keyring? (y/N) y
	uwe@taurus:~$ gpg --import k
	gpg: key 6637D326999B862C: 1 signature not checked due to a missing key
	gpg: key 6637D326999B862C: public key "Philipp Zabel <p.zabel@pengutronix.de>" imported
	gpg: Total number processed: 1
	gpg:               imported: 1
	gpg: no ultimately trusted keys found
	uwe@taurus:~$ gpg --with-colons --check-sigs 6637D326999B862C
	tru::1:1655760883:0:3:1:5
	pub:e:4096:1:6637D326999B862C:1402826245:1630570236::-:::sc::::::23::0:
	fpr:::::::::27C6398DC5B132E22A8D2B516637D326999B862C:
	uid:e::::1599034236::834E8111DE69C80CC6C776EEBD2DD3BB50DCD452::Philipp Zabel <p.zabel@pengutronix.de>::::::::::0:
	sig:?::1:0BE9E3157A1E2C64:1403019369:::::10x:::::2:
	sig:!::1:6637D326999B862C:1599034236::::Philipp Zabel <p.zabel@pengutronix.de>:13x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:
	sub:e:4096:1:8FCC408DE8F7F370:1402826245:1664799540:::::e::::::23:
	fpr:::::::::40ACEFA243542A5ADBFA706C8FCC408DE8F7F370:
	sig:!::1:6637D326999B862C:1633263540::::Philipp Zabel <p.zabel@pengutronix.de>:18x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:
	sub:e:4096:1:50C2881C709E60EB:1402828631:1664799540:::::s::::::23:
	fpr:::::::::06C071855D4568AC17B8238150C2881C709E60EB:
	sig:!::1:6637D326999B862C:1633263540::::Philipp Zabel <p.zabel@pengutronix.de>:18x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:
	sub:e:255:22:D585A725183762C0:1526278694:1664799540:::::s:::::ed25519::
	fpr:::::::::513BA17A59DA47D51D2F1A26D585A725183762C0:
	sig:!::1:6637D326999B862C:1633263540::::Philipp Zabel <p.zabel@pengutronix.de>:18x::27C6398DC5B132E22A8D2B516637D326999B862C:::8:

i.e. now the 2nd field of the uid is 'e' for expired.

Am I missing something?

Best regards
Uwe

#1013288#10
Date:
2022-06-30 21:39:32 UTC
From:
To:
Hi Uwe--

Thanks for the report.

I'm closing this bug report because i think GnuPG is "functioning as
intended" due to how OpenPGP works, but i completely understand how this
is perplexing.

The reason you're seeing this is not a User ID expiration at all -- it's
a key expiration, even though the place you're noticing it is the uid
expiration.

Let me explain in a bit more detail:

When you use the certificate with only the pengutronix.de user ID in it,
the self-sig's key expiry time subpacket says that the primary key is
expired.  If the primary key is expired, the user ID is expired as well.

When you bring in one of the other user IDs and its self-sig, the
primary key now gets its expiration date from the later key expiration
in that self-sig. So the primary key isn't expired any longer, and
therefore all of its user IDs (including the pengutronix one!) are
potentially valid.

hokey lint isn't saying that the user ID is expired -- it's complaining
that the *primary key* is marked for expiration by this self-sig, so if
this user ID alone was present, the whole cert ends up expired.  Note
that it says "Key expiration time" here:
 […]



Note that the primary key *also* changed its status, from:

        pub:-:4096:1:6637D326999B862C:1402826245:1664799531::-:::scESC::::::23::0:

to:

        pub:e:4096:1:6637D326999B862C:1402826245:1630570236::-:::sc::::::23::0:

This is because the primary key's status is derived from a combination
of key expiration times from all present uid self-sigs.

I note that OpenPGP also allows for a "signature expiration time"
subpacket.  If some self-sig contained that subpacket that pointed to
the past, i'd expect that user ID to be able to expire independently of
whatever is contained in the self-sigs of the other user IDs present in
certificate.

Thinking about this today, I tried hard to come up with a better way
that GnuPG could signal this more clearly, but my conclusion is that the
main source of confusion here is in the OpenPGP standard itself, not in
GnuPG's implementation.

One option would be for GnuPG to have a different status indication for
an expired User ID (due to sig expiration) than for a user ID that
happens to belong to an expired primary key.

I could imagine advocating for this outcome, but i don't know how
receptive GnuPG upstream would be to it.  If you think that would be a
satisfying resolution to the weird situation you found yourself in, feel
free to note the suggestion in the upstream bugtracker
(https://dev.gnupg.org) and reopen this issue in the debian BTS and
point it to the upstream bug report.

Thanks for reporting this!  Sorry to not have a simpler answer.

fwiw, i think that "hokey lint" is right to mark this situation as
problematic, because it is definitely a surprising and subtle situation
for a composable certificate format like OpenPGP.

Regards,

#1013288#15
Date:
2022-06-30 21:39:32 UTC
From:
To:
Hi Uwe--

Thanks for the report.

I'm closing this bug report because i think GnuPG is "functioning as
intended" due to how OpenPGP works, but i completely understand how this
is perplexing.

The reason you're seeing this is not a User ID expiration at all -- it's
a key expiration, even though the place you're noticing it is the uid
expiration.

Let me explain in a bit more detail:

When you use the certificate with only the pengutronix.de user ID in it,
the self-sig's key expiry time subpacket says that the primary key is
expired.  If the primary key is expired, the user ID is expired as well.

When you bring in one of the other user IDs and its self-sig, the
primary key now gets its expiration date from the later key expiration
in that self-sig. So the primary key isn't expired any longer, and
therefore all of its user IDs (including the pengutronix one!) are
potentially valid.

hokey lint isn't saying that the user ID is expired -- it's complaining
that the *primary key* is marked for expiration by this self-sig, so if
this user ID alone was present, the whole cert ends up expired.  Note
that it says "Key expiration time" here:
 […]



Note that the primary key *also* changed its status, from:

        pub:-:4096:1:6637D326999B862C:1402826245:1664799531::-:::scESC::::::23::0:

to:

        pub:e:4096:1:6637D326999B862C:1402826245:1630570236::-:::sc::::::23::0:

This is because the primary key's status is derived from a combination
of key expiration times from all present uid self-sigs.

I note that OpenPGP also allows for a "signature expiration time"
subpacket.  If some self-sig contained that subpacket that pointed to
the past, i'd expect that user ID to be able to expire independently of
whatever is contained in the self-sigs of the other user IDs present in
certificate.

Thinking about this today, I tried hard to come up with a better way
that GnuPG could signal this more clearly, but my conclusion is that the
main source of confusion here is in the OpenPGP standard itself, not in
GnuPG's implementation.

One option would be for GnuPG to have a different status indication for
an expired User ID (due to sig expiration) than for a user ID that
happens to belong to an expired primary key.

I could imagine advocating for this outcome, but i don't know how
receptive GnuPG upstream would be to it.  If you think that would be a
satisfying resolution to the weird situation you found yourself in, feel
free to note the suggestion in the upstream bugtracker
(https://dev.gnupg.org) and reopen this issue in the debian BTS and
point it to the upstream bug report.

Thanks for reporting this!  Sorry to not have a simpler answer.

fwiw, i think that "hokey lint" is right to mark this situation as
problematic, because it is definitely a surprising and subtle situation
for a composable certificate format like OpenPGP.

Regards,