OPTEE

OP-TEE

OP-TEE, or Open Portable Trusted Execution Environment, is a software framework that provides a secure execution environment for running sensitive code on modern embedded systems. It is an open-source implementation of the Global Platform Trusted Execution Environment (TEE) specification and is designed to be highly portable, flexible, and configurable.

OP-TEE is a software-based Trusted Execution Environment (TEE). It runs as a normal application on a hardware platform and provides a secure execution environment that is isolated from the normal operating system and applications running on the platform.

OP-TEE leverages the hardware security features of the underlying hardware platform, such as secure boot, secure storage, and secure interconnects, to create a trusted execution environment. However, the actual implementation of the TEE is done entirely in software, using a combination of secure operating system components, secure libraries, and trusted applications.

OP-TEE is designed to be highly portable and can run on a wide range of hardware platforms. This makes it a flexible and versatile solution for building secure systems on a variety of embedded and mobile devices.

OP-TEE provides a secure environment where sensitive code can run without interference from other software on the system. This makes it an ideal solution for a wide range of applications, including mobile devices, IoT devices, and other embedded systems that require a high level of security.

No alt text provided for this image


The architecture of OP-TEE consists of two main components: the normal world (REE) and the secure world (TEE). The normal world is the non-secure environment in which the operating system and applications run, while the secure world is a separate, isolated environment that provides a trusted execution environment for sensitive code. The two worlds communicate via a set of interfaces defined by the TEE specification, which provide a secure way for the normal world to communicate with the secure world.

The secure world in OP-TEE is implemented using ARM TrustZone technology, which provides hardware-based isolation between the normal world and the secure world. This ensures that sensitive code can run in a protected environment, isolated from the rest of the system.

OP-TEE provides a range of security features that help to ensure the integrity and confidentiality of sensitive code and data. These features include secure boot, secure storage, secure communication, and secure key management. The secure boot process ensures that only trusted code can be loaded into the secure world, while secure storage provides a protected area for storing sensitive data. Secure communication ensures that data is transmitted securely between the normal world and the secure world, while secure key management provides a secure way to manage cryptographic keys.

OP-TEE is highly flexible and configurable, allowing developers to customize the software to meet their specific needs. It supports a wide range of hardware platforms and can be customized to support different use cases and security requirements. Additionally, OP-TEE is designed to be easily integrated into existing software stacks, making it a versatile and convenient solution for developers.

In conclusion, OP-TEE is a powerful and flexible software framework that provides a secure execution environment for running sensitive code on modern embedded systems. It offers a wide range of security features and is highly configurable, making it an ideal solution for a wide range of applications. With its open-source implementation of the GlobalPlatform TEE specification and its support for a wide range of hardware platforms, OP-TEE is an excellent choice for developers looking for a trusted execution environment for their embedded systems.

OP-TEE is a software framework that provides a Trusted Execution Environment (TEE) for running trusted applications on modern embedded systems. A trusted application is an application that is designed to run within the TEE and provides a secure execution environment for sensitive code. A client application is an application that runs in the normal world, outside the TEE, and communicates with the trusted application to perform secure operations. OP-TEE OS is the operating system that provides the infrastructure for the TEE and manages the execution of trusted applications.

The communication flow between the client application and the trusted application in OP-TEE typically happens through a set of APIs (Application Programming Interfaces) that are provided by the TEE. These APIs allow the client application to securely communicate with the trusted application and perform operations that require a high level of security.

Let's take an example of a secure payment system to understand how the communication flow works between the client application and the trusted application in OP-TEE.

In this example, the client application is a mobile payment application that runs on a smartphone, while the trusted application is a payment processing application that runs in the TEE of the smartphone. The payment processing application is responsible for performing the cryptographic operations required for secure payment processing, such as generating and verifying digital signatures, and managing the storage of cryptographic keys.

