The long-running joke in the tech circles says that “the S in IoT stands for Security”. This poor reputation stems from a lot of insecure devices having flooded the IoT market over the years. However, this attitude is steadily changing, with more and more companies taking security into account very seriously in their products. Security of computer and Internet of Things products is also getting more and more attention from government regulators.
Indeed, the LwM2M protocol itself that we widely support and promote here at AVSystem has been designed with robust security in mind from the very beginning, requiring the use of DTLS, supporting many modes of ensuring proper trust between endpoints, including EST for example, and also mentioning various additional security considerations in the specification text.
Additionally, each year we see more and more of our customers ask for hardware-based security support, which isolates the root of trust to make the devices less vulnerable to both remote attacks and physical tampering.
Recognizing that perceived lack of security in the IoT environment and the difficulty in designing a proper security architecture, Arm Ltd. has been designing the Platform Security Architecture (PSA) set of specifications since 2017, which are intended to provide a holistic framework for building IoT applications that are secure from the ground up.
The PSA umbrella consists of many different documents, many of which are conceptual in nature – for example, the PSA Security Model document describes how different components of PSA are intended to interact with each other. These conceptual documents are very important for PSA Certified, Arm’s security certification program centered around PSA.
However, we will focus on the APIs exposed to the embedded software developers that have been created as part of the PSA initiative. Three such APIs have been released to date:
Additionally, PSA Firmware Update API is currently in the beta phase of development.
These APIs are intended to be implemented as calls into a secure element or a secure partition within firmware on platforms that support the Trusted Execution Environment (TEE). However, in principle, they can also be implemented directly in untrusted software, for example, for testing purposes or to reuse code on a platform that does not support the required security features.
In the previous post, linked above, we mentioned PKCS#11 as one of the leading software APIs for interfacing with hardware security modules and secure elements. While this is certainly true, PKCS#11 is a rather old standard, originally published in 1994 and designed for use with cryptographic devices connected to personal computers and laptops. The design has proven forward-thinking and generic enough to more or less translate into the modern era of highly integrated IoT devices – however still, the API may feel overly generic and verbose for this context.
On the other hand, attempting to interface with the security hardware directly is complicated and error-prone. Mbed TLS, the TLS implementation most commonly used in embedded software, does not even provide a uniform API to interface with such security hardware.
PSA Cryptography API has stabilized in early 2020 and has been designed with constrained devices in mind from the beginning. It provides APIs for key management and some basic cryptographic operations – similar in scope to PKCS#11 – that can be used e.g., to implement the TLS protocol, storage encryption, local network logon, etc.
The most important concept in the PSA Cryptography API is a key. Each key is identified by a numeric ID, which may be treated as a concept similar to a file name. Half of the 32-bit key ID space can be freely used by the application, while the other half is reserved for allocation by the PSA implementation itself. Aside from the key material itself, each key is assigned a set of attributes, including:
The attributes cannot be modified once a key exists within the PSA contexts and can only be further restricted when copying keys – unless the “export” operation is allowed.
The reference low-level implementation of the PSA Cryptography API has been provided in Mbed TLS since version 2.22. The higher layers of Mbed TLS (those that actually implement the TLS protocol) can also utilize keys accessed through the PSA API. So a typical device architecture could look like this.
Trusted Firmware-M, a complete set of services running in the secure partition on Cortex-M microcontrollers, is the reference implementation of the entire PSA stack (Cryptography, Attestation, Storage, and Firmware Update) and provides some additional related functionality such as secure boot.
This project is independent of the operating system running in the insecure partition, and integrations are available for CMSIS, FreeRTOS, Mbed OS, and Zephyr.
The latest version of Anjay includes a PSA driver in its hardware security subsystem, alongside the previously introduced PKCS#11 driver. It includes full support for elliptic curve keys generation and use for (D)TLS connectivity. Certificates can also be stored either as “raw data” keys via the PSA Cryptography API or as assets via the PSA Protected Storage API.
The PSA driver is enabled at compile time, by enabling the appropriate definitions in avs_commons_config.h
, or by setting the corresponding CMake options:
cmake -DWITH_AVS_CRYPTO_ENGINE=ON \
-DWITH_MBEDTLS_PKCS11_ENGINE=OFF \
-DWITH_MBEDTLS_PSA_ENGINE=ON .
When Anjay is configured in this way, the same functions as previously introduced for PKCS#11 can be used for PSA, just with a different query string format. For example, to use keys already present in the secure storage:
anjay_security_instance_t security_instance = {
.ssid = 1,
.server_uri = "coaps://try-anjay.avsystem.com:5684",
.security_mode = ANJAY_SECURITY_CERTIFICATE,
.public_cert = avs_crypto_certificate_chain_info_from_engine(
"kid=0x80000002"),
.private_key = avs_crypto_private_key_info_from_engine(
"kid=0x80000001"),
};
Similarly, the following code can be used to configure EST with secure key storage – in this case, the lifetime attributes can also be controlled (the default persistent storage lifetime is used if not specified):
const anjay_configuration_t CONFIG = {
/* ... usual Anjay configuration ... */
.est_engine_key_address = "kid=1,lifetime=0x401",
.est_engine_cert_address = "kid=2"
};
This code has been tested to work with the reference PSA API implementation in Mbed TLS (non-isolated, running on a PC) as well as the actual Trusted Firmware-M integration on top of Zephyr.
If you’re interested, please visit the Anjay product page, contact us and ask for an evaluation of the commercial version of Anjay.