Securing a microcontroller-based application for the IoT can be tricky. Security starts at the hardware level and then scales into the embedded software. To successfully secure the software, developers require that the underlying hardware support critical features such as:
- Secure boot
- Memory protection
- Cryptographic engine accelerators
- True random number generator (TRG)
- Secure pin multiplexing
- Software isolation
While some of these features are supported in the Arm® Cortex®-M processors such as the M0+, M3/4/7 series, it can be difficult and time consuming to create a successful solution.
A new solution that developers can leverage at the hardware level is to use the new Cortex-M23/33 series of microcontrollers which are based on the Armv8-M architecture. These processors are designed with security in mind and contain many security features like those listed earlier, including Arm TrustZone® for microcontrollers. In this article we will become more familiar with the Armv8-M architecture and explore how we can improve embedded security using TrustZone.
Introduction to the Armv8-M architecture
The first thing to realize about the Armv8-M architecture is that it is the latest microcontroller architecture from Arm that targets low cost, deeply embedded real-time embedded systems. There are three new processor types that are joining the family. The M23, which is a low-power variant, the M33, which is a high-performance variant, and the recently announced M35P which is a high-performance, physical security (think tamper-resistance) processor (Figure 1).
Figure 1: From a performance standpoint, the new Cortex-M23/33 processors fit into the family as improved Cortex-M0+ and Cortex-M4 processors. (Image source: Arm)
While the Armv8-M architecture does improve performance from previous architecture generations, several critical improvements to note include:
- Instruction set enhancements
- Flexible breakpoint configuration
- Dynamic reprioritization of interrupts
- Enhanced trace support
- Simpler Memory Protection Unit (MPU) setup
The biggest and most interesting improvement to the architecture is the ability to use Arm TrustZone. TrustZone is a security extension to the architecture that allows a developer to physically isolate executing code and memory regions such as RAM, code space, and peripherals in hardware. TrustZone allows the software to be broken up into secure and unsecure regions which then execute in either a secure or non-secure processor state. The secure state allows full access to the processor’s memory and peripherals, while the non-secure state can only access non-secure regions and secure functions that are purposely exposed to the non-secure code (Figure 2).
Figure 2: TrustZone uses hardware isolation to separate the processor and application into non-secure and secure states. Code executing in the non-secure state cannot access or manipulate secure memory or code. Secure memory and code can only be accessed while running in a secure state. (Image source: Arm)
Developers can choose which flash and RAM locations belong to the secure state and which belong to the non-secure state. When non-secure code calls a secure function, the switch between non-secure and secure states is handled completely in hardware in a deterministic manner that has a worst-case switch time overhead of three clock cycles. There are several registers within the CPU that are shared between the secure and non-secure states, but each state also has their own stack pointer, fault, and control registers. The M33 even has a stack limit register that can be used to detect a stack overflow.
It’s important to note that TrustZone is a processor extension, which means that it is up to the processor manufacturer as to whether they will include TrustZone support or not on the part. Since TrustZone is optional, let’s examine a few Armv8-M processors that are currently available and how they handle TrustZone.
Selecting an Armv8-M processor with TrustZone support
There are currently several processors that are available that support the Armv8-M processor. What’s interesting is that these parts are so new, that as of late summer 2018, the only manufacturer that has parts in production is Microchip Technology.
There have been announcements from other processor manufacturers such as Nuvoton that parts are coming. We can expect over the next 12 months to see a dramatic increase in the number of Armv8-M parts, including those that support TrustZone.
Microchip has produced two main versions of the Armv8-M architecture in their SAML10 and SAML11 family of parts. The SAML10 version does NOT include TrustZone, while the SAML11 parts do. Figure 3 shows all the variants for the SAML10 and SAML11 parts that are currently in production and available. The main differences between the variants is the availability of RAM, flash, pins and peripherals, which is what we expect when selecting a microcontroller.
Figure 3: The Microchip SAML10 and SAML11 microcontroller variants. Only the SAML11 parts include Arm TrustZone. (Image source: Microchip Technology)
For developers that are looking to get started with Armv8-M, there are two development kits to choose from. The Microchip SAML10 Xplained evaluation board includes the SAM L10E14A microcontroller which includes 16 Kbytes of flash, 2 Kbytes of data flash memory, 4 Kbytes SRAM, and comes in a 32-pin package. The Microchip SAML11 Xplained Evaluation Board includes the SAM L11E16A microcontroller which includes 64 Kbytes of flash, 2 Kbytes of data flash memory, 16 Kbytes SRAM and also comes in a 32-pin package. The development boards are identical minus the fact that the processors are different. The Xplained board can be seen in Figure 4.
Figure 4: The Microchip SAML10/L11 development board is based on the Armv8 architecture. The SAML11 version supports TrustZone (Image source: Keil)
How TrustZone applications work
Developers working with TrustZone will discover that the way in which an embedded application is developed is going to dramatically change. First, developers need to separate out their applications spaces to determine what code and libraries belong in the secure state and which belong in the non-secure state.
Once this is determined, a developer creates two different software applications; one for the secure code and one for the non-secure code. This can be done very easily using a compiler/IDE like Keil MDK. What a developer essentially ends up with is a multi-project workspace where one project is the secure code and the other is the non-secure code (Figure 5).
Figure 5: When using TrustZone, developers end up with a multi-project workspace where one project is specifically for the secure code and the other is for the user code. (Image source: Keil)
When a TrustZone application starts, the code begins executing in the secure state. This allows a developer to immediately establish a root of trust from which the rest of the application can execute. Once the system boots, the application will switch from the secure state to the non-secure and execute what is known as the user code. At this point, the application executes just like any other embedded application. The main difference is that the non-secure code can only access secure functions and callbacks through a secure gateway (Figure 6).
Figure 6: A TrustZone application starts execution from the secure state and enters the non-secure state once the root of trust has been established. The non-secure state can only make function calls to exposed functions within the secure code, otherwise an exception is thrown. (Image source: Keil)
If the user application attempts to access secure code, memory or peripherals without going through the secure gateway, an exception will be generated. Undoubtedly this means that either there is a bug in the software, or in a production environment, a hacker is attempting to access the system. At this point, the code can then decide how it should thwart the attack, such as restarting the system to remove any injected code that may be running in the non-secure SRAM.
Tips and tricks for securing an embedded application with TrustZone
There are many techniques that can help improve embedded security. Below are several tips and tricks that will help developers interested in using the Armv8-M architecture with TrustZone:
- Use the secure zone during reset to establish a root of trust and a trusted execution environment.
- Put security critical tasks, libraries, and keys into the secure zone.
- Let the user code be placed in the non-secure zone.
- To keep things simple, put the RTOS kernel in one place, either the secure or the non-secure zone.
- Use the MPU in the secure and non-secure zones to improve process isolation.
- Minimizing the code in the secure zone can help to minimize the secure codes attack surface.
- Make sure that secure code clears any secret information from unbanked registers before initiating a transition from the secure to non-secure state.
Securing a microcontroller-based application for the IoT is important but tricky. Security starts at the hardware level, but many traditional microcontroller families running Cortex-M0+, Cortex-M3/4/7 cores may lack the features necessary to successfully secure the device. Developers can now leverage the new Armv8-M architecture on the Cortex-M23 and Cortex-M33 cores to secure their embedded applications using a rising number