In “5 Elements to a Secure Embedded System – Part 2 Root-of-Trust,” we continued 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
- A secure boot solution
- A secure bootloader
- Secure storage
The main focus last time was that the system needs to have a Root-of-Trust (RoT) which forms the foundation for a chain-of-trust as the system boots and executes its application code. In today’s post, we will continue the discussion with secure boot.
Secure boot is much more than just simply adding a piece of software to the system. Secure boot requires a developer to carefully think through the boot sequence and develop a Chain-of-Trust that originates at the Root-of-Trust. (Image source: Beningo.com)
Element #3 – Secure Boot
Secure Boot is the process of validating code and images against hardware before they are used. The idea is that the system should not trust any code or image until it has been validated as being authentic and that its integrity is confirmed. The system, as mentioned, should use a hardware-based Root-of-Trust to validate the code. Many systems that I’ve encountered in my career simply assume that the code in their flash memory is correct and start executing it the moment the processor boots with few, if any checks. If a developer wants to secure their system, this is one practice that can longer be followed. The system needs to securely boot and validate all the code that it will be loading and executing.
Secure boot is probably the first element that we have been discussing that utilizes both hardware-based isolation and RoT. In the first phase, ROM code which establishes the RoT is used to calculate a hash over the contents of the boot code and verifies its contents. The calculated hash is usually compared with a hash that is immutable and has been “burned” into the flash during manufacturing. The initial secure boot phase will have configuration information built-in that then allow the boot sequence to validate subsequent boot phases. For example, this phase may then go through and calculate a hash over the bootloader and compare that hash to yet another one stored in flash that helps to establish trust in that phase. The bootloader can then be validated and executed which will then go through and validate its application image before running the application.
Now, secure boot as you can see happens in stages, but secure boot also often happens in isolated memory regions. A secure system will often first boot into an area of memory that is considered to be a secure execution environment. There are several different ways to do this. One way is to use a multicore microcontroller where one core is dedicated to security features and code execution and the other is allocated to application rich code. In this setup, interprocessor communication is used to communicate between the cores.
Alternatively, developers can use a single core technology that separates memory and the execution environment into secure and non-secure environments. An example is Arm TrustZone. With TrustZone, developers are able to specify which memory regions should be allocated to secure processing and which are not. These regions not only include code but also which peripherals, flash and RAM memory. The application will run its execution rich code and when it needs to make a call to a secure function, the processor transitions to a secure mode that is isolated and allows the secure functionality to be carried out. This helps to ensure that secure information such as private keys, data and so forth is inaccessible should a hacker gain access to the feature rich execution environment.
When using secure boot in an isolated environment, the secure processing region is often the first to start executing. In other words, secure boot operations are executed from the secure execution environment, which makes sense. Once the secure environment is up and running, yet another hash is calculated over the application rich code to ensure its integrity and authenticity. After it has passed this check, the secure execution environment will then allow that code to run.
At each point in the boot sequence, secure boot must authenticate the next code or image that is going to execute and verify its integrity. Starting from the RoT and then working its way through the bootloader and to the execution image. In a multicore system, there may even be multiple images that need to be verified across multiple processors.
Secure boot is much more than just simply adding a piece of software to the system. Secure boot requires a developer to carefully think through the boot sequence and develop a Chain-of-Trust that originates at the Root-of-Trust. As the system boots, each image and code are verified and only afterwards is it allowed to execute on the system. If a problem is detected, the system can either halt the boot sequence or maybe even revert to an earlier known working version of code. In order to revert the code, or update it to a new version, that requires the system to have a secure bootloader.
In the next part, we will discuss secure bootloaders, what it is and what it means to developers.
Jacob Beningo is an embedded software consultant who currently works with clients in more than a dozen countries to dramatically transform their businesses by improving product quality, cost and time to market. He has published more than 200 articles on embedded software development techniques, is a sought-after speaker and technical trainer, and holds three degrees which include a Masters of Engineering from the University of Michigan. Feel free to contact him at firstname.lastname@example.org, at his website, and sign-up for his monthly Embedded Bytes Newsletter.