Trusty, a Trusted Execution Environment
Applies to: Jetson Xavier NX series, Jetson AGX Xavier series, and Jetson TX2 series devices
Trusty consists of a set of software components for supporting a Trusted Execution Environment (TEE) on mobile devices. TEE provides an execution environment that includes security features to ensure code and data on a device is protected.
Trusty is part of the Android Open Source Project (AOSP). For more information about Trusty and the Trusted Execution Environment, see:
Trusty extends technology made available with the development of the Little Kernel (LK). LK is designed to provide OS primitives like threads and mutexes in a simple, lightweight package.
For more information about Little Kernel, see the LK documentation at:
Trusty is based on ARM® TrustZone Technology. For information about TrustZone, see the white paper at:
http://infocenter.arm.com/help/topic/com.arm.doc.prd29-genc-009492c/PRD29-GENC-009492C_trustzone_security_whitepaper.pdf
Trusty in NVIDIA® Jetson™ Linux Driver Package (L4T) enables booting a Trusted OS on NVIDIA® Jetson Xavier™ NX series, NVIDIA® Jetson AGX Xavier™ series, and NVIDIA® Jetson™ TX2 series devices. The following sections explain how to set up and use Trusty.
This topic uses some terms that are specific to Trusty:
• ATF: ARM Trusted Firmware
• CA: Client Application
• TA: Trusted Application; any application that runs within the Trusty TEE
• TEE: Trusted Execution Environment, the secure environment provided by Trusty for running Trusted Applications
• TOS: Trusted OS; Trusty is the Trusted OS used with L4T
• Trusty: A Trusted OS from the Android Open Source Project; the Trusted OS provided in L4T
Architecture
Trusty 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 mode is known as 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 secure mode enforced by hardware. This mode is known as the “secure world.” Trusty runs in this environment.
The normal world OS and Trusty software operate in a client-server relationship, with Trusty as the server.
The bootloader allocates a dedicated carveout, TZ-DRAM, to run a 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
1. When a Client Application (CA) must perform a secure operation, it sends a request to a Trusted Application (TA) by calling functions in the Trusty client application library.
2. The Trusty client library routes the request to the Trusty Linux Kernel Driver.
3. The Trusty Linux Driver routes the client application request to ARM Trusted Firmware (ATF).
4. A monitor routes the request to the Trusty Kernel.
The L4T monitor implementation is based on ATF. For more information about ATF, see:
5. The Trusty Kernel framework determines which Trusted Application (TA) is to handle the request.
6. The Trusty Kernel framework passes control to the TA to handle the request.
7. Upon completion, execution control returns along the reverse path to the client application, which receives a return value and any processed data.
Trusted Application Development
This section gives instructions for developing Trusted Applications (TAs) that run with Trusty's Trusted Execution Environment (TEE).
Default Trusted Applications
L4T enables three TAs by default:
• sample/ipc-unittest/main
• sample/ipc-unittest/srv
• nvidia-sample/hwkey-agent
The first two TAs constitute a functional testing framework developed as part of the Android Open Source Project (AOSP).
The third TA was developed by NVIDIA to serve as a reference for implementing hardware-backed encrypted keyblobs on Jetson devices. Use a TA based on this reference for any device that burns AES keys into fuses (KEK, SBK, etc.) if the device is to be provisioned with an encrypted blob containing keys or other encrypted content.
Two additional TAs from AOSP are packaged with Trusty, but are disabled by default. These TAs are located in the <TRUSTY_TOP>/trusty/app directory, where <TRUSTY_TOP> is the root directory of the Trusty source package.
Manifests for Trusted Applications
Each Trusted Application must have a corresponding manifest that specifies the TA’s configuration properties. The manifest data structure is:
typedef struct {
uuid_t uuid; /* UUID is the unique identifier for a TA */
uint32_t config_options[];
} trusty_app_manifest_t;
The manifest is defined at:
<TRUSTY_TOP>/trusty/lib/include/trusty_app_manifest.h
Where <TRUSTY_TOP> is the root directory that holds all Trusty code.
Use the manifest to specify configurations such as: stack size, heap size, and map the MMIO address. A UUID generator (
https://www.uuidgenerator.net/) creates the UUID.
This is an example of a TA manifest:
trusty_app_manifest_t TRUSTY_APP_MANIFEST_ATTRS trusty_app_manifest =
{
.uuid = SERVICE_SAMPLE_UUID,
.config_options =
/* optional configuration options here */
{
/* 4 pages for heap */
TRUSTY_APP_CONFIG_MIN_HEAP_SIZE(4 * 4096),
/* 4 pages for stack */
TRUSTY_APP_CONFIG_MIN_STACK_SIZE(4 * 4096),
/* request I/O mappings */
TRUSTY_APP_CONFIG_MAP_MEM(0,
TEGRA_DEVICE_ADDR, TEGRA_DEVICE_ADDR_LEN),
}
};
Accessing MMIO Regions
To access hardware registers, a Trusted Application must map the registers to MMIO regions in the address space.
To access the hardware registers
1. Specify the address regions in the TA manifest file.
2. Specify a unique ID for each mapping in the manifest.
3. Use the system functions mmap() and munmap() to map the address space.
The functions are declared at trusty_calls.h:
long mmap (void* uaddr, uint32_t size, uint32_t flags, uint32_t handle);
long munmap (void* uaddr, uint32_t size);
Direct Memory Access Operations
The Trusty system functions prepare_dma() and finish_dma() perform direct memory access (DMA) operations. The flags argument determines the direction of the DMA and cache operations.
Values for flags are defined at:
<TRUSTY_TOP>/trusty/lk/trusty/include/mm.h
Where <TRUSTY_TOP> is the root directory that holds all Trusty code. The functions are declared in trusty_syscalls.h:
long prepare_dma (void* uaddr, uint32_t size, uint32_t flags, void* pmem);
long finish_dma (void* uaddr, uint32_t size, uint32_t flags);
How to Implement a New Trusted Application
To implement a new trusted application, perform these steps:
1. Place the Trusted Application (TA) source files in a new application directory inside <TRUSTY_TOP>/trusty/app/ (e.g. <TRUSTY_TOP>/trusty/app/my_trusted_app/).
2. Create a TA manifest file.
• Update I/O mappings as needed (optional).
• Declare minimum stack and heap sizes (optional).
3. Add source files in the my_trusted_app/ directory.
Source code for a simple example TA is in the file:
<TRUSTY_TOP>/trusty/app/sample/skel/skel_app.c
4. Create a TA makefile (rules.mk) which specifies the TA's source files, include paths, and module dependencies.
A simple example TA makefile is in:
<TRUSTY_TOP>/trusty/app/sample/skel/rules.mk
5. Add the path of the TA makefile to the list of user tasks, TRUSTY_ALL_USER_TASKS, located in:
<TRUSTY_TOP>/trusty/device/nvidia/t186/project/t186-l4t.mk
Add the line:
TRUSTY_ALL_USER_TASKS += <path_to_app>
Where <path_to_app> is the pathname of the TA relative to the directory <TRUSTY_TOP>/trusty/app.
6. Rebuild Trusty.
Trusty and the TAs have a combined build. Rebuilding Trusty also rebuilds all of the TAs defined in TRUSTY_ALL_USER_TASKS in lk.bin.
Note | To protect the integrity and confidentiality of a Trusted OS binary, NVIDIA strongly recommends you use Secure Boot to both encrypt and sign the TOS image. |
How to Communicate with Other Applications
A TA uses the TIPC protocol to communicate with other TAs or with applications running in the normal world. The protocol is described in the Android documentation for Trusty TEE at:
Trusty API Reference
The Trusty API Reference may be found at:
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, that is, compromising them would have serious consequences. Trusty uses the Encrypted Keyblob (EKB) mechanism to provision keys and other confidential data.
Encrypted Keyblobs
Several specialized terms are used to discuss the EKB feature:
• EKB or EKS: Encrypted keyblob, an encrypted blob which holds developer-defined content.
• Keyslot: A secure storage area inside the Jetson Security Engine (SE). It can protect secure keys from unauthorized reading and writing. During early boot, Bootrom loads secure keys from fuse storage to keyslots so that later, a Trusty application can use SE to derive keys from keyslots.
• KEK2 fuse key: A 128-bit AES key that is burned into the KEK2 fuse. This key is not visible to software, but Trusty utilizes it during boot via the Security Engine (SE) to derive a key called the KEK2 Root key (KEK2_RK).
• KEK2_RK: A 128-bit AES key that is derived from SE KEK2 keyslot. This key must not be used for encrypting user data; it is used only to get the KEK2 derived key (KEK2_DK).
• KEK2_DK: A 128-bit AES key that is derived from KEK2_RK. Trusty 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 for secure key generation. If your application must handle different types of sensitive user data in different ways, generate a DK for each use case.
• EKB_EK: EKB Encryption Key, a 128-bit AES key that is one of KEK2_DKs. It is used only to encrypt and decrypt EKBs.
• EKB_AK: EKB Authentication Key, a 128-bit AES key that is one of KEK2_DKs. It is used only to encrypt and decrypt EKBs.
• FV: Fixed Vector, a fixed 16-byte value which is part of the KEK2_RK key derivation.
• SE: The Jetson Security Engine.
• MB2: The bootloader stage that passes the encrypted EKB contents to the Trusted OS. The boot flow executes MB2 before the Trusted OS initializes.
Note | For security, these keyslots must be cleared immediately after Trusty 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 be accessible to the Trusted OS. You can use EKB 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:
EKB Header (16 bytes) | EKB Content Ciphertext |
An EKB binary is often called eks.img, which is the name 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 (4 bytes) | Magic (8 bytes) | Reserved (4 bytes) |
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. There are no restrictions on it, although it is intended to hold encrypted keys or similar data.
Any data in the EKB content section is accessible to a Trusty TA during device boot. It is not visible to 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 TA in Trusty 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 KEK2 fuse key burned into the device’s KEK2 fuse.
A later section describes the operations behind the formula in more detail.
1. Define a format for the EKB content and generate the EKB content in plaintext.
2. Generate a 128-bit symmetric KEK2 fuse key.
3. Burn the KEK2 fuse key into the device's KEK2 fuse. For more information about the fuses, see the
Fuse Specification App Note for your Jetson device.
4. 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.
5. Compute KEK2_RK using AES ECB encryption according to the formula:
KEK2_RK = AES − 128 − ECB(FV, KEK2 fuse key)
6. Follow the NIST-SP-800-108 KDF recommendation to derive KEK2_DK. This value of KEK2_DK is to be used as EKB_EK.
7. Encrypt the EKB content plaintext with EKB_EK, using the desired crypto algorithm to obtain the EKB content ciphertext.
8. Append the EKB header to the EKB content ciphertext as described in the section
Encrypted Keyblob Format. The resulting file is a fully generated EKB binary.
9. 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 TA inside Trusty performs the following steps:
10. Ensures that the FV in the TA matches the FV used to derive KEK2_RK.
11. Requests the Security Engine (SE) to derive the KEK2_RK with the formula:
KEK2_RK = AES − 128 − ECB(FV, KEK2 fuse key)
12. Derives KEK2_DK (also called EKB_EK) following NIST-SP-800-108 KDF.
13. Maps the EKB content ciphertext into the TA’s memory. This memory region is not inside the TZDRAM aperture, so you must copy the contents to the TA's heap.
14. Decrypts the EKB content with EKB_EK using the chosen crypto algorithm to obtain plaintext. (There is no native crypto library in Trusty, so you must choose and import a crypto library.)
15. Utilizes the EKB content plaintext as desired within the TA.
The following diagram shows the process of EKB decryption.
SE Keyslot Clearing
After Trusty derives EKB_EK from the KEK2_RK that was derived from the KEK2 keyslot, there is no longer a need for the KEK2 fuse key to persist in the keyslot. NVIDIA strongly recommends that the key be wiped from the keyslot to prevent any component from utilizing it after the device boots.
The hwkey-agent TA demonstrates the keyslot clearing procedure. NVIDIA recommends that you use the se_clear_aes_keyslots() function provided in the hwkey-agent TA. This function clears several keyslots as a security precaution.
SE Usage
TAs inside Trusty must use SE only during boot. Using SE from Trusty 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 two secure sample applications, a CA and a TA. The CA helps users to encrypt or decrypt data with two different types of keys in the TA. The TA extracts the user-defined key from the EKB and derives another key, the Secure Storage Derived Key (SSK-derived key), from the SE SSK keyslot.
The SSK-derived key is unique on each Jetson Xavier NX series, Jetson AGX Xavier series, and Jetson TX2 series device. Once the data is encrypted with that key, it is bound to that device. In contrast, the user-defined key is the same for each device. The CA can decide which key to use in to perform cryptographic operations in each case.
The following diagram describes scenarios that apply to the secure sample applications.
Client Application: hwkey-app
The client application (CA) is a command-line program that illustrates how to encrypt and decrypt data with the key in trusted application (TA). It offers the user two options:
• Use the user-defined key stored in the EKB with the OpenSSL library in the TA.
• Use the SSK in the SSK keyslot of the hardware Security Engine (SE).The application uses the tegra-crypto library to perform cryptographic operations with the SE.
This option is disabled by default; you must enable it manually.
The CA has two major functional areas:
• OPENSSL_CRYPTO: Performs cryptographic operations with the user-defined key in the EKB, using the OpenSSL library in the TA.
• TEGRA_SE_CRYPTO: Performs cryptographic operations with the SSK in a keyslot, using the tegra-crypto library in the CA.
Trusted Application: hwkey-agent
The TA is a background service, started at boot time, which performs key management for two keys: a user-defined key in the EKB, and an SSK-derived key. It uses cryptographic services from the OpenSSL library.
The TA has two major functional areas:
• Key maintenance for the user-defined key and the SSK-derived key.
The TA derives the SSK-derived key (SSK_DK) from the SSK keyslot in the same way that it derives KEK2_DK from the KEK2 keyslot. This demonstrates how to derive keys from keyslots for security purposes. You can use the same procedure to derive an SSK_DK for your own needs.
• OPENSSL_CRYPTO: Provides an interface that can receive an IPC request with parameters that specify:
• Whether to encrypt or decrypt
• A data buffer containing the plaintext to be encrypted or the ciphertext to be decrypted
The TA uses the user-defined key by default. To use the SE with the SSK keyslot you must enable it manually.
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 the user-defined key in the EKB.
An EKB that holds one key looks like this:
EKB_header (16 bytes) | EKB_cmac (16 bytes) | Random_IV (16 bytes) | EKB ciphertext (16 bytes) |
The fields in the EKB are:
• EKB header: A 16‑byte EKB header.
• EKB_cmac: An authentication code based on the AES-CMAC algorithm. This 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:
EKB_header (16 bytes) | EKB_cmac_1 (16 bytes) | Random_IV_1 (16 bytes) | EKB ciphertext (16 bytes) | |
| | |
| | EKB_cmac_2 (16 bytes) | Random_IV_2 (16 bytes) | EKB ciphertext 2 (16 bytes) | |
| · · · | |
| | EKB_cmac_n (16 bytes) | Random_IV_ n (16 bytes) | EKB ciphertext n (16 bytes) |
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 Trusty runs. Because software cannot read it 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) and use that for further crypto operations.
Thus, there are two steps to getting a DK from a fuse key:
1. RK = AES-ECB-128(fuse key, FV)
2. 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 need different keys. NVIDIA strongly recommends using different keys for different purposes, using the KDF can be used to derive multiple keys.
This outline describes the flow of KDF generation of fuse keys:
1. FV (Fixed Vector).
Generate the FV with a random number generator. NVIDIA recommends using /dev/random or /dev/urandom.
This command generates a 16-byte random number and displays it in hexadecimal:
$ 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 from the KEK2 keyslot.
• FV_for_ssk_dk: Used to derive an RK for SSK_DK from an SSK keyslot.
2. RKs (Root Keys): Derived by the formulas:
KEK2_RK_for_ekb = AES-128-ECB(KEK2 keyslot, FV_for_ekb)
SSK_RK = AES-128-ECB(SSK keyslot, FV_for_ssk_dk)
3. DKs (Derived Keys): Derived by the formulas:
EKB_EK = NIST-SP-800-108(KEK2_RK_for_ekb, ...)
EKB_AK = NIST-SP-800-108(KEK2_RK_for_ekb, ...)
SSK_DK = NIST-SP-800-108(SSK_RK, ...)
Pseudocode for NIST-SP-800-108
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, output=&KO[count*128]);
}
}
Where:
• KI is a 128-bit input key
• KO is a 128-bit output key
• L is 128, the bit length of KO.
• context_string and label_string have the values shown in this table:
For derived key | context_string | label_string |
EKB_EK | "ekb" | "encryption" |
EKB_AK | "ekb" | "authentication" |
SSK_DK | "ssk" | "derivedkey" |
EKB Generation
As shown in the figure under
Key Maintenance and EKBs, the sample applications’ EKB layout is intended to help you design a mechanism that is secure enough to protect your private data in EKB blob. The sample applications store a user-defined key in the EKB. 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.
1. EKB ciphertext = AES-128-CBC(IV=Random_IV, Key=EKB_EK, EKB plain text)
• Random_IV is the initial vector to be used to generate a new EKB blob.
• EKB plain text is a user-defined key in plaintext.
2. EKB_cmac is the authentication code that will be used to verify if 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)
3. 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.
1. Compute the CMAC:
AES-CMAC_verify(EKB_cmac, Key=EKB_AK, EKB_content)
2. Compare the computed CMAC to the CMAC in the EKB. If they match, proceed.
3. Compute the EKB plaintext:
EKB_plaintext = AES-128-CBC_decrypt(IV=Random_IV, Key=EKB_EK, EKB_ciphertext)
Tool for EKB Generation
Before generating the EKB blob, refer to the
Secure Boot topic for information about burning keys into fuses, including the KEK2 fuse, and the secure boot requirements for using Trusty on Jetson devices.
As
KDF of Fuse Keys explains, you can generate the fixed vector (FV) or the user-defined key with a command line that runs the
openssl tool. You can generate these items separately and store them in different files.
Note that FVs must be the same for EKB extraction as for EKB generation. Exercise due caution to keep the FVs confidential.
This example shows how to run the EKB generation tool:
$ python3 gen_ekb.py -kek2_key <kek2_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.
• <fv_for_ekb_ek> is a fixed vector (FV) for deriving an RK from the KEK2 fuse. It must be the same as the FV used in hwkey-agent to derive the KEK2 RK for EKB encryption and decryption.
• <sym_key_file> is the kernel encryption key.
• <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.
EKB Extraction Sample
For an example of how to perform EKB extraction, see the source code for the hwkey-agent trusted application.
Hardware Random Number Generator Function
Many use cases need a secure random number source for key or password generation, network protocols, cryptographic processes, etc. Jetson processors provides a hardware-based random number source through in Linux device node /dev/random (which blocks until the kernel has accumulated enough entropic data to return the requested amount of random data) or /dev/urandom (which does not block).
Trusty provides an alternative source in the secure world, the Trusty random number generator (RNG). It is compliant with the NIST-SP 800-90 a/b/c draft specifications. It can reseed itself, and generates numbers that are truly random and uniformly distributed over the range of results.
A TA can provide an RNG service that the CA or other TAs can communicate with it to acquire random numbers.
This diagram shows the architecture of the Trusty RNG and how random numbers can be extracted from the secure world.
The service model of the RNG function is:
• During TA initialization the hwkey-agent TA creates the rng-srv service, an IPC channel that can receive and return random number requests from other applications.
• Other applications in either the normal or the secure world can request random numbers from rng-srv by initializing an IPC channel to extract random numbers from the hwkey-agent TA.
The Trusty source code includes a sample function named get_random() which returns random numbers obtained in this way. See the source file at $TRUSTY_TOP/app/nvidia-sample/hwkey-agent/CA_sample/hwkey-app.c.
rng-srv uses the hardware security engine (SE) RNG1 to generate random numbers. These numbers are compliant with the NIST-SP 800-90 a/b/c draft specifications.
An RNG IPC packet’s definition is:
#define RNG_SRV_DATA_SIZE 2048
typedef struct rng_srv_msg {
uint32_t rng_size;
uint8_t rng_data[RNG_SRV_DATA_SIZE];
};
The maximum length of random numbers the RNG function can return is 2048 bytes. If you need random numbers that are longer than that, query multiple times and concatenate the results to the length you need.
AES-256 Hardware Key Derivation Function in Trusty OS
A Jetson Linux trusted OS (TOS) has a hardware-based Key Derivation Function (KDF) which you can use to derive keys from the Key Encryption Key (ODM KEK) fuses.
Flow of the AES-256 Hardware KDF
This diagram shows the flow of key derivation from the ODM KEK fuse.
You can address and load the ODM KEK fuses KEK0 and KEK1 as separate 128‑bit fuses or as a single 256‑bit fuse, as shown in this table:
ODM KEK fuses related to Secure Boot Jetson Xavier NX series, Jetson AGX Xavier series, and Jetson TX2 series devices |
Bit size | Name | Key slot | Default value set by odmfuse.sh |
128 | KEK0 | 13 | Four 32‑bit registers named KEK00 through KEK03. |
128 | KEK1 | 12 | Four 32‑bit registers named KEK10 through KEK13. |
256 | KEK256 | 13 | Not a distinct fuse; addresses KEK0 and KEK1 as a single 256‑bit fuse. |
128 | KEK2 | 11 | Four 32‑bit registers named KEK20 through KEK23. |
The BctKEKKeySelect flag in the BootROM Boot Configuration Table (BR-BCT) determines how BootROM loads KEK0 and KEK1 into the Security Engine (SE) keyslot(s):
• If the flag is set to 0, BootROM loads the KEK0 and KEK1 fuses as two 128‑bit keys.
• If the flag is set to 1, BootROM loads the fuses as a single 256‑bit key.
BootROM loads the BR BCT from a configuration file that is stored in the directory at ${Linux_for_Tegra_folder}/bootloader/t186ref/BCT/. The file’s name is:
• For Jetson Xavier NX series: tegra194-br-bct-qspi.cfg
• For Jetson AGX Xavier series: tegra194-br-bct-sdmmc.cfg
• For Jetson TX2 series: emmc.cfg
To set the flag to 1, for example:
BctKEKKeySelect = 1;
After BootROM identifies the key provision source from a setting in BR BCT, you can use the hardware-based NIST-SP 800-108 KDF to derive keys from the ODM KEK fuse. The KDF generates the derived keys.
The odmfuse.sh script can use the options --KEK0 and --KEK1 to burn KEK0 and KEK1 as separate 128-bit keys, or the option --KEK256 to burn them as a single 256-bit key.
API Functions
Jetson Linux supports two APIs for hardware-based random number generation.
The hardware-based AES-CMAC functions are very similar to those in the
OpenSSL CMAC implementation. See
Hardware-Based AES-CMAC Functions for details.
The NIST 800-108 key definition functions implement the counter-mode KDF as defined in NIST-SP 800-108. See
NIST 800-108 Key Definition Functions for details.