Hi! Ludovic Courtès skribis: > The good news with this model is that an adversary cannot trick users > into fetching an unrelated branch where the authorizations would be > different: they can always detect that it’s a disconnected branch or > that it’s not a fast-forward pull. > > The bad news is that this also prevents “unauthorized forks” in general. > Unless Guix folks explicitly push a commit authorizing the key of the > person who forks, commits by that person will appear as unauthorized. > > So we need an extra mechanism to say: “this fork starts here”. However, > modifications to that piece of information must be detectable so that > one cannot serve a malicious fork that pretends to forego history. We have two issues to address: (1) bootstraping trust in a channel the first time ‘guix pull’ obtains it, and (2) supporting “unauthorized” forks as described above. The two are very similar. I think we need a way to “introduce” a channel to its users that goes beyond a mere URL. It should be possible to obtain a “channel introduction” out-of-band (i.e., not in the channel’s repo). For example, the introduction to the official ‘guix’ channel would be in ‘%default-channels’, in (guix channels), which users obtained in the binary tarball or ISO. For other channels where there’s no practical out-of-band transmission of the introduction, it would very much be trust-on-first-use (TOFU). I think the introduction needs to include: 1. The commit used as a starting point for ‘.guix-authorizations’ checks. 2. The OpenPGP fingerprint of the signer of this first commit. 3. A signature over this commit/fingerprint pair made by the signer of the commit. Rationale ~~~~~~~~~ 1. The ‘guix’ channel and others will have their authorization start long after their initial commit. Thus, authors need to state where to start the authentication process. (Currently the starting point is hard-coded in ‘Makefile.am’ and passed as an argument to ‘build-aux/git-authenticate.scm’.) If that information were stored in ‘.guix-channel’, it would be trivial for an attacker to fork the project (or push a new commit) and pretend the authentication process must not take previous commits into account. 2. The fingerprint of the signer of the initial commit makes it easy for ‘guix pull’ to verify that initial commit on its first clone. 3. The signature over the commit/fingerprint pair makes sure that it was emitted by an authorized party. Without it, anyone could emit a channel introduction that skips over a range of commits. 4. When publishing a fork of a channel, one emits a new channel introduction. Users switching to the fork have to explicitly allow that new channel via its introduction; flipping the URL won’t be enough because ‘guix pull’ would report unauthorized commits. 5. The channel URL is not included in the introduction. However, the official URL is an important piece of information: it tells users this is where they’ll get the latest updates. It should be possible to create mirrors, but by default users should go to the official URL. They should be aware that mirrors can be outdated. I think the official URL can be stored in ‘.guix-channel’ in the repo (which is subject to the authentication machinery). That way, ‘guix pull’ can let the user know if they’re talking to a mirror rather than to the official channel. Prototype ~~~~~~~~~ The attached code creates channel introductions. One implementation uses a “compact” binary encoding, which, one encoded in Radix-64, looks like this: -----BEGIN GUIX CHANNEL INTRODUCTION----- R1hDSQAAAAAAFJdEzHtGNvr7dyyUrbjwWWG1s58WPORkVYqE/cadtAz7CQsRmT2a67UCvaMBAbYC Sf2QDQMACgEJCxGZPZrrtQHLb2IAXtUHUCgoY29tbWl0ICI5NzQ0Y2M3YjQ2MzZmYWZiNzcyYzk0 YWRiOGYwNTk2MWI1YjM5ZjE2IikgKHNpZ25lciAiM2NlNDY0NTU4YTg0ZmRjNjlkYjQwY2ZiMDkw YjExOTkzZDlhZWJiNSIpKYkCMwQAAQoAHRYhBDzkZFWKhP3GnbQM+wkLEZk9muu1BQJe1QdQAAoJ EAkLEZk9muu1SlUQAIQVO6JeNmDywM5bAVIktX0VbPmPl0CNCt2oTN8jPZ30lwa3osckOEa2LqQv 0xP59n9tPUue8rXoACcdZ4RS7fZeWjn9qBGCr7h/cQIS0p7II08jHccovvEfgQGxqQCe5hZ++Ehv OyKV84bG3VOxLFe7B2wIqoIAtmFYCeNmqBfOixSWgzCwC/G5fh7frXR+O9BzvhfBVeFSgzgayNnu GxgO+Jx7ZhnxR8rRIxrOxCEUjbi8ilIhw++z4ea7g4yTFCkmpPY54HIhzgERanm0/iJUBj9nv9kQ TXnJ2dcFeZL7b+fWdh8kiKaTgYKV3BGQOKpdqSBQcV9Ys+FFJ+I5ZRCzmTxafPLmR8eGM3aT4Fld drCjSHga4hbppQJPpNyKsrhwJ4d5tLuLHYUNlXEhcYi11Uo2i30T+TbOynD/uWFRY1+s0ffI1LmX FhSaqk44jfQoXYeeS8FO471ze3087fsp2WVwNZ5kdPOFNa1Iv+uj/CDILsb4kooRrawQod2W7eb6 jMCayWCUApah22BisQepkFVtKeEAG6aSkIa6Haq4ZrEtzz9gu4n6Pmgv60+n3t77rb7GbPafdSKu LiJ8PeYSBR3II2YdjIn9PTQ75Xg90IeFxt5PF70q/yb/WoRTIokHFho1QEmbmAm1HBO8SVlmHG+X 8WFn7ex7cx3iYH6H =xZUu -----END GUIX CHANNEL INTRODUCTION----- (guix channels) could provide a ‘channel-introduction->channel’ procedure. In ~/.config/guix/channels.scm, one would write: (list (channel-introduction->channel "https://…" "\ -----BEGIN GUIX CHANNEL INTRODUCTION----- …")) The introduction needs to be decoded and checked only the first time ‘guix pull’ encounters a channel. This verbose interface creates an incentive to create a ‘guix channel’ command that could make it easier to add a new channel. Thoughts? Ludo’.