📜 ⬆️ ⬇️

TrustZone: trusted OS and its applications

In previous articles we looked at the TrustZone hardware and the operation of the Secure Monitor mechanism. Today we will talk about trusted OS (TEE) and its applications. And if the last time there were quite low-level things, now everything will be at a quite high level - at the level of the operating system.

What is TEE


What is TEE? This is a trusted execution environment (Trusted Execution Environment), in the first place, it is a program execution environment. We describe it in terms of function and properties, but not in the sense of programming, but in the philosophical sense.

For example, a long-distance train, an electric train and a taxi have the most important function - to transport people. But they differ in properties, for example: the train travels between cities, an electric train - outside the city, and taxis - mainly in the city. Train and train ticket, taxi - no. And so on.
')
The TEE function is to trust us to store some data for us and to run applications for us. We want to send TEE commands: run such an application, take such-and-such data and do this and that with them. In this case, the application code can not see, as well as the data. We will only get the result. Interaction with TEE is very similar to RPC.

This function is ideal for different cryptography, for example, for electronic signatures: the keys are stored in the TEE, and we ask the TEE to sign the transferred data with the key stored in the TEE. We get the result, but do not have access to the key.

TEE has a number of properties, but the main ones are as follows: a) we trust its implementation, and b) it is reliably separated from the main OS of the device, protected, it is difficult to break or break. There are other properties, but we call it a trusted OS for that. Property b) the most important thing is that TEE is separated and difficult to break, that is, it is protected.

If you look at TEE through the prism of functions and properties, it becomes clear that TEE is not even entirely about TrustZone. TrustZone is one of the ways to separate TEE from the main (guest) OS.

TEE Implementation Options


If the main features of TEE are that it is separated and difficult to break, then we can come up with different options for implementing TEE:


We will continue to talk only about the implementation of TEE in TrustZone, because this is a very common version of the implementation of TEE. But much will be said about TEE in general.

TEE as OS


In previous articles, we always called TEE a trusted OS and said that it was in many ways similar to real operating systems.

Without claiming generality, let's say that in the bulk of TEE have:

You can come up with more abbreviated versions of TEE, for example, without dynamic application loading, no interaction of processes, no threads, but the applications themselves, data storage, and the separation of the memory space of the processes and the kernel will remain.
Hidden text
An example of a stripped-down TEE can be seen now in the ARM Trusted Firmware-M project for the new generation of Cortex-M microcontrollers on the ARMv8-M platform. This is a stripped down TEE, now there is support for microcontrollers on the Cortex-M23 and Cortex-M33 cores. These are flash-based microcontrollers, roughly equivalent to Cortex-M0 and Cortex-M3, but with TrustZone support. They have little RAM, the program runs mostly from Flash, and therefore there is no dynamic program loading in TEE. At the moment, the TF-M is also single-threaded.

TEE software interface


To interact with other software components, TEE has an API:


Through system calls, programs save data and call OS functions. Like any decent OS, TEE tries to abstract programs from hardware to one degree or another.
For example, Linux abstracts work with files through open, read, write, close calls - all stdio functions in principle fall on the OS system calls. And TEE also allows its applications to work with stored data through calls, which in an abstract form save and load objects (data blocks) in the repository. Also, TEE can provide some cryptographic functions at the system level, etc.

For TEE there is a set of GlobalPlatform specifications, they describe the API, requirements, usage scenarios, etc.
The basic TEE APIs for its programs are described in the TEE Internal Core API Specification. It describes the data storage functions, cryptographic functions, and so on. And the TEE Client API describes how to call applications from Normal World.

If your TEE implements these APIs, writing an application for it will be quite easy. Thanks to one API, program portability is realized.

Differences TEE from normal OS


The two main differences between TEE Linux and other common-use operating systems:

  1. TEE performs actions not at the command of the user, but at the command of Normal World;
  2. TEE in TrustZone does not have its own scheduler.

In a normal OS, the user generates some input — enters commands, clicks the mouse over the icons, and the OS processes this input, transmits it to the programs, and the programs process it. In the server version, the input is not from the user, but from some clients, most likely over the network. But the OS, however, acts on the basis of external input data.

TEE does not process external data and does not transfer it to applications. Instead, it processes the commands and data transferred from the Normal World via the TEE Client API, and that’s about it. It turns out that TEE acts for the OS as some library with an RPC interface, whose functions are called. After processing the functions, TEE can do nothing.