The communication flow between the client application and the trusted application in this example typically happens as follows:

  1. The client application requests a payment transaction from the user, and the user enters the transaction details, such as the amount and the recipient.
  2. The client application sends the transaction details to the payment processing application through the TEE APIs. The TEE APIs ensure that the communication between the client application and the trusted application is secure and that the data is protected from other applications on the smartphone.
  3. The payment processing application generates a digital signature for the transaction using a cryptographic key that is stored securely in the TEE.
  4. The payment processing application sends the signed transaction back to the client application through the TEE APIs.
  5. The client application sends the signed transaction to the payment gateway for processing.

By using OP-TEE to run the payment processing application in the TEE, the payment system is more secure and less vulnerable to attacks, such as malware or other software exploits. Additionally, by using the TEE APIs to communicate between the client application and the trusted application, the system is protected from eavesdropping or other types of attacks that could compromise the security of the transaction.

In summary, OP-TEE provides a secure environment for running trusted applications that can be accessed by client applications through a set of APIs. By using OP-TEE to run trusted applications, developers can create more secure and trustworthy systems for sensitive applications, such as mobile payments, digital wallets, and other applications that require a high level of security.


Here are the step-by-step instructions for a client application (CA) to communicate with a trusted application (TA) running inside a TEE:

  1. Initialize the TEE context: The first step is to initialize the TEE context by calling TEEC_InitializeContext. This step is required to communicate with the TEE. The TEE context represents a handle to the TEE session and is used to manage the communication between the CA and the TEE.

TEEC_Context teec_ctx; 
TEEC_Result teec_res; 
teec_res = TEEC_InitializeContext(NULL, &teec_ctx); 
if (teec_res != TEEC_SUCCESS) { 
    // handle error 
}         

2. Open a session with the TA: After the TEE context has been initialized, the CA can open a session with the TA by calling TEEC_OpenSession. This step allows the CA to communicate with the TA and execute its functions. This function takes the TA's UUID as a parameter and returns a session ID that can be used to communicate with the TA.

TEEC_Session teec_sess; 
TEEC_UUID ta_uuid = {0x01234567, 0x89ab, 0xcdef, {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}}; 
teec_res = TEEC_OpenSession(&teec_ctx, &teec_sess, &ta_uuid, TEEC_LOGIN_PUBLIC, NULL, NULL, NULL); 
if (teec_res != TEEC_SUCCESS) { 
    // handle error 
}         

3. Prepare the command parameters: Once the session with the TA has been established, the CA needs to prepare the command parameters that will be passed to the TA function. This involves creating a TEEC_Operation struct and populating it with the appropriate values. These parameters can include input data, output data, and other parameters required by the TA function.

TEEC_Operation teec_op; 
memset(&teec_op, 0, sizeof(teec_op)); 
teec_op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INPUT, TEEC_VALUE_OUTPUT, TEEC_NONE); 
teec_op.params[0].value.a = num1; 
teec_op.params[1].value.a = num2;         

In this example, the TEEC_Operation struct is initialized with the input and output parameter types, and the input parameters (num1 and num2) are set to the appropriate values.

4. Invoke the TA function: Once the command parameters have been prepared, the CA can invoke the TA function by calling TEEC_InvokeCommand. This function takes the session ID, command ID (which is typically 0), the TEEC_Operation struct, and a TEEC_TempMemoryReference struct (which can be set to NULL in this case).

TEEC_InvokeCommand() is a synchronous function in the TEE Client API. It blocks until the execution of the command in the Trusted Application is complete and a response is returned.

However, there is an asynchronous version of this function called TEEC_InvokeCommandAsync(). This function allows the client application to execute a command in the Trusted Application asynchronously, meaning that the function returns immediately without waiting for the command to complete. The client application can then poll for the completion status of the command using the TEEC_Wait() function.

The use of synchronous or asynchronous function depends on the specific requirements of the client application. If the client application can tolerate blocking while waiting for a response, it can use the synchronous function. On the other hand, if the client application needs to perform other tasks while waiting for a response, it can use the asynchronous function.

teec_res = TEEC_InvokeCommand(&teec_sess, 0, &teec_op, NULL); 
if (teec_res != TEEC_SUCCESS) { 
    // handle error 
}         

