github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/binary_transparency/firmware/devices/usbarmory/README.md (about) 1 USB Armory 2 ========== 3 4 In this package is support for using the 5 [USB Armory](https://inversepath.com/usbarmory.html) hardware with the firmware 6 transparency demo. 7 8 Since the SoC on the hardware already has ROM we can't patch that to root our 9 trust there, so for now we'll simply use a first-stage EL3 bootloader to 10 "enforce" the correctness of the proof bundle before chaining to something 11 (e.g. a full linux image based app) that represents the firmware being made 12 transparent. 13 14 The enforcement code not being in the masked ROM is an obvious shortcoming of this 15 demo, however given the interesting array of security hardware on this board 16 it should be possible to use some of that as an alternative trust base. 17 18 Storage 19 ------- 20 21 > :warning: these are scratch notes, not yet reflective of reality, and so may 22 > change drastically! 23 24 We'll use the µSD card slot of the USB Armory for our purposes. 25 26 The SD card will contain: 27 - our "enforcing" [bootloader](./bootloader) 28 - the firmware being made discoverable 29 - a [proof bundle](/binary_transparency/firmware/api/update_package.go) 30 for the firmware which convinces the bootloader that it _is_ discoverable 31 and therefore ok to launch. 32 33 > :info: the USB Armory is built around an NXP i.MX6 SoC. When booting, the ROM 34 > loader on this SoC expects to find the first-stage bootloader at the 35 > 1024th byte of the external storage. 36 > This allows sufficient space beforehand to store a partition table. 37 38 The on-disk partition layout will be: 39 index | name | size | format | notes 40 ------|------------|---------|--------|----------------------------------------------- 41 1 | boot | 10M | raw | Must cover disk bytes 1024 onwards as we'll directly write the bootloader here. 42 2 | proof | 512KB | ext4 | EXT4 filesystem for storing a serialised proof bundle 43 3 | firmware | 64MB+ | ext4 | EXT4 filesystem containing the bootable firmware image, armory boot config, etc. 44 45 ### Preparing the SD Card 46 47 > :warning: When following the instructions below, be *very sure* you know which 48 > device is your SD card - if performed with an incorrect device, the instructions below 49 > can cause data loss! 50 51 #### Linux 52 53 ##### Partition & file-systems 54 55 First use the `parted -l` command to figure out which device corresponds to your 56 SD card. 57 > :tip: you can run the `parted -l` command twice, once with your SD card 58 > reader plugged in, and once without to help identify the device. 59 60 `/dev/my_sdcard` is used as a placeholder below, you should replace that with 61 the path for your SD card device. 62 63 ```bash 64 sudo parted /dev/my_sdcard 65 # double (triple!) check we've got the right device: 66 (parted) print 67 ... 68 (parted) mklabel msdos 69 # Create space for the bootloader 70 (parted) mkpart primary 1KB 10240KB 71 # Create a partition for the proofs 72 (parted) mkpart primary ext4 10241KB 10753KB 73 # Create a partition for the firmware 74 (parted) mkpart primary ext4 10754KB 100MB 75 76 # Check our work: 77 (parted) unit b 78 (parted) print 79 Model: Generic- Micro SD/M2 (scsi) 80 Disk /dev/sdc: 15931539456B 81 Sector size (logical/physical): 512B/512B 82 Partition Table: msdos 83 Disk Flags: 84 85 Number Start End Size Type File system Flags 86 1 512B 10240511B 10240000B primary lba 87 2 10240512B 10753023B 512512B primary ext4 lba 88 3 10753536B 100000255B 89246720B primary ext4 lba 89 90 ``` 91 92 Finally, create filesystems on the 2nd and 3rd partitions of our SDCard: 93 ```bash 94 $ sudo mkfs.ext4 /dev/my_sdcard2 -L proof 95 $ sudo mkfs.ext4 /dev/my_sdcard3 -L firmware 96 ``` 97 98 Next you'll build and install the bootloader on the card. 99 100 Compiling the bootloader 101 ------------------------ 102 103 Follow the instructions on the 104 [tamago-example](https://github.com/usbarmory/tamago-example#Compiling) 105 site to set up your tool-chain and environment variables. 106 107 To compile the bootloader itself, run the following command in the `bootloader` 108 directory: 109 110 ```bash 111 # Note that START_KERNEL corresponds to the offset of the firmware partition, 112 # and START_PROOF is the offset of the proof partition 113 make CROSS_COMPILE=arm-none-eabi- TARGET=usbarmory imx BOOT=uSD START_KERNEL=10753536 START_PROOF=10240512 LEN_KERNEL=89246720 114 ``` 115 116 If successful, this will create a few files - the one we're interested in is 117 `armory-boot.imx`, this is the "native format" bootloader code for the NXP SoC. 118 119 ##### Install bootloader 120 121 Finally, we'll write the bootloader we just built onto the SD card in the right 122 place: 123 124 ```bash 125 # Note that we're writing to the raw device here NOT the boot partition. 126 $ sudo dd if=armory-boot.imx of=/dev/myscard bs=512 seek=2 conv=fsync,notrunc 127 ``` 128 129 130 Firmware images 131 --------------- 132 133 Currently, the bootloader can only chain to either a Linux kernel, or a 134 bare-metal ELF unikernel (only tested with tamago-example thus far). 135 136 There are some invariants which must hold for this chain to work: 137 1. The `firmware` partition MUST be located at the precise offset mentioned 138 above. 139 2. The `firmware` partition MUST be formatted with ext4. 140 3. The `firmware` partition MUST contain a `/boot` directory with at least the 141 following contents: 142 * `armory-boot.conf` - a JSON file which tells the bootloader which files 143 to load 144 * Either: 145 * to boot a Linux Kernel: 146 * a valid ARM linux Kernel image 147 * a valid DTB file 148 * to boot ELF unikernel: 149 * a valid ARM bare-metal ELF binary/unikernel 150 151 Note that the `armory-boot.conf` file also contains SHA256 hashes of 152 all files referenced, and these MUST be correct. 153 154 To aid in the creation of valid firmware images, use the 155 `[cmd/usbarmory/image_builder/build.sh](/binary_transparency/firmware/cmd/usbarmory/image_builder/build.sh)` 156 script, e.g.: 157 158 ```bash 159 $ ./cmd/usbarmory/image_builder/build.sh -u ./testdata/firmware/usbarmory/example/tamago-example -o /tmp/armory.ext4 160 161 /tmp/armory.ext4: Writing to the journal is not supported. 162 Created image in /tmp/armory.ext4: 163 -rw-rw-r-- 1 al al 13M Nov 30 10:39 /tmp/armory.ext4 164 165 ``` 166 167 This image can be written to the target partition using the following commands: 168 169 ```bash 170 # first, log the image 171 $ go run ./cmd/publisher/ --logtostderr --binary_path /tmp/armory.ext4 --output_path /tmp/update.ota --device="armory" 172 173 # then flash the device firmware 174 $ sudo $(which go) ./cmd/flash_tool \ 175 --logtostderr \ 176 --device=armory \ 177 --update_file /tmp/update.ota \ 178 --armory_proof_mount_point /path/to/mounted/proof/partition 179 --armory_unikernel_dev /dev/mysdcard3 180 181 ``` 182 <details> 183 <summary>Alternative approach using regular shell commands</summary> 184 Alternatively, if you prefer to see what's going on, you can currently achieve a similar goal with the following 185 $ sudo dd if=/tmp/armory.ext of=/dev/my_sdcard3 bs=1M conf=fsync 186 187 # finally, copy over the proof bundle (assumes /dev/my_sdcard2 is mounted on /mnt/proof) 188 $ jq '.ProofBundle|@base64d|fromjson' /tmp/update.ota > /tmp/bundle.proof 189 $ sudo mv /tmp/bundle.proof /mnt/proof/bundle.json 190 ``` 191 </details> 192 193 ### Linux 194 195 > :frog: The [Armory Debian Base Image](https://github.com/usbarmory/usbarmory-debian-base_image/releases) 196 > is a good source for the kernel (zImage) and dtb files. 197 > 198 > You can decompress and mount the image to access the files like so: 199 > ```bash 200 > # decompress image 201 > $ xz -d usbarmory-mark-two-usd-debian_buster-base_image-20200714.raw.xz 202 > # mount image with loopback: 203 > # note the offset parameter below - the raw file is a complete disk image, this 204 > # offset is the first byte of the root partition (you can use fdisk or parted 205 > # on the raw file to view this yourself) 206 > $ sudo mount -o loop,ro,offet=5242880 /home/al/Downloads/usbarmory-mark-two-usd-debian_buster-base_image-20201020.raw /mnt 207 > # the files we're interested in are now visible in /mnt/boot: 208 > $ ls -l /mnt/boot 209 > total 8148 210 > -rw-r--r-- 1 root root 99319 Oct 20 17:13 config-5.4.72-0-usbarmory 211 > lrwxrwxrwx 1 root root 21 Oct 20 17:14 imx6ull-usbarmory.dtb -> imx6ulz-usbarmory.dtb 212 > -rw-r--r-- 1 root root 19938 Oct 20 17:14 imx6ulz-usbarmory-default-5.4.72-0.dtb 213 > lrwxrwxrwx 1 root root 38 Oct 20 17:14 imx6ulz-usbarmory.dtb -> imx6ulz-usbarmory-default-5.4.72-0.dtb 214 > -rw-r--r-- 1 root root 1488951 Oct 20 17:13 System.map-5.4.72-0-usbarmory 215 > lrwxrwxrwx 1 root root 25 Oct 20 17:14 zImage -> zImage-5.4.72-0-usbarmory 216 > -rwxr-xr-x 1 root root 6726952 Oct 20 17:13 zImage-5.4.72-0-usbarmory 217 > ``` 218 219 An example `armory-boot.conf` file configured to boot a Linux kernel is: 220 221 ```json 222 { 223 "kernel": [ 224 "/boot/zImage-5.4.51-0-usbarmory", 225 "aceb3514d5ba6ac591a7d5f2cad680e83a9f848d19763563da8024f003e927c7" 226 ], 227 "dtb": [ 228 "/boot/imx6ulz-usbarmory-default-5.4.51-0.dtb", 229 "60d4fe465ef60042293f5723bf4a001d8e75f26e517af2b55e6efaef9c0db1f6" 230 ], 231 "cmdline": "console=ttymxc1,115200 root=/dev/sdc3 rootwait rw" 232 } 233 ``` 234 235 TODO(al): Consider wrapping this up into a script. 236 237 ### ELF unikernel 238 239 > :frog: A good sample unikernel is the 240 > [tamago-example](https://github.com/usbarmory/tamago-example) 241 > application. 242 243 An example `armory-boot.conf` file configured to boot an ELF unikernel is: 244 245 ```json 246 { 247 "unikernel": [ 248 "/boot/tamago-example", 249 "aceb3514d5ba6ac591a7d5f2cad680e83a9f848d19763563da8024f003e927c7" 250 ] 251 } 252 ``` 253 254 255 Booting 256 ------- 257 258 If all is well, booting the USB Armory using the debug accessory will show 259 console output like so: 260 261 ``` 262 Terminal ready 263 �armory-boot: starting kernel image@80800000 params@87000000 264 Booting Linux on physical CPU 0x0 265 Linux version 5.4.72-0 (usbarmory@f-secure-foundry) (gcc version 7.5.0 (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04)) #1 PREEMPT Tue Oct 20 16:03:37 UTC 2020 266 CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c53c7d 267 CPU: div instructions available: patching division code 268 CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache 269 OF: fdt: Machine model: F-Secure USB armory Mk II 270 Memory policy: Data cache writeback 271 CPU: All CPU(s) started in SVC mode. 272 Built 1 zonelists, mobility grouping on. Total pages: 130048 273 Kernel command line: console=ttymxc1,115200 root=/dev/sda3 rootwait rw 274 Dentry cache hash table entries: 65536 (order: 6, 262144 bytes, linear) 275 ... 276 ``` 277 278 279 Firmware Measurement 280 -------------------- 281 282 The 'firmware measurement' hash for the USB Armory is defined to be the SHA256 283 hash of the raw bytes of the `ext4` **filesystem image** stored in the 284 'firmware' partition of the SD Card. 285 286 Note that this _may well_ be a different size than the partition itself.