In “5 Elements to Secure Embedded Systems – Part #1 Hardware-Based Isolation”, we started our discussion about the five essential elements required to begin securing an embedded system. As you may recall, the five elements that every developer should be looking to implement are:
- Hardware-based isolation
- A Root-of-Trust (RoT)
- A secure boot solution
- A secure bootloader
- Secure storage
Last time, the main focus was that the system needs to have hardware-based isolation to create a secure processing environment (SPE) and a nonsecure processing environment (NSPE). In today’s post, we will continue the discussion by discussing the Root-of-Trust.
Element #2 – Root-of-Trust (RoT)
When we power on an embedded system and begin the boot process, we want to ensure that our embedded system boots with legitimate software. The problem that many systems face is determining if the first code that runs on the device is, in fact, their code and authentic. Of course, the system could be booting successfully, but what happens if some piece of malware is the first thing that runs, and the rest of the software is trusting that code? A Root-of-Trust ensures from the moment the reset vector is executed that we are running the right software.
A Root-of-Trust is an immutable process or identity used as the first entity in a trust chain. Therefore, no ancestor entity can provide a trustable attestation (in digest or otherwise) for the Root-of-Trust’s initial code and data state. To put this another way, a Root-of-Trust for an embedded developer is an unchangeable identity and minimal software set that can successfully authenticate itself and facilitate secure operations on the system.
There are several critical points in the definition above that we should consider. First, an immutable process or identity is something that cannot change. When selecting a microcontroller for our product, we must ensure that we can permanently “burn-in” significant information used by the Root-of-Trust such as a company private key. Once in the microcontroller, we do not want this information to be changeable.
Second, we want to be able to attest the system. Attestation allows us to send the system an operation to perform, which it will then use its private key to sign. With access to the public key, I can then verify the operation result and identity the device.
Why use a Root-of-Trust?
A Root-of-Trust establishes from system boot that authorized software is running on the system. It serves as the base trusted software that then authenticates and validates the next piece of software loaded, which establishes a chain of trust. The system can be easily attacked without a Root-of-Trust because there would be nothing to authenticate the loaded firmware.
Establishing a Root-of-Trust can be a bit tricky. A typical vulnerability, for example, can occur if the contract manufacturer establishes it. But, then, it would be entirely possible for them to bypass my keys and put their Root-of-Trust on the microcontroller, allowing them to do whatever they wanted to the system!
Chances are, this probably won’t happen, but we’ve all heard the horror stories about manufacturers making extra copies of a device illegitimately or building cloned devices. We want our Root-of-Trust to be able to protect against activities such as:
- Device cloning
- Loading unauthorized firmware
- Loading malware
Establishing a Root-of-Trust
To avoid these types of issues, we want to create a hardware-based Root-of-Trust. We want the Root-of-Trust first to be established by the microcontroller vendor that we are using if possible. Suppose the Root-of-Trust is set by the microcontroller vendor, the moment the microcontroller is shipped. In that case, it already has an immutable Root-of-Trust that can attest to its identity and that it came from that manufacturer! The Root-of-Trust helps us to avoid counterfeit microcontrollers too!
With the vendor-established Root-Of-Trust, we can use an existing Root-of-Trust to transfer our Root-of-Trust to the device. Furthermore, when we transfer the Root-of-Trust to our company, we can provision the microcontroller with security policies and keys that describe how the system should behave!
Establishing that Root-of-Trust is then critical because it will burn in the security settings such as:
- Debug port enabled or disabled
- Firmware updates allowed or not
- Encrypted firmware updates or unencrypted
- Firmware rollback enabled or disabled
The security settings will also establish the security contexts in which the various software components in the chain of trust are allowed to operate.
With these initial settings, developers can ensure that the first code they run on their system is secure, immutable, and able to verify all the software that loads afterward.
Establishing a Root-of-Trust is critical to an embedded system. The Root-of-Trust is used to validate all the additional pieces of software that load on the system and is the first foundational link in a Chain-of-Trust that successfully boots an embedded system. A Root-of-Trust should be hardware-based and immutable. The Root-of-Trust cannot be tampered with, which then allows the system to detect if software loaded later can be trusted or not. Developers should be looking for microcontroller solutions that have a hardware-based Root-of-Trust built into them.
If a microcontroller does not have a Root-Of-Trust built-in, it is possible to establish one using third-party components, trusted firmware for Cortex-M (TF-M), and so forth. It just requires more work on the part of the developer.
In the next part, we will discuss secure boot, what it is and what it means to developers.