5. Process the output: After the TA function has been invoked. The TEE executes the TA function and returns the result to the CA. the output parameters are stored in the TEEC_Operation struct. The CA can read these values and use them as needed.

*result = teec_op.params[2].value.a;         

6. Close the session: Once the communication with the TA is complete, the CA should close the session with TA by calling TEEC_CloseSession.This step is important to ensure that system resources are properly released and to prevent any potential security vulnerabilities.

TEEC_CloseSession(&teec_sess);         

7. Finalize the TEE context: Finally, the CA should call TEEC_FinalizeContext to clean up the TEE Client API resources i.e destroy or release any resources allocated by the TEE. This step ensures that the TEE context is properly closed and that no resources are left open.

TEEC_FinalizeContext(&tee_ctx);        

Here is an example code snippet that demonstrates how to create a Trusted Application (TA), a Client Application (CA), and how they communicate with each other through the OP-TEE OS:

By following these steps, the CA can securely communicate with the TA and execute its functions in the TEE.

It is important to note that the exact implementation of these steps can vary depending on the specific TEE and programming language used. For example, some TEEs may have additional steps or require different parameter formats. It is important to consult the specific TEE documentation and programming guides for accurate implementation details.


Here are the API definitions for TEEC_InvokeCommandAsync() and TEEC_Wait() in the TEE Client API:


TEEC_Result TEEC_InvokeCommandAsync(TEEC_Session* session, uint32_t commandID, uint32_t paramTypes, TEEC_Operation* operation, uintptr_t userData);

This function is used to invoke a command in a Trusted Application asynchronously. The session parameter specifies the session handle to use, commandID specifies the ID of the command to execute, paramTypes specifies the types of the parameters used in the command, operation specifies the data buffer and length used in the command, and userData is a user-defined value that is passed to the completion callback function. This function returns a TEEC_Result value that indicates whether the command was successfully scheduled for execution.

TEEC_Result TEEC_Wait(TEEC_Context* context, TEEC_Operation* operation, uintptr_t timeout);

This function is used to wait for an asynchronous command to complete. The context parameter specifies the context handle to use, operation specifies the data buffer and length used in the command, and timeout specifies the maximum time to wait for the command to complete in milliseconds. This function returns a TEEC_Result value that indicates whether the command completed successfully within the specified timeout.

In addition to TEEC_InvokeCommandAsync() and TEEC_Wait(), the TEE Client API also provides other functions for asynchronous operations, such as:

  • TEEC_RegisterSharedMemory() and TEEC_AllocateSharedMemory(): These functions are used to register and allocate shared memory that can be accessed by both the client application and the Trusted Application.
  • TEEC_ReleaseSharedMemory(): This function is used to release shared memory that is no longer needed.
  • TEEC_RequestCancellation(): This function is used to request cancellation of an asynchronous command that is in progress.

These functions provide the client application with the flexibility to perform asynchronous operations and manage shared memory between the client application and the Trusted Application.


Trusted Application (TA) code:

There are standard functions of the Trusted Application Framework (TA Framework) that are provided by the TEE implementation.

The TEE provides an environment for executing TAs securely and isolating them from the normal world. When a TA is loaded into the TEE, it registers entry points with the TEE using these APIs. Then, when a normal world application wants to invoke a service provided by the TA, it makes a TEE Client API call to the TEE. The TEE then forwards this call to the appropriate TA entry point, which executes the requested service securely within the TEE.

For example, TA_CreateEntryPoint is a function that is called when a TA is first loaded into memory, and it is responsible for initializing the TA's data structures and setting up any required resources. Similarly, TA_DestroyEntryPoint is called when the TA is unloaded, and it is responsible for cleaning up any resources that were allocated by the TA.

Other standard functions include TA_OpenSessionEntryPoint, which is called when a client opens a session with the TA, and TA_CloseSessionEntryPoint, which is called when the session is closed. These functions provide a standard way for clients to interact with the TA and for the TA to manage its resources.

The specific names and functionality of these functions may vary slightly depending on the TEE implementation, but the overall concept of a TA Framework with standard functions for creating, initializing, and destroying TAs is common across many TEEs.

