📺 B站视频讲解(Bilibili)https://www.bilibili.com/video/BV1k1C9BYEAB/

📘 《Yocto项目实战教程》京东购买链接Yocto项目实战教程


Jetson Secure Boot:从 PKC/SBK 密钥到熔丝烧录与安全刷机

适用场景:Jetson Orin 系列等支持 Secure Boot 的平台;目标读者为已经熟悉 Linux/Yocto/刷机脚本的嵌入式工程师,希望 真正跑通一次完整的 Secure Boot + PKC + SBK 实战流程


在这里插入图片描述

一、为什么要关心 Secure Boot,以及这篇文章到底解决什么问题?

在量产之前,绝大多数 Jetson 开发板都处于“非安全启动”状态:

  • 任意人都可以使用 flash.sh 刷入自定义 Bootloader 和 Kernel;
  • eMMC / NVMe 里的 Bootloader 可以被 dump、逆向、替换
  • OTA 升级如果被中间人替换,设备也不会拒绝启动;
  • 你的算法模型、密钥、业务逻辑,都有可能随着固件一起被拷走。

Secure Boot(安全启动) 的目的,就是让 Jetson 从上电开始,到 Kernel 启动为止,始终处在一条 “只能执行被信任的代码” 的链路上;并在需要时配合加密机制,确保这些代码 即使被拿走,也看不懂、解不开

在 Jetson 平台上,官方给出的完整流程可以概括为:

  1. 生成一对 PKC 非对称密钥对
  2. 准备一个 SBK 对称密钥
  3. 准备 K1/K2 密钥
  4. 根据需要构建 EKB(Encrypted Key Blob)
  5. 准备 Fuse 配置文件(描述要烧入哪些熔丝、写入哪些密钥);
  6. 使用 熔丝配置 + 工具(历史上是 odmfuse.sh,现已被 Factory Secure Key Provisioning 替代)烧写熔丝;
  7. 使用 flash.sh 和密钥选项(-u / -v)刷写 已签名/加密的安全镜像

这篇文章要做的事情,就是把上述每一步拆开,讲明白:

  • 每个步骤要做什么、为什么要做;
  • 需要哪些文件、命令、参数;
  • 对应的示例长什么样;
  • 各步骤之间是如何串起来,形成“整体融合和签名二进制流程”的。

阅读完本文,你应该可以做到:

  • 从零准备一套自己的 PKC/SBK/K1/K2/EKB;
  • 写出一份正确的 Fuse 配置文件;
  • 理解 odmfuse.sh 和 Factory Secure Key Provisioning 大致差异;
  • 使用 flash.sh -u -v 刷写安全镜像,并验证 Secure Boot 是否生效。

二、整体视角:Jetson Secure Boot 的“签名 + 熔丝 + 刷机”大流程

在进入细节之前,先用一张“脑内的流程图”把整体逻辑串起来:

  1. 生成密钥

    • 用 OpenSSL 或 HSM 生成 PKC 密钥对(私钥 + 公钥)
    • 随机生成 SBK
    • 随机生成 K1/K2,用于 EKB 加密等用途。
  2. 构建 EKB(可选但强烈建议)

    • 把未来 OTA、磁盘加密或应用层用到的密钥,打包成一个 加密的 Key Blob
    • 使用 K1/K2 把这些敏感内容进一步加密,避免明文散落在系统中。
  3. 准备 Fuse 配置文件

    • 把上述 PKC 的 公钥 Hash、SBK、K1 等信息写入 XML / CFG;
    • 指定要烧写哪些熔丝位、是否开启 Secure Boot、是否锁定调试等。
  4. 烧写熔丝(Fusing)

    • 开发阶段:可以先用 odmfuse.sh 或工厂工具的“Dry‑Run / 仿真模式”测试;
    • 量产阶段:通过 Factory Secure Key Provisioning(FSKP)在产线批量写入熔丝;
    • 一旦熔丝烧入并锁定,就 不可回退,设备从此被“绑定”到这套密钥。
  5. 签名/加密启动二进制

    • 利用 PKC 私钥对 BCT、MB1、MB2、UEFI 乃至 Kernel/DTB 等进行签名;
    • 利用 SBK 对 Bootloader、部分敏感镜像进行对称加密;
    • 生成一整套“安全版”的启动镜像文件。
  6. 刷写安全镜像

    • 使用 flash.sh -u <pkc-key.pem> -v <sbk.key> 指定你的密钥;
    • flash.sh 内部调用签名/加密脚本,将安全镜像写入 eMMC / NVMe;
    • 首次启动会走完整的 Secure Boot 流程,逐级验证签名和解密镜像。
  7. 验证 Secure Boot 是否生效

    • 通过串口日志 / 工具输出确认 Secure Boot 已启用;
    • 尝试刷入未签名镜像或篡改镜像,验证设备是否拒绝启动;
    • 在量产之前,完成一轮完整的“攻击模拟 + 防护验证”。

