Tuesday 8 February 2022

Bitcoin v22.0 and Guix; Stronger defense against the "Trusting Trust Attack"

TLDR; Bitcoin v22.0 moves to Guix so that we can "trust the compiler" even less

<tinfoil_hat_fud>

With any software that handles finance or private keys, the question of trust is important. Most have a general concept of this stuff, and that is usually fine for most anyone's needs. But there is always the rare case where trust policies are too laxed and users get burned, like the Electrum v3.3.3 phishing attack. Here I'll try to go through the minimal level of trust all the way down to the theoretical limit of what can be done. At the heart of the matter is the concept of extended trust. In most trust-tests, we start with something that has more trust and see if we can connect it to something with less trust. I'll walk through a few examples from the top down. In general we will go through the following levels:

  1. Trust the site
  2. Trust the builders
  3. Trust the compiler
  4. Trust the kernel
  5. Trust the hardware

Trusting the site

When downloading software such as bitcoin-core, at a minimum it is important to ensure you download from bitcoin.org and not some site like download.com. If you grab software from a sketchy site, it may come packaged with code to steal your keys (See "Electrum phishing" above).

In the realm of "trusting the site" there are those who trust the browser to get you to bitcoin.org and others who are more paranoid and will ensure that SSL is enforced. Unfortunately, unless the site uses something like DNSSEC, DANE, or other cryptographic domain verification, you can just never be sure. Attacks like bitsquatting and dns-poisoning can get past even the best intentions of DNS security. So... sites can't be trusted.

Trusting the builders

In most cases, trusting the builders is the what most recommend. This process completely ignores WHERE the binaries were taken from (even download.com) and instead rely on a builder's cryptographic signature delivered with, or embedded in, the file. These are usually either GPG signatures or CodeSigning certificates like Authenticode. Main issues here is that many user's don't know WHO the builders are. In many cases, most simply assume that a trusted product, must have a trusted package owner / builder. A recent example of where this went horribly wrong was when ownership of a popular JavaScript library was left to a randome contributor. The new owner went about crafting back-doors to steal bitcoin. Since JavaScript is interpretive, it was quickly spotted, but it shows the danger of entrusting new package builders or maintainers. Clever projects (like bitcoin) get around this problem by having reproducible builds.

Reproducible builds are a way to design software so that many community developers can each build the software and ensure that the final installer built is identical to what other developers produce. With a very public, reproducible project like bitcoin, no single developer needs to be completely trusted. Many developers can all perform the build and attest that they produced the same file as the one the original builder digitally signed.

In most situations, those who are not developers are fine to stop here. Just insist that the software you use is open-source, well audited, reproducible, with multiple maintainers who all attest to the same verified compiled binaries. Bitcoin meets this test on all counts

Trusting the compiler

For those who may fear an evil cabal of developers, or feel their project is not audited enough, the next level down is to trust nothing but the compiler. These users will build the project from source code removing the need to trust the project builders. Many may imagine that this is the furthest down the "rabbit hole" this topic can go, but in actuality it isn't. In a 1984 award speech, the recipient, Ken Thompson, posited the question "Should you trust your compiler?". He goes on to outline a method called the "Trusting Trust Attack". Since even the most paranoid users usually trust the compiler, Ken suggested the compiler is the perfect place to put your Trojan.

The basics of this attack are due to the fact that to make a new compiler binary, you generally use the last compiler binary. But what if compiler binary had malicious code to infect new binaries. This is particularly problematic since compilers building compliers goes back pretty far. Android was made with Linux that was made from Minix. Apple was made with BSD and BSD was made from Unix. These build genealogies go back decades. So what if the original Unix back in the 60's had a trojan in the compiler that has been carried forward for the last 60 years?

As involved as this sounds, there have been many proof of concepts done to prove the attack's viability. And with distrust of state security agencies getting worse year after year, it's not hard to imagine that some agency would want to pull off such attack. The main attack "surface" here are what builders call the "seed binaries". These are the previous versions of compiler and tools needed to build the next compiler. If you can "seed" your build with a smaller set of binaries then, in theory, you may get the set so small that examination, byte for byte, could look for "bad code".

In version 22.0, bitcoin moved to the Guix build system for their official builds. This reduced the "weight" of those seed binaries from 550 MB down to 120 MB. The Guix team is prototyping a new compiler build with a reduced seed weight of 357 bytes. That's a reduction of 99.999935% from the binary seed weight of Bitcoin v0.21.2

This claim is a bit hyperbolic, but less than you might think. The complier build requires a proto-complier (mes) and a shell (guile). This reduction is only for mes not guile. Though there is work to do the same reduction on guile that was done on mes, but that may still be a few years out.

Trusting the Kernel

Implicit in the trust of the compiler is the trust of the kernel and OS that the compiler is running on. So if a trusting-trust trojan decided to propagate and infect in both a compiler and kernel, then reducing your binary seed may not be enough. This is a harder attack to pull off since a 357 byte seed build will likely be hand audited for the first few iterations. The trojan would need to know to infect the process far enough along to where it wasn't visible any more.

The solution to this is to bootstrap your compiler build, without a kernel. This can be done up until a point. The hex assembler and macro assembler can be loaded directly out of a legacy bootloader (think 0x7C00) and work is ongoing in in the stage0 project that helped in the mes bootstrap. But realistically, I'm not sure how far they can take this.

Trusting the Hardware

Imagining if you could bootstrap without the kernel, there is still the trust of the hardware. A builder is trusting that the processor and instruction pipeline is not doing something malicious if it detects a compiler bootstrap is in place. Although this is pretty deep paranoia, people are still thinking about this stuff. The reduced mes bootstrap is working to have a x86 and arm bootstrap independent of each other. Although one can be cross-compiled on the other, it was thought to be better if arm software didn't have to trust x86 hardware for a bootstrap, and vice-versa.

</tinfoil_hat_fud>

References

© hash: 68a4dd4bc6d2c0cc9

submitted by /u/brianddk
[link] [comments]

No comments:

Post a Comment