Here are some of the important ones:

1.TA_CreateEntryPoint: =>

TEE_Result TA_CreateEntryPoint(void)         

This function is called when the TA is loaded into memory for the first time. It is used to initialize the TA and set up any data structures or resources that it requires. The function takes a single parameter, which is a pointer to the TA context structure.


2. TA_DestroyEntryPoint:

void TA_DestroyEntryPoint(void )        

This function is called when the TA is unloaded from memory. It is used to free any resources that were allocated by the TA during its lifetime. The function takes a single parameter, which is a pointer to the TA context structure.


3. TA_OpenSessionEntryPoint:

TEE_Result TA_OpenSessionEntryPoint(uint32_t nParamTypes, TEE_Param pParams[4], void **ppSessionContext )        

This function is called when a client application requests to open a session with the TA. It is used to set up any session-specific data structures or resources that the TA requires. The function takes three parameters: a pointer to the TA context structure, a parameter buffer containing any parameters that were passed by the client application, and the size of the parameter buffer.


4. TA_CloseSessionEntryPoint:

void TA_CloseSessionEntryPoint(void *pSessionContext )        

This function is called when a client application closes a session with the TA. It is used to free any resources that were allocated by the TA during the lifetime of the session. The function takes two parameters: a pointer to the TA context structure, and a session ID that identifies the session to be closed.


5. TA_InvokeCommandEntryPoint:

TEE_Result TA_InvokeCommandEntryPoint(void *pSessionContext, uint32_t nCommandID, uint32_t nParamTypes, TEE_Param pParams[4] )        

This function is called when a client application sends a command to the TA. It is used to perform the requested operation and return any results to the client. The function takes four parameters: a pointer to the TA context structure, a session ID that identifies the session in which the command was sent, a command ID that identifies the command, and a parameter buffer containing any parameters that were passed by the client application.


6. TA_ExportEntryPoint:

TEEC_Result TA_ExportEntryPoint(uint32_t type
                                 void *buf,
                                 uint32_t *len); ,        

This function exports the public key of the entry point of the trusted application to a buffer. This public key can be used by other trusted applications to authenticate and establish secure communication with the trusted application. The type parameter specifies the format of the exported key (e.g. raw binary, X.509 certificate), buf is the buffer to store the exported key, and len is a pointer to the size of the buffer. The function returns a TEEC_Result status code.


7. TA_GetEntryPointUUID:

void TA_GetEntryPointUUID(TEEC_UUID *uuid) ;        

This function retrieves the UUID of the trusted application's entry point. The uuid parameter is a pointer to a TEEC_UUID structure that will be filled with the UUID. This function does not return a value.


8. TA_GetInstanceUUID:

void TA_GetInstanceUUID(TEEC_UUID *uuid) ;        

This function retrieves the UUID of the currently running instance of the trusted application. The uuid parameter is a pointer to a TEEC_UUID structure that will be filled with the UUID. This function does not return a value.

These are some of the standard functions that are part of the TA Framework and provided by the TEE implementation. The parameters and use of each function may vary based on the specific implementation of the TEE.

#include <tee_internal_api.h>
#include <tee_internal_api_extensions.h>

// TA function to add two numbers
TEE_Result TA_AddNumbers(uint32_t param_types, TEE_Param params[4]) {
    uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
                                               TEE_PARAM_TYPE_VALUE_INPUT,
                                               TEE_PARAM_TYPE_VALUE_OUTPUT,
                                               TEE_PARAM_TYPE_NONE);
    if (param_types != exp_param_types) {
        return TEE_ERROR_BAD_PARAMETERS;
    }

    // Add the two input numbers
    uint32_t sum = params[0].value.a + params[1].value.a;

    // Set the output parameter
    params[2].value.a = sum;

    return TEE_SUCCESS;
}

// TA entry point
TEE_Result TA_CreateEntryPoint(void) {
    return TEE_SUCCESS;
}

void TA_DestroyEntryPoint(void) {
    return;
}

TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types,
                                     TEE_Param params[4],
                                     void **sess_ctx) {
    return TEE_SUCCESS;
}