接下来,我们逐步展开每一个步骤。


三、步骤一:生成 PKC 密钥对(Public Key Cryptography)

3.1 PKC 在 Jetson Secure Boot 中的角色

在 Jetson SoC 内部,BootROM 会从熔丝中读取 公钥哈希(PublicKeyHash),并用它来验证从 BCT 到 Bootloader 的所有签名。

  • 私钥:只在你的安全环境(HSM/离线机器)里保存,用来对镜像进行签名;
  • 公钥:不会直接烧进熔丝,而是将其 Hash 值写入熔丝,用来做校验;
  • 签名算法:一般为 RSA(比如 2048/3072 位),具体依官方文档和版本而定。

只要私钥不泄露,任何人都无法伪造“看起来合法”的镜像;只要公钥 Hash 一旦写入熔丝,就很难再更换信任根,这就是 Secure Boot 强约束的来源。

3.2 在开发机上生成 PKC 密钥对

下面以常见的 openssl 为例,演示如何生成一对 RSA 密钥:

# 1. 生成 3072 位 RSA 私钥(文件名可根据实际项目命名)
openssl genrsa -out jetson_pkc_privkey_rsa3072.pem 3072

# 2. 从私钥中导出公钥
openssl rsa -in jetson_pkc_privkey_rsa3072.pem \
            -pubout -out jetson_pkc_pubkey_rsa3072.pem
``

这里建议:

- **长度**:选择官方文档建议的强度,例如 RSA‑3072;
- **保护**:私钥文件应该保存在 **受控的安全环境**,不要放在多人共享目录或开发板上;
- **命名**:使用项目名 + 平台 + 功能等信息命名,便于区分不同项目/批次。

### 3.3 从 PKC 公钥导出 PublicKeyHash

熔丝中并不是直接存公钥,而是存放公钥的哈希值(例如 SHA‑256)。

一般文档会给出官方脚本或者步骤,比如:

1. 使用脚本读取 `jetson_pkc_pubkey_rsa3072.pem`2. 对公钥的某一段数据做 Hash;
3. 输出为 32 字节(或其他长度)的十六进制串,用于写入 Fuse 配置。

一个可能的示例命令(伪代码,仅作理解):

