安全启动使用指南
文档说明
本文档以 HiDiTingV100 / 3322 SDK 的安全启动实现为例,介绍安全启动的工作原理、快速验证方式、关键文件和代码走读,以及安全启动的启用和验证方法。
警告:eFuse 写入、锁位和生命周期切换通常不可逆。开发阶段请使用测试密钥和可恢复开发板;私钥不得提交到 SDK、Demo、日志或文档仓库。
安全启动背景知识
安全启动工作原理
安全启动用于阻止设备加载未经授权或被篡改的软件。启动时,BootROM 从 eFuse 读取安全启动状态和根公钥哈希,建立硬件信任锚点;每一级已验证的镜像再验证下一级镜像,直至目标应用被允许执行。
图 1 安全启动镜像逐级校验流程

操作流程
表 1 启动流程说明
图中仅展示启动阶段顺序,各阶段的校验内容如下。
| 阶段 | 校验内容 | 可信依据 | 校验通过后 |
|---|---|---|---|
| BootROM | 读取安全启动状态,校验根公钥区哈希 | eFuse 中的安全启动使能位和 OEM 根公钥哈希 | 确认根公钥区,进入 SSB 校验。 |
| 根公钥区 | 用根公钥校验 SSB 的密钥区和镜像内容 | 已通过 BootROM 确认的根公钥 | 进入 SSB。 |
| SSB | 校验 FlashBoot 的密钥区和镜像内容 | SSB 中的受信任二级公钥 | 进入 FlashBoot。 |
| FlashBoot | 校验分区表、SELiteOS、App、Recovery 及可选业务镜像 | 已验证的启动阶段密钥和验签表 | 按产品启动路径加载通过校验的镜像。 |
| 应用镜像 | 镜像头、签名、版本和代码区哈希 | FlashBoot 已完成的验签结果 | 允许进入目标软件执行。 |
任一阶段校验失败时,必须停止该启动路径,并进入产品定义的安全失败处理;不得读取、复制、映射或执行失败镜像。
关键参数说明
普通镜像由固定的签名头和代码区组成。FlashBoot 传给 secure_verify_image() 的地址必须指向 Key Area 起始位置,而不是代码区。
图 2 已签名镜像结构

| 区域 | 作用 | 开发注意事项 |
|---|---|---|
| Key Area | 包含镜像 ID、二级公钥和密钥区签名 | 签名配置中的 ImageId 必须与验签登记表匹配。 |
| Code Info | 包含镜像 ID、版本、代码长度、哈希和签名 | CodeInfoImageId 必须与验签登记表匹配。 |
| Code / Payload | 实际代码或数据 | 代码区哈希必须与 Code Info 一致;普通镜像的代码区偏移为 0x300。 |
SDK 的普通镜像校验顺序为:检查验签是否使能 → 选择根公钥或上级二级公钥 → 校验 Key Area → 校验 Code Info → 校验代码区哈希。
eFuse、生命周期与签名参数
| 项目 | 起始位 | 长度(bit) | 作用与检查重点 |
|---|---|---|---|
hash_oem_root_pub_key |
1728 | 256 | OEM 根公钥的哈希;烧录前必须核对根公钥来源。 |
MRK (OEM) |
1248 | 128 | OEM 管理的根密钥材料,用于 SE LiteOS 固件加密密钥生成。 |
SEC_LOCK_MRK_OEM |
1645 | 1 | 锁定 OEM MRK,写入后不可再修改。 |
SEC_LOCK_pub_key |
1644 | 1 | 锁定根公钥哈希区域。 |
msid / SEC_LOCK_msid |
1664 / 1643 | 32 / 1 | 市场 ID 及其锁位。 |
swd_soft_debug_en |
298 | 1 | 配置 SWD 调试端口的软开关方式。 |
secure_boot_enable |
715 | 4 | 0xA 为未使能出厂状态;其他值表示安全启动已使能。 |
lifecycle_sts |
1634 | 4 | 0x0000 空白、0x001x OEM 配置、0x01xx 最终用户、0x1xxx 退役。 |
签名配置位于 src/build/config/target_config/3322/sign_config/。SignSuite、ImageId、CodeInfoImageId、KeyOwnerId、KeyId、版本、MSID 和签名私钥来源必须与产品安全策略及验签登记表一致。
API 接口列表
| 接口/对象 | 说明 |
|---|---|
| uapi_partition_get_info() | 获取目标镜像分区的地址和长度 |
| uapi_efuse_init() | 初始化 eFuse 模块 |
| uapi_drv_cipher_sha256() | 对代码区计算 SHA-256 |
| uapi_drv_cipher_pke_ecdsa_verify() | 执行 ECDSA 验签 |
| secure_verify_init() | 注册 3322 验签表并更新根密钥状态 |
| secure_verify_image() | 验证 Key Area、Code Info 和代码区 |
| register_verify_info() | 向通用验签框架注册验签表和回调 |
| verify_image_key_area() / verify_image_code_info() / verify_image_code_area() | 分别验证镜像的三个逻辑区域 |
更多安全驱动接口请参考 安全 API 参考。
快速启用安全启动
功能说明
本节说明如何使用已有 3322 产品 target 启用安全启动:构建签名固件、在受控环境中烧录必需镜像和 eFuse 配置、重启后确认设备只接受已签名镜像。
编译
完成 CLI 开发环境配置后,在应用工程根目录执行以下命令。pack_diting_community 是 3322 的完整固件打包目标:
构建完成后,先使用一站式 CLI 烧写同一产品配置生成的完整固件包,并打开 UART2 日志串口;将 COM3 替换为实际端口:
fbb flash -f "$env:FBB_SDK_DIR\output\3322\fwpkg\diting-community.fwpkg" --chip 3322 -d --timeout 180
fbb monitor --port COM3 --baud 750000
- 安全启动相关镜像由该目标的构建和打包流程统一生成;CLI 整包烧写只部署固件,不能替代后续受控的 eFuse 配置流程。
- 烧写时使用
.fwpkg,不要以手工替换的原始.bin代替。 - 签名配置中的
ImageId和CodeInfoImageId必须与本文“关键参数说明”中的验签规则一致。
使用方式
准备工作:
- 使用同一产品配置生成根公钥区、SSB、分区表、SELiteOS、App 及其他必需镜像;禁止混用不同产品或不同密钥策略的产物。
- 在受控构建环境中准备测试密钥或签名服务,私钥不得提交到 SDK、日志或交付包。
- 使用可恢复开发板完成验证;确认串口日志、烧录工具和状态查询工具可用。
- 在配置 eFuse 前,完成签名镜像、根公钥哈希和市场 ID 的双人复核。eFuse 锁位与生命周期切换不可逆。
启用步骤:
- 使用烧录工具写入同一产品配置生成的根公钥区、SSB、分区表、SELiteOS、App 和其他必需镜像。
- 在启用前回读并核对根公钥哈希、MSID 和镜像版本;确认对应 eFuse 锁位尚未被错误写入。
- 按产品烧录流程配置
hash_oem_root_pub_key、必要锁位、MSID、调试策略和生命周期。字段含义见“关键参数说明”。 -
发送以下 AT 命令使能安全启动:
-
重启设备。使能后,设备只能加载通过当前信任链验签的镜像。
说明:
AT+SECUREBOOT和 eFuse 配置必须在镜像、根公钥和回读数据全部确认无误后执行。量产环境应由受控烧录流程完成,不能用开发板试错代替。
预期结果
重启后,通过 AT 工具查询安全状态:
预期结果:
- 安全启动状态为“启用”,生命周期为产品预期状态。
- 已签名镜像可以正常启动。
- 使用篡改后的镜像替换测试分区时,FlashBoot 验签失败,目标镜像不被加载或执行。
文件结构与代码走读
文件结构
安全启动的构建、验签和加载实现分布在以下位置:
src/
├── build/cmake/build_sign.cmake
├── build/config/target_config/3322/sign_config/
├── drivers/chips/3322/porting/security_verify_boot/
│ ├── secure_verify_boot_porting.h
│ └── secure_verify_boot_porting.c
└── bootloader/flashboot_3322/main.c
各文件职责
| 文件 | 职责 | 关键内容 |
|---|---|---|
build_sign.cmake |
根据构建目标触发签名 | TARGETS_LIST、GENERAT_SIGNBIN。 |
sign_config/*.cfg |
定义镜像签名输入、输出、Image ID 与密钥策略 | SignSuite、ImageId、CodeInfoImageId。 |
secure_verify_boot_porting.h |
定义 3322 镜像 ID 和验签接口 | secure_verify_image()、镜像 ID 宏。 |
secure_verify_boot_porting.c |
注册各镜像的 Key Area / Code Info ID | g_verify_table_registered[]、secure_verify_init()。 |
flashboot_3322/main.c |
定位分区、验签并加载已有系统镜像 | uapi_partition_get_info()、ssb_verify_app_image()。 |
签名配置解析
build_sign.cmake 根据构建目标和 sign_config 中的配置生成签名产物。配置中的 ImageId 对应 Key Area,CodeInfoImageId 对应 Code Info;二者必须与端口层验签表一一对应。
验签表解析
secure_verify_boot_porting.c 中的 g_verify_table_registered[] 为每种基础镜像类型分别登记 KEY_EREA_TYPE 和 CODE_INFO_TYPE。任一条目缺失或 ID 不一致时,验签将返回“无效区域类型”或“无效镜像 ID”。
FlashBoot 加载解析
FlashBoot 使用 uapi_partition_get_info() 查询 App 镜像分区,再以 Key Area 起始地址调用 secure_verify_image()。已有 App 镜像的验证入口如下:
errcode_t ssb_verify_app_image(uint32_t key_addr)
{
return secure_verify_image(OEM_MCU_BOOT_TYPE, key_addr, SSB_FLASH_REGION_START);
}
只有返回 ERRCODE_SUCC 后,FlashBoot 才允许复制、映射或跳转到镜像内容。
注意事项
- eFuse 写入、锁位和生命周期切换不可逆;量产前必须完成正常启动、升级、恢复和篡改拒绝测试。
- 私钥应保存在签名服务或受控离线环境,严禁提交到 SDK、Demo、日志和交付包。
- 根公钥区、SSB、分区表、SELiteOS、App 和其他必需镜像必须来自同一产品配置与密钥策略。
- 已有镜像的 Key Area Image ID、Code Info Image ID 与签名配置必须保持一致。
- 开发定位时可在隔离构建中启用
CONFIG_SECURE_VERIFY_BOOT_DEBUG_ON;量产版本应按产品日志策略关闭。
常见错误
| 现象或错误码 | 常见原因 | 排查方法 |
|---|---|---|
未生成 *_signed.bin |
产品 target 未进入签名规则或 .cfg 路径错误 |
检查 build_sign.cmake、构建目标名称和 DstFile。 |
ERRCODE_BOOT_VERIFY_TABLE_UNREGISTERED |
未执行 secure_verify_init() 或初始化顺序错误 |
检查 FlashBoot 初始化流程。 |
ERRCODE_BOOT_VERIFY_INVALID_AREA_TYPE |
Key Area 或 Code Info 登记项缺失 | 检查 g_verify_table_registered[]。 |
ERRCODE_BOOT_VERIFY_INVALID_IMAGE_ID |
.cfg 中的 ID 与验签表不一致 |
对比 ImageId、CodeInfoImageId 与端口层宏。 |
ERRCODE_BOOT_VERIFY_INVALID_HASH_RESULT |
镜像被篡改、地址错误或烧录不完整 | 检查签名头偏移、分区地址和烧录文件。 |
ERRCODE_BOOT_VERIFY_INVALID_IMAGE_TYPE |
镜像类型未登记或枚举不一致 | 检查 BASE_IMAGE_TYPE_* 与 OEM_*_TYPE。 |
| 版本校验失败 | 镜像版本低于 eFuse 策略 | 检查版本字段、掩码和反回滚策略。 |