void TA_CloseSessionEntryPoint(void *sess_ctx) {
    return;
}

TEE_Result TA_InvokeCommandEntryPoint(void *sess_ctx,
                                       uint32_t cmd_id,
                                       uint32_t param_types,
                                       TEE_Param params[4]) {
    switch (cmd_id) {
        case 0:
            return TA_AddNumbers(param_types, params);
        default:
            return TEE_ERROR_BAD_PARAMETERS;
    }
}
        

The above code defines a simple TA function called TA_AddNumbers that adds two input numbers and returns the result in an output parameter. The TA_CreateEntryPoint, TA_DestroyEntryPoint, TA_OpenSessionEntryPoint, and TA_CloseSessionEntryPoint functions are used to manage the lifecycle of the TA.

Client Application (CA) code:

#include <stdio.h>
#include <stdlib.h>
#include <tee_client_api.h>
#include <tee_api_defines.h>

#define TA_UUID {0x12345678, 0x8765, 0x4321, \
                 {0xab, 0xcd, 0xef, 0x00, 0x11, 0x22, 0x33, 0x44}}

// Function to add two numbers using the TA
TEE_Result CA_AddNumbers(uint32_t num1, uint32_t num2, uint32_t *result) {
    TEEC_Result teec_res;
    TEEC_Context teec_ctx;
    TEEC_Session teec_sess;
    TEEC_Operation teec_op;
    TEEC_UUID ta_uuid = TA_UUID;

    teec_res = TEEC_InitializeContext(NULL, &teec_ctx);
    if (teec_res != TEEC_SUCCESS) {
        return teec_res;
    }

    teec_res = TEEC_OpenSession(&teec_ctx, &teec_sess, &ta_uuid,
                                TEEC_LOGIN_PUBLIC, NULL, NULL, NULL);
    if (teec_res != TEEC_SUCCESS) {
        TEEC_FinalizeContext(&teec_ctx);
        return teec_res;
    }

    memset(&teec_op, 0, sizeof(teec_op));
    teec_op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INPUT,
                                          TEEC_VALUE_OUTPUT, TEEC_NONE);
    teec_op.params[0].value.a = num1
    teec_op.params[1].value.a = num2;

    teec_res = TEEC_InvokeCommand(&teec_sess, 0, &teec_op, NULL);
    if (teec_res != TEEC_SUCCESS) {
        TEEC_CloseSession(&teec_sess);
        TEEC_FinalizeContext(&teec_ctx);
        return teec_res;
    }

    *result = teec_op.params[2].value.a;

    TEEC_CloseSession(&teec_sess);
    TEEC_FinalizeContext(&teec_ctx);

    return TEEC_SUCCESS;
}

int main(void) {
    TEE_Result tee_res;
    uint32_t num1 = 5, num2 = 10, result;
    tee_res = CA_AddNumbers(num1, num2, &result)
    if (tee_res != TEEC_SUCCESS) {
        printf("Error: Failed to add numbers (%x)\n", tee_res);
        return 1;
    }

    printf("Result: %d\n", result);

    return 0;
}        

The above code defines a simple function called `CA_AddNumbers` that uses the TEE Client API to communicate with the TA and add two input numbers. The `main` function simply calls `CA_AddNumbers` and prints the result.


General sequence diagram that shows the flow of communication between a CA (Client Application) and a TA (Trusted Application):

