Firmware security
Please copy/paste "{{Translationlist | xx | origlang=en | translated={{{translated}}}}}" (where xx is ISO 639 language code for your translation) to Firmware security/translations | HowTo [ID# 277873] +/- |
Scope
This page describes the role of Open Firmware in Bitfrost security on XO.
Goals
- Run recovery firmware if primary firmware is bad
- No access to ok prompt without developer key
- Firmware update images must be signed
- Boot images must be signed
- Unactivated laptops will only boot the activation image
- Boot alternate OS image if primary OS image is bad
Files
The files listed below are on the internal storage. Further details on the zip files mentioned below are explained at Firmware zip file handling. Implementation notes and rationale are in italics.
- Primary images are in /boot, secondary images are in /boot-alt
- At the start of an upgrade process, boot is copied to boot-alt; this doesn't need to be automatic. When upgrade is complete and validated, the upgraded files will be moved automatically to /boot. The automatic substitution requires /boot to be a symlink to the 'real' boot directory. See Early boot for more details on the upgrade process.
- The activation lease is named "/security/lease.sig".
- The activation lease is in the firmware activation lease format with hashname "sha"
- The developer key is named "/security/develop.sig".
- The developer key is in the firmware developer key format with hashname "sha"
- Once the developer key has been read for the first time, it is copied by firmware into reserved space in the flash.
- The normal OS image is in "/boot/runos.zip" and "/boot/runrd.zip". An activation OS image is in "/boot/actos.zip", and "/boot/actrd.zip".
- The new firmware image is "/boot/bootfw.zip"
- The backup files in /boot-alt have the same names and are in the same formats as /boot.
On USB flash drive or SD card, the files are as follows:
- Only one directory, /boot, containing runos.zip, bootfw.zip, and an optional runrd.zip as before
- Security dictates that we boot from an authenticated filesystem. Rather than have OFW authenticate the full USB/SD contents, we'll boot from an authenticated ramdisk, which can then authenticate whatever other files it needs (if any) from the USB/SD drive. For this reason, there should always be a ramdisk, but it may be monolithic with the kernel in runos.zip rather than in a separate runrd.zip file.
- We should be careful to ensure that the files are authenticated after they have been loaded into memory, to prevent attacks involving switching files between authentication and later use.
Process
- If OFW fails to come up correctly, a firmware recovery procedure is attempted - (future enhancement).
- If the "O" gamepad key is held down during boot, OFW uses "/boot-alt" in the following steps, thus selecting the secondary copies of the OS and ramdisk images ; otherwise (the normal case), OFW uses "/boot", thus selecting the primary copies.
- OFW loops over the list of boot devices, performing the following steps for each such device. The boot device list is USB FLASH drive, external SD card, internal micro SD card or NAND FLASH (depending on which is present).
- If a filesystem is present on the device, processing continues; otherwise OFW proceeds to the next device
- OFW checks for a developer key in /security/develop.sig . If that file is present and contains a valid dev01: signature line for this machine, OFW exits from the secure boot process, returning to OFW's interactive boot process.
- OFW checks for a new firmware image in /boot{-alt}/bootfw.zip . If that file is present and contains a valid OFW image (in the archive's data.img component) that is more recent than the current firmware version, and the signature (in the archive's data.sig component) verifies, OFW reflashes itself and reboots.
- If the "rt" tag is present in manufacturing data, OFW checks for an RTC reset file in /security/rtcreset.zip . If one is present and the signature verifies, OFW rewrites the RTC Anti-rollback timestamp area to valid contents.
- OFW chooses whether to use actos/actrd or runos/runrd. If the "ak" tag is present in manufacturing data, OFW chooses runos/runrd. Otherwise, if the "rt" tag is present and an RTC rollback attack is detected, OFW chooses actos/actrd. Otherwise, if the file /security/lease.sig is present and contains an "act01:" line for this machine with a valid signature, OFW chooses runos/runrd. Otherwise, OFW chooses actos/actrd.
- OFW looks for the chosen OS file - either /boot{-alt}/actos.zip or /boot{-alt}/runos.zip . If that file is present and its signature (in the data.sig component) verifies, OFW disables further write access to the SPI FLASH using hardware mechanisms, then prepares the program image (the data.img component) for execution; otherwise OFW proceeds to the next device in the list.
- If the OS image format is one that requires a ramdisk, OFW looks for a ramdisk image file - either /boot{-alt}/actrd.zip or /boot{-alt}/runrd.zip . If that file is present and its signature (in the data.sig component) verifies, OFW loads the ramdisk image (the data.img component) into memory for use by the OS kernel; otherwise OFW proceeds to the next device in the list.
- Upon successful completion of the steps above, OFW executes the loaded program (the "os" image) in a manner appropriate for its format (i.e. Linux kernel files are executed directly, Forth source files are interpreted, etc.)
- If the process fails for all of the devices, OFW displays an error screen and halts.
During OS startup, the OS should check the firmware version and if it matches or is greater than the version in the new firmware image file on disk, the OS should delete or rename that file so the firmware won't see it the next time.
Usage notes
- After boot, userland can determine the source from the OFW device tree - /ofw/chosen/bootpath is the OFW device specifier of the kernel file, /ofw/chosen/ramdisk is the device specifier of the initrd file (if any), and /ofw/chosen/bootargs is the cmdline. This can be used to determine whether activation is needed (actos.zip) or whether booting is being performed from the secondary source (boot-alt/*).
- Although outside the scope of this spec, there are primary and secondary filesystem roots in /run/a and /run/b corresponding to the kernels in /boot and /boot-alt. /boot/runrd.img will typically be absent to speed boot. However, /boot-alt/runrd.img will typically be required in order to switch to /run/b so that kernel and userland match. When we clone /boot into /boot-alt at the beginning of an upgrade, we link in an appropriate /boot-alt/runrd.img (See Early Boot for more information.)
- When the alternate kernel is booted and we've switched into /run/b, we can either:
- add a /boot/runrd.zip link so that if we reboot into the primary we can switch the filesystem back /run/a, or
- Swap /boot and /boot-alt, making future boots start this kernel. This option is preferred. We should ensure that we've done another upgrade before we try to boot into a different kernel again.
- We will typically use hard or soft links to avoid storing multiple os and ramdisk images. The current status quo is that we have only one kernel and one ramdisk image; the ramdisk looks at how it was invoked to determine whether this is an upgrade, activation, or alternate boot.
Summary
Case | File | Expiry | Signed Object | Signature (ASCII) | Computation | Key | Effect on Success |
---|---|---|---|---|---|---|---|
OS/Ramdisk Images | /boot{,-alt}/ {run,act}{os,rd}.zip | - | data.img in .zip | data.sig in .zip | sha256->rsassa-pss-2048 | OLPC_OS_Key | Load image |
Firmware Images | /boot{,-alt}/bootfw.zip | - | data.img in .zip | data.sig in .zip (2 lines) | sha256->rsassa-pss-2048, rmd160->rsassa-pkcs-v1_5-2048 | OLPC_FW_Key | Update firmware |
Developer | /security/develop.sig | - | <SN>:<UU>:Time0 | keydata on sig line | sha256->rsassa-pss-2048 | OLPC_DEVELOP_Key | Unlock firmware |
Activation Lease | /security/lease.sig | time on sig line | <SN>:<UU>:<Expiry> | keydata on sig line | sha256->rsassa-pss-2048, check time | OLPC_LEASE_Key | Use runos not actos |
Rationale:
- .sig, not .key, because it contains signatures, not keys
- no need to reiterate the name for the .img file; it just complicates the code
- prefer RSASSA-PSS signatures (see PKCS #1) due to known attacks on RSASSA-PKCS [1], [2]
- ripemd160 protects against false-positive flaws in signature verification algorithm; algorithm choice is constrained by those supported by PKCS #11.
- "Time0" is in same 16-character format as a legitimate time, but it is ignored.
Notes
- I am assuming that the primary use of USB/SD boot is to do OS, firmware, or activity upgrades where bandwidth is a limitation. These can easily be done with the mechanism provided by just sticking a (properly signed) "magic upgrade key" into the USB port and power-cycling.
- USB probing is time-consuming and perilous (although SD is not). At some point (after manufacturing processes are fixed) we'll only try to boot from USB if the 'X' game key is pressed during boot.
- We could be more user-friendly by detecting "failed boot after linux kernel invocation" in some way, and automatically booting from the backup in this case. This seems like post-FRS work.
- Firmware RTC *must be UTC*. Quanta must set the RTC to UTC at the factory; antitheft server must sync to UTC during antitheft interaction.
Multiple-Key Support
This section describes an enhancement whereby additional keys can be provided in Open Firmware, so that a deployment can use its own keys, either in place of or in addition to OLPC's keys.
The deployment-specific keys are stored in the manufacturing data area of SPI FLASH, so they are unaffected by firmware updates.
The enhanced version is expected to be deployed in Open Firmware version Q2F03.
Deployment Key Manufacturing Data Tags
Reference: http://wiki.laptop.org/go/Manufacturing_data
(Need to add this info to the mfg data page)
Open Firmware has 5 different public keys:
- Developer key - permits full (unsecure) access to all firmware features
- Firmware key - permits reflashing the firmware stored in SPI FLASH
- Filesystem key - permits rewriting the filesystem on NAND FLASH
- OS key - permits the execution of a booted program (typically the OS)
- Activation lease key - permits OS execution in "already activated" mode
An OLPC "master" version of each of those public keys is stored within the Open Firmware image, so that it will be rewritten upon a firmware update.
Deployment-specific keys, if any, are stored in the manufacturing data with tag names as follows. As with all manufacturing data tags, each tag name is two case-sensitive ASCII characters.
- Developer key - tag names d0 .. d9 (d for developer)
- Firmware key - tag names w0 .. w9 (w for firmWare)
- Filesystem key - tag names s0 .. s9 (s for fileSystem)
- OS key - tag names o0 .. o9 (oh for OS)
- Activation lease key - tag name a0 .. a9 (a for activation)
- Antitheft server (aka OATS) keys - tag name t0 .. d9 (t for theft, see Theft deterrence protocol)
- 't' keys are (currently) not used by the firmware, however the OS as of v8.2.1 does read them from the manufacturing data
If a tag with numeric suffix 0 is present, the tag data overrides the corresponding OLPC key, so that the signed object will verify only if it is signed with a deployment-specific key, not if it is signed with the OLPC key.
Numeric suffixes between 1 and 9 inclusive, each such tag's data provides additional keys as alternatives to the OLPC key or the 0-suffix key.
The numbers 1..9 need not appear in sequence or in order; it's okay to have tags s7 and s3, for example. Apart from the special treatment of tag 0, there is no implied precedence of different tag numbers from 1 to 9, since a given signed object will either match one of the keys or it won't.
The keys for the various purposes are independent. You could, for example, have an o0 tag to override the OLPC OS key, s1 and s5 tags to augment the OLPC filesystem key, and no deployment-specific tags for the developer, firmware, and leas keys.
TBD - is there a need for multiple override keys? If so, we could adopt the policy that, if a key X0 exists, then the OLPC key is invalidated, but all the additional keys X1 .. X9 are valid.
The tag data contains the verbatim binary data for the public key. For the current version of the key format, that is 270 bytes. Since that is longer than 127 bytes, the "long data" tag format must be used (OFW's tag creation tools choose a suitable format automatically). The manufacturing data sector in SPI FLASH is 64K bytes, of which only a few hundred are already used, so there is plenty of room for the maximum possible number of deployment keys.
Making New Deployment Keys
The "bios-crypto" code at http://dev.laptop.org/git?p=bios-crypto has tools for making new key pairs and for signing objects with those keys.
To compile the kit, get the source, go into the "build" subdirectory, and type "make cli".
The file "build/README" tells how to use the various tools to make new keys and to sign objects.
Adding Deployment Keys to Manufacturing Data
To create a manufacturing data tag containing a deployment key, you can use the OFW "add-tag-from-file" command. For example:
ok add-tag-from-file s1 u:\myfskey.pub
add-tag-from-file will abort with an error message if that tag name already exists.
To delete a deployment key tag, you can use the delete-tag command, for example:
ok delete-tag s1
Be careful when changing tags to avoid accidental loss of important system information in other tags.
Procedures for Adding Deployment Keys En Masse
For large orders, Quanta are able to manufacture laptops with the special keys present in the firmware. Make sure this request (and the public keys) are communicated well in advance.
We must also consider the case when the XOs have already been manufactured without deployment keys, and a deployment wants to add the keys at a later time. The process for this is:
- The deployment shall generate the keypairs and send the public halves to OLPC
- The communication must clearly indicate which key is to go into which tag, e.g. "the key named firmware.public should go into tag w0"
- The communication must also indicate the SKU(s) which the keys need to be loaded onto
- OLPC may request more authentication (e.g. GPG signing and chain-of-trust) to ensure the integrity of the keys
- OLPC will review the request, and if accepted, will produce a special firmware to inject the public keys
- This special firmware will have a version number crafted so that the XO views it as an upgrade, which will cause a reflash and reboot.
- When booted on a machine with appropriate SKU, the special firmware will inject the keys into the manufacturing data, and then reflash with a "real" non-keyjector firmware, and reboot
- This firmware may also be time-limited, with a fixed expiry date
Inspecting Deployment Keys
From OFW, you can use the exiting ".mfg-data" command or "test-all" to view deployment keys. They are displayed as sequences of hex bytes.
From Linux, you can access the deployment keys as files in /ofw/mfg-data . Since the deployment key "files" contain binary data, a hex dump program like "od -x" is convenient for viewing.
Test Plan
- for device in sd usb nand
- for X in 's' 'o' 'w' 'd' 'l'
- scenario 1: No extra keys - Intent - the current status quo should still work
- object signed with the OLPC key - should succeed
- object signed with a different key - should fail
- corrupted object signed with the OLPC key - should fail
- scenario 2: Override key (X0) in mfg data - Intent - override key should work and block the OLPC key
- object signed with the OLPC key - should fail
- object signed with the override key - should succeed
- corrupted object signed with the override key - should fail
- scenario 3: Override key (X0) and augment key (X1 .. X9) in mfg data - Intent - extra keys should augment the override key
- object signed with the OLPC key - should fail
- object signed with the override key - should succeed
- object signed with the augment key - should succeed
- scenario 4: Multiple augment keys (X1 .. X9) in mfg data - Intent - augment keys should work in addition to OLPC key
- object signed with the OLPC key - should suceed
- object signed with the first augment key - should succeed
- object signed with the second augment key - should succeed
- object signed with a different key - should fail
- scenario 4a: Different n and m for augment keys Xn and Xm - Intent - it shouldn't matter which numbers from 1..9 are used for augment keys
- repeat scenario 4 tests with different names for augment keys
- scenario 4b: Nine different augment keys - Intent - maximum number of augment keys doesn't break anything
- repeat scenario 4 with nine augment keys
- scenario 1: No extra keys - Intent - the current status quo should still work
- for X in 's' 'o' 'w' 'd' 'l'
Test the ability to install and remove keys from mfg data - create several new keys, both augment and override. Delete and recreate in various orders. Check attempts to create keys that already exist, deleting the last key, etc. Verify that the mfg data looks correct after each operation.
Check the visibility of the keys from Linux (in /mfg-data).