跳转至

安全启动使用指南

文档说明

本文档以 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/SignSuiteImageIdCodeInfoImageIdKeyOwnerIdKeyId、版本、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 的完整固件打包目标:

# 设置当前工程的构建目标(首次构建或切换目标时执行)
fbb set-target pack_diting_community

# 编译并打包固件
fbb build

构建完成后,先使用一站式 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 代替。
  • 签名配置中的 ImageIdCodeInfoImageId 必须与本文“关键参数说明”中的验签规则一致。

使用方式

准备工作:

  • 使用同一产品配置生成根公钥区、SSB、分区表、SELiteOS、App 及其他必需镜像;禁止混用不同产品或不同密钥策略的产物。
  • 在受控构建环境中准备测试密钥或签名服务,私钥不得提交到 SDK、日志或交付包。
  • 使用可恢复开发板完成验证;确认串口日志、烧录工具和状态查询工具可用。
  • 在配置 eFuse 前,完成签名镜像、根公钥哈希和市场 ID 的双人复核。eFuse 锁位与生命周期切换不可逆。

启用步骤:

  1. 使用烧录工具写入同一产品配置生成的根公钥区、SSB、分区表、SELiteOS、App 和其他必需镜像。
  2. 在启用前回读并核对根公钥哈希、MSID 和镜像版本;确认对应 eFuse 锁位尚未被错误写入。
  3. 按产品烧录流程配置 hash_oem_root_pub_key、必要锁位、MSID、调试策略和生命周期。字段含义见“关键参数说明”。
  4. 发送以下 AT 命令使能安全启动:

    AT+SECUREBOOT
    
  5. 重启设备。使能后,设备只能加载通过当前信任链验签的镜像。

说明AT+SECUREBOOT 和 eFuse 配置必须在镜像、根公钥和回读数据全部确认无误后执行。量产环境应由受控烧录流程完成,不能用开发板试错代替。

预期结果

重启后,通过 AT 工具查询安全状态:

AT+GETSECURESTATE

预期结果:

  • 安全启动状态为“启用”,生命周期为产品预期状态。
  • 已签名镜像可以正常启动。
  • 使用篡改后的镜像替换测试分区时,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_LISTGENERAT_SIGNBIN
sign_config/*.cfg 定义镜像签名输入、输出、Image ID 与密钥策略 SignSuiteImageIdCodeInfoImageId
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_TYPECODE_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 与验签表不一致 对比 ImageIdCodeInfoImageId 与端口层宏。
ERRCODE_BOOT_VERIFY_INVALID_HASH_RESULT 镜像被篡改、地址错误或烧录不完整 检查签名头偏移、分区地址和烧录文件。
ERRCODE_BOOT_VERIFY_INVALID_IMAGE_TYPE 镜像类型未登记或枚举不一致 检查 BASE_IMAGE_TYPE_*OEM_*_TYPE
版本校验失败 镜像版本低于 eFuse 策略 检查版本字段、掩码和反回滚策略。