? ? ? ? ?CA? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?TA
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? ?TA_CreateEntryPoint()? ? ? ? ? ? ? ? ? |
? ? ? ? ? |--------------------------------------------->|
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? ? ? ? TA_GetEntryPointUUID()? ? ? ? ? ? |
? ? ? ? ? |--------------------------------------------->|
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? ? ? ? TA_ExportEntryPoint()? ? ? ? ? ? ?|
? ? ? ? ? |--------------------------------------------->|
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? ? ? ? TA_InitializeEntryPoint()? ? ? ?  |
? ? ? ? ? |--------------------------------------------->|
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? ? ? ? TA_OpenSession()? ? ? ? ? ? ? ? ? |
? ? ? ? ? |<---------------------------------------------|
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? TA_InvokeCommand()? ? ? ? ? ? ? ? ? ? ??|
? ? ? ? ? |--------------------------------------------->|
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? ?TA_CloseSession()? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |<---------------------------------------------|
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? ?TA_FinalizeEntryPoint()? ? ? ? ? ? ? ? |
? ? ? ? ? |<---------------------------------------------|
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |        

  1. The CA first calls the TA_CreateEntryPoint() API to create an instance of the TA.
  2. The CA then calls the TA_GetEntryPointUUID() API to retrieve the UUID of the TA.
  3. The CA then calls the TA_ExportEntryPoint() API to export the TA's public key and other metadata.
  4. The CA then calls the TA_InitializeEntryPoint() API to initialize the TA instance.
  5. The CA then calls the TA_OpenSession() API to establish a session with the TA.
  6. The CA then calls the TA_InvokeCommand() API to execute a command on the TA.
  7. The TA processes the command and returns a response to the CA.
  8. The CA then calls the TA_CloseSession() API to close the session with the TA.
  9. The CA finally calls the TA_FinalizeEntryPoint() API to finalize the TA instance.

The communication flow between the TA and the CA happens as follows:

1. The CA calls `CA_AddNumbers` and passes in two input numbers and a pointer to an output parameter.

2. `CA_AddNumbers` initializes the TEE Client API and opens a session with the TA using the TA's UUID.

3. `CA_AddNumbers` sets up a TEEC_Operation with the input and output parameters, and invokes the TA function `TA_AddNumbers` using TEEC_InvokeCommand.

4. `TA_AddNumbers` adds the two input numbers and returns the result in an output parameter.

5. The output parameter is read by `CA_AddNumbers` and returned to the `main` function, which prints the result.


Note that in a real-world scenario, the TA would typically provide more complex functionality and the CA would need to perform more error handling and parameter validation. The above code is intended only as a simple example to demonstrate the basic communication flow between a TA and a CA using OP-TEE OS.

Compilation Steps:

To compile the above code, you'll need to install the OP-TEE OS development environment on your system. This typically involves downloading the OP-TEE OS source code, configuring and building it, and installing the necessary toolchains and dependencies.

Below are optee build components:

No alt text provided for this image

Link for Optee:


Once you have a working OP-TEE OS development environment, you can compile the code by running the following commands in a terminal:

$ arm-linux-gnueabihf-gcc -I<OPTEE-OS-INC-DIR> -c ca.c -o ca.o
$ arm-linux-gnueabihf-gcc -I<OPTEE-OS-INC-DIR> -c ta.c -o ta.o
$ arm-linux-gnueabihf-gcc -I<OPTEE-OS-INC-DIR> -o ca ca.o -L<OPTEE-OS-LIB-DIR> -lteec
$ arm-linux-gnueabihf-gcc -I<OPTEE-OS-INC-DIR> -o ta ta.o -L<OPTEE-OS-LIB-DIR> -lteec -L<OPTEE-OS-LIB-DIR> -lutee        

Replace <OPTEE-OS-INC-DIR> and <OPTEE-OS-LIB-DIR> with the paths to your OP-TEE OS include and library directories, respectively.

The output of the above code should be:

Result: 15         

This is the result of adding the two input numbers (5 and 10) in the TA function TA_AddNumbers. The result is returned to the CA function CA_AddNumbers, which prints it to the console.

BTW what is UUID?

UUID (Universally Unique Identifier) is a 128-bit value used to uniquely identify an entity or object in computer systems. In the context of Trusted Execution Environments (TEEs), UUIDs are used to identify trusted applications (TAs) and to establish communication between the client application (CA) and the TA.

When a TA is created, it is assigned a UUID that is unique across all TAs on the system. This UUID is used by the CA to identify the TA and establish a session with it. The UUID is stored in the TA's binary file and is typically specified in the TA's manifest file.

