2. 安全启动流程实现
任务目标
在RH850 U2A的HSM(硬件安全模块)上实现安全启动流程:启动时对主核Flash中的启动镜像进行完整性校验(HMAC-SHA256)与真实性认证(基于非对称签名的RSA-PSS验证),校验通过后才允许主核跳转执行。本案例聚焦HSM侧固件的核心验证逻辑与主核侧的触发/获取结果流程。
环境与依赖
- 硬件:RH850/U2A(HSM核与主核共享Flash,HSM拥有独立RAM与加密引擎)
- 软件:CS+ for CC(或GHS MULTI),HSM固件使用RH850系列编译器
- 依赖:HSM驱动库(提供HSM_Init、HSM_ReadFlash、HSM_WriteMailbox等底层接口);主核侧需包含HSM通信头文件(hsm_api.h)
实现方案
安全启动分为两级:HSM自启动(HSM核上电后首先执行,完成自身完整性校验)与主镜像认证(HSM校验主核启动镜像)。本案例实现主镜像认证部分:主核在跳转前通过Mailbox向HSM发送启动请求,HSM从Flash读取镜像,依次执行HMAC完整性校验与RSA-PSS签名验证,将结果通过Mailbox返回。密钥(HMAC密钥与RSA公钥)预置于HSM专用安全Flash区域,启动时由HSM内部硬件机制保护,不经过总线暴露。
关键完整代码
/* hsm_secure_boot.c - HSM侧安全启动核心实现 */
#include "hsm_platform.h"
#include "hsm_crypto.h"
#include "hsm_mailbox.h"
#define IMAGE_BASE_ADDR 0x00100000u /* 主核镜像起始地址 */
#define IMAGE_MAX_SIZE 0x00080000u /* 镜像最大512KB */
#define HMAC_KEY_SLOT 0x01u /* HMAC密钥存储槽位 */
#define RSA_PUBKEY_SLOT 0x02u /* RSA公钥存储槽位 */
#define BOOT_MAGIC 0xA5A5A5A5u
typedef struct {
uint32_t magic;
uint32_t image_size;
uint32_t reserved[2];
} boot_header_t;
static uint8_t work_buffer[1024];
/* HMAC-SHA256完整性校验 */
static int verify_integrity(uint32_t addr, uint32_t size) {
hmac_ctx_t ctx;
uint32_t offset = 0;
uint8_t calc_mac[32];
uint8_t ref_mac[32];
/* 从安全Flash读取参考HMAC值(镜像末尾附加的32字节) */
if (hsm_secure_read(HMAC_KEY_SLOT, ref_mac, 32) != HSM_OK) {
return HSM_ERR_KEY_ACCESS;
}
hmac_sha256_init(&ctx, HMAC_KEY_SLOT);
while (offset < size) {
uint32_t chunk = (size - offset > sizeof(work_buffer)) ?
sizeof(work_buffer) : (size - offset);
hsm_flash_read(addr + offset, work_buffer, chunk);
hmac_sha256_update(&ctx, work_buffer, chunk);
offset += chunk;
}
hmac_sha256_final(&ctx, calc_mac);
return (memcmp(calc_mac, ref_mac, 32) == 0) ? HSM_OK : HSM_ERR_INTEGRITY;
}
/* RSA-PSS签名验证(真实性认证) */
static int verify_authenticity(uint32_t addr, uint32_t size) {
rsa_pss_ctx_t ctx;
uint8_t hash[32];
uint8_t signature[256];
uint32_t sig_offset;
/* 签名位于镜像头部固定偏移处 */
sig_offset = sizeof(boot_header_t);
hsm_flash_read(addr + sig_offset, signature, sizeof(signature));
/* 计算镜像内容(不含头部与签名)的SHA-256哈希 */
sha256_compute(addr + sig_offset + sizeof(signature),
size - sig_offset - sizeof(signature), hash);
rsa_pss_init(&ctx, RSA_PUBKEY_SLOT);
return rsa_pss_verify(&ctx, hash, sizeof(hash),
signature, sizeof(signature));
}
/* 主入口:接收主核启动请求并执行验证 */
int hsm_secure_boot_process(void) {
boot_header_t header;
uint32_t img_addr = IMAGE_BASE_ADDR;
uint32_t img_size;
int result;
/* 读取镜像头部 */
hsm_flash_read(img_addr, (uint8_t*)&header, sizeof(header));
if (header.magic != BOOT_MAGIC) {
hsm_mailbox_send_result(HSM_ERR_HEADER);
return HSM_ERR_HEADER;
}
img_size = header.image_size;
if (img_size > IMAGE_MAX_SIZE) {
hsm_mailbox_send_result(HSM_ERR_SIZE);
return HSM_ERR_SIZE;
}
/* 第一步:HMAC完整性校验 */
result = verify_integrity(img_addr + sizeof(header),
img_size - sizeof(header));
if (result != HSM_OK) {
hsm_mailbox_send_result(result);
return result;
}
/* 第二步:RSA-PSS签名验证 */
result = verify_authenticity(img_addr, img_size);
hsm_mailbox_send_result(result);
return result;
}
主核侧触发代码
/* main_core_boot.c - 主核启动流程中调用HSM验证 */
#include "hsm_api.h"
int main_core_secure_boot(void) {
uint32_t result;
/* 通过Mailbox发送启动验证请求 */
hsm_send_command(HSM_CMD_SECURE_BOOT);
/* 等待HSM完成验证(带超时保护) */
if (hsm_wait_result(&result, 1000) != HSM_OK) {
return -1; /* 通信超时 */
}
if (result == HSM_OK) {
/* 验证通过,跳转到镜像入口 */
jump_to_image(IMAGE_BASE_ADDR);
return 0;
}
/* 验证失败,进入错误处理 */
handle_boot_failure(result);
return -1;
}
运行与验证
- 构建HSM固件:将hsm_secure_boot.c编译链接为HSM核可执行文件,烧录至HSM专用Flash。
- 构建主核程序:主核程序包含main_core_boot.c,编译后生成带签名与HMAC的镜像(需使用配套的签名工具,将RSA私钥签名与HMAC值附加到镜像指定位置)。
- 执行流程:系统上电→HSM核先启动并等待Mailbox命令→主核运行至安全启动点,发送验证请求→HSM执行上述验证→返回结果。
通过判定标准:
- 使用正确签名的镜像启动时,主核能正常跳转执行(观察LED或串口日志输出“Boot Success”);
- 篡改镜像任意一个字节(如修改0x100100处的数据)后重新烧录,启动应停在错误处理函数中(日志输出“Boot Failed: 0xNN”);
- 使用错误密钥签名的镜像,同样应被拒绝启动。
常见问题
- Mailbox通信超时:检查HSM是否已完成初始化(hsm_platform_init),以及中断优先级配置是否正确。
- HMAC校验总失败:确认参考HMAC值存储位置与代码中HMAC_KEY_SLOT一致,且计算范围(不含头部)与签名工具生成时使用的范围完全相同。
- RSA验证失败:确认公钥槽位已正确烧录,且签名算法参数(模长2048位、PSS盐长度)与签名工具一致。