-
Notifications
You must be signed in to change notification settings - Fork 10
Firmware Transparency
Armory Drive provides a pocket encrypted drive solution based on the USB armory Mk II. It allows one-tap unlock of a microSD backed encrypted USB drive through its companion F-Secure Armory Drive iOS app.
Binary releases are available
for the Armory Drive firmware, all
releases include the armory-drive-install
tool which provides interactive upgrade of all installation modes.
The installer and firmware work together through a combination of Secure Boot and Firmware Transparency frameworks to authenticate firmware updates.
Secure boot allows firmware authentication with burned in read-only public keys, as well as confidential configuration storage with device specific hardware keys.
Firmware Transparency enables the installer and the device to authenticate all updates through tamper-evident logs powered by Google transparency framework.
The following table summarizes the firmware authentication options supported by the installer.
Secure Boot | Firmware Transparency |
---|---|
disabled | Yes |
with OEM keys | Yes |
with user own keys | No |
All published Armory Drive firmware releases are signed with the Armory Drive firmware private key, each release is also appended to a publicly verifiable log.
The authenticity of each release is verified with the corresponding Armory Drive firmware public key.
In case a malicious actor gains access to the Armory Drive firmware private key, a compromised release of Armory Drive firmware could be published, or delivered by other means, to users.
Such a malicious release could be installed by the user without any warning: all the signature verifications performed during installation or upgrade will succeed.
To counteract such potential attacks the Armory Drive firmware and the Armory Drive installer implement Firmware Transparency, in a similar manner to Certificate Transparency.
The publicly verifiable log allows users to verify that the firmware image they are retrieving is identical to the version all other users see.
The verification is performed by the Armory Drive installer upon downloaded of the firmware and also by the firmware running on-device during the upgrade procedure.
This means that no firmware releases can be "silently" published, as a release is not valid unless it has been added to the log.
The installer is not subject to this verification, however it is published with GitHub verified releases and its source code is available and reproducible (just like the Armory Drive firmware) from the armory-drive repository.
By following the release notes users can precisely reproduce the Armory Drive firmware binary from source code. This leverages Go's native support for reproducible builds, enabling users to verify that the published signed firmware binary firmware matches the published source code.
A JSON release manifest exists for every published Armory Drive firmware. This manifest contains information about the release, including the firmware's SHA256 checksum:
{
"description": "armory-drive v2021.09.22",
"platform_id": "UA-MKII-ULZ",
"revision": "v2021.09.22",
"artifact_sha256": {
"armory-drive.csf": "/f636l9GHbwub5gKdaWKP7/DA6/vPoa1JXDfGxfb6vk=",
"armory-drive.imx": "MVorRrFrzXT89Gu+FE4/aeX12QiGPcRoHiLuR6Kq+6g=",
"armory-drive.sdp": "+G9bzK+phhIXb5786VW79poRvLg4T7EnoggDV0E0tL8="
},
"source_url": "https://github.com/usbarmory/armory-drive/tarball/v2021.09.22",
"source_sha256": "X6rkBnT+Ht3kBcJXJ7YK4RvIXEZ16VnkT5xy6iNVvBc=",
"tool_chain": "tamago version go1.17.1 linux/amd64",
"build_args": {
"REV": "efeb733"
}
}
The manifest is signed with the Armory Drive Firmware private key. The signature, in Go sumdb signed note format, is appended to the release manifest:
— armory-drive WpWkG+RY85Ha0j+iWxLeWI+GV8eRBnxOttH7wb3Pu4g5v2E2zCHnop0+UkR77l3YH1O8+tVwdLiTvVDTasagTsUBhwM=
These signed release manifests are generated with the create_release tool.
The transparency log is based on a Merkle tree data structure as depicted in the following figure:
The log's root hash, along with the origin name
string (e.g. Armory Drive Prod 2
)
and tree size
(e.g. 1
), are written to a checkpoint
which is signed by the
Armory Drive Log private key (the corresponding public key is published
here).
Again, the signature is in Go sumdb signed note format:
Armory Drive Prod 2
1
KvoY5jZIlLScjQlPBPGjM1U4I4uI6N57z5tD63CpFgo=
— armory-drive-log FlQbj1P9yxoOrsdhBUWS5SF2R/YiAgz6+lhj7VC1jfH5pJ0xLivnrRJmyAdumQGRg9gh/8VzUiXNkgfCuCeE+L5SKAU=
The creation and signing of this checkpoint is performed by a GitHub action triggered by the push_to_master workflow.
The Armory Drive Log private key is kept on GitHub servers so that it can be provided to the action in the form of a GitHub secret. While the Armory Drive log key is shared with GitHub the Armory Drive firmware key is tighly controlled and known only by USB armory maintainers.
When a new firmware release needs to be published its signed release manifest is appended to the Armory Drive log and a new checkpoint is generated:
To ensure the firmware is valid, clients must verify that it is present in the transparency log. The inclusion verification is performed by both the Armory Drive installer and the Armory Drive firmware itself.
The installer can check the presence of the relevant hash directly against the published log.
The firmware, not having network access, is unable verify the inclusion
directly with the log but instead does so via a proof bundle passed from
the installer.
This proof bundle contains a new checkpoint covering the new firware release, the
firmware manifest, and all the leaf hashes from the log (i.e. HASH_1
, HASH_2
, … , etc.)
Note that these fields are all base64 encoded:
{
"NewCheckpoint": "QXJtb3J5IERyaXZlIFByb2QgMgoxCkt2b1k1alpJbExTY2pRbFBCUEdqTTFVNEk0dUk2TjU3ejV0RDYzQ3BGZ289CgrigJQgYXJtb3J5LWRyaXZlLWxvZyBGbFFiajFQOXl4b09yc2RoQlVXUzVTRjJSL1lpQWd6NitsaGo3VkMxamZINXBKMHhMaXZuclJKbXlBZHVtUUdSZzlnaC84VnpVaVhOa2dmQ3VDZUUrTDVTS0FVPQo=",
"FirmwareRelease": "ewogICJkZXNjcmlwdGlvbiI6ICJhcm1vcnktZHJpdmUgdjIwMjEuMDkuMjIiLAogICJwbGF0Zm9ybV9pZCI6ICJVQS1NS0lJLVVMWiIsCiAgInJldmlzaW9uIjogInYyMDIxLjA5LjIyIiwKICAiYXJ0aWZhY3Rfc2hhMjU2IjogewogICAgImFybW9yeS1kcml2ZS5jc2YiOiAiL2Y2MzZsOUdIYnd1YjVnS2RhV0tQNy9EQTYvdlBvYTFKWERmR3hmYjZ2az0iLAogICAgImFybW9yeS1kcml2ZS5pbXgiOiAiTVZvclJyRnJ6WFQ4OUd1K0ZFNC9hZVgxMlFpR1BjUm9IaUx1UjZLcSs2Zz0iLAogICAgImFybW9yeS1kcml2ZS5zZHAiOiAiK0c5YnpLK3BoaElYYjU3ODZWVzc5cG9SdkxnNFQ3RW5vZ2dEVjBFMHRMOD0iCiAgfSwKICAic291cmNlX3VybCI6ICJodHRwczovL2dpdGh1Yi5jb20vZi1zZWN1cmUtZm91bmRyeS9hcm1vcnktZHJpdmUvdGFyYmFsbC92MjAyMS4wOS4yMiIsCiAgInNvdXJjZV9zaGEyNTYiOiAiWDZya0JuVCtIdDNrQmNKWEo3WUs0UnZJWEVaMTZWbmtUNXh5NmlOVnZCYz0iLAogICJ0b29sX2NoYWluIjogInRhbWFnbyB2ZXJzaW9uIGdvMS4xNy4xIGxpbnV4L2FtZDY0IiwKICAiYnVpbGRfYXJncyI6IHsKICAgICJSRVYiOiAiZWZlYjczMyIKICB9Cn0KCuKAlCBhcm1vcnktZHJpdmUgV3BXa0crUlk4NUhhMGoraVd4TGVXSStHVjhlUkJueE90dEg3d2IzUHU0ZzV2MkUyekNIbm9wMCtVa1I3N2wzWUgxTzgrdFZ3ZExpVHZWRFRhc2FnVHNVQmh3TT0K",
"LeafHashes": [
"KvoY5jZIlLScjQlPBPGjM1U4I4uI6N57z5tD63CpFgo="
]
}
The presence of the leaf hashes allows the firmware to prove to itself that the checkpoint provided when the currently-running firmware was installed is consistent with (i.e. an ancestor of) the new one, ensuring that the tree history has not been compromised.