OP-TEE: Open Portable Trusted Execution Environment
Applies to the Jetson AGX Orin series, the Jetson Orin NX series, and the Jetson Orin Nano series.
Open Portable Trusted Execution Environment (OP-TEE) is an open-source trusted execution environment (TEE) based on Arm® TrustZone® technology, created by trustedfirmware.org, and maintained by Linaro.
The overall framework of OP-TEE combines with two major components: optee_os, which is the trusted side of the TEE (the secure world), and optee_client, which is the untrusted, or “normal,” side of the TEE (the normal world).
optee_os
is a TEE operating system running at ARMv8 secure EL-1 level. It provides generic OS-level functions
like interrupt handling, thread handling, crypto services, and shared memory. It implements the
GlobalPlatform
TEE Internal Core API.
You can use this API to build Trusted Applications (TAs) that run in the secure world at ARMv8 secure EL-0 level.
optee_client
has two components: a normal world user space library, and a normal world user space daemon.
The library libteec.so
implements the GlobalPlatform TEE Client API,
which defines the interface with which normal world Client Applications (CAs) communicate with the TA in the secure world.
The daemon tee-supplicant
implements some miscellaneous features for TrustedOS, for example, file system access
to load the TAs from the normal world file system into the secure world.
OP-TEE Documentation is available on the Web. The documentation source files are in ReStructuredText (RST) format, and are available from the OPTEE/optee_docs project on GitHub.
The OP-TEE project also provides a sanity test suite,
optee_test,
which offers thousands of tests, collectively known as xtest
. See the optee_test
project itself and the
optee_test documentation
for more information.
OP-TEE in Jetson Linux
OP-TEE in NVIDIA® Jetson™ Linux enables you to boot OP-TEE on supported Jetson devices. The following sections explain how to set up and use OP-TEE.
This topic uses some terms that are specific to trusted applications and OP-TEE in particular:
ATF: Arm Trusted Firmware.
CA: Client Application.
TA: Trusted Application; any application that runs within OP-TEE.
TEE: Trusted Execution Environment, the secure environment provided by OP-TEE for running trusted applications.
TOS: An acronym for “Trusted OS.” OP-TEE is a TOS supported by Jetson Linux.
Architecture
OP-TEE resides in a separate storage partition and boots as part of a chain of trust or a secure boot sequence. It creates two environments in a device with different security modes:
Non-Secure Environment (NSE): An environment for running software components in non-secure mode. This environment constitutes the “normal world.” A rich OS, such as Linux, typically runs in this environment.
Trusted Execution Environment (TEE): A separate environment that provides trusted operations and runs in a secure mode enforced by hardware. This environment constitutes the “secure world.” OP-TEE runs in this environment.
The normal world OS and OP-TEE software operate in a client-server relationship, with OP-TEE as the server.
Bootloader allocates a dedicated carveout, TZ-DRAM, to run OP-TEE or another secure OS. All secure operations are initiated by a client application running in the non-secure environment. A trusted application, in the secure world, never initiates contact with the non-secure environment.
This diagram shows the relationships among the components:
Execution Steps
When a client application (CA) must perform a secure operation, it sends a request to a trusted application (TA) by calling functions in the TEE Client API library.
The TEE Client API library routes the request to the OP-TEE Linux Kernel Driver.
The OP-TEE Linux Driver routes the client application request to Arm Trusted Firmware (ATF).
A monitor routes the request to the OP-TEE OS.
The Jetson Linux monitor implementation is based on ATF. For more information about ATF, see the Trusted Firmware A (TF-A).
The OP-TEE OS framework determines which trusted application (TA) is to handle the request.
The OP-TEE OS framework passes control to the TA to handle the request.
Upon completion, execution control returns along the reverse path to the client application, which receives a return value and any processed data.
Trusted Application and Client Application Development
This section gives a brief overview of the OP-TEE Trusted Application and Client Application (TA/CA) architecture.
The OP-TEE TA/CA is a client-server model that follows the GlobalPlatform TEE API. The Client Application uses the TEE Client API to invoke the Trusted Application service in the secure world. The Trusted Application implements the functions defined by TEE Internal Core API Specification.
This diagram shows a simplified working model of the OP-TEE TA/CA and the APIs that the TAs must implement to support the model.
Shared Memory is a memory block which the OP-TEE framework uses internally to communicate data between CAs in the non-secure world and TAs in the secure world. See the hello_world sample application in GitHub for a working example.
How to Cross Compiling a Trusted Application and Run it on Jetson Devices
Download the appropriate Jetson-Linux toolchain from Jetson release page (https://developer.nvidia.com/embedded/jetson-linux-archive).
Create a folder and extract the toolchain in this folder:
mkdir jetson-toolchain
cd jetson-toolchain
tar xf <bootlin toolchain gcc 9.3 package>
Download the appropriate Jetson-Linux BSP source package from Jetson release page (https://developer.nvidia.com/embedded/jetson-linux-archive).
Create a folder, extract the BSP source package in this folder, and extract the nvidia-jetson-optee-source.tbz2 file.
mkdir jetson-public-srcs
cd jetson-public-srcs
tar xf <public_sources.tbz2>
cd Linux_for_Tegra/source
mkdir jetson-optee-srcs
cd jetson-optee-srcs
tar xf ../nvidia-jetson-optee-source.tbz2
To build the OP-TEE components (including the OP-TEE image, optee_client, and optee_test files), complete the steps in the
atf_and_optee_README.txt
file. This file is a part of thenvidia-jetson-optee-source.tbz2
file. ATF and TOS image building is only needed when plan to change the Jetson OP-TEE.
Note
You need to build the Jetson OP-TEE source package because the user CA and TA building requires the optee_client
and optee_os
header files and configurations.
Run the following command to build your trusted application.
make -C <source directory> \
CROSS_COMPILE="<jetson-toolchain>/bin/aarch64-buildroot-linux-gnu-" \
TA_DEV_KIT_DIR="<jetson-optee-srcs>/optee/build/t234/export-ta_arm64/" \
OPTEE_CLIENT_EXPORT="<jetson-optee-srcs>/optee/install/t234/usr" \
TEEC_EXPORT="<jetson-optee-srcs>/optee/install/t234/usr" \
-j"$(nproc)"
Copy the CA to the
/usr/sbin
directory of your Jetson device.Copy the TA to the
/lib/optee_armtz
directory of your Jetson device.You can now run the CA. When the CA requests services from the TA, OP-TEE automatically loads the TA from
/lib/optee_armtz
.
How to Implement a New Trusted Application or Port an Existing One
Every TA must conform to a structure determined by the TA/CA model, and when you design a new TA, it must conform too. See the
Trusted Applications
section of the OP-TEE official documentation for a detailed description with a hello_world
example. This section explains useful concepts and shows you how to create and set up
a TA step by step from the beginning of the process through TA signing and encryption.
To port an existing TA from another TOS to OP-TEE, you must replace the application’s original API calls with calls to the GlobalPlatform TEE API. For example, a Trusty TA uses IPC to handle low-level message communication between the TA and CAs. For OP-TEE functions in both TA and CA sides. To operate with OP-TEE it must use an RPC (Remote Procedure Call) function instead. See the GlobalPlatform API section of the OP-TEE documentation for information about the API the client uses. Other Trusty API calls must be replaced by other OP-TEE Internal Core API calls.
There are two groups of cryptographic functions you may use. The GlobalPlatform TEE Internal Core API provides procedures for using the cryptographic functions
provided by optee_os
. Alternatively,you may use the
MbedTLS library,
which is bundled with optee_os
. If the original TA already uses one of these groups of functions, no conversion is needed.
Types of Trusted Applications
There are two types of TAs, user mode TAs and pseudo TAs (PTAs). See the Trusted Applications section in the “Architecture” chapter of the OP-TEE official documentation for a more detailed description. Jetson Linux provides secure sample apps for both types.
A user mode TA runs as a secure application in ARMv8 S-EL0 mode, which is the user space layer of the secure world. It gets OS services exclusively by calling the GlobalPlatform TEE Internal Core API. When you implement a new TA or port an existing TA from another TEE, it is of this type.
A pseudo TA runs in ARMv8 S-EL1 mode, which is the OS layer of the secure world. Running in this layer, a pseudo TA cannot use the GlobalPlatform TEE Internal Core API. If you need a specific secure function that the API does not provide, you can implement it in a pseudo TA and export it as a function to user mode TAs. For example, you can implement pseudo TAs to provide user mode TAs with access to hardware drivers.
Key Derivation Function of a Fuse Key and User-Defined Key
Different security functions often need different types of keys to encrypt and decrypt data. These keys usually are confidential and sensitive, and compromising them would have serious consequences. Jetson Linux with OP-TEE uses the Encrypted Keyblob (EKB) mechanism to provision keys and other confidential data.
Encrypted Keyblobs
We need several specialized terms to discuss the EKB mechanism:
EKB or EKS: Encrypted keyblob, an encrypted blob that holds developer-defined content.
Keyslot: A secure storage area in the Jetson Security Engine (SE) that protects the secure keys from unauthorized reading and writing.
For the Jetson AGX Orin series, the Jetson Orin NX series, and the Jetson Orin Nano series, during the early boot, PSC-BL1 () loads the secure keys from fuse storage to the keyslots so that an OP-TEE application can use SE later to derive the keys from the keyslots.
EKB fuse key: An AES key that is burned into a fuse.
This key is not visible to the software, but OP-TEE uses it during boot through the SE to derive
EKB_RK
, which is the EKB Root Key. For the Jetson AGX Orin series, the Jetson Orin NX series, and the Jetson Orin Nano series, this key has 256 bits and can be burned into theOEM_K1
fuse or theOEM_K2
fuse. We recommend that you use theOEM_K1
fuse as the EKB fuse key.EKB_RK: A 128-bit AES key that is derived from the
EKB fuse key
.This key must not be used for encrypting user data, because it is used only to get the EKB-derived keys (
EKB_DK
).EKB_DK: A 128-bit AES key that is derived from
EKB_RK
.OP-TEE uses a Key Derivation Function (KDF) that follows NIST-SP-800-108 to derive the key.
NVIDIA strongly recommends that you use the same KDF as OP-TEE uses. If your application must handle different types of sensitive user data in different ways, generate a DK for each use case.
EKB_EK: An EKB Encryption Key.
This 128-bit AES key is one of EKB_DKs and is used only to encrypt and decrypt EKBs.
EKB_AK: An EKB Authentication Key.
This 128-bit AES key is one of EKB_DKs and is used only to authenticate the EKB content.
FV: A Fixed Vector that has a fixed 16-byte value and is part of the
EKB_RK
key derivation.SE: The Jetson Security Engine.
MB2: The Bootloader stage that passes the encrypted EKB contents to OP-TEE. The boot flow executes MB2 before the Trusted OS is initialized.
Note
For security, these SE keyslots must be cleared immediately after OP-TEE uses them.
Encrypted Keyblob Overview
A common use case for a Trusted OS is managing secret keys. Such keys
often must be provisioned on the device in a secure manner and must be
accessible to the Trusted OS. You can use the EKB mechanism to accomplish this. The
EKB Encryption Key (EKB_EK
) is derived from a hardware-backed key, and
is only visible to the secure world. The EKB content is visible in
plaintext only to the secure world.
Encrypted Keyblob Format
The encrypted keyblob (EKB) format is designed to be as generic as
possible, giving you full control of the actual keyblob structure. An
EKB binary (an .img
file) has a 16-byte EKB header that is prefixed to
an EKB blob’s contents:
An EKB binary is often called “eks.img
,” which is the filename of the EKB binary that is flashed to the EKS partition by default.
EKB Header
EKB header information is consumed by the MB2 bootloader. It must match the following layout:
EKB_size
is the length of the EKB binary starting from the Magic
field.
EKB_size
is four bytes long, in little endian format. Its value must be
4 less than the length of the EKB binary in bytes.
Magic
is eight bytes long, and must contain the exact string "NVEKBP\0\0"
.
Reserved
contains four unused bytes. NVIDIA recommends that these bytes be set to binary zero.
EKB Content
EKB content is completely implementation-defined. It is intended to hold encrypted keys or similar data, but there are no restrictions on it.
Any data in the EKB content section is accessible to an OP-TEE PTA during device boot. It is not visible in the normal world as plaintext.
EKB Binary Size Restrictions
For security reasons, an EKB binary must be at least 1024 bytes long. It may not exceed the EKS partition size. If an EKB binary’s size is not in this range, flashing fails.
If you have very little EKB content, pad the EKB binary to a length of at least 1024 bytes. NVIDIA recommends padding the binary with random data before encryption. The PTA in OP-TEE decrypts the entire binary, then discards the padding.
Encrypted Keyblob Generation and Device Provisioning
NVIDIA recommends that the EKB content be encrypted with a 128-bit symmetric key that is derived from a hardware-backed fuse key.
A later section describes the operations behind the recommended key derivation formula in more detail.
Define a format for the EKB content and generate the EKB content in plaintext.
Generate a symmetric key as an EKB fuse key. For the Jetson AGX Orin series, the Jetson Orin NX series, and the Jetson Orin Nano series, the key size must be 256 bits.
Burn the EKB fuse key into the device’s fuse.
For the Jetson AGX Orin series, Jetson Orin NX series, and Jetson Orin Nano series, the fuse is OEM_K1 or OEM_K2.
For more information about the fuses, see the Fuse Specification Application Note for your Jetson device.
For more information, see the topic Secure Boot.
Change the Fixed Vector (FV) constant to a randomly generated value. (This step is not required, but NVIDIA recommends it.)
The default FV is
0xbad66eb4484983684b992fe54a648bb8
.Compute
EKB_RK
by using AES ECB encryption based on the following formula:EKB_RK = AES − 128 − ECB(FV, EKB fuse key)
Follow the NIST-SP-800-108 KDF recommendation to derive
EKB_DK
, and this value will be used asEKB_EK
.Encrypt the EKB content plaintext with
EKB_EK
, using the desired crypto algorithm to obtain the EKB content ciphertext.Append the EKB header to the EKB content ciphertext as described in Encrypted Keyblob Format. The resulting file is a fully generated EKB binary.
Flash the EKB binary to the Jetson device’s EKS partition.
This flow diagram illustrates the EKB generation process:
Encrypted Keyblob Decryption
During boot, a PTA inside OP-TEE performs the following steps:
Ensures that the FV in the PTA matches the FV used to derive
EKB_RK
.Requests the SE to derive the EKB_RK with the following formula:
EKB_RK = AES − 128 − ECB(FV, EKB fuse key)
Derives EKB_DK (also known as EKB_EK) following the NIST-SP-800-108 KDF.
Maps the EKB content ciphertext into the TA’s memory. This memory region is not inside the TZDRAM aperture, so if you want to retain the EKB, you must copy the contents to the PTA’s heap.
Decrypts the EKB content with EKB_EK using the chosen crypto algorithm to obtain plaintext.
Utilizes the EKB content plaintext as desired within the PTA.
The following diagram shows the process of EKB decryption.
SE Keyslot Clearing
After a PTA in OP-TEE derives EKB_EK from the EKB_RK that was derived from the EKB fuse key, the EKB fuse key no longer needs to persist in the keyslot. To prevent a component from using this key after the device boots, NVIDIA strongly recommends that you wipe the key from the keyslot.
The jetson_user_key
PTA demonstrates the keyslot clearing procedure. NVIDIA
recommends that you use the tegra_se_clear_aes_keyslots()
function provided
by the SE
driver. This function clears several keyslots as a security precaution.
SE Usage
PTAs inside OP-TEE must use the SE only during boot. Using the SE from OP-TEE after boot may cause a system crash because there is no guarantee that the SE clocks are enabled. This means that EKB_EK must be derived and the keyslot must be cleared during boot. After booting you must utilize EKB_EK through a software crypto library.
Secure Samples
The diagram below shows an overview of secure sample applications. There are:
A PTA,
jetson_user_key_pta
in the OP-TEE OSTwo TAs,
hwkey-agent
andlusk-srv
, with corresponding CAs in the normal world user space
Refer to Disk Encryption for more information about the luks-srv
application.
Sample Pseudo Trusted Application: jetson_user_key_pta
This TA is an OP-TEE OS layer PTA. It is bundled with OP-TEE OS to export interfaces of key management functions and hardware services (the random number generator, or RNG) to user space TAs.
The PTA’s internals show how to derive keys from the SE keyslot. and derive other keys for different security purposes.
jetson_user_key_pta Derived Root Keys
This PTA’s derived root keys are:
ekb_rk
: The derived root key from the EKB fuse key with AES-ECB-KDF.This key is used with EKB encryption, decryption, and authentication.
ssk_rk
: A per-device unique key. The derived root key is derived from this key, and so is per-device unique as well. You can use it to encrypt data that is bound to the device. The sample PTA does does not use this key, but only shows how to derive it.demo_256_rk
: A key that the PTA derives to show how to use the hardware-based NIST-SP 800-108 KDF to derive a 256-bit key from a 256-bit SE keyslot. The PTA does not use this key.user_sym_keys
: User-defined symmetric keys stored in the EKB. The PTA shows how to extract these keys from the EKB using the derived keys from EKB fuse key.
Later topics describe the key derivation process and key usages in detail.
jetson_user_key_pta Service Interfaces
Before you study this PTA’s service interfaces, you should know how GlobalPlatform TEE API defines the application communication interface and flow. This pattern applies to communications between TA and TA, TA and PTA, and CA and TA.
A user space TA uses
TEE_OpenTASession
to initialize a session with the PTA. The session needs the PTA’sUUID
as input to know which PTA to communicate with.After the session is created, the TA uses
TEE_InvokeTACommand
with a command ID and parameters stored in the structureTEE_Param
to invoke the service in the PTA.The
TEE_Param
structure can store two types of data, value or memory reference pointer.
See also checking TA parameters in the official OP-TEE documentation.
For security reasons, the keys should not be allowed to leave the secure world. Only the PTA services can be accessed by user space TAs.
This code block shows the service interfaces provided by jetson_user_key_pta
.
/*
* Each trusted app UUID should have a unique UUID that is
* generated from a UUID generator such as
* https://www.uuidgenerator.net/
*
* UUID : {e9e156e8-e161-4c8a-91a9-0bba5e247ee8}
*/
#define JETSON_USER_KEY_UUID \
{ 0xe9e156e8, 0xe161, 0x4c8a, \
{0x91, 0xa9, 0x0b, 0xba, 0x5e, 0x24, 0x7e, 0xe8} }
/*
* JETSON_USER_KEY_CMD_GET_EKB_KEY - Query the EKB key
* param[0] in (value) a: EKB key index
* param[1] out (memref) key buffer, key size
* param[2] unused
* param[3] unused
*/
#define JETSON_USER_KEY_CMD_GET_EKB_KEY 0
/*
* EKB user symmetric keys.
*/
typedef enum {
EKB_USER_KEY_KERNEL_ENCRYPTION,
EKB_USER_KEY_DISK_ENCRYPTION,
EKB_USER_KEYS_NUM,
} ekb_key_index_t;
/*
* JETSON_USER_KEY_CMD_GET_RANDOM - Get random bytes from RNG
* param[0] out (memref) RNG data, RNG size
* param[1] unused
* param[2] unused
* param[3] unused
*/
#define JETSON_USER_KEY_CMD_GET_RANDOM 1
/*
* JETSON_USER_KEY_CMD_GEN_UNIQUE_KEY_BY_EKB - Generate a unique key by EKB key
* param[0] in (value) a: EKB key index
* param[1] in (memref) label string, length
* param[2] out (memref) key, size
* param[3] unused
*/
#define JETSON_USER_KEY_CMD_GEN_UNIQUE_KEY_BY_EKB 2
/*
* JETSON_USER_KEY_CMD_GEN_KEY - Generate a key by a input key
* param[0] in (memref) input key, size
* param[1] in (memref) context string, length
* param[2] in (memref) label string, length
* param[3] out (memref) output key, size
*/
#define JETSON_USER_KEY_CMD_GEN_KEY 3
#define LUKS_SRV_FLAG (1U << 0)
#define PTA_SRV_FLAG (1U << 31)
/*
* JETSON_USER_KEY_CMD_GET_FLAG - Get the service flag
* param[0] in (value) a: flag
* param[1] out (value) a: flag status
* param[2] unused
* param[3] unused
*/
#define JETSON_USER_KEY_CMD_GET_FLAG 4
/*
* JETSON_USER_KEY_CMD_SET_FLAG - Set the service flag
* param[0] in (value) a: flag, b: flag status
* param[1] unused
* param[2] unused
* param[3] unused
*/
#define JETSON_USER_KEY_CMD_SET_FLAG 5
hwkey-agent Trusted Application
This TA is a user space TA that provides two functions:
Data encryption and decryption by EKB key. The TA queries the user-defined EKB key from
jetson_user_key_pta
and uses the key to encrypt or decrypt data from a CA.Get random number from the hardware RNG (random number generator).
The hardware RNG is accessed through
jetson_user_key_pta()
. The query from CA will be bypassed to the PTA.The hardware RNG is compliant with the NIST-SP 800-90 a/b/c draft specifications. It can reseed itself and generate numbers that are truly random and uniformly distributed over the range of results.
This code block shows the service interfaces provided by hwkey-agent
TA.
/*
* Each trusted app UUID should have a unique UUID that is
* generated from a UUID generator such as
* https://www.uuidgenerator.net/
*
* UUID : {82154947-c1bc-4bdf-b89d-04f93c0ea97c}
*/
#define HWKEY_AGENT_TA_UUID \
{ 0x82154947, 0xc1bc, 0x4bdf, \
{ 0xb8, 0x9d, 0x04, 0xf9, 0x3c, 0x0e, 0xa9, 0x7c} }
/*
* HWKEY_AGENT_TA_CMD_ENCRYPTION - Data encryption by EKB USER KEY
* param[0] in (memref) IV data, IV size
* param[1] in (memref) payload, payload size
* param[2] out (memref) output_buf, output_buf size
* param[3] unused
*/
#define HWKEY_AGENT_TA_CMD_ENCRYPTION 0
/*
* HWKEY_AGENT_TA_CMD_DECRYPTION - Data decryption by EKB USER KEY
* param[0] in (memref) IV data, IV size
* param[1] in (memref) payload, payload size
* param[2] out (memref) output_buf, output_buf size
* param[3] unused
*/
#define HWKEY_AGENT_TA_CMD_DECRYPTION 1
/*
* HWKEY_AGENT_TA_CMD_GET_RANDOM - Get random bytes from RNG
* param[0] out (memref) RNG data, RNG size
* param[1] unused
* param[2] unused
* param[3] unused
*/
#define HWKEY_AGENT_TA_CMD_GET_RANDOM 2
nvhwkey-app Client Application
This CA is a command-line program that illustrates how to encrypt and decrypt data with a user-defined key in an EKB and query a random number from the secure world.
Key Maintenance and EKBs
One important purpose of the sample applications is to demonstrate secure techniques for deriving keys from hardware-based fuse keys, using them for different purposes, and securing a user-defined key in the EKB.
An EKB that holds one key looks like this:
The fields in the EKB are:
EKB header: A 16-byte EKB header.
EKB_cmac
: An authentication code based on the AES-CMAC algorithm. It is used to authenticate the EKB content of Random_IV and the EKB ciphertext.Random_IV
: A random initial vector that is used for EKB content encryption and decryption.EKB ciphertext: The encrypted user-defined key.
You can add additional keys to an EKB by adding additional sets of
(EKB_cmac
, Random_IV
, EKB ciphertext) fields. You can do this by
extending the script (see
Tool for EKB Generation)
to support additional keys. Then the EKB layout looks like this:
In use, the TA uses EKB_AK
to authenticate the EKB. Only if
authentication succeeds, confirming that the EKB has not been modified,
does it decrypt the EKB ciphertext.
KDF of Fuse Keys
The fuse keys are loaded into keyslots during an early boot stage, before OP-TEE runs. Because software cannot read them back from the keyslots, a TA can only derive the keys from the keyslots through the AES-ECB algorithm. With the derivation key from SE, it is called the Root Key (RK). An RK is not used directly for crypto operations. Use the NIST-SP-800-108 KDF recommendation to derive a Derived Key (DK) from the RK and a random fixed vector (FV), and use the DK for further crypto operations.
Thus, there are two steps to getting a DK from a fuse key:
RK = AES-ECB-128(fuse key, FV)
DK = NIST-SP-800-108(RK)
The sample applications use a counter mode KDF described in NIST-SP-800-108 with a CMAC pseudo-random function (PRF).
A production application typically has multiple use cases that each need a key. NVIDIA strongly recommends using a different key for each use case. Use the KDF to derive as many keys as are needed.
This outline describes the flow of KDF generation of fuse keys:
FVs (fixed vectors), generated with a random number generator. NVIDIA recommends using
/dev/random
or/dev/urandom
.This command generates a 16-byte random number and saves it in hexadecimal form:
$ openssl rand -rand /dev/urandom -hex 16 > iv_hex_file
The sample applications require two FVs:
FV_for_ekb
: Used to derive an RK for EKB.FV_for_ssk_dk
: Used to derive an RK for SSK_DK from an SSK keyslot.
RKs (Root Keys), derived by the formulas:
RK_for_ekb = AES-128-ECB(EKB fuse key keyslot, FV_for_ekb)
SSK_RK = AES-128-ECB(SSK keyslot, FV_for_ssk_dk)
DKs (Derived Keys), derived by the formulas:
EKB_EK = NIST-SP-800-108(EKB_RK_for_ekb, …)
EKB_AK = NIST-SP-800-108(EKB_RK_for_ekb, …)
SSK_DK = NIST-SP-800-108(SSK_RK, …)
Pseudocode for NIST-SP-800-108
This pseudocode describes the NIST-SP-800-108 algorithm:
NIST-SP-800-108(KI, KO, L, context_string, label_string) {
uint8_t count = 0x01;
for (count=0x01; count<=L/128; count++) {
AES-128-CMAC(key=KI, count || label_string || 0x00 || context_string || L, output=&KO[count*128]);
}
}
Where:
KI
is a 128-bit or 256-bit input keyKO
is a output keyL
is multiple of 128, the bit length of KO.context_string
andlabel_string
have the values shown in this table:
For derived key |
context_string |
label_string |
---|---|---|
|
“ekb” |
“encryption” |
|
“ekb” |
“authentication” |
|
“ssk” |
“derivedkey” |
EKB Generation
The sample applications’ EKB layout is intended to help you design a mechanism that is secure enough to protect your private data in an EKB blob. The sample applications store a user-defined key in the EKB. As the figures under Key Maintenance and EKBs show, you can easily extend EKB layout, for example, by adding multiple sections for multiple keys.
NVIDIA strongly recommends that you use the same layout as the sample programs, or replace it with one that you know to be even more secure.
The following outline shows the most logical sequence of operations for creating an EKB:
EKB ciphertext = AES-128-CBC(IV=``Random_IV``, Key=``EKB_EK``, EKB plaintext)
Where:
Random_IV
is the initial vector to be used to generate a new EKB blob.“EKB plaintext” is a user-defined key in plaintext.
EKB_cmac
is the authentication code to be used to determine whether the message had been changed.Compute
EKB_content
(an intermediate result) as:EKB_content
=Random_IV
+EKB_ciphertext
Then compute
EKB_cmac
as:EKB_cmac
= AES-CMAC(Key=``EKB_AK``,EKB_content
)EKB blob = EKB Header +
EKB_cmac
+EKB_content
EKB Extraction
The following outline shows the most logical sequence of operations for extracting information from an EKB. It is essentially the reverse of the process for EKB generation.
Compute the CMAC:
AES-CMAC_verify(
EKB_cmac
, Key=``EKB_AK``,EKB_content
)Compare the computed CMAC to the CMAC in the EKB. If they match, proceed.
Compute the EKB plaintext:
EKB plaintext = AES-128-CBC_decrypt(IV=``Random_IV``, Key=``EKB_EK``,
EKB_ciphertext
)
Tool for EKB Generation
Before you generate the EKB blob, refer to Secure Boot for more information about burning keys into fuses, including the KEK2 and OEM_K1 or OEM_K2 fuses, and the Secure Boot requirements for using OP-TEE on Jetson devices. for information about burning keys into fuses, including the KEK2 and OEM_K1 or OEM_K2 fuses, and the Secure Boot requirements for using OP-TEE on Jetson devices.
As
KDF of Fuse Keys
explains, you can generate the fixed vector (FV) or the user-defined key by running the openssl
tool from the command line. You can generate these items separately and store them in different files.
Note that you must use the same FVs for EKB extraction as for EKB generation. Exercise due caution to keep the FVs confidential.
The following example shows you how to run the EKB generation tool for the Jetson AGX Orin series, Jetson Orin NX series, and Jetson Orin Nano series:
$ python3 gen_ekb.py -chip t234 -oem_k1_key <oem_k1_fuse_key_file> -fv <fv_for_ekb_ek> -in_sym_key \
<sym_key_file> -in sym_key2 <sym2_key_file> -out <eks_image_file>
Where:
<kek2_fuse_key_file>
is the key that is stored in the KEK2 fuse.<oem_k1_fuse_key_file>
is the key that is stored in the OEM_K1 fuse.<fv_for_ekb_ek>
is a FV for deriving an RK from the fuse. It must be the same as the FV used injetson_user_key_pta
to derive the EKB RK for EKB encryption and decryption.<sym_key_file>
is the user encryption key.This is the user encryption key provided by the
--uefi-enc
option in the flash command(refer to Prepare the User Key in the topic Secure Boot for more information) The encryption key must be the same as the one used to encrypt custom-built kernel images. (See the same topic.)
<sym2_key_file>
is the disk encryption key.This key is used in two reference implementations. One is the secure sample implemented by hwkey-agent and hwkey-app. This sample uses the key for data encryption and decryption. In another case, the key is the source key of the key generation of the LUKS key in the disk encryption reference implementation.
<eks_image_file>
is an image file generated from the Encrypted Binary Blob (EKB) file by the EKB generation tool. The output binary blob file is intended to be flashed onto the EKS partition of the device.
Note
For the Jetson AGX Orin series, the Jetson Orin NX series, and the Jetson Orin Nano series, you can copy and substitute <Linux_for_Tegra>/bootloader/eks.img
by using the EKS image you create. To test EKS and key derivation functionalities without burning fuses, if OP-TEE determines that the device has no burned fuses, a test key will be used when OP-TEE boots. The corresponding EKS image for the test key can be generated by example.sh
, which can is in the OP-TEE source package.
EKB Extraction Sample
For an example of how to perform EKB extraction, see the source code for the jetson_user_key_pta
trusted application.
AES-256 Hardware Key Derivation Function in jetson_user_key_pta
A Jetson Linux trusted OS (TOS) has a hardware-based key derivation function (KDF), which you can use to generate derived keys from the Key Encryption Key (ODM KEK) fuses.
API Functions
Jetson OP-TEE OS provides API functions for you to use with your TAs. These APIs are provided in the OS layer and exported to user space TAs via the interface from a PTA.
The Jetson platform provides several API functions for calling the hardware random number generator (RNG).
Hardware Random Number Generator Calls
To call from the hardware RNG driver:
/* * Get random bytes from the SE RNG module * * *data_buf [out] the output of the random data buffer * data_len [in] the length of the random bytes */ TEE_Result tegra_se_rng_get_random(void *data_buf, uint32_t data_len);
You can use this function in the OS layer.
To call via OP-TEE OS hooks to the hardware RNG driver:
/* * crypto_rng_read() - read cryptograhically secure RNG * @buf: Buffer to hold the data * @len: Length of buffer. * * Eventual queued events are also added to their pools during this * function call. */ TEE_Result crypto_rng_read(void *buf, size_t len);
You can also use this function in the OS layer.
The TEE API for a user space TA to query random numbers from the TOS. This hooks to HW RNG as well.
/* Cryptographic Operations API - Random Number Generation Functions */ void TEE_GenerateRandom(void *randomBuffer, uint32_t randomBufferLen);
The user space TA can access the hardware RNG via the interface of command IDs
JETSON_USER_KEY_CMD_GET_RANDOM
throughjetson_user_key_pta
.
Key Definition Function Calls
Key definition function calls implemented by OP-TEE in Jetson Linux are:
The hardware-based NIST-SP 800-108 KDF for OS-layer PTA. This function implements counter-mode KDF with AES-CMAC as the PRF.
/* * A hardware-based NIST-SP 800-108 KDF; * derives keys from the SE keyslot. * * Use this function only during OP-TEE initialization at boot time * (the device boot stage). To derive keys from a key buffer at runtime, * use nist_sp_800_108_cmac_kdf(). * * keyslot [in] the SE keyslot where the key stores. * key_len [in] length in bytes of the input key. * *context [in] a pointer to a NIST-SP 800-108 context string. * *label [in] a pointer to a NIST-SP 800-108 label string. * dk_len [in] length of the derived key in bytes; * may be 16 (128 bits) or any multiple of 16. * *out_dk [out] a pointer to the derived key. The function stores * its result in this location. */ TEE_Result tegra_se_nist_sp_800_108_cmac_kdf(se_aes_keyslot_t keyslot, uint32_t key_len, char const *context, char const *label, uint32_t dk_len, uint8_t *out_dk);
The software-based NIST-SP 800-108 KDF for OS-layer PTA. This function implements counter-mode KDF with AES-CMAC as the PRF.
/* * A software-based NIST-SP 800-108 KDF. * derives keys from a key in a key buffer. * * *key [in] input key for derivation. * key_len [in] length in bytes of the input key. * *context [in] a pointer to a NIST-SP 800-108 context string. * *label [in] a pointer to a NIST-SP 800-108 label string. * dk_len [in] length of the derived key in bytes; * may be 16 (128 bits) or any multiple of 16. * *out_dk [out] a pointer to the derived key. The function stores * its result in this location. */ TEE_Result nist_sp_800_108_cmac_kdf(uint8_t *key, uint32_t key_len, char const *context, char const *label, uint32_t dk_len, uint8_t *out_dk);
The user space TA can access the software-based NIST 800-108 KDF via the interface of command IDs
JETSON_USER_KEY_CMD_GEN_KEY
throughjetson_user_key_pta
.The HW AES-ECB KDF.
/* * SE AES ECB KDF - Derives root key from SE keyslot. * * derived_key [out] pointer of the output buffer of the derived_key. * derived_key_len [in] the length of the derived_key. * iv [in] pointer of the initial vector. * iv_len [in] the length of the initial vector. * keyslot [in] SE keyslot. */ TEE_Result tegra_se_aes_ecb_kdf(uint8_t *derived_key, size_t derived_key_len, uint8_t *iv, size_t iv_len, uint32_t keyslot);