Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expired-pgp-keys plugin checks an expiration key of the freshly downloaded key, not an expiration of the installed key #2099

Open
ppisar opened this issue Mar 3, 2025 · 5 comments · May be fixed by #2135
Assignees
Labels
Priority: MEDIUM Triaged Someone on the DNF 5 team has read the issue and determined the next steps to take

Comments

@ppisar
Copy link
Contributor

ppisar commented Mar 3, 2025

I'm trying to upgrade rpminspect and librpminspect packages from this Copr repository:

baseurl=https://download.copr.fedorainfracloud.org/results/dcantrell/rpminspect/fedora-$releasever-$arch/ 
gpgkey=https://download.copr.fedorainfracloud.org/results/dcantrell/rpminspect/pubkey.gpg

and I get not unhelpful error message:

# dnf --assumeyes upgrade 
Updating and loading repositories:
Repositories loaded.
 https://download.copr.fedorainfracloud.org/results/rpmsoftwar 100% |  24.4 KiB/s |   1.0 KiB |  00m00s
 https://download.copr.fedorainfracloud.org/results/dcantrell/ 100% |  24.2 KiB/s |   1.0 KiB |  00m00s
Package                        Arch     Version                                Repository          Size
Upgrading:
 librpminspect                 x86_64   2.1-0.1.202502281937git3d0dde4b.fc43   rpminspect     800.9 KiB
   replacing librpminspect     x86_64   2.1-0.1.202412161945git210c1706.fc42   rpminspect     790.0 KiB
 rpminspect                    x86_64   2.1-0.1.202502281937git3d0dde4b.fc43   rpminspect     374.8 KiB
   replacing rpminspect        x86_64   2.1-0.1.202412161945git210c1706.fc42   rpminspect     377.7 KiB

Transaction Summary:
 Upgrading:          2 packages
 Replacing:          2 packages

Total size of inbound packages is 420 KiB. Need to download 0 B.
After this operation, 8 KiB extra will be used (install 1 MiB, remove 1 MiB).
[1/2] librpminspect-0:2.1-0.1.202502281937git3d0dde4b.fc43.x86 100% |   0.0   B/s |   0.0   B |  00m00s
>>> Already downloaded                                                                                 
[2/2] rpminspect-0:2.1-0.1.202502281937git3d0dde4b.fc43.x86_64 100% |   0.0   B/s |   0.0   B |  00m00s
>>> Already downloaded                                                                                 
-------------------------------------------------------------------------------------------------------
[2/2] Total                                                    100% |   0.0   B/s |   0.0   B |  00m00s
Running transaction
Transaction failed: Signature verification failed.
OpenPGP check for package "librpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64" (/var/cache/libdnf5/rpminspect-5528942c86b17233/packages/librpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64.rpm) from repo "rpminspect" has failed: Problem occurred when opening the package.

Direct update with rpm explains that the problem is an expired key:

