View previous topic :: View next topic |
Author |
Message |
inf1nity n00b
Joined: 05 Apr 2015 Posts: 15
|
Posted: Thu Jan 18, 2024 11:35 am Post subject: Binpkg update ignored for signed package: file removed |
|
|
Hi,
I've been using signed binary packages for a few months now and everything was working just fine.
Last update on my binary package server was 8th of January.
At that time (end of the updates) there were 1251 signed binary packages in /var/cache/binpkgs, with extension .gpkg.tar .
I just ran eix-sync and in the course of approx. 15 minutes it informed me, that:
Code: | Binpkg update ignored for signed package: ... the file will be removed. |
After it was done there were only 196 signed binary packages remaining.
Code: | emerge -uDNav @world | only wants to update/rebuild 156 packages total.
It would take quite a few hours to somehow rebuild every missing binary package, if I can figure out which are now missing.
Normally I take snapshots of /var/cache/binpkgs and use those for distribution to client systems. Now lots of packages would be missing.
This commit here seems to be my problem: https://github.com/gentoo/portage/commit/a7bbb4fc4d38f770fc943f3b856c5de56e315fe4
Can somebody please explain to me what happened? This is a huge waste of resources. |
|
Back to top |
|
|
Hu Administrator
Joined: 06 Mar 2007 Posts: 22745
|
Posted: Thu Jan 18, 2024 4:11 pm Post subject: |
|
|
You had signed packages, which needed to be updated, probably for a pkgmove. The move would invalidate the signatures, rendering the package unusable. The following options exist to handle this:- Delete the package. This is easy, and was what the Portage developers chose.
- Update the contents, and leave the signature invalid. Portage should refuse to handle a package with an invalid signature, so this seems like a bad choice.
- Update the contents, and remove the signature. If the user is signing packages, the user is probably validating the signatures, so this would again make the package unusable.
- Update the contents, and rebuild the signature. As discussed in the linked commit, this was judged to be a lot of trouble, so it was not done.
- Ignore the update, and leave the old metadata. This would probably cause problems later.
I saw quite a few pkgmove events come through recently as packages migrated into the dev-debug/ category.
It would be nice if the signature could have been regenerated. This seems like an area for a Portage improvement, if someone were to volunteer to write it. |
|
Back to top |
|
|
sam_ Developer
Joined: 14 Aug 2020 Posts: 1991
|
Posted: Thu Jan 18, 2024 4:49 pm Post subject: |
|
|
Just to be explicit: before that commit, Portage would crash.
It's also complicated by the fact that even if we have signing capabilities locally, they may not match the keyring used to verify too.
Maybe if we implement Zac's suggestion in bug 921431 to verify on fetch and then not again for getbinpkg, that'd work, but I'm hesistant to mess with that for now.
As a workaround, you may be able to use some Portage options on your builder so it refreshes the binpkgs (if there isn't a suitable one, we might be able to then add one). |
|
Back to top |
|
|
inf1nity n00b
Joined: 05 Apr 2015 Posts: 15
|
Posted: Thu Jan 18, 2024 6:29 pm Post subject: |
|
|
Thank you both for the explanations.
As far as I'm concerned, please correct me if I'm wrong, there should be two gpg homedirs, one where the binary package server signing key is stored and the /etc/portage/gnupg directory where the public keys are stored for verification.
Both are set up correctly on the binary package host and /etc/portage/gnupg on all clients.
Everything is working there.
What I found was that I had to add the following gpg-agent.conf file in the gpg homedir where the signing key is stored
Code: | # Default cache ttl from 600s (10 mins) to 1800s (30mins).
default-cache-ttl 1800
# Max cache ttl from 7200s (2 hours) to 172800 (48 hours).
max-cache-ttl 172800 |
for gpg-keepalive to actually work. The first is so that in case zstd compression + signing takes longer than 5 minutes the keyring isn't closed and the second so that emerge jobs running for more than 2 hours don't error out on gpg signing failure, as the keepalive code can't counteract max-cache-ttl.
Now regarding resigning the packages and this is - as far as I'm concerned - only relevant for the binary package host as I don't care if the clients have to refetch stuff and that is surely, I can agree with that, the safe approach.
If the signature found on binary packages matches the key vailable via
Code: |
BINPKG_GPG_SIGNING_GPG_HOME=
BINPKG_GPG_SIGNING_KEY= |
then a resigning should take place.
For that the signature would have to be removed, the archive modified by adjusting the metadata file(s) within, and resigned.
From what I've read of the source code it shouldn't be hard to do. The unpacking code is already present, the metadata editing code should exist - otherwise non-signed binary packages couldn't be modified -, the packaging code must exist and the signing code as well.
How much work can this really be for someone familiar with the functions - please correct me if my guess is wrong ?
I'm expecting the packages to take at least 6-10 hours to rebuild.
And now every time someone decides they need to move packages this happens?
Last edited by inf1nity on Thu Jan 18, 2024 7:48 pm; edited 1 time in total |
|
Back to top |
|
|
inf1nity n00b
Joined: 05 Apr 2015 Posts: 15
|
Posted: Thu Jan 18, 2024 7:05 pm Post subject: |
|
|
So getting the fingerprint out of the archive seems to involve doing this:
tar -C /tmp/tempdir -xf libreoffice-7.5.9.2.gpkg.tar libreoffice-7.5.9.2/metadata.tar.zst.sig
gpg --list-packets /tmp/tempdir/libreoffice-7.5.9.2/metadata.tar.zst.sig | grep 'issuer fpr'
I'm sure there is also a python method for that.
Getting the private key fingerprints of those in the binary package key gpg homedir should be relatively easy and then one could just compare them and if a match is found invoke the gpg unlock class so that the user is asked for the password to the signing key.
After that the whole archive would have to be extracted, both .sig files removed, new signatures generated and repacked. |
|
Back to top |
|
|
inf1nity n00b
Joined: 05 Apr 2015 Posts: 15
|
Posted: Thu Jan 18, 2024 7:43 pm Post subject: |
|
|
The --list-packets gnupg option seems to be for debug purposes only and shouldn't be relied on.
This works and is based on the signature verification code:
Code: | import gnupg
gpg = gnupg.GPG(gnupghome=BINPKG_GPG_SIGNING_GPG_HOME)
stream = open('/tmp/tempdir/libreoffice-7.5.9.2/metadata.tar.zst.sig', "rb")
verified = gpg.verify_file(stream, '/tmp/tempdir/libreoffice-7.5.9.2/metadata.tar.zst')
if not verified:
print("signature verify failed")
else:
fpr = verified.fingerprint
private_keys = gpg.list_keys(True)
for pkey in private_keys:
for skey in pkey["subkeys"]:
if fpr in skey:
print("signing key present")
break
else:
continue
break
stream.close() |
I'm sure this can be improved upon.
Especially the data returned by pkey["subkeys"] I'm unsure of how to properly parse. |
|
Back to top |
|
|
sam_ Developer
Joined: 14 Aug 2020 Posts: 1991
|
Posted: Thu Jan 18, 2024 8:09 pm Post subject: |
|
|
inf1nity wrote: |
[...]
How much work can this really be for someone familiar with the functions - please correct me if my guess is wrong ?
I'm expecting the packages to take at least 6-10 hours to rebuild.
And now every time someone decides they need to move packages this happens? |
I think sentiments like this are unhelpful and don't really motivate me at least to work on it. You can express that you think the feature is meaningful, but implying everything else around it is easy (either not renaming or just writing the code) isn't going to get us anywhere. If it was trivial, then someone would have probably done it.
I should also note that pkgmoves en-masse are very rare. We're moving a lot at the moment because we came up with a bunch of new categories, so you're seeing a lot of moves of packages themselves and then updates to anything referencing them (they multiply). That doesn't happen very often.
One issue (as noted in the commit message) is that we don't always clearly distinguish between fetched and local binpkgs. Interacting with gnupg can also sometimes be rough. We would first have to check if the local key, if one even exists, is usable. If someone is using binpkgs from e.g. Gentoo, they may want to keep the original binpkgs fetched from Gentoo and not tamper with the signatures at all, even if they're able to resign them (as you can't prove provenance then).
What if the key has changed in the meantime (transitioning to a new key) but the user just runs 'emerge ...' locally, without creating binpkgs, then Portage applies pkgmoves?
The fear when implementing things like this in Portage is that there's often a case where you do it and then someone pops up and says they really want the opposite behaviour, and then we have to add yet another option for it.
It's not impossible at all, it just requires: a) thinking out the edge cases; b) deciding on a plan; c) writing the gnupg glue (this last part isn't helped by the fact we currently do not use python-gnupg or any other bindings/library for it, maybe we should, but adding new deps into the PM is always a thing to be done with care). It is very much doable by a motivated contributor, just explaining why I didn't simply do it to begin with. |
|
Back to top |
|
|
inf1nity n00b
Joined: 05 Apr 2015 Posts: 15
|
Posted: Thu Jan 18, 2024 9:14 pm Post subject: |
|
|
Maybe my point of view is truly limited because I'm having a hard time thinking of cases where I would want them to be resigned and I can only come up with one that is sane enought for portage to automatically perform the action. It was not my intention to offend.
If the user has set BINPKG_GPG_SIGNING_GPG_HOME, BINPKG_GPG_SIGNING_KEY and FEATURE binpkg-signing, then they intend to sign packages. If not, just remove the package, as is currently implemented. For my use case this would already filter out all client systems, because they have neither of them set. But to be sure:
If a package that is signed is encountered, get the fingerprint of the signature inside the package. Compare it against the private keys - you can't sign without it - in BINPKG_GPG_SIGNING_GPG_HOME. If no match is found, just remove it as is.
If a match is found, then the user not only intends to sign packages on that host but also has the private key that was used to create the signature on that package, meaning the user has the power to resign it with the exact same key. Only the owner of the binary package host should match here.
I would not assume that a user ever gets access to the Gentoo private signing key, otherwise this whole security concept would fall apart, correct? So that issue is removed.
Should the intention be to support key-migration, then portage would need to support something like
BINPKG_GPG_SIGNING_KEY_MIGRATION["old-id/fingerprint"]="new-id/fingerprint"
for every old key that could be encountered. It should be possible to filter out expired private keys, via either gpg or python-gnupg, and the keys of the BINPKG_GPG_SIGNING_KEY_MIGRATION array, although they should have been set to expired. If no match for the fingerprint encountered in the signed package is found via this logic fallback to package removal.
Which edge cases would remain? I mean the moment you require that the exact same private key that created the packages signature or its configured migration key is present and valid and force the resigning to be with that key, it should either succeed or fail, correct?
Regarding another issue I had, because I want to manage the contents myself:
Should whoever intends to merge getuto into portage read this, please keep
PORTAGE_TRUST_HELPER=true
so that it doesn't import the Gentoo signing keys into /etc/portage/gnupg. I would like that to be another security mechanism and only have my own signing keys (public) imported on clients, so that no other binpkgs are accidentally installed. Them I manage via my own update script similarly to how getuto does it. |
|
Back to top |
|
|
inf1nity n00b
Joined: 05 Apr 2015 Posts: 15
|
Posted: Thu Jan 18, 2024 9:45 pm Post subject: |
|
|
This seems to work for listing secret subkeys and their expiration date (date +%s format), if it exists, otherwise it will probably be an empty string, but I'd have to look at it again to be sure:
Code: | gpg --homedir="$BINPKG_GPG_SIGNING_GPG_HOME" --with-colons -K | awk -F: 'BEGIN { found=0 } $1 == "ssb" { found=1; expdate=$7; next } found && $1 == "fpr" { print $10, expdate; found=0 }' |
And this shows the fingerprint of the key used for the signature in the package:
Code: | # gpg --homedir=/etc/portage/gnupg --verify /tmp/tempdir/libreoffice-7.5.9.2/metadata.tar.zst{.sig,}
gpg: WARNING: unsafe permissions on homedir '/etc/portage/gnupg'
gpg: Signature made Mon Jan 8 16:01:40 2024 CET
gpg: using RSA key FINGERPRINT-WAS-HERE
gpg: Good signature from ". . ." [full] |
If it doesn't say 'Good signature', remove the package, if it doesn't print 'using ... key FINGERPRINT', remove the package. Otherwise proceed with the given fingerprint and compare it against the list above, excluding expired keys by comparing with date +%s.
At least that is how I'd do it at the moment if I had to program it and I weren't allowed to use python-gnupg. |
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|