![]() |
Deeptrust for PCI security architecture
SPEC98T17 rev E
Specification of Deeptrust, the Security Architecture for Cortex-M.
|
Reference
SPEC98T17
This document describes the Deeptrust architecture and API.
Deeptrust is a security architecture designed by Maxim Integrated. This architecture allows software isolation and privilege limitation of software running on a System-on-Chip (SoC) (aka microcontroller) with an ARM® Cortex®-M3/4 core. This security design prevents applications hosted on the same platform from accessing sensitive data, peripherals, executable code.
Deeptrust has been designed to pass the Payment Card Industries – Pin Transaction Security 5.0 certification. This architecture aims to be approved as conforming to those requirements, so the customer will only need to build a conforming terminal (which must be evaluated) and have their changes to Deeptrust approved. The coverage of the requirements is exposed in the section Security Guidelines.
Software running in the platform is split into secure containers in order to:
The Deeptrust offering contains the following:
Deeptrust relies on the following elements of architecture:
Note to the reader: the security architecture presented here is composed of elements closely tight together and heavily depending on each other. Therefore it is advised to read this twice.
Let's introduce some essential concepts now for the sake of understanding this document. These concepts will be further explained later though.
The architecture of Cortex-M3/4 cores provides the following security mechanisms:
Software isolation is achieved by a lightweight security hypervisor (also simply called hypervisor below) that leverages the Cortex-M security mechanisms.
The lightweight security hypervisor in use is ARM® mbed uVisor (see [DOC1]). Software isolation means that the various software components run inside secure containers (aka "boxes") isolated from each other, and also from the hypervisor itself.
In this security architecture, the hypervisor is the only code running in Handler privileged mode of execution, and hence is fully and exclusively controlling the MPU.
In this architecture, we distinguish the Core firmware from the Secure boxes.
Core firmware: the core firmware contains the trusted executable code and is signed using the firmware signing key of the secure boot ROM aka CRK (see ), i.e.:
The core firmware integrity and authenticity is verified and executed by the secure boot ROM (see Hypervisor initialization). This component is part of the PCI firmware perimeter.
Secure boxes are software containers enforced by the hypervisor. Thanks to the hypervisor, each box has:
This way, even if all are running with unprivileged permissions, different boxes can protect their own secrets and execute critical code securely.
Note that the hypervisor allows the existence of a "Public box". In this design, the public box is part of the "Core firmware" and is actually not executing code. It is not at the same level as Secure Boxes described below.
There are three levels of secure box privilege levels:
(*) the hypervisor still has protected memory that is not visible from Thread/user mode, hence from no box whatever the box privileges are.
The box privilege is granted at box loading time based on the signing key of the box. If the signing key was K_fw and the signature verification of the box is successful, the the "Box firmware" privilege is granted.
This box privilege level defines two kinds of privileges:
The box privilege policy can be customized:
For secure boxes, unprivileged access to selected hardware peripherals and memories must be explicitly granted through Access Control Lists (ACLs). ACLs are managed by the hypervisor. ACLs are defined at boot time and cannot be modified at runtime. When running out of a secure box, access to memories and peripherals is the most restrictive: access that are not explicitly granted are denied by default.
Software running in a box can access only the memory ranges it has been allowed to (through the Access Control Lists, ACLs), with the access type enforced (RWX, RO, etc...) for each range. The definition of the privileges of a box is done at compilation and remains static, i.e. cannot be modified at runtime.
In addition, the secure box binary code, constant data and variable initialiation values and its ACL are signed as a whole (single binary image) using a private signing key. As the whole image signature is verified upon boot, the box privileges and ACLs are protected against modification. The application's box privileges are read by the hypervisor during the early initialization of the SoC (see Hypervisor initialization) and stored into the hypervisor protected memory so they cannot be modified from the application's box.
Let's explain how the hypervisor implements the isolation of secure boxes. The hypervisor is the only software running in Handler privileged mode. All other software runs in Thread User mode (see Cortex-M mechanisms: MPU, privileges, NVIC), even the core firmware's unprivileged code.
The hypervisor is therefore the only software component allowed to control the MPU (initial configuration, reconfiguration during context switches, secure interrupt handling) and catch the exceptions and interrupts. This is verified as:
The only way to jump back to Handler privileged mode is through exceptions (interrupts and exception, SVC instruction). As exception vectors belong to the hypervisor, the hypervisor keeps the monopoly of execution in Handler Privileged mode.
The hypervisor relies on the two hardware mechanisms described hereafter (see Cortex-M mechanisms: MPU, privileges, NVIC).
Secure boxes cannot be instantiated at runtime. Instantiation is done at compilation time, as the definition of the ACLs, using the hypervisor API. Once compiled, the binary resulting of the build process contains the application executable image, containing the ACLs. This image must be signed so it can be part of the 2nd level application.
The file sources/deeptrust_api/box_example/example.cpp
illustrates this instantiation.
In the first version of this specification, the compilation of the whole embedded software must be done in a single operation. In the resulting binary image, the core firmware binary is separated and signed separately using the ROM secure boot signing key. Other secure boxes code is also separated from each other and signed with different signing keys. However the software binary image remains monolithic and must be loaded entirely in a single operation. Secure boxes are stored in a contiguous memory area.
In the next release, it will be possible to compile secure boxes separately, and load them separately from each other.
Secure boxes have the following structure in memory:
Note: The box name must be unique. Note: The above is signed using a dedicated key that is different from the CRK core firmware signing key. This scheme allows to consider secure boxes as separate from the core firmware.
The verification key ID defines the box privileges. If one posseses the K_fw signing key, he can write code having the "box firmware" privilege. The K_trusted shall be distributed
Even if no unsigned code can be executed (this leads to a platform reset), any code must be carefully reviewed before being signed and loaded into the platform.
Let's precise that the code signing key management is left at the discretion of users of Deeptrust. The foreseen usage is:
This scheme can be further extended with more keys, and customized by reworking the uvisor_check_acl
function. Ultimately the vendor is in charge of managing the code verification keys present in the platform, and how to distribute/update them.
The Makefile present at the root of the project is in charge of signing secure boxes according to this 3-level privilege design.
Notes:
During the boot of the SoC, the Secure Boot ROM starts running in "Handler/Privileged" mode (the Cortex-M boots in that mode). It verifies the digital signature of the "2nd level application" stored in flash memory, and, if successful, jumps into the entry point (aka startup) of the latter, also in "Handler/Privileged" mode.
The "2nd level application" is a term used in the Secure Boot ROM documentation. It designates the binary executable image that sits in a flash memory and that is verified by the Secure Boot ROM. In our design, the "2nd level application" is the "core firmware" described above.
The "core firmware" execution begins by the initialization of the hypervisor itself, which also runs in Handler/Privileged mode. During this initialization phase, the hypervisor sets up a protected environment using the MPU: the MPU is configured so that the hypervisor keeps ownership of its own memories and the security-critical peripherals, in order to keep them protected from the unprivileged code. The hypervisor secures two main memory blocks, in flash and SRAM respectively (it places its own constants, data and stack in secured areas of memory, separated from the unprivileged code). In both cases, it protects its own data and the data of the secure boxes it manages from the unprivileged code.
This initialization step makes some peripherals impossible to access to the unprivileged code whatever the ACLs are. Therefore accessing to some security-critical peripherals (like DMA) requires SVCall-based APIs for the unprivileged code. The MPU configuration, the vector table, the NVIC configuration are also made inaccessible from the unprivileged code.
The hypervisor initialization is as follows:
The hypervisor prevents CPU registers leakage when switching execution between Handler privileged and Thread user code and between mutually untrusted unprivileged boxes. It also remaps the stack and modifies the MPU according to the destination context.
During a context switch, the hypervisor stores the state of the previous context and then:
Memory map varies according to context. The diagram below shows the modification of the memory map when switching from a Box A to a box B
All the code that is not explicitly part of the hypervisor is generally referred to as unprivileged code. The unprivileged code is the code that runs in Thread/User mode, and that is therefore unable to modify neither the configuration of the MPU (privileged access required) nor its own access privileges.
The "main()" function of the 2nd level application, called from the startup file, after the initialization of the hypervisor and the C/C++ runtime, is such unprivileged code. Indeed, after initialization, the hypervisor starts executing the "main()" after having switched into the Thread/User mode of execution.
Unprivileged code runs with the following capabilities:
Exceptions/interrupts make the Cortex-M switch to Handler privileged mode. Therefore the hypervisor must catch the exception, switch to Thread/User mode and call the registered unprivileged handler.
To this end, interrupt vectors are relocated to the SRAM but protected by the hypervisor. Access to them is made through specific APIs: the unprivileged code can register for unprivileged interrupts. Therefore the hypervisor needs to catch, forward and de-privilege interrupts to the unprivileged handler that has been registered for them.
A context switch is triggered automatically every time an exception handling routine (interrupts) belongs to a different secure box.
Interaction from the Thread user code to the Handler privileged code is achieved by exposing SVCall-based APIs. As exception vectors are handled exclusively by the hypervisor, SVC exceptions are caught by this one exclusively, as all the other forms of exceptions (and interrupts).
The hypervisor allows inter-box communication through RPCs (Remote Procedure Calls). The callee box can check the origin of the call using the box ID of the caller (and hence it's unique name), and also the box privilege of the caller, in order to determine whether the requested action is legitimate or not. RPC calls trigger context switches.
Definitions:
Security context switch (from Box A context to box B context) is done via RPC calls
On return, inverse process is applied.
Context switches can also be triggered by interrupts also handled by the hypervisor, the same way. An interrupt makes the Cortex-M enter the Handler privileged mode. However exception vectors are protected by the hypervisor hence the hypervisor catches the interrupt. The execution mode of the Cortex-M is set back to unprivileged by the hypervisor and it then calls the registered interrupt handler.
The secure Boot ROM is a trusted immutable code in read-only memory that allows booting the SoC. The use of a Read-Only Memory guarantees de-facto the integrity and authenticity of the Secure Boot firmware itself, as modification of the ROM on an IC die is assumed too costly and highly technical. Integrity of the ROM is verified by a CRC verification before boot: the hardware initialization state machine verifies the CRC before releasing the CPU upon each reset. The CPU will start executing the code only if the ROM CRC is correct.
The Secure Boot ROM guarantees that the firmware that gets executed next is genuine and not modified (authenticity and integrity verification). This is mandated for building trust in the system. The Secure Boot ROM is the Root of Trust.
The secure Boot ROM is designed to launch a 2nd level application from the internal flash memory of the SoC. It requires that the 2nd level application’s digital signature is correct and has been performed with the correct CRK_sign signing key, otherwise it refuses to start it. This digital signature is verified using a public key (Customer Root Key, CRK_verif) stored in a write once memory (OTP, one-time programmable memory) of the SoC.
The CRK_verif integrity is also verified before use. Indeed the MAX325xx contains a public key in ROM (the MRK, Maxim Root Key), owned by Maxim Integrated. The MRK allows verifying the signature of the customer public key (CRK_verif) before it is used. Therefore, customers must submit their public key CRK_verif to Maxim beforehand. Maxim signs this public key with the MRK private counterpart, and returns this signed CRK_verif to the customer. The customer then has to download this signed CRK_verif through the above-mentioned SCP protocol (SCP packets are pre-generated offline in a secure environment using a private key see [DOC11])
As the secure boot ROM firmware and the CRK_verif and MRK verification keys cannot be replaced, the integrity and authenticity of the booted 2nd level application is guaranteed.
The below items guarantee that only trusted code can be loaded into the platform.
The default ACL policy does not grant write access to the internal flash to store executable code and therefore does not allow code updates. However the Secure Boot ROM is capable of updating applications through a serial protocol called SCP. It can securely download new applications into the platform’s non-volatile memory through a serial port or a USB port.
Note: The SCP protocol also allows configuration, life-cycle management and key management. See [DOC11]
In the second version of this specification, a partial update service will be offered, where secure boxes can be independently loaded and/or updated. Those secure boxes must be signed, and the verification will be performed during the uploading (in addition to theit boot time verification already described). An alternate loading service will be provided too, in order to second the SCP offered by the ROM.
To allow partial build, the core firmware will publish the location of symbols so that additional boxes can refer to those symbols (e.g peripheral drivers entry points, C library functions). In order to be able to update the core firmware without breaking the compatibility of the additional boxes already present in the platform's flash memory, those adresses must be kept the same. Some indirect calls can be used to make the preservation of constant adresses easier. Note that an update of the core firmware will most of the time require a recompilation and an update of all secure boxes. Otherwise, secure boxes will possibly be modified, built and loaded separately without any impact on the rest of the software.
Secure boxes will have to be built using position independent code so that they can be stored at random locations. The volatile memory needed by them will also have to be dynamically allocated, because the precense of other secure boxes using potentially the same otherwise static volatile memory adresses may conflict.
Interfacing secure boxes
Secure boxes cannot contain general purpose code accessible through direct call. As a matter of fact, existing secure boxes are usually not aware of newly added boxes and therefore cannot really use them. The boxes can however publish services in a jump table. Those services are RPC functions. Additional boxes can use services by other boxes already present in the platform's flash memory. They can refer to these services knowing the targeted box's name and service ID.
Software item | PCI Perimeter? | Execution privilege | Signing key | Verification key | Location of verification key | Verification of verification key by: | Verification of software item by: |
---|---|---|---|---|---|---|---|
ROM secure boot | Yes | Handler privileged | None | n/a | n/a | Hardware state machine performs CRC-32 of ROM | |
Core firmware - privileged (hypervisor) | Yes | Handler privileged | CRK_sign | CRK_verif | OTP memory | ROM secure boot, using a hard-coded MRK public key in ROM | ROM secure boot |
Secure box - "box firmware" privilege | Yes | Thread user | K_fw | K_fw_verif | In core firmware binary image | ROM secure boot, together with the Core firmware image | Core firmware's hypervisor |
Secure box - "box trusted" privilege | No | Thread user | K_trusted | K_trusted_verif | In core firmware binary image | ROM secure boot, together with the Core firmware image | Core firmware's hypervisor |
Secure box - "box other" privilege | No | Thread user | K_other | K_otehr_verif | In core firmware binary image | ROM secure boot, together with the Core firmware image | Core firmware's hypervisor |
The following paragraphs give additional justifications to the consistence of the above, security-wise
All MAX325xx SoCs released in the field have no JTAG interface enabled. Therefore it is not possible to bypass or perturbate the executed firmware (in particular the secure boot ROM), or to inject arbitrary code for execution by the platform through a debug interface.
No test mode can be activated after manufacturing operations at Maxim Integrated therefore no possibility to bypass security is provided.
No intentional backdoors for re-enabling the JTAG or any test mode are existing.
The Secure Boot ROM is always executed after reset. It cannot be skipped.
The platform software can be executed from internal flash and optionally internal RAM, and the runtime data are stored in internal RAM. Long term data may be stored in internal flash. Access to the SoC internal memories is a costly attack defeated by the presence of a die shield and is assumed impossible in the present context.
The platform software executed from external flash and the related data are protected by the on-the-fly integrity and encryption, and the external flash is protected from physical tampering/replacement throught the SoC intrusion sensors that prevent intrusions in the enclosure. Therefore the external flash memory is protected against manipulation logically. There's is no need for an additional physical protection to protect the external memory ICs and the communication path to the main SoC.
Therefore, the only means to load executable code into the platform is through the Secure Update provided by the Secure Boot ROM.
The SoC always boots the Secure Boot ROM in any circumstances and starts the 2nd level application (if valid, as discussed above).
The 2nd level application begins by the early initialization of the SoC, the initialization of the security sensors of the SoC and then the initialization of the the lightweight security hypervisor.
The hypervisor is initialized right after device start-up and takes ownership of its most critical assets, like privileged peripherals, the vector table and memory management.
From this moment on, the operating system/application runs in Thread user mode and in the default context, which is the one of the main box.
The next step consists in the creation of the various boxes, the registration of their ACLs and the beginning of the execution of the OS Scheduler that will execute the various threads (a box may contain one or more threads). The overall code is covered by the Secure Boot ROM integrity and authenticity verification and can therefore be trusted.
Additional firmware independent components can be verified and launched by the initial trusted firmware already verified above.
The following hardware features are leveraged by the software described above.
The Cortex-M3/4's Memory Protection Unit and the Execution mode/Privilege level (Thread/Handler modes of execution, Privileged/User Access) are used to support the software isolation.
The Cortex-M MPU is used to grant/deny access to regions of the memory map to the unprivileged code (i.e. all the code except the hypervisor)
The MPU could also restrict access even to the privileged code (without the possibility for the privileged code to modify the access) but this feature is not used currently, in the security architecture presented here.
The Cortex-M's 2-level execution mode (Handler, Thread) combined with the 2-level privilege system (Privileged, User) prevents code running in Thread/User mode from breaking the MPU configuration that requires Privileged access. This hardware feature is leveraged by the lightweight security hypervisor. Return to the Privileged/Thread mode can be done only via a SVCall-based API (see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0179b/ar01s02s07.html), i.e. a software triggered exception that can be cached only by the Privileged Handler actually implemented by the Lightweight security hypervisor and that cannot be modified by/re-routed to unprivileged code.
The interrupt controller is exclusively controlled by the hypervisor, hence no other unprivileged code can register exception handlers. This is vital since the Cortex-M executes exception handlers in Privileged/Handler mode.
Sensitive data can be stored in the MAX325xx’s battery backed RAM which gets immediately erased in case of tampering detection (physical tampering, environmental perturbations). The NVSRAM is leveraged by the Key Manager to store long-term secret/private keys that get erased whenever the device is under attack.
Environment perturbations (temperature, glitches, die shield, external dynamic sensors,...) lead to the generation of a non maskable interrupt that stops the execution of the platform's software and thus prevents running away into a non secure mode. Sensors are activated before the security hypervisor initialization in order to guarantee the physical integrity of the platform before running further code.
The Secure Boot ROM is non modifiable and thus inherently trusted, and its configuration or the code verification keys are in a write-once memory (OTP) and cannot be changed. The ROM and the OTP memory areas integrity is verified (Checksum) before use.
Note: hardware security mechanisms are evaluated in a separate report. See report [DOC12].
Access to PCI PTS POI sensitive services via API with security policy.
The services offered by the Maxim software library are contained in 3 boxes and can be invoked via RPC calls as described above.
The API entry points are implemented following this behaviour:
3 boxes are offered:
Additional services such as OPEN protocols would also fit into the Secure Sandbox Services.
The API can be found further in this document, see Reference Guide
The source code of the whole Deeptrust software offer is stored on a secure server at Maxim Integrated. This server features access control:
The list of stakeholders is controlled by the project manager and can be also modified by some IT administrators. All are personel with a high level of confidence. Roles are:
The source control is implemented using GIT, more precisely a self-hosted Gitlab server. The server is located on Maxim's internal network with all the usual protections applied to corporate level servers that contain company vital data.
Bugs are tracked using Gitlab's bug tracker. Bugs can be reported by any stakeholder. They can be closed by the integrator or the project manager.
The following code review process is applied:
The public repositories containing the third party source code included in Deeptrust offer is checked weekly for security bugs and vulnerabilities, in addition to a subscription to the bug trackers:
Such issues are reported in Maxim's internal Bug tracking system for immediate analysis and correction if they are found exploitable. In case of exploitable vulnerabilities, new software releases are published to customers as fast as possible together with the notice describing the issue.
In order to prevent the introduction of vulnerabilites, Maxim Software developers follow company rules for secure coding. These rules can be provided upon request.
In addition, static analysis is performed on the source code to detect potential security issues (RATS, CPPCheck, Visual Code Grepper are all used).
A thorough validation is also performed using the following strategy:
The firmware is versioned following this scheme: vX_Y_Z
The firmware is developed internally at Maxim using the source control, bug tracking and development guidelines described above. Reviews are performed and recorded on a regular basis, at least before each customer delivery. Validation is performed and recorded, at least before each customer delivery.
Firmware deliveries are tagged and documented (description of the list of changes), together with the review and validation records.
Firmware is released to customers using a public GIT server owned by Maxim, with strict read-only access and access control: Only customers being granted access can read the source code. The hypervisor is released in binary format only. The binary hypervisor is released in the mbed-os source tree, and included into the final software during the mbed-os build step.
The above architecture provides a strong isolation of the sensitive data from regular applications. Sensitive data are handled within Secure Boxes only. Other boxes cannot get access to the data manipulated by these boxes as well as to some peripherals of the platform.
Isolation is enforced by the lightweight security hypervisor, which code and configuration data are protected by the MPU and the execution mode/privilege level system of the Cortex-M core and verified by the ROM based secure boot. the lightweight security hypervisor is executed early in the startup sequence before any user code, and no debug/test/executable code loading exist in the platform.
Therefore the software isolation mechanism cannot be bypassed.
The overall architecture relies on the following elements
The architecture enforces the least privilege principle.