Building a Secure Bootloader for the Intel Quark Microcontrollers D2000 and SE C1000
Years after Intel released the low-power, Linux-compatible Quark X1000 processor, which runs on the Intel Galileo and numerous IoT gateways, the chipmaker last year launched three microcontroller-like Quarks that do not run Linux. Like the original Quarks, the Quark D1000 is limited to Pentium ISA compatibility and supports only bare metal implementations. The Quark D2000 and similar Quark SE C1000, which drives the Intel Curie module, also supply full Intel x86 ISA. They lack an x86 FPU but can still run RTOSes like Zephyr.
Considering the minimal MCU footprint, and lack of Linux-associated technologies like U-Boot, Intel had to develop a Quark D2000/SE bootloader from scratch. At the Embedded Linux Conference in February, Intel software engineer Daniele Alessandrelli detailed the inner workings of the Intel Quark Microcontroller Bootloader (QM-Bootloader). In his presentation, Alessandrelli also described security extensions added to version 1.4 of the BSD-licensed QM-Bootloader.
Designed for the D2000 and SE C1000, the QM-Bootloader offers typical bootstrap features such as system initialization, trim code computation, and restore context from sleep. It also provides Firmware Management (FM) functionality based on the DFU (Device Firmware Update) protocol and its most popular host tool, dfu-util.
Alessandrelli and his team needed to adapt dfu-util to work over UART as well as USB. This would provide a uniform firmware-upgrade experience whether developers were working with the USB 1.1-enabled SE or the standard D2000, which lacks USB support.
The D2000 and SE Quarks both feature 32MHz, x86-based Lakemont cores, but only the SE offers a 32MHz ARC sensor subsystem core. Further complicating the QM-Bootloader development process was the fact that the SE provides more memory: 80kB SRAM and 384kB flash. Both models, however, conveniently share an 8kB allotment of OTP (one-time programmable) SRAM.
“From the bootloader point of view the two Quarks are quite similar because we put our bootloader in OTP,” said Alessandrelli, who, together with Jesus Sanchez-Palencia, is the
maintainer of the project. “The 8kB limitation was a restraint, but we were still able to implement a modular approach so we could add new transports and potentially OTA updates in future.”
The foundation of the QM-Bootloader is the DFU protocol, which provides a way to transfer data to the device with DFU_DNLOAD for FM, as well as extract data with DFU_UPLOAD. Both are block-based mechanisms: All blocks except the last must have the same size.
“We decided to use DFU because it is open source, well documented, and designed for resource constrained devices,” said Alessandrelli. “Also, DFU doesn’t define any specific image format, and we wanted to do our own image format with its own metadata and authentication mechanism. We don’t have enough RAM or flash to store a full image, so we needed to develop our own block-wise transfer/flashing protocol to allow us to write an image a block at a time.”
To adapt DFU for UART, the Intel team created a Quark DFU Adaptation (QDA) protocol. “QDA makes DFU available over any message transport,” said Alessandrelli. “Because UART is stream oriented, we added the old XMODEM-CRC protocol layer to transport QDA packets. QDA provides all DFU request/response messages, such as DFU_UPLOAD, and also mimics some generic USB functionality, including active alternate settings. We needed a different host code for QDA/UART, so we modified dfu-util to replace the USB layer with QDA/UART.” The resulting qm-dfu-util code is available on GitHub, licensed under GPLv2.
On top of the QDA layer, the Intel team defined a Quark Format Upgrade (QFU) image format that works with generic DFU tools and supports firmware authentication. This “very simple block-wise format” adds a header to the first block of the binary, “so it’s processed before the image,” said Alessandrelli. The header is subdivided into a base header, which contains information like the target device and the vendor and product ID, as well as an extended header used for authentication.
“We do not add any specific memory address to the header, but instead assume the flash is divided into partitions, and that every image is targeting a partition,” said Alessandrelli. This setup enables the bootloader to support a single partition on the D2000, and two partitions on the ARC-enabled SE model. This also enables future schemes such as multiple partitions per core, which might come in handy for OTA.
Finally, the Quark Firmware Management (QFM) protocol runs on top of the DFU layers, thereby enabling functionality beyond firmware upgrade, such as key provisioning, application erase, and system/firmware information retrieval. QFM is basically a request (DFU_DNLOAD ) or response (upload) protocol.
QM-Bootloader 1.4 adds security features
Alessandrelli went on to describe new Secure Firmware Upgrade extensions that have been added to QM-Bootloader 1.4’s QFM layer to enable authenticated firmware upgrades. Due to the Quark’s limitations, he could not use a public key scheme. Instead, he chose a simple symmetric key scheme called HMAC256.
“With HMAC, the image is verified using the same key that is used to sign it, and the key must be located within the device,” said Alessandrelli. “We decided not to hard-code the key, but instead provided users with the key management functionality so at runtime they can provide the key.”
The QFU header is extended with an HMAC extended header. “We don’t compute the HMAC for the entire image, but we authenticate the header, adding an array of hashes, one for each block that composes the image,” said Alessandrelli. “We authenticate the header using HMAC, then start receiving blocks of images.We compute the SHA of every block and compare it with the SHA in the header.”
The security enhancements address the challenge of ensuring partition consistency -- how to handle failures that can leave partitions in an inconsistent state, for example, due to a reset during a firmware update. The new code associates a consistency flag to every partition and stores this metadata in a bootloader file called BL-Data.
The updated bootloader also adds key management. “We basically define and authenticate a key update request, an extension of QFM,” said Alessandrelli. “We use double-signing, providing both the firmware key, which is used to authenticate an image, as well as a revocation key.” Although this scheme will need to be modified if they add OTA support in the future, “since right now we’re only supporting wired and point to point USB or UART transfer, a man in the middle attack is defeatable,” he noted.
Alessandrelli also described security enhancements used to protect BL-DATA using CRC and further explained how partitions are related to targets. The enhancements are designed to support future upgrades to OTA and other additions, such as BLE modules with their own firmware.
Alessandrelli concluded with some lessons learned, such as the importance of reusing existing open source code and using a modular approach. “By not pre-optimizing for footprint, we can adapt to changing requirements,” he said. “By using link-time optimization, we could offset most of the overhead from the modular approach, giving us 15 to 20 percent savings in flash footprint saving.”
Watch the complete presentation below.
Connect with the Linux community at Open Source Summit North America on September 11-13. Linux.com readers can register now with the discount code, LINUXRD5, for 5% off the all-access attendee registration price. Register now to save over $300!