The second difference follows from the first. TEE in TrustZone shares processor time with Normal World and is called as a library. TEE does not allocate processor time for itself all the time, it spends as much time as it needs to fulfill the request and then transfers control to Normal World. And if so, then she should not have her own scheduler - she needs a guest OS scheduler.

The primary OS scheduler transfers control to TEE indirectly:


TEE Applications


Applications running in TEE are called troughts - by analogy with applets that work in smart cards.
Quote from wikipedia:
Applet (English applet from application - application and -let - diminutive suffix) is a non-independent component of the software, working in the context of another, full-fledged application, designed for one narrow task and having no value in isolation from the basic application.

Trustlet is a Trusted Applet. This is a program for TEE, as we have already found out, it communicates with TEE through system calls, it has a life cycle, etc.

But still the name indicates that it is a non-dependent component. Here the lack of independence is expressed in the fact that the trust will make calls from Normal World, and then disconnect with TEE. If it spins in an infinite loop, the processor core will stop performing the functions of the OS, and everything will eventually hang. But a program for a normal OS can spin in an infinite loop and mine some tasks, this is completely normal for a program. In this regard, it is more independent than the trust.

A trustlet must have some kind of identifier so that Normal World can call it. It is customary to give trusts as a UUID name — unique identifiers.

The life cycle of the trustlet


Consider how the launch of the trustlet and the execution of commands.

It would be logical to load the trustlet into memory and start working, but in the GlobalPlatform TEE Client API to launch the trustlet you need to create a context and establish a session with the trustlet.

Context creation is the establishment of a connection between Normal World and TEE. In this case, the GlobalPlatform specification assumes that there are several TEEs in the device, and at the time of creating the context, you can choose which TEE to apply to.

The GlobalPlatform TEE Client API provides for this function:

 TEEC_Result TEEC_InitializeContext (const char * name, TEEC_Context * context)

This function is called from the Normal World application. Here, the name indicates the selected TEE. If we want TEE by default or are sure that we have only one TEE, we substitute NULL. In context, the created context is saved.

After creating the context, you need to establish a session with the trustlet. Here we need the UUID of the trummer. To do this, call the function:

 TEEC_Result TEEC_OpenSession (
	 TEEC_Context * context, TEEC_Session * session,
	 const TEEC_UUID * destination, uint32_t connectionMethod,
	 const void * connectionData, TEEC_Operation * operation,
	 uint32_t * returnOrigin)

A session is equivalent to working with a program instance in a normal OS: there can be many instances of one program in the OS, and they will work independently. And in TEE there are many sessions, and in fact they are connections to unique instances of the trustlet in memory. In this case, the code area will most likely be the same, displayed through the MMU in the memory of different processes. But the data area will have its own process for each process, allowing instances to work independently. Just like in Linux.

When the TEEC_OpenSession is called, the context of the context and the UUID of the destination destination are transmitted as input data. The established session will be saved in “session”. Some parameters hereinafter we will not consider, they are not so important for understanding.

At the time of the session creation, the trustlet can be loaded into memory. This is the same thing that happens with applications in the operating system. In a large TEE, the linker is responsible for this, he downloads a binary image of the trustlet, this is such a signed ELF file. If this is a small TEE, the trustlet must already be loaded into memory - it can be statically linked or, for flash-microcontrollers, written into flash-memory at a given address.

Let's assume that we have a large TEE, and we need to load the trustlet into memory. Where does he come from? In principle, TEE needs an object with a certain UUID at the time of loading, and any mechanism for obtaining this object can be:


Ask yourself later, how does this TEE load data from the file system or over the network? !!!

After downloading the image of the trustlet, he verifies the electronic digital signature. A certificate system is used, and TEE will verify that the trust has been signed by a party that trusts and TEE. This is very important because it excludes the possibility of downloading a replaced trustlet with some kind of malware.

When the image of the trustlet is obtained and the signature is verified, TEE creates the address space for the instance of the trustlet in MMU, and the linker loads the code area into memory, maps it to the address space of the trustlet, and initializes the data area. The result is a fully initialized instance of a trustlet for working with a specific invoking application - this is the creation of a session.

