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-dev for USB debug port support.

  • openssh-server package for OpenSSL.

  • efitools package for the cert-to-efi-sig-list utility.

  • 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.tbz2

  • Tegra_Linux_Sample-Root-Filesystem_<VERSION>_aarch64.tbz2

  • host_overlay_fskp_tools_<VERSION>_aarch64.tbz2

  • public_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#

  1. Create a directory for your PKC keys:

    cd ~/work_dir
    mkdir pkc_keys
    cd pkc_keys
    
  2. Generate three PKC keys.

    Note

    We recommend that you generate three keys because you can burn keys only once.

  3. 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 the PublicKeyHash fuse data of a fuse configuration file. Assume that the three pubkeyhash values are PUBKEYHASH, PUBKEYHASH_1, and PUBKEYHASH_2 for each <pkc.pem>.

For details on key generation and PublicKeyHash generation, refer to Fuse Configuration File.

Prepare the Fuse Configuration File#

  1. Create your fuse configuration directory and create a fuse.xml file:

    cd ~/work_dir
    mkdir fuse_config
    cd fuse_config
    touch fuse.xml
    
  2. 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"/>
    
  3. 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#

  1. 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 --test with --burn in 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 out folder in <top>/l4t/tools/flashtools/fuseburn.

  2. Burn the fuse.

    1. Set your device to recovery mode:

      cd <top>
      sudo ./tools/board_automation/boardctl -t topo recovery
      
    2. 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 --burn in place of --test, and then proceed with the following command. A fuse blob that you generate with --test is 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#

  1. Create a UEFI keys configuration file. If enrolling an OEM kernel key, ensure that the UEFI_DEFAULT_DB_ESL_1 entry corresponds to the db_1.esl file 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"
    
  2. Generate the UefiDefaultSecurityKeys.dtbo file:

    cd <top>
    sudo ./tools/gen_uefi_keys_dts.sh uefi_keys/uefi_keys.conf
    

Flash the Jetson Orin Device#

  1. Set the device into recovery mode:

    cd <top>
    sudo ./tools/board_automation/boardctl -t topo recovery
    
  2. 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
    
  3. 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.xml example 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.img is 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#

  1. Reset the Jetson Orin device:

    cd <top>
    sudo ./tools/board_automation/boardctl -t topo reset
    
  2. Complete the NVIDIA OOBE on the monitor (attach an HDMI connector) to configure the system and create an account and password.

  3. Log in to your account.

  4. Check whether Secure Boot is enabled. Enter the following commands in the second terminal window.

    • Use mokutil. (If mokutil is missing, install it with sudo 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:

      • 01 indicates Secure Boot enabled.

      • 00 indicates 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:

      • 00 indicates user mode (PK enrolled; Secure Boot is active).

      • 01 indicates setup mode (no PK; Secure Boot is disabled); can accept new keys.

  5. 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-..., and PK-... entries. To dump them, use efi-readvar. (efi-readvar comes from efitools: sudo apt install efitools.)

    sudo efi-readvar -v PK
    sudo efi-readvar -v KEK
    sudo efi-readvar -v db
    sudo efi-readvar -v dbx