auth-tarball-from-git: Verifying tarballs with signed git tags
by kpcyrd, short read,
I noticed there’s a common anti-pattern in some PKGBUILDs, the short scripts that are used to build Arch Linux packages. Specifically we’re looking at the part that references the source code used when building a package:
source=("git+https://github.com/alacritty/alacritty.git#tag=v${pkgver}?signed")
validpgpkeys=('4DAA67A9EA8B91FCC15B699C85CDAE3C164BA7B4'
'A56EF308A9F1256C25ACA3807EA8F8B94622A6A9')
sha256sums=('SKIP')
This does:
- ✅ authentication: verify the git tag was signed by one of the two trusted keys.
- ❌ pinning: the source code is not pinned and git tags are not immutable, upstream could create a new signed git tag with an identical name and arbitrarily change the source code without the PKGBUILD noticing.
In contrast consider this PKGBUILD:
source=($pkgname-$pkgver.tar.gz::https://github.com/alacritty/alacritty/archive/refs/tags/v$pkgver.tar.gz)
sha256sums=('e48d4b10762c2707bb17fd8f89bd98f0dcccc450d223cade706fdd9cfaefb308')
- ❌ authentication: there’s no signature, so this PKGBUILD doesn’t cryptographically verify authorship.
- ✅ pinning: the source code is cryptographically pinned, it’s addressing the source code by it’s content. There’s nothing upstream can do to silently change the code used by this PKGBUILD.
Personally - if I had to decide between these two - I’d prefer the later because I can always try to authenticate the pinned tarball later on, but it’s impossible to know for sure which source code has been used if all I know is “something that had a valid signature on it”. This set could be infinitely large for all we know!
But is there a way to get both? Consider this PKGBUILD:
makedepends=('auth-tarball-from-git')
source=($pkgname-$pkgver.tar.gz::https://github.com/alacritty/alacritty/archive/refs/tags/v$pkgver.tar.gz
chrisduerr.pgp
kchibisov.pgp)
sha256sums=('e48d4b10762c2707bb17fd8f89bd98f0dcccc450d223cade706fdd9cfaefb308'
'19573dc0ba7a2f003377dc49986867f749235ecb45fe15eb923a74b2ab421d74'
'5b866e6cb791c58cba2e7fc60f647588699b08abc2ad6b18ba82470f0fd3db3b')
prepare() {
cd "$pkgname-$pkgver"
auth-tarball-from-git --keyring ../chrisduerr.pgp --keyring ../kchibisov.pgp \
--tag v$pkgver --prefix $pkgname-$pkgver \
https://github.com/alacritty/alacritty.git ../$pkgname-$pkgver.tar.gz
}
- ✅ authentication: auth-tarball-from-git verifies the signed git tag and then verifies the tarball has been built from the commit the tag is pointing to.
- ✅ pinning: the source code and the files containing the public keys are cryptographically pinned.
In this case sha256sums=
is the primary line of defense against tampering with build inputs and the git tag is “only” used to document authorship.
For more infos on how this works you can have a look at the auth-tarball-from-git repo, there’s also a section about attacks on signed git tags that you should probably know about.
Thanks
This work is currently crowd-funded on github sponsors. I’d like to thank @SantiagoTorres, @repi and @rgacogne for their support in particular. ♥️