1. HSM固件安全启动链验证
任务说明
本案例面向集成硬件安全模块(HSM)的MCU平台,完成HSM外设的初始化,并验证基于HSM的安全启动流程。安全启动的核心目标是:在MCU上电后,由HSM对引导加载程序(Bootloader)镜像进行完整性校验与认证,仅当认证通过后才允许应用代码执行,从而防止未授权或篡改的固件运行。
硬件与依赖
本案例基于NXP S32K3系列MCU(集成CSEc HSM模块),开发环境为S32 Design Studio for S32 Platform,使用S32K3标准外设驱动库。需要准备:S32K3-EVB开发板、PE Micro调试器、S32 Design Studio IDE。HSM模块通过CSEc(Cryptographic Services Engine)IP核实现,支持AES-128、SHA-256及安全启动所需的密钥存储与签名验证功能。
实现方案
安全启动流程分为两个阶段:启动认证阶段——HSM对Bootloader镜像进行SHA-256哈希计算,并使用预置的公钥对镜像签名进行RSA-2048验证;应用跳转阶段——认证通过后,MCU将程序计数器跳转至Bootloader入口地址执行。本案例代码实现HSM模块的初始化配置、安全启动状态查询以及启动结果判定逻辑。
代码实现
/* main.c - HSM安全启动验证示例 */
#include "Cse.h"
#include "Cse_Crypto.h"
#include "Mcu.h"
#include "flash.h"
#define BOOT_IMAGE_START_ADDR 0x100000u /* Bootloader存放起始地址 */
#define BOOT_IMAGE_SIZE 0x8000u /* Bootloader镜像大小(32KB) */
#define SIGNATURE_ADDR 0x100000u + BOOT_IMAGE_SIZE /* 签名存储位置 */
/* HSM密钥槽位:公钥索引 */
#define HSM_PUBLIC_KEY_SLOT 0x0u
/* 安全启动状态 */
typedef enum {
SEC_BOOT_NOT_DONE = 0u,
SEC_BOOT_SUCCESS,
SEC_BOOT_FAIL
} SecBootStatus;
static SecBootStatus boot_status = SEC_BOOT_NOT_DONE;
/* 安全启动验证函数 */
static SecBootStatus SecureBoot_Verify(void)
{
uint8_t hash[32];
uint8_t signature[256];
Cse_StatusType cse_ret;
Cse_Crypto_VerifyStatusType verify_result;
/* 1. 计算Bootloader镜像的SHA-256哈希 */
cse_ret = Cse_Crypto_Sha256(BOOT_IMAGE_START_ADDR, BOOT_IMAGE_SIZE, hash);
if (cse_ret != CSE_STATUS_SUCCESS) {
return SEC_BOOT_FAIL;
}
/* 2. 从Flash读取预存的签名数据 */
Flash_Read(SIGNATURE_ADDR, signature, sizeof(signature));
/* 3. 使用HSM公钥验证签名 */
cse_ret = Cse_Crypto_RsaVerify(HSM_PUBLIC_KEY_SLOT,
hash,
sizeof(hash),
signature,
sizeof(signature),
&verify_result);
if (cse_ret != CSE_STATUS_SUCCESS) {
return SEC_BOOT_FAIL;
}
/* 4. 判定验证结果 */
if (verify_result == CSE_CRYPTO_VERIFY_OK) {
return SEC_BOOT_SUCCESS;
} else {
return SEC_BOOT_FAIL;
}
}
/* HSM模块初始化 */
static void Hsm_Init(void)
{
/* 初始化CSEc驱动 */
Cse_Init(NULL);
/* 配置HSM时钟与电源 */
Mcu_InitClock();
Mcu_InitCanonical();
/* 等待HSM就绪 */
while (Cse_GetStatus() != CSE_STATUS_IDLE) {
/* 轮询等待 */
}
}
int main(void)
{
/* 系统级初始化 */
Mcu_Init();
Flash_Init();
/* 初始化HSM模块 */
Hsm_Init();
/* 执行安全启动验证 */
boot_status = SecureBoot_Verify();
/* 根据验证结果决定是否跳转至Bootloader */
if (boot_status == SEC_BOOT_SUCCESS) {
/* 跳转至Bootloader入口 */
void (*boot_entry)(void) = (void (*)(void))BOOT_IMAGE_START_ADDR;
boot_entry();
} else {
/* 验证失败:停留在安全启动代码,禁止跳转 */
while (1u) {
/* 错误处理:可在此处点亮LED或记录错误码 */
}
}
/* 正常流程不会到达此处 */
return 0;
}
关键配置说明
上述代码中,BOOT_IMAGE_START_ADDR指向Bootloader在Flash中的物理地址,SIGNATURE_ADDR为签名数据存放位置。实际项目中,Bootloader镜像的SHA-256哈希值和RSA签名由上位机工具在固件构建时生成,并烧录至指定Flash区域。HSM公钥通过CSEc密钥注入流程在芯片出厂或首次配置时写入安全存储区,本案例使用密钥槽0。
验证方法
测试准备:使用S32K3 SDK提供的csec_key_tool生成RSA-2048密钥对,将公钥注入HSM密钥槽0,使用私钥对Bootloader镜像签名并烧录至SIGNATURE_ADDR地址。
执行步骤:
- 编译工程并烧录至S32K3-EVB开发板;
- 在IDE中设置断点于
SecureBoot_Verify()函数返回处; - 全速运行,观察程序是否停在断点位置;
- 检查
boot_status变量值。
判定标准:
- 当Bootloader镜像未被篡改时,
boot_status应为SEC_BOOT_SUCCESS,程序跳转至Bootloader执行; - 人为修改Bootloader区域任意字节后重新烧录,
boot_status应为SEC_BOOT_FAIL,程序停留在错误处理循环中; - 通过调试器观察HSM寄存器状态,确认CSEc模块无错误中断标志。
预期输出
在验证通过场景下,程序计数器跳转至0x100000地址处开始执行Bootloader代码;验证失败场景下,程序停留在while(1)错误循环中,可通过调试器观察boot_status变量值为2(SEC_BOOT_FAIL)。