Alrighty, we initially planned a part two with NixOS, but 1) we’d have to learn scheme (and we’d rather not) 2) somebody needs to to do it for alpine anyway. Pack yo toothbrush, we got supplychains that need securin’!

First of all, @ariadneconill went up and beyond and un-dead-ended us by implementing –ignore-devno and –renumber-inodes in cpio.c, sending patches to busybox and then uploading a patched busybox 1.33.1-r3 to alpine for us to continue with. Outstanding work!

This looks really good, the initramfs is indeed reproducible now as it’s not showing up in the diff anymore. The APKINDEX.tar.gz is a package index of all apks that are baked into the raspi image. This is generated with apk index, so that’s what we’re patching next.

We’re slightly hesitant here if there are any side-effects (also, C). The original code uses the current time for every file from 1970-01-01, that happens for DESCRIPTION and APKINDEX. Instead of implementing SOURCE_DATE_EPOCH in apk we just roll with the 70s for those files.

First success. We’re far from done tho, time to crank up the difficulty slider. 🔥🔥🔥

Before we do that tho, there’s an easy bug we’re fixing first, during debugging we’ve unpacked the image a few times and one file survived the rm -vr ./* since it starts with a dot. Upon inspection we notice that’s the current date although we’re setting SOURCE_DATE_EPOCH to 0.

This is obviously going to cause issues unless the image gets verified on the same day (this rabbit hole is actually quite deep, more on that later though). We somehow missed $build_date so we’re moving our code around a bit and also specify utc to avoid timezone issues.

There’s actually a tool called reprotest in alpine [testing] that helps to detect things like that, but we have bigger problems to look at first.

We’re doing multiple things now: First, we finally enable abuild-sign again. Also, previously both builds had access to our developer secret key. We don’t want to share that file though, so the rebuilder is now getting its own keypair. 🔥 Fasten your seat-belts ladies/gents/*.

This doesn’t seem that bad, the signature-difference is back, but also the modloop thingy. Something we can’t see: the actual public key. Since the public key is essential to verify any signature, maybe we can just avoid signing in the first place instead of reusing signatures?

Lots of digging later, we found the code that’s using this signature. It seems this is specifically to secure a modloop device that might’ve been downloaded during boot. Since this isn’t the case for us we can safely disable it, this doesn’t explain the missing public key though.

Ok, this clears it up. It’s specifically going through keys in /etc/apk/keys/ and those are getting copied from the host, not $ABUILD_USERDIR. If the local filesystem contains a signature from one of those keys it’s going to verify it. So we just don’t generate one.


Unfortunately this means the signature in the APKINDEX.tar.gz is very likely going to be verified. We don’t know if verification can be disabled, so instead of building twice we’re now going to take the first image as an additional build input and steal^W reuse the signature.

Doing this with bash would be really annoying, so we’re rolling with rust again. About 4h, 255 lines of rust, and some memes in the local ctf signal group later we got a working implementation, let’s try to integrate this into our other build script. github.com/kpcyrd/abuild-reusesig

Fingers crossed everybody 👀

Close.. we’ve normalized the build user id and name in our rust program but didn’t edit abuild-sign yet. This was… err.. on purpose - of course - to demonstrate copying the signature works.


We did it fam! The rebuilt image is bit-for-bit identical, including the sig, despite the 2nd build not having access to the secret key. This is not the end of the story, next up is “what are buildinfo files and why do we need ‘em”. But not today.

As you can tell by the (not-normalized) timestamps this was a multi-day effort and we took a day off work today for the final lift and editing. Please consider sponsoring on github for more content. Thank you! ❤️

This post was originally published on Twitter.