# rpm -Uvh  ./rpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64.rpm ./librpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64.rpm
error: Verifying a signature using certificate FA6386F31766C13FD7B7AB807ACA04AFCBBB3765 (dcantrell_rpminspect (None) <dcantrell#[email protected]>):
  1. Certificate 7ACA04AFCBBB3765 invalid: certificate is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
  2. Key 7ACA04AFCBBB3765 invalid: key is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
warning: ./rpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64.rpm: Header V4 RSA/SHA256 Signature, key ID cbbb3765: NOTTRUSTED
error: Verifying a signature using certificate FA6386F31766C13FD7B7AB807ACA04AFCBBB3765 (dcantrell_rpminspect (None) <dcantrell#[email protected]>):
  1. Certificate 7ACA04AFCBBB3765 invalid: certificate is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
  2. Key 7ACA04AFCBBB3765 invalid: key is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
Verifying...                          error: Verifying a signature using certificate FA6386F31766C13FD7B7AB807ACA04AFCBBB3765 (dcantrell_rpminspect (None) <dcantrell#[email protected]>):
  1. Certificate 7ACA04AFCBBB3765 invalid: certificate is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
  2. Key 7ACA04AFCBBB3765 invalid: key is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
error: Verifying a signature using certificate FA6386F31766C13FD7B7AB807ACA04AFCBBB3765 (dcantrell_rpminspect (None) <dcantrell#[email protected]>):
  1. Certificate 7ACA04AFCBBB3765 invalid: certificate is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
  2. Key 7ACA04AFCBBB3765 invalid: key is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
error: Verifying a signature using certificate FA6386F31766C13FD7B7AB807ACA04AFCBBB3765 (dcantrell_rpminspect (None) <dcantrell#[email protected]>):
  1. Certificate 7ACA04AFCBBB3765 invalid: certificate is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
  2. Key 7ACA04AFCBBB3765 invalid: key is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
error: Verifying a signature using certificate FA6386F31766C13FD7B7AB807ACA04AFCBBB3765 (dcantrell_rpminspect (None) <dcantrell#[email protected]>):
  1. Certificate 7ACA04AFCBBB3765 invalid: certificate is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
  2. Key 7ACA04AFCBBB3765 invalid: key is not alive
      because: The primary key is not live
      because: Expired on 2025-02-25T15:11:22Z
################################# [100%]
Preparing...                          ################################# [100%]
        package librpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64 does not verify: Header V4 RSA/SHA256 Signature, key ID cbbb3765: NOTTRUSTED
        package rpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64 does not verify: Header V4 RSA/SHA256 Signature, key ID cbbb3765: NOTTRUSTED

And indeed the key in RPM database is expired:

# rpm -qi gpg-pubkey-cbbb3765-5e57dc1a | gpg --list-packets
# off=0 ctb=99 tag=6 hlen=3 plen=269
:public key packet:
        version 4, algo 1, created 1582816282, expires 0
        pkey[0]: [2048 bits]
        pkey[1]: [17 bits]
        keyid: 7ACA04AFCBBB3765
# off=272 ctb=b4 tag=13 hlen=2 plen=72
:user ID packet: "dcantrell_rpminspect (None) <dcantrell#[email protected]>"
# off=346 ctb=89 tag=2 hlen=3 plen=340
:signature packet: algo 1, keyid 7ACA04AFCBBB3765
        version 4, created 1582816282, md5len 0, sigclass 0x13
        digest algo 8, begin of digest 80 88
        hashed subpkt 33 len 21 (issuer fpr v4 FA6386F31766C13FD7B7AB807ACA04AFCBBB3765)
        hashed subpkt 2 len 4 (sig created 2020-02-27)
        hashed subpkt 27 len 1 (key flags: 2F)
        hashed subpkt 9 len 4 (key expires after 5y0d0h0m)
        hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 2)
        hashed subpkt 21 len 5 (pref-hash-algos: 10 9 8 11 2)
        hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
        hashed subpkt 30 len 1 (features: 01)
        hashed subpkt 23 len 1 (keyserver preferences: 80)
        subpkt 16 len 8 (issuer key ID 7ACA04AFCBBB3765)
        data: [2047 bits]

When I download the key from the web, it has prolonged expiration:

# gpg --list-packets pubkey.gpg 
# off=0 ctb=99 tag=6 hlen=3 plen=269
:public key packet:
        version 4, algo 1, created 1582816282, expires 0
        pkey[0]: [2048 bits]
        pkey[1]: [17 bits]
        keyid: 7ACA04AFCBBB3765
# off=272 ctb=b4 tag=13 hlen=2 plen=72
:user ID packet: "dcantrell_rpminspect (None) <dcantrell#[email protected]>"
# off=346 ctb=89 tag=2 hlen=3 plen=340
:signature packet: algo 1, keyid 7ACA04AFCBBB3765
        version 4, created 1709005284, md5len 0, sigclass 0x13
        digest algo 8, begin of digest ac aa
        hashed subpkt 27 len 1 (key flags: 2F)
        hashed subpkt 11 len 4 (pref-sym-algos: 9 8 7 2)
        hashed subpkt 21 len 5 (pref-hash-algos: 10 9 8 11 2)
        hashed subpkt 22 len 3 (pref-zip-algos: 2 3 1)
        hashed subpkt 30 len 1 (features: 01)
        hashed subpkt 23 len 1 (keyserver preferences: 80)
        hashed subpkt 33 len 21 (issuer fpr v4 FA6386F31766C13FD7B7AB807ACA04AFCBBB3765)
        hashed subpkt 2 len 4 (sig created 2024-02-27)
        hashed subpkt 9 len 4 (key expires after 9y0d12h30m)
        subpkt 16 len 8 (issuer key ID 7ACA04AFCBBB3765)
        data: [2048 bits]

I guess this is a perfect use case for the expired-pgp-keys plugin. But I have installed it:

# rpm -qa | grep expired-pgp-keys
libdnf5-plugin-expired-pgp-keys-5.2.10.0-20250303010733.58.g97496331.fc43.x86_64

it is enabled:

# cat /etc/dnf/libdnf5-plugins/expired-pgp-keys.conf 
[main]
name = expired-pgp-keys
enabled = 1

Yet, it does not attempt to remove that key from the database:

# dnf upgrade 
Updating and loading repositories:
Repositories loaded.
 https://download.copr.fedorainfracloud.org/results/rpmsoftwar 100% |  26.3 KiB/s |   1.0 KiB |  00m00s
 https://download.copr.fedorainfracloud.org/results/dcantrell/ 100% |  24.2 KiB/s |   1.0 KiB |  00m00s
Package                        Arch     Version                                Repository          Size
Upgrading:
 librpminspect                 x86_64   2.1-0.1.202502281937git3d0dde4b.fc43   rpminspect     800.9 KiB
   replacing librpminspect     x86_64   2.1-0.1.202412161945git210c1706.fc42   rpminspect     790.0 KiB
 rpminspect                    x86_64   2.1-0.1.202502281937git3d0dde4b.fc43   rpminspect     374.8 KiB
   replacing rpminspect        x86_64   2.1-0.1.202412161945git210c1706.fc42   rpminspect     377.7 KiB

Transaction Summary:
 Upgrading:          2 packages
 Replacing:          2 packages

Total size of inbound packages is 420 KiB. Need to download 0 B.
After this operation, 8 KiB extra will be used (install 1 MiB, remove 1 MiB).
Is this ok [y/N]: y
[1/2] librpminspect-0:2.1-0.1.202502281937git3d0dde4b.fc43.x86 100% |   0.0   B/s |   0.0   B |  00m00s
>>> Already downloaded                                                                                 
[2/2] rpminspect-0:2.1-0.1.202502281937git3d0dde4b.fc43.x86_64 100% |   0.0   B/s |   0.0   B |  00m00s
>>> Already downloaded                                                                                 
-------------------------------------------------------------------------------------------------------
[2/2] Total                                                    100% |   0.0   B/s |   0.0   B |  00m00s
Running transaction
Transaction failed: Signature verification failed.
OpenPGP check for package "librpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64" (/var/cache/libdnf5/rpminspect-5528942c86b17233/packages/librpminspect-2.1-0.1.202502281937git3d0dde4b.fc43.x86_64.rpm) from repo "rpminspect" has failed: Problem occurred when opening the package.

I confirmed with strace that the plugin is loaded. There is no relevant message in the log besides:

2025-03-03T09:00:36+0000 [1923] DEBUG Loading plugin library file="/usr/lib64/libdnf5/plugins/expired-p
gp-keys.so"
2025-03-03T09:00:36+0000 [1923] INFO Loaded libdnf plugin "expired-pgp-keys" ("/usr/lib64/libdnf5/plugi
ns/expired-pgp-keys.so"), version="1.0.0"
2025-03-03T09:00:36+0000 [1923] DEBUG Trying to load more plugins using the "expired-pgp-keys" plugin.
2025-03-03T09:00:36+0000 [1923] DEBUG End of loading plugins using the "expired-pgp-keys" plugin.

and literally last lines:

2025-03-03T09:00:37+0000 [1923] DEBUG [librepo] lr_download: Target: https://download.copr.fedorainfracloud.org/results/dcantrell/rpminspect/pubkey.gpg (-)
2025-03-03T09:00:37+0000 [1923] DEBUG [librepo] Selecting mirror for: https://download.copr.fedorainfracloud.org/results/dcantrell/rpminspect/pubkey.gpg
2025-03-03T09:00:37+0000 [1923] INFO [librepo] Downloading: https://download.copr.fedorainfracloud.org/results/dcantrell/rpminspect/pubkey.gpg
2025-03-03T09:00:37+0000 [1923] DEBUG [librepo] prepare_next_transfer: Resume ignored, existing file was not originally being downloaded by Librepo
2025-03-03T09:00:37+0000 [1923] DEBUG [librepo] lr_download: Downloading started
2025-03-03T09:00:37+0000 [1923] DEBUG [librepo] Transfer finished: https://download.copr.fedorainfracloud.org/results/dcantrell/rpminspect/pubkey.gpg (Effective url: https://download.copr.fedorainfracloud.org/results/dcantrell/rpminspect/pubkey.gpg)

It seems that the plugin does nothing for me.

@ppisar
Copy link
Contributor Author

ppisar commented Mar 3, 2025

For a reproducer purposes, this is the old, expired key I have in the RPM database:

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

mQENBF5X3BoBCADE3MXkgECKxxPn9R/LpNocOSUz6k/SXTFYnOSrFBl+ZSePCZaK
il1ZV2tdIP8t5OQd1QbIWe3bgFe9AFdzw8n4dwbnZeYuiIZ4bmnKWfrgo8yxW1Hh
VW8bdtZPha9mwFCro2A5V52y2I8dRNFVpoOn2kr13ksryz+RbzglgV0xOaOzSZHi
v/VR+adt0lGp3WEPDKbafok1sP/RBr3q/3fDxQpgW2Kpswy1B7QccVrimORJbg23
5FukPZ1pl6DL2kECrrTB+oMazfCV/ev1ZfV3y0qV07Z8yZVVPb5DRbp9qF5uvUGH
t8mCrImqKI4BovR0GUYJAZVUc+8nIRWYlK+BABEBAAG0SGRjYW50cmVsbF9ycG1p
bnNwZWN0IChOb25lKSA8ZGNhbnRyZWxsI3JwbWluc3BlY3RAY29wci5mZWRvcmFo
b3N0ZWQub3JnPokBVAQTAQgAPhYhBPpjhvMXZsE/17ergHrKBK/LuzdlBQJeV9wa
AhsvBQkJZgGABQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEHrKBK/LuzdlgIgH
/32Za78342Xwqb4lMQrYbwsVm078IeymHMNIi+enWaPp7ybXFqjox/pUEcB1Gte/
q6DsERsP8pKUjDpwpMRcobRVDG/APrFa5UW+aQvdSTAv8gIVRlriBuf1U8Q9RQLc
h0pOOTmPy9pfcz+BdZNOviQJcJv8Pui9iYg9JrzdStwTX1BvFYGg3a6lYg+ZcZdL
us655IpGRuqTDbTiD4A5Fs59pbQo4b6N1Tv80XBGT06kncQrIznrSvV8E3XA9mfd
OtoZ1SA0aEi6ufT/psdM0Yx88buie+bTiZELvNF/efFAUuWQ2+g+mDkvhQUXyppP
0gWFy0Ijhj3M5Lwl4EaWvy4=
=jtdC
-----END PGP PUBLIC KEY BLOCK-----

@jan-kolarik
Copy link
Member

Thanks Petr for reporting this.

Could you please provide the output of:

rpm -q --qf "%{DESCRIPTION}" gpg-pubkey-cbbb3765-5e57dc1a | gpg --show-keys --with-colon

Right now, we parse the information from the 7th field of the first row of this output, which should be the expiration date (based on, e.g., https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob_plain;f=doc/DETAILS). So, the following command should give the human-readable expiration date in the output:

rpm -q --qf "%{DESCRIPTION}" gpg-pubkey-cbbb3765-5e57dc1a | gpg --show-keys --with-colon | cut -d':' -f7 | xargs -I{} date -d @{}

I was testing the functionality of expired-pgp-keys based on this presumption and it seemed to work using e.g. dnf-nightly COPR repo and faketime to shift the time.

@ppisar
Copy link
Contributor Author

ppisar commented Mar 10, 2025

You could have obtain the data from the key block I've already quoted. Nevertheless, here is the output:

# rpm -q --qf '%{DESCRIPTION}' gpg-pubkey-cbbb3765-5e57dc1a |gpg --show-keys --with-colon | cut -d':' -f7 | xargs -I{} date -d @{}
gpg: WARNING: No valid encryption subkey left over.
Tue Feb 25 04:11:22 PM CET 2025

Stdout was the second line with the date.

@ppisar
Copy link
Contributor Author

ppisar commented Mar 10, 2025

If I understand the plugin code correctly then it does:

(1) It downloads keys for all enabled repositories.
(2) It checks that the key is already installed.
(3) It obtains an expiration time of the downloaded key.
(4) If the expiration is in the past, the key is removed from the RPM database.

The flaw is in the third step. It should query the expiration time of the installed key. Not the time of the downloaded key.

@ppisar ppisar changed the title expired-pgp-keys plugin seems not working expired-pgp-keys plugin checks an expiration key of the freshly downloaded key, not an expiration of the installed key Mar 10, 2025
@ppisar ppisar added Priority: MEDIUM Triaged Someone on the DNF 5 team has read the issue and determined the next steps to take labels Mar 10, 2025
@ppisar ppisar self-assigned this Mar 10, 2025
@jan-kolarik
Copy link
Member

(3) It obtains an expiration time of the downloaded key.

Oh yeah, you're right. This dumb issue is really happening. It appeared after trying to improve the workflow of the original dnf4 expired-pgp-keys plugin where this issue should not be present.

Maybe if we would keep the same approach with the generic removal of any expired keys on the system, it would also resolve this related issue: #2108.

ppisar added a commit to ppisar/dnf5 that referenced this issue Mar 14, 2025
There was a flaw in what this plugin did: Instead of checking an
expiration time of the keys in an RPM database, it downloaded keys of
enabled repositories from the Internet and checked their expiration
time. As a side effect, this plugin repeatedly downloaded the keys on
every invocation.

This patch fixes both the issues by checking keys which are in the RPM
database instead.

The new implementation removes all expired and confirmed keys in
a single RPM transaction. It also removes the unnecessary crosscheck
that a key obtained from an RPM database axtually exists in the
database. All that speeds up the operation at the expense that
reporting a success of the removal happens after the user selecting
all the keys for the removal.

The user query now reports a fingerprint instead of a path to the key
file. The reason is that a name of the key file is a temporary file
now because we take the keys from the RPM database. The current API
does allow importing from memory, neither changing the file attribute
of KeyInfo object.

This patch intentionally does not enhance any interface, inluding
newly identified bugs to be fixed independenlty later:

Respect --install-root option. We should probably move some code to
libdnf5/rpm/rpm_signature.cpp, or expose more code from there.

libdnf5::repo callbacks API is badly designed as it cannot be used
independetly from libdnf5::repo::RepoQuery object. That interface
should be moved closer to base as it is deals with a user interface
and not the repositories.

Resolves rpm-software-management#2099
Resolves rpm-software-management#2108
ppisar added a commit to ppisar/dnf5 that referenced this issue Mar 14, 2025
There was a flaw in what this plugin did: Instead of checking an
expiration time of the keys in an RPM database, it downloaded keys of
enabled repositories from the Internet and checked their expiration
time. As a side effect, this plugin repeatedly downloaded the keys on
every invocation.

This patch fixes both the issues by checking keys which are in the RPM
database instead.

The new implementation removes all expired and confirmed keys in
a single RPM transaction. It also removes the unnecessary crosscheck
that a key obtained from an RPM database axtually exists in the
database. All that speeds up the operation at the expense that
reporting a success of the removal happens after the user selecting
all the keys for the removal.

The user query now reports a fingerprint instead of a path to the key
file. The reason is that a name of the key file is a temporary file
now because we take the keys from the RPM database. The current API
does allow importing from memory, neither changing the file attribute
of KeyInfo object.

This patch intentionally does not enhance any interface, inluding
newly identified bugs to be fixed independenlty later:

Respect --install-root option. We should probably move some code to
libdnf5/rpm/rpm_signature.cpp, or expose more code from there.

libdnf5::repo callbacks API is badly designed as it cannot be used
independetly from libdnf5::repo::RepoQuery object. That interface
should be moved closer to base as it is deals with a user interface
and not the repositories.

Resolves rpm-software-management#2099
Resolves rpm-software-management#2108
ppisar added a commit to ppisar/dnf5 that referenced this issue Mar 14, 2025
There was a flaw in what this plugin did: Instead of checking an
expiration time of the keys in an RPM database, it downloaded keys of
enabled repositories from the Internet and checked their expiration
time. As a side effect, this plugin repeatedly downloaded the keys on
every invocation.

This patch fixes both the issues by checking keys which are in the RPM
database instead.

The new implementation removes all expired and confirmed keys in
a single RPM transaction. It also removes the unnecessary crosscheck
that a key obtained from an RPM database axtually exists in the
database. All that speeds up the operation at the expense that
reporting a success of the removal happens after the user selecting
all the keys for the removal.

The user query now reports a fingerprint instead of a path to the key
file. The reason is that a name of the key file is a temporary file
now because we take the keys from the RPM database. The current API
does allow importing from memory, neither changing the file attribute
of KeyInfo object.

This patch intentionally does not enhance any interface, inluding
newly identified bugs to be fixed independenlty later:

Respect --install-root option. We should probably move some code to
libdnf5/rpm/rpm_signature.cpp, or expose more code from there.

libdnf5::repo callbacks API is badly designed as it cannot be used
independetly from libdnf5::repo::RepoQuery object. That interface
should be moved closer to base as it is deals with a user interface
and not the repositories.

Resolves rpm-software-management#2099
Resolves rpm-software-management#2108
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Priority: MEDIUM Triaged Someone on the DNF 5 team has read the issue and determined the next steps to take
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants