验证流程

Manifest 组成与作用

在安全启动的验证流程中,芯片需要从固件中读取各种信息来完成验证: 版本号、算法、公钥、签名等。这些信息全部被组织在 Manifest 中。Manifest 可以理解为固件的"身份描述文件":它是一个二进制格式的元数据块,被附加在可执行固件的头部。 以下三个部分均拥有独立的 Manifest:

  • Image1(Bootloader):引导程序,负责验证密钥证书和应用固件;

  • Cert(Key Certificate):密钥证书,用于传递应用固件的公钥哈希值;

  • Image2(Application):应用固件,用户的应用程序。

验证流程详解

安全启动建立在"信任链"机制之上,信任链从不可篡改的硬件 ROM 和 OTP 开始, 通过逐级验证延伸至最终的应用固件。下图展示了完整的三级验证流程:

标准验证流程:
../../_images/secure_boot_flow.svg

芯片启动验证过程根据模式略有差异: 标准 ECC 模式仅验证 ECC 签名,PQC 混合模式需同时验证 ECC 和 PQC 两种签名。但无论哪种模式,每级验证都包含三个核心步骤:

  1. 首先校验公钥可信性:计算 Manifest 中公钥的哈希值,与 OTP 中烧录的公钥哈希值对比;

  2. 再验证 Manifest 可靠性:使用公钥验证 Manifest 签名;

  3. 最后验证固件可靠性:计算实际固件的哈希值,与 Manifest 中的编译后处理阶段生成的固件哈希值对比。

任一步骤失败,芯片都将终止启动。具体流程如下:

第一级 :Boot ROM → Bootloader(image1)

Boot ROM 从 OTP 读取公钥哈希值,计算 Bootloader Manifest 中公钥的哈希值并对比。 两者一致后,使用公钥验证 Manifest 签名(被签名的内容是除 Signature 外的所有 Manifest 字段)。 验签成功后,读取 Manifest 中的固件哈希,计算实际固件哈希并进行对比,验证通过后跳转执行 Bootloader。

第二级 :Bootloader → Key Certificate(cert)

Bootloader 使用 OTP 中的公钥来验证密钥证书,确认证书的公钥与 OTP 匹配后再验证证书签名。 验签通过后从证书提取应用固件的公钥哈希值,建立后续验证的信任锚点。 证书不包含可执行固件,无需验证固件可靠性。

第三级 :Bootloader → Application Firmware(image2)

Bootloader 使用证书中的公钥哈希验证应用固件公钥,后续流程与第一级验证相同。

明确验证流程后,下面介绍公钥哈希和算法配置方法。

参数配置

参数配置总览

安全启动涉及多个关键参数,涵盖签名密钥、哈希算法和存储位置等。下表汇总了主要参数:

参数名称

功能

manifest.json5 配置字段

IC 存储位置

私钥

对固件进行数字签名

sboot_private_key

IC 端不存储

公钥

IC 启动时用于验证固件签名

sboot_public_key

Manifest 数据块

公钥哈希

信任根锚点,验证公钥合法性

sboot_public_key_hash

OTP PK1 或者 PK2 区域

RMA 公钥哈希

RMA 模式下的备用公钥哈希

sboot_public_key_hash

OTP RMA_PK 区域

HMAC 密钥

固件哈希计算密钥(仅 HMAC 模式)

sboot_hmac_key

OTP S_IPSEC_Key2 区域

签名算法

指定签名类型(如 ed25519)

sboot_algorithm

OTP SECURE_BOOT_AUTH_ALG 比特位

哈希算法

指定固件摘要算法(如 sha256)

sboot_hash_alg

OTP SECURE_BOOT_HASH_ALG 比特位

安全启动使能

启用安全启动功能

sboot_enable

OTP SECURE_BOOT_EN 比特位

了解整体参数配置后,下面详细介绍各参数的存储位置和配置方法:

公钥哈希存储详解

安全启动通过 OTP 存储公钥哈希值,形成不可篡改的硬件信任根。 芯片启动时,Boot ROM 计算 Manifest 中公钥的哈希值并与 OTP 中存储的公钥哈希值对比, 验证通过后继续执行启动流程。三级验证流程中使用的公钥哈希值分别存储在不同位置:

  • Image1(Bootloader):公钥哈希默认存储在 OTP 的 PK1 区域(物理地址 0x320~0x33F

  • Cert(Key Certificate):

    • SDK 默认配置下,密钥证书使用与 Bootloader 相同的 PK1 密钥对。

    • Bootloader 和应用固件由不同团队开发时,使用 PK2 实现密钥隔离,确保证书密钥泄露不影响 Bootloader 安全。使用 PK2 时,公钥哈希需存储在 OTP 的 PK2 区域(物理地址 0x340~0x35F),并修改 {SDK}/component/soc/amebaxxx/usrcfg/ameba_bootcfg.c 文件:

    /* 默认使用 PK1。如使用 PK2 独立密钥,请改为 SEC_PKKEY_PK2_0 */
    u32 Cert_PKHash_OTP_ADDR = SEC_PKKEY_PK1_0;
    
  • Image2(Application):公钥哈希存储在密钥证书中,不需要烧录到 OTP。除默认密钥哈希外,可修改 manifest.json5 文件增加自定义密钥哈希到证书中。

不同芯片的 OTP 配置如下:

RTL8721Dx:

模式

名称

OTP 地址

大小(比特)

描述

常规

PK1

物理地址 0x320~0x33F

256

为兼容不同算法与曲线,公钥哈希值(SHA256)存储于 OTP

PK2

物理地址 0x340~0x35F

256

为兼容不同算法与曲线,公钥哈希值(SHA256)存储于 OTP

PK1_W_Forbidden_EN

物理地址 0x365[1]

1

烧录后 PK1 不可修改

PK2_W_Forbidden_EN

物理地址 0x365[2]

1

烧录后 PK2 不可修改

SECURE_BOOT_EN_PHY

物理地址 0x368[3]

1

任意使能位烧录后即启用安全启动

  • 设备处于开发调试阶段时,建议使用 SECURE_BOOT_EN_LOG ,因其可恢复禁用安全启动

  • 设备处于量产阶段时,建议烧录 SECURE_BOOT_EN_PHY 以永久启用安全启动

SECURE_BOOT_EN_LOG

逻辑地址 0x3[2]

1

RMA

RMA_PK

物理地址 0x720~0x73F

256

RMA 模式下安全启动公钥的哈希值

出于安全考虑,用户可维护与 PK1/PK2 不同的 RMA 密钥

RMA_PK_W_Forbidden_EN

物理地址 0x702[2]

1

烧录后 RMA_PK 不可修改

完成公钥哈希的 OTP 配置后,接下来需要选择签名和哈希算法。

认证与哈希算法

签名和哈希算法配置项会被写入 Manifest,作为算法标识。支持两种配置方式:

  1. 开发阶段:OTP 中未指定算法时,芯片依据固件 Manifest(manifest.json5)中的配置进行验签。

  2. 量产阶段:在 OTP 中永久锁定哈希与签名算法。

不同芯片支持的算法及 OTP 配置如下:

RTL8721Dx:

名称

OTP 地址

长度(比特)

描述

SECURE_BOOT_AUTH_ALG

物理地址 0x36B[3:0]

4

指定签名曲线

  • 0x0: (EdDSA) ed25519

SECURE_BOOT_HASH_ALG

物理地址 0x36B[7:4]

4

指定哈希算法

  • 0x0: SHA2 256

  • 0x1: SHA2 384

  • 0x2: SHA2 512

  • 0x3: HMAC-SHA2 256

  • 0x4: HMAC-SHA2 384

  • 0x5: HMAC-SHA2 512

一旦在 OTP 锁定算法配置, manifest.json5 中的 auth_alghash_alg 设置必须与 OTP 完全一致,否则芯片将无法启动。 该限制将同时应用于 Bootloader、密钥证书和应用固件。

HMAC 密钥

本章节仅适用于采用 HMAC 进行固件哈希校验的场景。HMAC 通过密钥增强哈希计算的安全性,需在 OTP 中预先配置统一密钥用于所有固件的哈希校验。 存储位置及保护设置如下:

名称

OTP 地址

大小(比特)

描述

S_IPSEC_Key2

物理地址 0x220~0x23F

256

HMAC 密钥存储位置。

S_IPSEC_Key2_R_Protection_EN

物理地址 0x365[5]

1

置 1 后,CPU 无法读取密钥(防止密钥被窃取)。

S_IPSEC_Key2_W_Protection_EN

物理地址 0x365[6]

1

置 1 后,密钥不可再被修改(防止密钥被篡改)。

使用方法

完成上述参数配置后,按以下步骤完成安全启动的完整配置流程。整个使用流程分为三个阶段:

  • 开发阶段:由开发者完成,包括密钥生成、项目配置和固件编译;

  • 量产阶段:由产线完成,包括固件烧录和 OTP 配置;

  • 运行阶段:由芯片执行,包括设备复位和日志验证。

开发阶段

1. 生成密钥对

密钥对是安全启动的基础:私钥用于签名固件,公钥写入 Manifest 用于验证签名。 进入 SDK {SDK}/tools/scripts 目录,根据不同的签名算法,使用不同的密钥生成命令:

$ python axf2bin.py encrypt keypair -a ed25519 -o keypair.json5
  • 支持的 ECC 曲线:ed25519、secp192r1、secp224r1、secp256r1、bp256r1、secp192k1、secp224k1、secp256k1

  • 支持的 PQC 算法:ml_dsa_65

脚本执行后会生成 keypair.json5 文件。 建议为应用固件( image2 )和 Bootloader( image1)分别生成不同的密钥对,以实现密钥隔离。

keypair.json5 文件中,各算法的密钥字节序和公钥哈希计算方式如下:

算法

私钥字节序

公钥字节序

公钥哈希算法

哈希基于的公钥字节序

ECDSA

大端

大端

SHA-256

大端

Ed25519

小端

小端

SHA-256

小端

ML-DSA-65

小端

小端

SHA-256

小端

ECC 密钥文件示例:
{
   sboot_algorithm: ed25519,
   sboot_private_key: "6AA34203018334474B25A0600996CA0968AA6228B886FF234B4EB9628B703C0A",
   sboot_public_key: "E2A0D6500BBF1DD8DC212098C230EB731ECE3A81AA11D0E6E538FA36BBA4FF6E",
   sboot_public_key_hash: "72B2E1CB0E8F715262AF38DFA0E522C95660D0EBFD920F4B1A229845E599C697",
}

2. 修改安全启动配置脚本

将密钥和算法配置写入 SDK/component/soc/amebaxxx/project/manifest.json5。 编译后处理脚本将使用文件中的密钥和算法进行固件签名,并将公钥等信息写入固件的 Manifest。 manifest.json5 的不同字段对应不同的验签阶段:

  • image1:第一级验证(Boot ROM 验证 Bootloader),存储 Bootloader 的签名配置;

  • cert:第二级验证(Bootloader 验证证书),存储密钥证书的签名配置;

  • image2:第三级验证(Bootloader 验证应用固件),存储应用固件的签名配置。

ECC 配置说明:

keypair.json5 中的密钥内容复制并覆盖到 manifest.json5 的对应位置,并使能安全启动( sboot_enable: true )。 下面的示例中, image1cert 使用相同的 PK1 密钥对, image2 使用不同的密钥对:

{
   version: 1,
   image1: {
      sboot_private_key: "6AA34203018334474B25A0600996CA0968AA6228B886FF234B4EB9628B703C0A",
      sboot_public_key: "E2A0D6500BBF1DD8DC212098C230EB731ECE3A81AA11D0E6E538FA36BBA4FF6E",
      sboot_public_key_hash: "72B2E1CB0E8F715262AF38DFA0E522C95660D0EBFD920F4B1A229845E599C697",
   },

   /* cert/image2 share img_id/img_ver, cert and image3 img are packed in app.bin */
   cert: {
      sboot_private_key: "6AA34203018334474B25A0600996CA0968AA6228B886FF234B4EB9628B703C0A",
      sboot_public_key: "E2A0D6500BBF1DD8DC212098C230EB731ECE3A81AA11D0E6E538FA36BBA4FF6E",
      sboot_public_key_hash: "72B2E1CB0E8F715262AF38DFA0E522C95660D0EBFD920F4B1A229845E599C697",
   },
   image2: {
      sboot_private_key: "9FC60C4CB6162E49C54FB94511497E16F5EB605167836F15DECBB8363B18E243",
      sboot_public_key: "45BABD665908AD5576D9DA4A80287262A4CB1475ACAD543E27A9C2598579FC72",
      sboot_public_key_hash: "1DFC2FE01CA8274F06E2E112D027C3C6FF9CED59EE79944BED46ADE35C44B422",
   },

   ...

   /* ============================ Secure Boot globle settings ============================ */
   sboot_enable: true,
   sboot_algorithm: "ed25519",
   sboot_hash_alg: "sha256",
   sboot_hmac_key: ["otp_key_0x220"],

   ...

   /* =================================== OTP key value =================================== */
   /* 仅在使用 HMAC 时配置 */
   otp_key_0x220: "9874918301909234686574856692873911223344556677889900aabbccddeeff",
}

3. 编译固件

为防止 TOCTOU 攻击,Bootloader(IMG1)不支持 XIP,需要在 menuconfig 中配置 IMG1 运行在 SRAM:

$ ameba.py menuconfig

(Top)  CONFIG Link Option  IMG1(Bootloader) running on FLASH or SRAM

执行编译命令,SDK 脚本会自动根据 manifest.json5 的配置对固件进行签名:

$ ameba.py build

4. 生成 Flash Loader

使能安全启动后,芯片只能从已授权的固件启动。因此用于下载固件的工具固件(Flash Loader)也必须经过签名,这是安全启动信任链的延伸。 每次更换密钥或修改签名、哈希算法后,需要重新生成 Flash Loader,以确保其签名配置与目标固件一致:

$ ameba.py build -g gen_imgtool_floader

签名后的 Flash Loader 文件路径为: {SDK}/component/soc/amebaxxx/project/project_km4tz (or project_hp)/gnu_utility/image_tool_flashloader/amebagreen2_acut/floader_amebaxxx.bin。 将此文件拷贝到 ImageTool 烧录工具路径下的 {ImageTool}/Devices/Floaders 文件夹中,覆盖原有文件。

量产阶段

5. 烧录安全启动相关 OTP 位

警告

  1. 使用 AT+SEC 命令前需在 menuconfig 中使能 CONFIG_ATCMD_SECURE (默认关闭),路径: CONFIG SHELL Enable ATCMD SECURE

  2. OTP 烧录前提:设备 Flash 中需已存在一个可正常启动的固件,以便通过串口发送 AT 命令。以下命令中的密钥字符串仅作为示例,勿用于生产。

  3. OTP 区域只能写入一次,无法擦除或撤销。请在执行写入命令前,仔细核对地址和数据。

  4. 量产阶段建议先在少量样机上验证通过后,再进行批量操作。

  5. 特别注意 OTP 地址是逻辑区还是物理区。具体的 OTP 操作方法请参考 OTP 串口编程章节

Step 5.1: 烧录 ROT 公钥哈希

将公钥哈希烧录到 OTP,建立不可篡改的信任锚点。

ECC 配置说明:

manifest.json5 中找到 image1 -> sboot_public_key_hash,将其写入 PK1 区域:

AT+SEC=SBOOT_PK,pk1,72B2E1CB0E8F715262AF38DFA0E522C95660D0EBFD920F4B1A229845E599C697

若配置了独立的证书密钥(使用 PK2 校验 Cert),还需将 cert 公钥哈希值写入 PK2 并修改 ameba_bootcfg.c 配置文件:

AT+SEC=SBOOT_PK,pk2,XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

注意,在 PQC 或混合签名模式下 PK2 固定用于 PQC 公钥哈希。

Step 5.2: 烧录 HMAC 密钥(仅 HMAC 模式需要)

manifest.json5sboot_hash_alg 设置为 HMAC 时才需要执行此步骤。写入 HMAC 密钥:

AT+SEC=SBOOT_HMAC,9874918301909234686574856692873911223344556677889900aabbccddeeff

写入后命令会自动回读 OTP 并校验。

Step 5.3: 启用安全启动

根据当前阶段选择合适的启用方式:

开发调试阶段:

开发调试阶段用于验证签名流程,允许失败后关闭安全启动。只需临时使能对应功能:

  • ECC 安全启动:

    AT+SEC=SBOOT_EN,temp
    
  • PQC 安全启动:

    AT+SEC=SBOOT_PQC,temp
    
  • 混合签名模式:同时使能 ECC 和 PQC:

    AT+SEC=SBOOT_EN,temp
    AT+SEC=SBOOT_PQC,temp
    

关闭上述临时使能(若已通过 perm 永久使能,则此命令无效):

AT+SEC=SBOOT_EN,temp_off
AT+SEC=SBOOT_PQC,temp_off

6. 下载固件

使用 ImageTool 和已签名的 Flash Loader 将固件下载至设备。 启动时芯片会读取这些签名信息进行验证。

运行阶段

7. 复位验证

启动后检查串口日志以确认安全启动状态。

ECC 验证日志:

ECC 安全启动使能日志:

IMG1 SBOOT EN

RMA 状态下的安全启动

上述步骤涵盖了正常量产流程下的安全启动配置。当产品因故障需要返厂分析时,会进入 RMA 退货授权状态

RMA 状态下,OTP 安全区域不可读写,可保障密钥等用户机密信息不外泄。 Realtek 提供了独立的 RMA 安全启动机制,芯片仅检测当前固件是否由 "RMA 私钥" 签名,常规模式下的安全启动验证机制失效。

根据是否烧录 RMA 公钥哈希值,RMA 模式存在两种运行状态:

  • 已烧录 RMA 公钥哈希值:RMA 模式下强制启用安全启动,仅允许运行由对应 RMA 私钥签名的固件。

  • 未烧录 RMA 公钥哈希值:RMA 模式下安全启动禁用,可运行任意代码。

建议维护与常规安全启动密钥(PK1 和 PK2)不同的 RMA 密钥,通过烧录 OTP 设置一组专门用于 RMA 模式的公钥哈希(物理地址 0x720~0x73F),以实现权限隔离。

启用 RMA 安全启动的步骤:

  1. 烧录 RMA 公钥哈希值(物理地址 0x720):

    AT+OTP=WRAW,0x720,0x20,<RMA 公钥哈希值>
    
  2. 锁定 RMA 公钥哈希(物理地址 0x702):

    AT+OTP=WRAW,0x702,0x1,FB
    

小心

  • 在 RMA 状态下,PQC 安全启动验证将自动跳过,仅执行 RMA ECC 安全启动验证。

  • Flash Loader:在 RMA 模式中用于下载固件的 Flash Loader, 也必须使用 RMA 密钥重新签名。

  • HMAC 限制:若量产时锁定了 HMAC 算法,RMA 模式下也必须遵循该限制。但由于 RMA 状态下的用户信息保护机制,软件无法读取 OTP 区域中的正确的 HMAC 密钥,只能读到 0xFF 。因此在编译 RMA 固件时,需将 manifest.json5 的 HMAC 密钥字段填充为全 0xFF

备注

进入 RMA 状态后,如果启动了 RSIP ,此时读到的 RSIP 解密密钥为全 F ,无法正确解密固件,启动会报错。可以在编译固件时将密钥改成全 F 以临时规避此问题。