Quick Start Guide to Enable Secure Boot for Jetson Orin#
This guide describes how to enable Secure Boot on a Jetson Orin device, covering environment setup, key generation, fuse burning, EKB image preparation, UEFI key enrollment, QSPI signing and flashing, and OS installation.
Environment Setup#
To follow this guide, we recommend opening two terminal windows:
Use one terminal window on your host machine to run commands.
Use another terminal window to monitor the Jetson Orin UART output:
sudo minicom -D /dev/ttyACM0 -w -c on
Requirements#
The following steps must be performed on a Linux host machine (Ubuntu 22.04 or later).
The following software packages are required:
libftdi-devfor USB debug port support.openssh-serverpackage for OpenSSL.efitoolspackage for thecert-to-efi-sig-listutility.Full installation of the latest Jetson Linux release on the host.
A USB cable connecting the USB-C port of the Jetson Orin device to the host.
If necessary, a USB cable that connects the USB micro-B port to the host.
You also need a full installation of the latest Jetson Linux release:
Jetson_Linux_<VERSION>_aarch64.tbz2Tegra_Linux_Sample-Root-Filesystem_<VERSION>_aarch64.tbz2host_overlay_fskp_tools_<VERSION>_aarch64.tbz2public_sources.tbz2
Note
The current released version (<VERSION>) is R39.2.0.
Create a working directory on your host machine:
mkdir ~/work_dir
cd ~/work_dir
Download the BSP packages into ~/work_dir, and then unzip and install them as follows:
# Execute the following commands in ~/work_dir
tar -xpvf ./Jetson_Linux_<VERSION>_aarch64.tbz2
sudo tar -xpf ./Tegra_Linux_Sample-Root-Filesystem_<VERSION>_aarch64.tbz2 -C \
Linux_for_Tegra/rootfs/
tar -xvjf ./host_overlay_fskp_tools_<VERSION>_aarch64.tbz2
tar -xvf ./public_sources.tbz2
tar -xvf ./Linux_for_Tegra/source/nvidia-jetson-optee-source.tbz2 -C \
Linux_for_Tegra/source/
cd Linux_for_Tegra/
sudo ./apply_binaries.sh
sudo ./tools/l4t_flash_prerequisites.sh
Throughout the rest of this guide, we refer to the Linux_for_Tegra directory as <top>.
Some utilities must be run from this parent directory and are denoted with <top> in the
command path.
Pre-UEFI#
Pre-UEFI includes low-level firmware boot components like MB1, MB2, and CPU bootloader UEFI. Secure Boot at this level is ensured through fuses, so you need to prepare a fuse configuration file that contains keys and other settings to enable Secure Boot, convert the file into a fuseblob, and then burn the fuseblob to the device.
Preparing the PKC Keys#
Create a directory for your PKC keys:
cd ~/work_dir mkdir pkc_keys cd pkc_keys
Generate three PKC keys.
Note
We recommend that you generate three keys because you can burn keys only once.
Generate the PKC hash to use in the fuse blob using
tegrasign_v3.py:sudo <top>/bootloader/tegrasign_v3.py --pubkeyhash <pkc.pubkey> <pkc.hash> --key <pkc.pem>
<pkc.pem>is the input PKC key pair (.pem) file.<pkc.pubkey>is the output public key of the<pkc.pem>key pair.<pkc.hash>is the output public key hash of the<pkc.pem>key pair.
The hexadecimal value shown on the screen after
tegra-fuse format (big-endian):can be used directly as thePublicKeyHashfuse data of a fuse configuration file. Assume that the threepubkeyhashvalues arePUBKEYHASH,PUBKEYHASH_1, andPUBKEYHASH_2for each<pkc.pem>.
For details on key generation and PublicKeyHash generation, refer to Fuse Configuration File.
Prepare the Fuse Configuration File#
Create your fuse configuration directory and create a
fuse.xmlfile:cd ~/work_dir mkdir fuse_config cd fuse_config touch fuse.xml
In
fuse.xml, register the PKC hash as shown:<fuse name="PublicKeyHash" size="64" value="PUBKEYHASH"/> <fuse name="PkcPubkeyHash1" size="64" value="PUBKEYHASH_1"/> <fuse name="PkcPubkeyHash2" size="64" value="PUBKEYHASH_2"/>
Fill in other fuse values as shown in the example
fuse.xml. The following XML file enables only signature verification:<genericfuse MagicId="0x45535546" version="1.0.0"> <fuse name="PscOdmStatic" size="4" value="0x00000060"/> <fuse name="OemK1" size="32" value="0xf3bedbff9cea44c05b08124e8242a71ec1871d55ef4841eb4e59a56b5f88fb2b"/> <fuse name="OemK2" size="32" value="0x76d723099bc81a39cfc8bd109deb7ef39aa1d0f5ab4658180ad33e1d983a2e84"/> <fuse name="PublicKeyHash" size="64" value="0xad2474627c14e3f7f4944a832bd15d0640938a3dc162f558692458f3d12f9453e11bea2ec75df3f83e8b29c47fc3d2483d528d3e94a5469c4ba1ec61f1584b23"/> <fuse name="PkcPubkeyHash1" size="64" value="0xd87796fb510d79738f8509c98511be0bb79dcc17d204a2f0f0bea9680b91bd1273ee2ae7a8a6bdb8b95deb0f421e72404939ae20d12c82649712283027201f39"/> <fuse name="PkcPubkeyHash2" size="64" value="0x99a5b6eac64dfb29698cb684165529e5d8650c1aab0e18b677c5d5f0998af53f8a8a1f09ad1d79368bc500e57eb199e9108fc7b1499995d869b028fec3f367db"/> <fuse name="OptInEnable" size="4" value="0x1"/> <!-- Bits[2:0]=001:RSA3K --> <fuse name="BootSecurityInfo" size="4" value="0x2be1"/> <fuse name="SecurityMode" size="4" value="0x1"/> </genericfuse>
The following is a sample fuse.xml file for enabling encryption and signature verification.
<genericfuse MagicId="0x45535546" version="1.0.0">
<fuse name="PscOdmStatic" size="4" value="0x00000060"/>
<fuse name="OemK1" size="32" value="0xf3bedbff9cea44c05b08124e8242a71ec1871d55ef4841eb4e59a56b5f88fb2b"/>
<fuse name="OemK2" size="32" value="0x76d723099bc81a39cfc8bd109deb7ef39aa1d0f5ab4658180ad33e1d983a2e84"/>
<fuse name="PublicKeyHash" size="64" value="0xad2474627c14e3f7f4944a832bd15d0640938a3dc162f558692458f3d12f9453e11bea2ec75df3f83e8b29c47fc3d2483d528d3e94a5469c4ba1ec61f1584b23"/>
<fuse name="PkcPubkeyHash1" size="64" value="0xd87796fb510d79738f8509c98511be0bb79dcc17d204a2f0f0bea9680b91bd1273ee2ae7a8a6bdb8b95deb0f421e72404939ae20d12c82649712283027201f39"/>
<fuse name="PkcPubkeyHash2" size="64" value="0x99a5b6eac64dfb29698cb684165529e5d8650c1aab0e18b677c5d5f0998af53f8a8a1f09ad1d79368bc500e57eb199e9108fc7b1499995d869b028fec3f367db"/>
<fuse name="SecureBootKey" size="32" value="0x123456789abcdef0fedcba987654321023456789abcdef01edcba9876543210f"/>
<fuse name="OptInEnable" size="4" value="0x1"/>
<!-- Bits[2:0]=001:RSA3K; Bit[3]=1:SBK Encryption enable -->
<fuse name="BootSecurityInfo" size="4" value="0x2be9"/>
<fuse name="SecurityMode" size="4" value="0x1"/>
</genericfuse>
Note
In new versions of Jetson AGX Orin, Jetson Orin NX and Jetson Orin Nano, the bits[8:5] of the fuse BootSecurityInfo are burned in advance.
Fuse the Board#
Generate your fuse blob.
Note
In this Quick Start guide, we demonstrate generating a fuse blob without using an FSKP key. The resulting fuse blob is unencrypted. You can use this method to fuse the board for experiment or development purposes.
To fuse for production, we recommend generating an encrypted fuse blob by using an FSKP key. For more information, refer to Factory Secure Key and Expansion Key Provisioning.
Note
The following command generates a dry-run fuse blob. If you use this dry-run fuse blob when executing step 2 (burn the fuse), the fuse blob is sent to the device but not actually burned.
To prepare a fuse blob that can be burned to the device, replace
--testwith--burnin the following command.For Jetson AGX Orin
cd <top>/l4t/tools/flashtools/fuseburn sudo ./fskp_fuseburn.py --board-spec orin-agx-board-spec.txt \ -f ~/work_dir/fuse_config/fuse.xml --skipfskpkey --test \ -g out/ -c 0x23 -B <top>/jetson-agx-orin-devkit.conf
For Jetson Orin NX
cd <top>/l4t/tools/flashtools/fuseburn sudo ./fskp_fuseburn.py --board-spec orinnx-board-spec.txt \ -f ~/work_dir/fuse_config/fuse.xml --skipfskpkey -test \ -g out/ -c 0x23 -B <top>/jetson-orin-nano-devkit.conf
For Jetson Orin Nano
cd <top>/l4t/tools/flashtools/fuseburn sudo ./fskp_fuseburn.py --board-spec orinnano-board-spec.txt \ -f ~/work_dir/fuse_config/fuse.xml --skipfskpkey -test \ -g out/ -c 0x23 -B <top>/jetson-orin-nano-devkit.conf
Select No when prompted for continuation of the board fusing. You should now have an
outfolder in<top>/l4t/tools/flashtools/fuseburn.Burn the fuse.
Set your device to recovery mode:
cd <top> sudo ./tools/board_automation/boardctl -t topo recovery
Run the following commands to send the pre-generated fuse blob and trigger the fuse burning process:
Caution
Fuse burning is irreversible and permanently modifies your board. To actually burn the fuses, regenerate the fuse blob in step 1 (generate your fuse blob) with
--burnin place of--test, and then proceed with the following command. A fuse blob that you generate with--testis sent to the device but no fuses are burned.For Jetson AGX Orin
cd <top>/l4t/tools/flashtools/fuseburn sudo ./fskp_fuseburn.py --board-spec orin-agx-board-spec.txt -P out/ \ -c 0x23 -B <top>/jetson-agx-orin-devkit.conf
For Jetson Orin NX
cd <top>/l4t/tools/flashtools/fuseburn sudo ./fskp_fuseburn.py --board-spec orinnx-board-spec.txt -P out/ \ -c 0x23 -B <top>/jetson-orin-nano-devkit.conf
For Jetson Orin Nano
cd <top>/l4t/tools/flashtools/fuseburn sudo ./fskp_fuseburn.py --board-spec orinnano-board-spec.txt -P out/ \ -c 0x23 -B <top>/jetson-orin-nano-devkit.conf
Select Yes when prompted to continue. You can verify a successful dry run or fuse burn by checking the UART output of the board for a confirmation message in the second terminal window.
Preparing the EKB Image#
To generate the EKB image, you need to use the OemK1 key that you have just burned to the
fuse. The oem_k1.key is the value that is burned to the OemK1 fuse and is used to encrypt and sign the EKB.
The sym_t234.key is a 32-byte UEFI payload encryption key file.
The auth_t234.key is a 16-byte UEFI variable authentication key file. For more information, refer to UEFI Variable Protection.
cd <top>/source/optee/samples/hwkey-agent/host/tool/gen_ekb
### Fill OemK1 fused content that is burned in the previous step as oem_k1.key
echo "f3bedbff9cea44c05b08124e8242a71ec1871d55ef4841eb4e59a56b5f88fb2b" >oem_k1.key
### Generate a random number to sym_t234.key
openssl rand -rand /dev/urandom -hex 32 >sym_t234.key
### Generate a random number to auth_t234.key
openssl rand -rand /dev/urandom -hex 16 >auth_t234.key
python3 gen_ekb.py -chip t234 \
-oem_k1_key oem_k1.key \
-in_sym_key sym_t234.key \
-in_auth_key auth_t234.key \
-out eks_t234.img
### Copy the newly generated image into <top>/bootloader
sudo cp eks_t234.img <top>/bootloader/
For more details on these steps, refer to EKB Generation.
Secure UEFI#
Enable UEFI Secure Boot to ensure that the UEFI payload signature—specifically, the OS loader—is verified prior to execution.
Prepare UEFI Keys#
To generate the PK, KEK, and db RSA key pairs, their certificates, and the EFI signature list files, run the following commands:
cd <top>
mkdir uefi_keys
cd uefi_keys
GUID=$(uuidgen)
### Generate PK RSA Key Pair, Certificate, and EFI Signature List File
openssl req -newkey rsa:2048 -nodes -keyout PK.key -new -x509 -sha256 -days 3650 -subj \
"/CN=my Platform Key/" -out PK.crt
cert-to-efi-sig-list -g "${GUID}" PK.crt PK.esl
### Generate KEK RSA Key Pair, Certificate, and EFI Signature List File
openssl req -newkey rsa:2048 -nodes -keyout KEK.key -new -x509 -sha256 -days 3650 -subj \
"/CN=my Key Exchange Key/" -out KEK.crt
cert-to-efi-sig-list -g "${GUID}" KEK.crt KEK.esl
### Generate db_1 RSA Key Pair, Certificate, and EFI Signature List File
openssl req -newkey rsa:2048 -nodes -keyout db_1.key -new -x509 -sha256 -days 3650 -subj \
"/CN=my Signature Database key/" -out db_1.crt
cert-to-efi-sig-list -g "${GUID}" db_1.crt db_1.esl
### Generate db_2 RSA Key Pair, Certificate, and EFI Signature List File
openssl req -newkey rsa:2048 -nodes -keyout db_2.key -new -x509 -sha256 -days 3650 -subj \
"/CN=my another Signature Database key/" -out db_2.crt
cert-to-efi-sig-list -g "${GUID}" db_2.crt db_2.esl
Create UEFI Keys and Enroll Keys to Key Configuration File#
Create a UEFI keys configuration file. If enrolling an OEM kernel key, ensure that the
UEFI_DEFAULT_DB_ESL_1entry corresponds to thedb_1.eslfile generated in the Prepare UEFI Keys section:cd <top>/uefi_keys vim uefi_keys.conf
Insert the following lines:
UEFI_DB_1_KEY_FILE="db_1.key"; # UEFI payload signing key UEFI_DB_1_CERT_FILE="db_1.crt"; # UEFI payload signing key certificate UEFI_DEFAULT_PK_ESL="PK.esl" UEFI_DEFAULT_KEK_ESL_0="KEK.esl" UEFI_DEFAULT_DB_ESL_0="db_1.esl" UEFI_DEFAULT_DB_ESL_1="db_2.esl"
Generate the
UefiDefaultSecurityKeys.dtbofile:cd <top> sudo ./tools/gen_uefi_keys_dts.sh uefi_keys/uefi_keys.conf
Flash the Jetson Orin Device#
Set the device into recovery mode:
cd <top> sudo ./tools/board_automation/boardctl -t topo recovery
Verify that the device has successfully rebooted into recovery mode by listing your USB devices on your host machine and confirming that the NVIDIA device is listed as described in Environment Setup:
lsusb
Flash the Jetson device:
For Jetson AGX Orin
To use internal EMMC as rootfs storage, run the following command:
cd <top> sudo ./l4t_initrd_flash.sh -u <pkc_keyfile> [-v <sbk_keyfile>] \ --uefi-keys uefi_keys/uefi_keys.conf [--uefi-enc <uefi_enc.key>] \ --showlogs --network usb0 \ jetson-agx-orin-devkit internal
To use an external NVMe drive as rootfs storage, run the following command:
cd <top> sudo ./l4t_initrd_flash.sh -u <pkc_keyfile> [-v <sbk_keyfile>] \ --uefi-keys uefi_keys/uefi_keys.conf [--uefi-enc <uefi_enc.key>] \ --external-device nvme0n1p1 -c ./tools/kernel_flash/flash_l4t_t234_nvme.xml \ -p "-c ./bootloader/generic/cfg/flash_t234_qspi.xml" \ --showlogs --network usb0 \ jetson-agx-orin-devkit external
For Jetson Orin NX or Jetson Orin Nano
To use an external NVMe drive as rootfs storage, run the following command:
cd <top> sudo ./l4t_initrd_flash.sh -u <pkc_keyfile> [-v <sbk_keyfile>] \ --uefi-keys uefi_keys/uefi_keys.conf [--uefi-enc <uefi_enc.key>] \ --external-device nvme0n1p1 -c ./tools/kernel_flash/flash_l4t_t234_nvme.xml \ -p "-c ./bootloader/generic/cfg/flash_t234_qspi.xml" \ --showlogs --network usb0 \ jetson-orin-nano-devkit external
The optional flags are required only under specific provisioning conditions:
Flag
When Required
Key File Contents
-v <sbk_keyfile>Device image is SBK-protected (encryption enabled), as in the second
fuse.xmlexample shown in Prepare the Fuse Configuration File. Omit for non-SBK/non-encrypted devices.The Secure Boot Key (SBK) binary/key file matching the device’s fused keys.
--uefi-enc <uefi_enc.key>eks_t234.imgis generated with-in_sym_key <sym_t234.key>specified. Refer to Preparing the EKB Image.Must be the same value as
sym_t234.key.
Reboot the Jetson Orin Device#
Reset the Jetson Orin device:
cd <top> sudo ./tools/board_automation/boardctl -t topo reset
Complete the NVIDIA OOBE on the monitor (attach an HDMI connector) to configure the system and create an account and password.
Log in to your account.
Check whether Secure Boot is enabled. Enter the following commands in the second terminal window.
Use
mokutil. (Ifmokutilis missing, install it withsudo apt install mokutil.)sudo mokutil --sb-state
The output is one of the following messages:
SecureBoot enabled
SecureBoot disabled
This system doesn’t support Secure Boot
The expected output is “SecureBoot enabled.”
Read the EFI variable directly:
sudo od -An -tx1 /sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c
The output is five bytes:
XX XX XX XX YY. The last byte (YY) is what matters:01indicates Secure Boot enabled.00indicates Secure Boot disabled.
Also check SetupMode:
sudo od -An -tx1 /sys/firmware/efi/efivars/SetupMode-8be4df61-93ca-11d2-aa0d-00e098032b8c
Examine the last byte of the output:
00indicates user mode (PK enrolled; Secure Boot is active).01indicates setup mode (no PK; Secure Boot is disabled); can accept new keys.
Verify that the enrolled keys are actually present:
ls /sys/firmware/efi/efivars/ | grep -E '^(PK|KEK|db|dbx)-'
The expected output is similar to the following:
db-d719b2cb-3d3a-4596-a3bc-dad00e67656f dbx-d719b2cb-3d3a-4596-a3bc-dad00e67656f KEK-8be4df61-93ca-11d2-aa0d-00e098032b8c PK-8be4df61-93ca-11d2-aa0d-00e098032b8c
You should see
db...,KEK-..., andPK-...entries. To dump them, useefi-readvar. (efi-readvarcomes fromefitools:sudo apt install efitools.)sudo efi-readvar -v PK sudo efi-readvar -v KEK sudo efi-readvar -v db sudo efi-readvar -v dbx