From d3bbc22d540ab278f14724d06a69ad1969bb5a07 Mon Sep 17 00:00:00 2001 From: Trammell Hudson Date: Sat, 6 Aug 2016 18:45:56 -0400 Subject: [PATCH] signing details --- README.md | 166 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 35151f9a..5490cac0 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,35 @@ Installation requires disassembly of your laptop or server, external SPI flash programmers, possible risk of destruction and significant frustration. + +Threat model +--- +Heads considers two broad classes of threats: +* Attackers with physical access to the system +* Attackers with ring0 code execution on the runtime system + +The first is hardest to deal with since it allows an attacker to +make physical changes to the machine. Without a hardware root of +trust and secrets stored inside that CPU, it is very difficult to +project against a physical attackers who can replace components and +fake measurements. Hardware measurements of the boot ROM (such as +Intel's Boot Guard) can help, although a dedicated attacker could +replace the CPU with one that is not fused to do the initial measurement. +The best that we can do is to lock the bootblock on the SPI flash, +perform the first measurement from it and hope that there are not any +exploits against the chip itself. + +The second class is also a difficult challenge, but since it is only +a software attack, we have better hopes of handling with some harware +modifications. The SPI flash chip's boot block protection modes can +be locked on and the WP# pin grounded, which will prevent any software +attacks from overwriting that portion of the boot ROM. This gives us +a better root of trust than any of the other x86 boot processes, +since we now have + + + + --- Components: @@ -28,7 +57,7 @@ Components: * Linux * busybox * kexec -* tpmtotp +* tpmtotp (with qrencode) * QubesOS (Xen) --- @@ -40,3 +69,138 @@ Notes: * Booting Qubes requires patching Xen's real mode startup code; see `patches/xen-4.6.3.patch` and add `no-real-mode` to start of the Xen command line. +* Builds are not reproducible; this is a significant project + + +dm-verity setup +=== +This set of tools isn't the easiest to use. It is possible to store +hashes on the device that is being hashed if some work is done ahead +of time to reserve the last few blocks or if the file system can be +resized. + +The size of the hash table grows logarithmic with the size of the +filesystem. Every 4K block is hashed, and then 4K of those blocks +are hashed, and so on until there is only one hash left. +Each hash is 32 bytes, so the hash tree size is 32 * log_4096(fs) + +The hashes can be stored on a separate device or on the free space +at the end of an existing partition. This will require resizing +if you didn't allocate the space initially. + +The sizes of physical partitions can be read (in 512-byte blocks) from +`/sys/class/block/sda1/size`. The `resize2fs` tool (assuming you're using +a normal ext4 filesystem) will not resize smaller than the free +space. Figure out the desired size + + fs_size = $[30 * 1024 * 1024] + e2fsck hdd.img + resize2fs hdd.img $fs_size + +Once the file system has been resized to make space at the end, +the dm-verity tools can generate the hashes. The file system +must be unmounted before this is done, otherwise the hashes +will not be correct. + + veritysetup \ + --data-blocks $[$fs_size / 4096] \ + --hash-offset $fs_size \ + format hdd.img hdd.img \ + | tee verity.log + +This will output a text file that contains several important +constants for mounting the filesystem later: + + VERITY header information for hdd.img + UUID: 73532888-a3e9-4f16-a50a-1d03a265b94f + Hash type: 1 + Data blocks: 7680 + Data block size: 4096 + Hash block size: 4096 + Hash algorithm: sha256 + Salt: 3d0cd593d29715005794c4e1cd5164c14ba6456c3dbd2c6d8a26007c01ca9937 + Root hash: 91beda90d7fa1ab92463344966eb56ec9706f4f26063933a86d701a02a961a10 + +Unfortunately this is in the wrong form for the `dmsetup` command +and must be reformmated like this: + + dmsetup create vroot --readonly --table \ + "0 61440 verity 1 /dev/sda /dev/sda 4096 4096 7680 7681 sha256 "\ + "c51e171a1403eda7636c89f10d90066d6a593223399fdd4c36ab214da3c6fc11 "\ + "f6c6c6b6cbdf2682d6213e65b0e577cb57c8af3015f88f9a40fb512eaf48aca9" + +The 61440 is the number of 512-byte blocks that the filesystem uses. +The two 4096 are the data block size and hash block size. +The 7680 is the number of data blocks and the 7861 is the first +datablock containing hashes (note that block 7680 contains the `VERITY` +header and the salt, but not the root hash). The hash and salt are +reversed in the order from the `veritysetup` printout. + +We sign this command and stash it in the block after the `VERITY` +header so that the firmware can validate the image before mounting it. +This does require that the firmware be able to find the header; +for now we have it hard coded. + + +mbedtls vs OpenSSL +--- +mbedtls is a significantly smaller and more modular library than +OpenSSL's libcrypto (380KB vs 2.3MB). It is not API compatible, +so applications must be written to use it. + +One the build host side we can make use of openssl's tools, but in +the firmware we are limited to the smaller library. They are mostly +compatible, although the tools are quite different. + +Generate the private/public key pair (and copy the public key to +the initrd): + + openssl genrsa -aes256 -out signing.key + openssl rsa -pubout -in signing.key -out signing.pub + +Sign something (requires password and private key): + + openssl pkeyutl \ + -sign \ + -inkey signing.key \ + -in roothash \ + -out roothash.sig + +Verify it (requires public key, no password): + + openssl pkeyutl \ + -verify \ + -pubin + -inkey signing.pub \ + -sigfile roothash.sig \ + -in roothash + +but this doesn't work with pk_verify from mbedtls. more work is necessary. + + +Signing with GPG +--- +`gpgv` is a stripped down version of GPG that can be used to verify +signatures without extraneous libraries. This works well with the +Free Software workflow that we want to use. + + gpg --clearsign roothash + +The `roothash` and `roothash.sig` files can be embedded into the +HDD image and then extracted at firmware boot time: + + gpgv --keyring /trustedkeys.gpg roothash.sig roothash \ + || echo "FAILED" + +The `mount-boot` script is a start at doing this automatically. +There needs to be an empty block at the end of the partition +that includes a signed script to be executed; typically it will +contain the dm-verity parameters to build the `dmsetup` command +line to mount `/boot`. + +The boot script can't be stored in the boot filesystem since the +dm-verity hashes that protect the filesystem would need to have their +own hash pre-computed, which is not feasible with a good hashing +algorithm. You could store the hashes in the ROM, but that would +not allow upgrades without rewriting the ROM. +