```bash
# 提取公钥 modulus,再做 SHA256(具体命令以官方脚本为准)
openssl rsa -in jetson_pkc_privkey_rsa3072.pem -modulus -noout \
  | openssl dgst -sha256

# 输出形如:
# (stdin)= 0123456789ABCDEF......

你需要把这个 Hash 值写入 Fuse 配置文件的 PublicKeyHash 字段中,后面在“步骤五:准备 Fuse 配置文件”中会给出示例。

3.4 关于私钥的安全存储与备份

一旦你对设备烧入了 PublicKeyHash 对应的 Hash,这台设备就被永久地“绑定”到这套 PKC 密钥 上:

  • 私钥丢失 → 无法再签新的镜像 → 无法再刷机;
  • 私钥泄露 → 任何人都可以伪造合法镜像 → Secure Boot 形同虚设。

因此建议:

  • 使用 HSM 或内网专用签名服务器 来保存私钥;
  • 至少有一份离线备份存放在安全介质(加密硬盘、保险柜等);
  • 对不同产品线/客户/项目使用 不同 PKC 密钥对,避免单点泄露。

四、步骤二:准备 SBK(Secure Boot Key,对称加密密钥)

4.1 SBK 的作用:保护“看得见的固件内容”

如果 PKC 解决的是“谁有权执行”的问题,SBK 解决的就是“别人能不能看懂”的问题。

  • PKC 只验证镜像是否被篡改,不阻止别人把镜像复制走;
  • SBK 则通过对称加密,将 Bootloader 等敏感镜像加密后再写入设备;
  • 启动时,SoC 使用烧入熔丝中的 SBK 解密镜像,外部无法直接解析固件内容。

对商业设备来说,SBK 对保护 Bootloader 实现细节、调度逻辑、早期安全机制 以及某些敏感配置非常关键。

4.2 如何生成 SBK

SBK 通常是一个 128-bit 或 256-bit 的随机数(具体长度请以官方文档为准)。

示例:在 Linux 开发机上生成 128 bit(16 字节)随机数:

# 生成 16 字节随机数,并转为十六进制存入文件
head -c 16 /dev/urandom | xxd -p > jetson_sbk_128.key

cat jetson_sbk_128.key
# 示例输出:
# 2f8c7b9e3d4a6b1c9d0e5f7a12345678

你可以:

  • 直接使用十六进制字符串作为 SBK 值;
  • 在 Fuse 配置文件中,以 SecureBootKey 或类似字段的形式写入;
  • 在刷机时,通过 flash.sh -v jetson_sbk_128.key 指定 SBK 文件。

4.3 SBK 的注意事项

  • SBK 一旦通过熔丝烧入,就 无法修改
  • 同一产品家族可以共用一个 SBK,也可以为不同批次使用不同 SBK;
  • 与 PKC 一样,SBK 文件必须妥善保存,否则未来无法再重新加密、刷机。

五、步骤三:准备 K1/K2 密钥(用于 EKB 等扩展用途)

5.1 K1/K2 是什么?

除了 PKC 和 SBK,Jetson Secure Boot 还提供了扩展密钥机制

  • K1/K2 一般用作加密 EKB(Encrypted Key Blob)或其他扩展安全数据;
  • 它们通常也是 对称密钥,长度与算法(例如 AES‑128/256)由平台决定;
  • 在 Fuse 配置文件中,会有对应字段(例如 OemK1 等)指向这些密钥。

通俗理解:

  • SBK 是“专注于 Bootloader 加密”的系统级密钥;
  • K1/K2 更像是“你可以用来装自己业务密钥的保险柜的钥匙”。

5.2 生成 K1/K2 示例

与 SBK 类似,我们用 /dev/urandom 生成两个随机密钥:

# 生成 K1
head -c 16 /dev/urandom | xxd -p > jetson_k1_128.key

# 生成 K2
head -c 16 /dev/urandom | xxd -p > jetson_k2_128.key

输出文件中会是十六进制字符串,例如:

jetson_k1_128.key:  89af01cd23ee45b6a1b2c3d4e5f60718
jetson_k2_128.key:  76bc5a1f09de34561234abcd98765432

后续你可以:

  • 将 K1/K2 写入 Fuse 配置文件;
  • 在构建 EKB 时,用它们作为加密/认证密钥;
  • 在启动后的 OP‑TEE 或安全应用中,再使用这些密钥解包 EKB,拿到真正业务密钥(如 OTA 签名密钥、磁盘密钥等)。

5.3 何时需要 K1/K2?

  • 你计划在设备上使用 EKB 存储更多密钥(例如 OTA、磁盘、应用密钥);
  • 你希望在 Secure Boot 的基础上,扩展一层 自定义安全体系
  • 你需要与 NVIDIA 的 Factory Secure Key Provisioning 机制对接扩展密钥时。

如果只是做最基础的 Secure Boot + SBK 加密 Bootloader,K1/K2 并不是“必选项”,但从长期产品规划看,提前设计好 K1/K2 和 EKB 结构会更容易扩展


六、步骤四:准备 EKB(Encrypted Key Blob,加密密钥包)

6.1 EKB 的核心思想

EKB 可以理解为:“一个经过加密和完整性保护的密钥仓库文件”。

它的典型用途包括:

  • 存放 应用层密钥:如加密模型的解密密钥、API Token、License Key;
  • 存放 OTA 升级系统的签名/加密密钥
  • 存放 磁盘加密(LUKS)所需的主密钥
  • 甚至可以存储某些与客户绑定的“设备身份标识密钥”。

整个流程一般是:

  1. 在安全环境中整理好要放入的密钥列表;
  2. 使用 K1/K2 对这些数据进行加密、计算 MAC;
  3. 得到一个 ekb.bin 或类似名字的 二进制文件
  4. 在刷机或启动过程中,将 EKB 放入特定分区/偏移;
  5. 启动后由 OP‑TEE 或安全服务解密 EKB,从中取出真正业务密钥。

6.2 EKB 构建的典型形式(示意)

实际实现因版本和工具不同而异,下面给一个抽象示例,用来帮助理解:

假设你有一个 JSON 或配置文件,描述要存储的密钥:

{
  "keys": [
    {
      "name": "ota_signing_key",
      "type": "aes-256",
      "value_hex": "0123456789abcdeffedcba98765432100123456789abcdef0123456789abcdef"
    },
    {
      "name": "disk_luks_key",
      "type": "aes-256",
      "value_hex": "89abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234567"
    }
  ]
}

然后,通过官方提供的 EKB 生成脚本,例如:

python3 gen_ekb.py \
  --config   my_ekb_keys.json \
  --k1       jetson_k1_128.key \
  --k2       jetson_k2_128.key \
  --output   ekb.bin

最终得到的 ekb.bin 是一块已经经过 K1/K2 加密、带完整性校验的数据块。

在设备启动后的安全环境中,只要你持有 K1/K2(或者导出的派生密钥),就能解密 ekb.bin,取出里面真正的密钥,用于 OTA 验签、模型解密等。

6.3 在刷机流程中如何使用 EKB

典型做法包括:

  • Linux_for_Tegra/bootloader/ 目录下放入 ekb.bin
  • 在某些配置文件中指定 EKB 所在的分区/偏移;
  • flash.sh 或相关脚本会在刷机时把 ekb.bin 写入对应位置;
  • 启动时,Bootloader 或 OP‑TEE 知道哪里可以找到并解密 EKB。

不同版本的 Jetson Linux/工具,具体步骤有所差异,但总体思路相同——EKB 是连接“Secure Boot + OP‑TEE + 应用层安全”的桥梁


七、步骤五:准备 Fuse 配置文件(描述要烧写的熔丝)

7.1 Fuse 配置文件是什么?

Jetson SoC 内有一组 一次性可写的熔丝(FUSE),用于存放:

  • PublicKeyHash(PKC 公钥哈希);
  • SecureBootKey(SBK);
  • 各种 OEM 自定义密钥(如 OemK1、OemK2);
  • 安全模式、调试模式、rollback 保护等配置位。

我们不可能逐个用寄存器写入这些熔丝,因此官方提供了一种 配置文件形式 的描述方式:

  • 一般为 XML 或特定格式(如 fuse_config.xml);
  • 通过脚本解析后,调用底层接口写入对应熔丝位;
  • 同一个配置文件可以在多台设备上重复使用(前提是这些设备属于同一安全域)。

7.2 示例 Fuse 配置文件片段(示意)

以下仅为示意结构,字段名称和层级请以官方文档为准:

<FuseConfiguration>
  <!-- 公钥哈希,对应 PKC 公钥 -->
  <PublicKeyHash>
    0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
  </PublicKeyHash>

  <!-- SBK:Secure Boot Key,用于 Bootloader 加密 -->
  <SecureBootKey>
    0x2f8c7b9e3d4a6b1c9d0e5f7a12345678
  </SecureBootKey>

  <!-- OEM 自定义密钥,例如 OemK1,用于 EKB 加密 -->
  <OemK1>
    0x89af01cd23ee45b6a1b2c3d4e5f60718
  </OemK1>

  <!-- 其他安全相关熔丝位(示意) -->
  <SecurityConfig>
    <EnableSecureBoot>1</EnableSecureBoot>
    <DisableJTAG>1</DisableJTAG>
    <RollbackProtection>1</RollbackProtection>
  </SecurityConfig>
</FuseConfiguration>

7.3 编写 Fuse 配置文件的建议

  1. 测试环境 vs 量产环境分离

    • 为开发板/内测板准备一套“测试配置”,尽量保留一定的调试能力;
    • 为量产设备准备“正式配置”,关闭 JTAG、限制调试口等。
  2. 统一管理

    • 将 Fuse 配置文件纳入版本管理系统(Git);
    • 使用标签或分支区分不同项目/批次。
  3. 明确字段含义

    • 在 XML 或注释中写清楚每个字段用途;
    • 对于未来会使用的熔丝位,预留规划,避免日后冲突。

八、步骤六:烧写熔丝——odmfuse.sh 与 Factory Secure Key Provisioning

8.1 历史工具:odmfuse.sh

在较早版本的 Jetson Linux 中,odmfuse.sh 是官方提供的标准熔丝烧录脚本:

  • 输入:Fuse 配置文件(XML/CFG)、开发板处于 Recovery 模式;
  • 输出:将配置中指定的熔丝位写入 SoC;
  • 优点:对开发者友好,易于测试和快速验证。

典型的使用示例(伪示例):

sudo ./odmfuse.sh \
  --fuse_config fuse_config.xml \
  --chip 0x23 \
  --instance 0 \
  --keep

一般脚本会执行以下步骤:

  1. 解析 fuse_config.xml
  2. 通过 USB 与 Jetson BootROM/即将启动的引导代码通信;
  3. 写入相应熔丝位;
  4. 重启或提示你断电重新上电。

8.2 新机制:Factory Secure Key Provisioning(FSKP)

随着 Jetson 平台迭代,NVIDIA 引入了 Factory Secure Key Provisioning(FSKP) 来替代在产线使用 odmfuse.sh 的做法:

  • FSKP 的目标是:在 安全性较低的工厂环境 中,依然用加密方式安全传输熔丝数据;
  • 使用一套称为 FSKP Key 的平台密钥,在 SoC IROM 与 OEM HSM 之间建立安全通道;
  • 产线拿到的是“加密后的熔丝数据包”,工厂人员无法直接看到明文密钥。

对开发者来说,有几点需要理解:

  1. 配置格式仍然兼容:你在文档中看到的 Fuse 配置文件格式、密钥格式,与历史上 odmfuse.sh 使用的是同一套设计;
  2. FSKP 更适合量产:在真正量产场景中,应优先使用 FSKP + 合作方工具链,而不是在工厂执行 odmfuse.sh
  3. 开发阶段仍可本地测试:在开发板上,你仍然可以使用本地工具或仿真方式验证“如果烧入这些熔丝会发生什么”,只是在量产阶段需要迁移到 FSKP 流程。

8.3 熔丝烧录的关键原则

无论是 odmfuse.sh 还是 FSKP,有几个原则必须牢记:

  1. 熔丝是一次性的:写错了就无法恢复,最多只能在尚未锁死前利用剩余位做一定纠错,但总体来说“写一次就定终身”;

  2. 先在模拟/开发板上验证

    • 可以先在少量样机上测试:

      • PKC 是否能正常验证签名;
      • SBK 是否能正确解密 Bootloader;
      • 设备是否还能刷机、是否有调试能力;
    • 确认无误之后再批量烧录。

  3. 记录每批次的熔丝配置:将 Fuse 配置文件与硬件批次、生产日期一一对应保存,方便未来进行问题追踪与安全审计。


九、步骤七:签名与加密启动二进制(BCT/MB1/MB2/UEFI/Kernel 等)

9.1 整体思路

烧好熔丝之后,仅仅是“在芯片里写入了信任根”;但如果镜像本身没有签名/加密,Secure Boot 仍然无法工作。

因此我们需要:

  1. 利用 PKC 私钥对所有关键启动镜像进行 签名
  2. 利用 SBK 对 Bootloader 等敏感部分进行 加密
  3. 确保最终写入 eMMC/NVMe 的镜像,与熔丝中的 PKC/SBK 完全匹配。

9.2 使用 flash.sh 的常见方式

在 Jetson Linux 的 Linux_for_Tegra/ 目录下,flash.sh 是一个“总控脚本”,它会:

  • 根据你指定的参数,选择对应的 Board Config 和分区布局;
  • 调用内部脚本对 BCT/Bootloader/Kernel/RootFS 等进行打包;
  • 执行签名和加密操作(如果你传入了 -u / -v 等选项);
  • 最终通过 USB 向设备写入整套镜像。

一个典型的 Secure Boot 刷机命令示例:

cd Linux_for_Tegra

sudo ./flash.sh \
  -u ./keys/jetson_pkc_privkey_rsa3072.pem \
  -v ./keys/jetson_sbk_128.key \
  jetson-orin-nano-devkit \
  mmcblk0p1

含义大致为:

  • -u:指定 PKC 私钥,用于签名所有需要签名的启动镜像;
  • -v:指定 SBK 密钥文件,用于对 Bootloader 等镜像进行对称加密;
  • jetson-orin-nano-devkit:开发板平台名,对应 p3450-0000 一类的板级配置;
  • mmcblk0p1:刷写目标(例如 eMMC 上的某个分区)。

9.3 签名/加密过程中发生了什么?

内部逻辑(简化说明)通常包括:

  1. 使用 PKC 私钥对 BCT/MB1/MB2/UEFI 等镜像生成签名;
  2. 将签名与镜像一起打包为受保护的容器;
  3. 使用 SBK 对 Bootloader 类镜像进行 AES 加密;
  4. 将所有这些内容写入指定分区、偏移或分区镜像文件;
  5. 在刷机阶段,通过 USB 将整体镜像写入 Jetson 存储设备。

当设备上电后:

  • BootROM 根据熔丝中的 PublicKeyHash 选择对应的公钥;
  • 对从存储中读出的 BCT/MB1 等镜像签名进行验证;
  • 对需要解密的镜像使用 SBK 进行解密;
  • 一旦任何一步验证失败,启动流程会中断,Secure Boot 将阻止不可信代码运行。

十、步骤八:刷写安全镜像并验证 Secure Boot 是否生效

10.1 刷写安全镜像的完整示例

假设你已经完成了以下准备:

  • 已安装 Jetson Linux 的 BSP 与 Secure Boot 软件包;

  • 已生成:

    • jetson_pkc_privkey_rsa3072.pem
    • jetson_sbk_128.key
    • jetson_k1_128.key / jetson_k2_128.key(如有需要)
    • ekb.bin(如有需要)
    • fuse_config.xml(熔丝配置);
  • 已通过 odmfuse.sh 或 FSKP 烧入熔丝,启用了 Secure Boot。

此时,你可以在 Linux_for_Tegra/ 目录下执行:

# 1. 让 Jetson 进入 Recovery 模式,连接到开发机
#    (具体按键组合因开发板而异)

# 2. 刷写安全镜像
sudo ./flash.sh \
  -u ./keys/jetson_pkc_privkey_rsa3072.pem \
  -v ./keys/jetson_sbk_128.key \
  jetson-orin-nano-devkit \
  mmcblk0p1

刷写完成后,设备会自动重启。此时:

  • 如果镜像签名、加密与熔丝中的密钥完全一致,则设备会正常启动;
  • 如果你故意改坏了某个签名或换成未签名的 Bootloader,设备应该拒绝启动。

10.2 如何确认 Secure Boot 已经真正启用?

常见的验证方式包括:

  1. 刷入篡改镜像测试

    • 修改某个启动镜像(例如随意修改 UEFI 的某个字节);
    • 不重新签名,直接刷入;
    • 如果 Secure Boot 已启用,设备应拒绝启动或进入故障模式。
  2. 查看日志/寄存器

    • 通过串口终端观察启动日志;
    • 在某些平台上,可以通过工具或 /sys 节点读取 Secure Boot 状态位。
  3. 验证无法刷入未签名镜像

    • 在某些 Secure 配置下,flash.sh 会拒绝使用错误密钥或格式不正确的镜像;
    • 这说明刷机流程已经被绑定到你的密钥体系之上。

十一、从头到尾跑通一次实际流程:一个“最小可用”示例

为了让你对整体流程更有全局感知,这里用一个“最小可用”示例来串联前面所有步骤。

场景:

  • 你有一块 Jetson Orin Nano 开发板;

  • 希望启用最基本的 Secure Boot:

    • 使用 PKC 验证所有 Boot 代码;
    • 使用 SBK 加密 Bootloader;
    • 暂不引入复杂的 EKB/OP‑TEE 扩展。

步骤 1:生成 PKC 密钥对

mkdir -p ~/jetson_secure_keys
cd ~/jetson_secure_keys

openssl genrsa -out jetson_pkc_privkey_rsa3072.pem 3072
openssl rsa -in jetson_pkc_privkey_rsa3072.pem -pubout \
        -out jetson_pkc_pubkey_rsa3072.pem

# 使用官方脚本/命令从公钥导出 PublicKeyHash
# 假设得到:0123456789abcdef...(64 字节)

步骤 2:生成 SBK

head -c 16 /dev/urandom | xxd -p > jetson_sbk_128.key
cat jetson_sbk_128.key
# 假设输出:2f8c7b9e3d4a6b1c9d0e5f7a12345678

步骤 3:编写 Fuse 配置文件

~/jetson_secure_keys/ 中创建 fuse_config_orin.xml

<FuseConfiguration>
  <PublicKeyHash>
    0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
  </PublicKeyHash>

  <SecureBootKey>
    0x2f8c7b9e3d4a6b1c9d0e5f7a12345678
  </SecureBootKey>

  <SecurityConfig>
    <EnableSecureBoot>1</EnableSecureBoot>
    <DisableJTAG>0</DisableJTAG> <!-- 测试阶段可以先不关 -->
  </SecurityConfig>
</FuseConfiguration>

步骤 4:使用工具烧写熔丝

注意:这一步存在不可逆风险,务必在少量测试设备上验证无误后再用于量产。

假设你仍然可以使用 odmfuse.sh 进行测试:

cd Linux_for_Tegra

sudo ./odmfuse.sh \
  --fuse_config ~/jetson_secure_keys/fuse_config_orin.xml \
  --chip 0x23 \
  --instance 0

脚本运行完毕后,设备重启。此时,熔丝中的 PublicKeyHash 和 SBK 已经被写入。

步骤 5:使用 flash.sh 刷写安全镜像

cd Linux_for_Tegra

sudo ./flash.sh \
  -u ~/jetson_secure_keys/jetson_pkc_privkey_rsa3072.pem \
  -v ~/jetson_secure_keys/jetson_sbk_128.key \
  jetson-orin-nano-devkit \
  mmcblk0p1

过程结束后,设备应该能够正常启动,并且已经受到 Secure Boot 保护。

步骤 6:验证 Secure Boot 生效

  1. 备份当前 Bootloader 镜像;
  2. 在备份镜像中随便修改几个字节(例如用十六进制编辑器改一个字符串);
  3. 不做重新签名,直接用 flash.sh 或其他方式写回;
  4. 启动设备,观察是否拒绝启动、进入错误状态。

如果设备拒绝启动,那么说明 Secure Boot 正在生效。


十二、量产阶段的思考:FSKP、EKB 与安全体系的升级

前面的示例更多针对“工程师在实验室里手动操作”的流程。在真正的量产环境中,还需要考虑:

  1. 如何避免在工厂暴露明文密钥?

    • FSKP(Factory Secure Key Provisioning)提供了一种机制:

      • 在安全环境中生成密钥、Fuse 配置,并加密成“熔丝数据包”;
      • 工厂只拿到加密后的数据包,通过专用工具烧写熔丝;
      • 这样可以防止工厂人员直接接触到 PKC/SBK/K1/K2 等明文。
  2. 如何管理不同批次、不同客户的密钥?

    • 对不同项目使用不同 PKC/SBK/K1/K2 组合;
    • 使用统一的密钥管理策略和审核流程;
    • 给每套密钥建立文档和变更追踪。
  3. 如何把 Secure Boot 与 OP‑TEE、磁盘加密、OTA 等结合起来?

    • 使用 EKB 存放 OTA 签名密钥、LUKS 密钥;
    • 在 OP‑TEE 中解密 EKB,提供安全 API 给普通世界使用;
    • 将 Secure Boot、磁盘加密、应用层认证串成一条完整的“从上电到业务”的安全链。

十三、常见坑与排查建议

  1. 熔丝写错 / 重复写入

    • 原因:在未充分验证配置的前提下,盲目在量产板上烧写熔丝;

    • 建议:

      • 必须先在开发板上完成全流程验证;
      • 使用版本管理记录每份 Fuse 配置文件;
      • 在正式烧录前进行“Dry‑Run”或读回校验。
  2. 私钥/SBK 丢失

    • 结果:设备无法再被刷入新镜像,或者无法解密 Bootloader;

    • 建议:

      • 至少两份以上的离线备份,存放在不同安全地点;
      • 内部规定私钥/SBK 只能由特定安全管理员掌控,不进入一般开发流程。
  3. 签名/加密算法或长度不匹配

    • 表现:设备启动失败、报错,或者 flash.sh 中途失败;

    • 建议:

      • 严格按照对应 Jetson Linux 版本的官方文档指定的密钥长度与算法;
      • 不要混用不同版本生成的脚本、工具。
  4. 工厂流程与研发流程割裂

    • 问题:研发阶段使用 odmfuse.sh,量产时又临时改为 FSKP,导致配置不一致;

    • 建议:

      • 研发阶段就以“未来量产将使用 FSKP”为前提设计密钥体系与 Fuse 配置;
      • 与供应链、硬件厂商、NVIDIA 渠道提前沟通获取相关 FSKP 支持包。

十四、总结:Secure Boot 是“工程体系”,不是一个开关

如果只看官方文档的“Overall Fusing and Signing Binaries Flow”,你会看到短短几行:

  • 生成 PKC 密钥对;
  • 准备 SBK;
  • 准备 K1/K2;
  • 准备 EKB;
  • 准备 Fuse 配置文件;
  • 烧写熔丝;
  • 使用 flash.sh 刷写安全镜像。

但真正落地到一个 Jetson 量产项目时,每一行背后都对应着:

  • 密钥策略设计;
  • 工程实现细节;
  • 产线流程与安全管理;
  • 与 OP‑TEE、OTA、磁盘加密、应用安全的整体协同。

这篇文章按照“从密钥 → 配置 → 熔丝 → 签名/加密 → 刷机 → 验证”的顺序,把每一步中常见的问题和注意事项展开说明,并给出了一个可操作的“最小可用流程示例”。

在实际项目中,你可以:

  • 以本文的流程为基础,先在实验室完成一套完整的 Secure Boot 演练;
  • 再结合 Factory Secure Key Provisioning,将熔丝烧录迁移到工厂安全流程中;
  • 最终将 Secure Boot 与 OP‑TEE、EKB、OTA 等能力连接起来,构建真正可持续维护、可审计、可扩展的安全体系。

只要你真正跑通了上述每一个步骤,Secure Boot 就不再是一段文档中的“概念”,而会成为你 Jetson 产品的 基础安全能力


📺 B站视频讲解(Bilibili)https://www.bilibili.com/video/BV1k1C9BYEAB/

📘 《Yocto项目实战教程》京东购买链接Yocto项目实战教程


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