The verifiable map in this firmware transparency demonstrates how annotations (also known as attestations) about a piece of firmware can be verifiably presented to clients. The naive way of doing this would be to simply give the client inclusion proofs to the annotations in the log. The problem with this approach is that there is no way to prove to the client that they have been presented all relevant annotations; logs do not support proofs of non-inclusion.
The map is constructed exclusively from the data in the log, which means that the state of a map at a given size depends only on:
- The number of entries it consumes from the log
- The map and reduce functions that are applied to convert the log entries into map entries
Map Checkpoints contain the Log Checkpoint they were constructed from, along with the number of entries the map consumed. The functions used in the map are deterministic, and public knowledge. These two facts mean that anybody with sufficient computing power to process the log can verify the map state by running the same map building calculation, and comparing root hashes.
The map in this demonstration creates two types of entry in the map:
- A log of all firmware for each device
- For each logged piece of firmware, the aggregation of all corresponding annotations
The first of these is a proof of concept and isn't currently read by clients (TODO(mhutchinson): remove this if needed for simplicity).
The second of these is used as an additional check when flashing firmware to check that no scanners have found malware in it, if the map_url
argument is provided to the flash tool.
TODO(mhutchinson): make the map and reduce functions super clear in the code and refer to them from here.
There are some pre-requisites to running this part of the demo:
- Have set up the environment and successfully run the Trillian batchmap demo
- Keep the Python Portable Beam Runner listening on port
8099
- Have deployed the FT demo above using Docker, and have some firmware in there
First add some good and bad firmware to the log, and then ensure the malware annotator has seen this and pushed its findings to the log.
The workflow script in the README in the firmware
directory does this, but if you're short on time the following is a minimum set of client calls:
# Put a good piece of firmware in the log
go run ./cmd/publisher/publish.go --logtostderr --v=2 --timestamp="2021-10-10T15:30:20.19Z" --binary_path=./testdata/firmware/dummy_device/example.wasm --output_path=/tmp/update.ota --device=dummy
# Put a bad piece of firmware in the log
go run ./cmd/publisher/publish.go --logtostderr --v=2 --timestamp="2020-10-10T23:00:00.00Z" --binary_path=./testdata/firmware/dummy_device/hacked.wasm --output_path=/tmp/bad_update.ota --device=dummy
# Run the monitor to annotate
go run ./cmd/ft_monitor/ --logtostderr --v=1 --keyword="H4x0r3d" --state_file=/tmp/ftmon.state --annotate
Now generate the map from the log, storing the resulting data in a sqlite DB at ~/ftmap.db:
go run ./cmd/ftmap --alsologtostderr --v=2 --runner=universal --endpoint=localhost:8099 --environment_type=LOOPBACK --map_db ~/ftmap.db --trillian_mysql="test:zaphod@tcp(127.0.0.1:3336)/test"
The map server can now be run to serve from this DB:
go run ./cmd/ftmapserver --map_db ~/ftmap.db --alsologtostderr --v=1 &
The map server will now be running at localhost:8001
. We can point the flash tool at this server to perform additional checks by passing --map_url=http://localhost:8001
when flashing to the device, e.g:
go run ./cmd/flash_tool/ --logtostderr --update_file=/tmp/update.ota --device_storage=/tmp/dummy_device --device=dummy --map_url=http://localhost:8001
After performing all of the other checks, this will verifiably read the aggregated findings for the candidate firmware from the map and check that no malware has been reported for it.