After the session is created, the trustlet is in full readiness and can execute requests from the calling application. In order to call the trustlet functions from the OS, the function is used:

 TEEC_Result TEEC_InvokeCommand (
	 TEEC_Session * session,
	 uint32_t commandID,
	 TEEC_Operation * operation,
	 uint32_t * returnOrigin) 

Here “session” refers to our session, that is, the TEE instance and the instance of the trustlet we are working with.

"CommandID" indicates the called function of the trustlet. This is exactly the function of the trustlet, not the function of TEE. All TEE's concern is to start the trustlet and send commands, and which commandID numbers to assign to communicate with the trustlet is your business, there is no rule or global list of functions.

If you need to pass the parameters of the called function, they are passed through the operation - this is a pointer to the TEEC_Operation structure. Let's not go deep now, just note that this structure contains up to 4 function parameters (type TEEC_Parameter). Parameters can be a simple TEEC_Value value or a memory pointer. Parameters also have directional typing: TEEC_VALUE_INPUT (input data), TEEC_VALUE_OUTPUT (output data), or TEEC_VALUE_INOUT (bidirectional).

If we pass a pointer to the TEEC_Operation structure, we first need to initialize it: set all values ​​and directions. Upon completion of the call, we can check the returned values ​​in this structure (for TEEC_VALUE_OUTPUT and TEEC_VALUE_INOUT).

During the session, we can call the functions of the trustlet as many times as we need. At the end of the work, you will need to end the session and release the context with calls to TEEC_CloseSession and TEEC_FinalizeContext.

All this is very similar to RPC, is not it? In principle, all operations with TEE are conceived as RPC, and because of this, you can work with a variety of implementations of TEE: in TrustZone, in a separate core, in a separate chip.

Supplicant


Above we asked: how does TEE load data from the file system or over the network?
If you think about it, TEE itself does not have access to the OS file system. That is, the TEE implemented in TrustZone could have such access, but then she would have to share it with Normal World, and this is not so easy. For example, Linux constantly works with the file system, and its current state is only in the memory of the Linux kernel, and not on the disk. If TEE wants to intervene and work with the file system in parallel, it will be very difficult. With network sharing is the same.

In addition, TEE is a rather small OS, and it would be unprofitable to implement low-level drivers for working with media, with a network controller, to support a network stack or a file system driver. In addition, it greatly increases the attack surface - there would be a chance to hack TEE, slipping an unusual inode on ext2 or something. We don't want that.
Therefore, when the OS starts, the so-called Supplicant is loaded. She is in conjunction with TEE all the time, and TEE uses her to access Normal World resources.

Therefore, if TEE wants to download an image of a trustlet from the file system, it calls Supplicant:

TEE: What about an object with such a UUID?
Supplicant: (Loads object from file system) Excuse-with!

Of course, such appeals should be checked for security. In this case, we check the signature in the trustlet and take almost no risk - either the signature is correct and the trustlet goes to work, or the signature is incorrect. That is, we risk - trust may not turn out, Supplicant may not be launched, but this is another part of the threat model.

Userspace library


The program interface (calls to TEEC_OpenSession, etc.) is implemented using a library that translates the call from the application level to the TEE.

When implementing TEE in TrustZone for this, the library must first transfer the call to the OS kernel level, since only the OS kernel can call the Secure Monitor Call (SMC).
In the Linux + OP-TEE bundle, the userspace library is libteec. It translates GlobalPlatform TEE Client API calls to the kernel driver through ioctl operations on the device file: when the OS starts, the kernel module (driver) is loaded, the driver creates the device file. By opening a device file using libteec, a user program can work with the TEE Client API.

That is, this construction works:
Application> libteec> device file> kernel driver> SMC> TEE> trustlet.

An example of a trust


Here's how it works in real life:
image
Here the trustlet is used to electronically sign documents. A Linux program calls a trustlet, for which a TEE context is created successively, a session with the trustlet is transmitted, the data for the signature is transmitted, and the electronic signature is returned.

Conclusion


In this article we figured out what are TEE and trustlets. We got acquainted with the TEE API and learned how trustlets are called.

We deliberately left aside many things, such as using Shared Memory and writing trusts, because the article does not claim to be an exhaustive guide.

If you are interested in the topic of TEE, then continue to explore on your own: you can start by studying the specifications of GlobalPlatform or parsing the work of OP-TEE. You can also send us a resume marked “TrustZone”.

Source: https://habr.com/ru/post/428311/


All Articles