It is important to choose a UUID carefully to ensure that it is unique and does not conflict with other UUIDs in the system. One common approach is to use a UUID generator tool, such as uuidgen on Linux, to generate a random UUID. Another approach is to use a UUID namespace, such as the one defined by the Internet Engineering Task Force (IETF), to generate a UUID that is guaranteed to be unique within the namespace.

Here is an example of how to generate a UUID using uuidgen on Linux:

$ uuidgen b5db2d5a-0bb4-4d4f-b81a-2ee39ca41742         

Once a UUID has been generated or chosen, it should be included in the TA's manifest file, which is used by the TEE to register the TA and make it available to the CA. The manifest file typically includes information about the TA, such as its UUID, name, version, and required permissions.

Here is an example of a TA manifest file that includes a UUID:

{
    "uuid": "b5db2d5a-0bb4-4d4f-b81a-2ee39ca41742",
    "name": "example-ta",
    "author": "Amit Nadiger",
    "version": "1.0",
    "description": "An example trusted application",
    "config": {},
    "properties": {},
    "commands": [
        {
            "name": "example_command",
            "description": "An example command",
            "uuid": "b5db2d5a-0bb4-4d4f-b81a-2ee39ca41742",
            "types": [
                "value-input",
                "value-input",
                "value-output",
                "none"
            ]
        }
    ],
    "default_permission": "false"
}        

In this example, the uuid field specifies the UUID of the TA, and the commands field specifies the UUID of the command that can be invoked by the CA. When the TA is loaded by the TEE, it registers itself using the UUID specified in the manifest file, making it available for the CA to connect to and invoke its commands.

What is A Trusted Application's (TA) manifest file

A Trusted Application's (TA) manifest file is a JSON-formatted file that contains information about the TA, such as its UUID, name, version, and required permissions. The manifest file is required by the Trusted Execution Environment (TEE) to register the TA and make it available to the Client Application (CA).

The manifest file is typically included in the TA's binary package and is installed along with the TA when it is loaded into the TEE. When the TEE starts up, it reads the manifest files of all installed TAs and registers them, making their commands available for the CA to invoke.

The manifest file serves several important purposes:

  1. Identifying the TA: The UUID field in the manifest file uniquely identifies the TA, allowing the TEE to distinguish it from other TAs on the system.
  2. Providing metadata: The name, version, and description fields in the manifest file provide metadata about the TA, making it easier for the CA and other developers to understand what the TA does and how it can be used.
  3. Specifying permissions: The manifest file can specify the permissions that the TA requires to function properly. For example, a TA that provides cryptographic functions may require access to the device's hardware cryptography module.
  4. Defining commands: The manifest file can define the commands that the TA supports, including their names, descriptions, and input/output parameters. This information is used by the CA to invoke the appropriate command on the TA.

How the OP-TEE OS authenticates and checks integrity of TAs when loading in to TEE?

The OP-TEE OS needs to be compiled along with the normal OS that runs on the device. The normal OS acts as the Rich Execution Environment (REE) and communicates with the Trusted Execution Environment (TEE) provided by the OP-TEE OS through a set of secure interfaces.

Regarding the authenticity and integrity check of TA with OP-TEE OS, the TA needs to be signed using a private key that corresponds to a public key stored in the OP-TEE OS. This ensures that only trusted TAs are loaded into the TEE and executed. The signature is verified by the OP-TEE OS during the TA loading process.

The process of verifying the authenticity and integrity of a TA involves several steps:

  1. Compilation of TA: The TA source code is compiled into a binary format that is compatible with the OP-TEE OS.
  2. Signing of TA: The TA binary is signed using a private key that corresponds to a public key stored in the OP-TEE OS. The signature is generated using a digital signature algorithm such as RSA or ECC.
  3. Verification of TA signature: During the TA loading process, the OP-TEE OS checks the signature of the TA using the public key stored in its secure storage. If the signature is valid, the TA is loaded into the TEE. If the signature is invalid, the TA is rejected and not loaded into the TEE.
  4. Measurement of TA: The OP-TEE OS also measures the TA binary to ensure its integrity. This involves calculating a cryptographic hash of the TA binary and comparing it with a pre-defined hash value stored in the OP-TEE OS. If the two hash values match, the TA is considered to be intact and trustworthy.

