In an earlier blog I discussed the security challenges for embedded memory and stressed that making products, such as IoT-enabled devices, more secure should be taking a much higher priority than it currently is. And in another blog, I outlined how embedded memory might be attacked and offered some simple solutions. Now, it’s time to discuss how to secure embedded memory.
Applications that use a lot of memory (particularly NVM) are attractive targets for hackers, because that’s where the data they’re after (and/or the functionality they hope to compromise) resides.
The first thing to do to secure embedded memory is to have enforced hardware partitioning. Many microcontrollers split their internal memory into secure and non-secure regions, where only the former should be used for executable code. For example, many ARM-based microcontrollers are available with internal memory protection units (MPUs), one for each memory region.
However, many systems require additional memory; often to support ease of expansion at a later date and/or to have the same micro at the heart of a family of products; i.e. you can stick with your preferred micro.
An MPU can control which areas of memory can be accessed (and with which privileges – e.g. read only or read-write) during the different modes of system operation.
For example, in an earlier blog I explained how memory buffer overflow attacks work; essentially data expected as in input during normal operation that overspills into space occupied executable code.
Strict hardware partitioning would prevent anything being written to memory space intended for executable code during normal system operation. This practice is often referred to as executable space protection (ESP).
But what about at other times? For example, many embedded systems are vulnerable during bootload.
Memory’s role in secure bootloading
Most bootloaders – certainly in simple, low-cost embedded systems – are basic and perform checksums to verify the software/firmware image is whole. However, a bootloader has the ability to establish a chain-of-trust, which is essential for connected embedded systems such as IoT devices and those that accommodate upgrades in the field through physical access.
As most readers will know, the bootloading process is roughly as follows. For new firmware, a checksum (a.k.a. hash) is generated and then encrypted using a private key to create a signature. The firmware, which is sometimes also encrypted, and the signature are then bootloaded into the system in the field. The system then uses a public key to decrypt the checksum and, if necessary, the firmware. Authenticated and intact (as verified by the checksum) software/firmware can then be loaded.
However, to facilitate secure bootloads, the microcontroller of the system in the field will need to support a number of things. These include a cryptographic engine, secure storage for keys and, of course, memory protection.
The OS and Software Language
Whilst the focus of the blog is on physical memory, we do need to touch on the subjects of operating systems and the language in which the embedded system is programmed.
A secure operating system (a.k.a. a trusted operating system, OS) is one that has been tested against the internationally recognised Common Criteria (CC) security evaluation standard and been given an evaluation assurance level (EAL) ranking. There are seven CC EAL levels, which can be applied to not just OSs but also IT products and embedded systems. You can read up on CC EAL in our How to Secure Embedded Systems guide
The things that make an OS trustworthy include memory protection, file protection, user authentication and I/O device access control.
As for programming languages, and as alluded to in an earlier blog, low level languages (like C) are unconstrained; and the reason memory buffer flows can happen, by accident or intentionally. You are better off using a higher-level language. For example, Java automatically checks array bounds so memory buffer overflows are generally not possible.
The Heart of the System
As mentioned, memory protection is something a good microcontroller should provide. However, on the basis that authentication is crucial to warding off cyberattacks you may wish to consider running additional protection alongside your microcontroller (or microprocessor).
For example, Microchip Technology has a family of small, low-power CryptoAuthentication devices that can work alongside any microcontroller/microprocessor. Device features include a unique and non-changeable 72-bit serial number (set by Microchip), a 512bit one-time programmable (OTP) zone, a random number generator and a SHA-256 hash algorithm for data encryption. They also include APIs for storing, retrieving and manipulating X.509 certificates for Transport Layer Security (TLS) integration.
This technology is great because it has a role to play in establishing the aforementioned chain-of-trust.