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.