How sharing of key pair happens between op-tee os and TA developer?

The process of sharing the public key between the TA developer and the OP-TEE OS involves several steps:

  1. Generate a key pair: The TA developer generates a key pair consisting of a private key and a corresponding public key. The private key is kept secret and used to sign TAs, while the public key is shared with the OP-TEE OS.
  2. Include public key in TA manifest file: The TA developer includes the public key in the TA manifest file. This allows the OP-TEE OS to verify the authenticity of the TA during the loading process.
  3. Install public key on device: The TA developer provides the public key to the device manufacturer or system administrator, who installs it on the device as part of the OP-TEE OS installation process. The public key is stored securely in the OP-TEE OS.
  4. Sign TA with private key: The TA developer signs the TA binary with the private key. This generates a digital signature that can be verified by the OP-TEE OS using the public key.
  5. Load TA into OP-TEE OS: The TA developer provides the signed TA binary to the device manufacturer or system administrator, who loads it into the OP-TEE OS. During the loading process, the OP-TEE OS verifies the signature using the public key and loads the TA into the TEE if the signature is valid.

It's important to note that the private key should be kept secure and not shared with anyone else, as it is used to sign TAs and is an essential component of the authentication process. The public key, on the other hand, can be shared freely with anyone who needs to verify the authenticity of the TA.

Advantages of OP-TEE:

  1. Security: OP-TEE provides a secure execution environment that is isolated from the normal operating system and applications running on the platform, ensuring that sensitive data and processes are protected from potential attacks.
  2. Flexibility: OP-TEE is designed to be highly portable and can run on a wide range of hardware platforms, making it a flexible and versatile solution for building secure systems on a variety of embedded and mobile devices.
  3. Open-source: OP-TEE is an open-source project, which means that the source code is freely available and can be audited and modified by anyone. This promotes transparency and allows for community collaboration and improvement.
  4. Compatibility: OP-TEE is designed to be compatible with the GlobalPlatform TEE specification, ensuring interoperability with other TEE-enabled devices and systems.

Disadvantages of OP-TEE:

  1. Performance: Running code in a secure environment can have an impact on performance, as it requires additional processing and overhead to ensure the security of the system. This can lead to slower execution times and increased power consumption.
  2. Complexity: Developing and deploying applications for a TEE can be more complex than traditional application development, as it requires specialized knowledge and tools.
  3. Limited resources: TEEs typically have limited resources, such as memory and processing power, which can constrain the functionality and performance of applications running within them.
  4. Integration: Integrating a TEE into an existing system can be challenging, as it requires modifications to the underlying hardware and software infrastructure.

OP-TEE limitations,:

  1. Limited hardware support: While OP-TEE is designed to be portable and run on a variety of hardware platforms, it may not be compatible with all hardware configurations. This can limit its use in certain applications or devices.
  2. Resource constraints: TEEs typically have limited resources, such as memory and processing power. This can limit the functionality and performance of applications running within them.
  3. Limited ecosystem: The use of TEEs is still relatively new, and there is a limited ecosystem of tools and resources available for developing and deploying TEE-based applications. This can make it challenging for developers to adopt and use OP-TEE in their projects.
  4. Integration challenges: Integrating a TEE into an existing system can be challenging, as it requires modifications to the underlying hardware and software infrastructure. This can be time-consuming and expensive, particularly in complex systems.
  5. Security vulnerabilities: While OP-TEE is designed to provide a secure execution environment, it is not immune to security vulnerabilities. As with any software, there is always a risk of security breaches or attacks, and developers must take steps to mitigate these risks.


Thanks for reading till end ! Please let me know if you know any other TEE.

References:

Optee documentation: OP-TEE Documentation — OP-TEE documentation documentation (optee.readthedocs.io)

Please see sample apps in below:

optee_examples/hello_world at master · linaro-swg/optee_examples (github.com)

Page not found – Kickstart Embedded

要查看或添加评论,请登录

社区洞察

其他会员也浏览了