当前位置: 首页 > news >正文

芯片安全启动架构与信任之 TLS/SSL/mTLS 安全通信

第一部分 安全模块固件代码细节

1.1 多核安全信息交互架构

现代SoC通常包含多个处理器核心(如Cortex-M4 + Cortex-M0,或RISC-V双核),安全模块需要处理多核之间的安全信息交互。核心挑战包括:

  • 安全上下文隔离:安全核心与非安全核心之间的数据隔离。

  • 核间通信:通过共享内存或Mail-box进行消息传递。

  • 权限管理:确保只有授权核心能访问安全资源。

1.1.1 多核安全交互架构
+-------------------+ +-------------------+ | 安全核心 (S) | | 非安全核心 (NS) | | (Cortex-M4) | | (Cortex-M0) | +-------------------+ +-------------------+ | | | Mail-box 消息通道 | |<------------------------>| | (安全消息队列) | +-------------------+ | 共享安全内存 | | (加密存储区域) | +-------------------+ | 中断控制器 | | (核间中断) | +-------------------+

1.2 Mail-box驱动开发

Mail-box是一种硬件通信机制,允许核心之间通过寄存器传递消息。它通常包含发送寄存器、接收寄存器和状态寄存器。

1.2.1 Mail-box寄存器定义
/** * @file mailbox.h * @brief Mail-box 寄存器定义 */ ​ /* Mail-box 基址(假设) */ #define MAILBOX_BASE 0x30000000 #define MAILBOX_SEND_REG (*(volatile uint32_t *)(MAILBOX_BASE + 0x00)) #define MAILBOX_RECV_REG (*(volatile uint32_t *)(MAILBOX_BASE + 0x04)) #define MAILBOX_STATUS_REG (*(volatile uint32_t *)(MAILBOX_BASE + 0x08)) #define MAILBOX_CTRL_REG (*(volatile uint32_t *)(MAILBOX_BASE + 0x0C)) #define MAILBOX_INT_REG (*(volatile uint32_t *)(MAILBOX_BASE + 0x10)) #define MAILBOX_INT_MASK (*(volatile uint32_t *)(MAILBOX_BASE + 0x14)) ​ /* 状态寄存器位 */ #define MAILBOX_STATUS_TX_FULL (1 << 0) /* 发送缓冲区满 */ #define MAILBOX_STATUS_RX_EMPTY (1 << 1) /* 接收缓冲区空 */ #define MAILBOX_STATUS_TX_PENDING (1 << 2) /* 发送等待 */ #define MAILBOX_STATUS_RX_PENDING (1 << 3) /* 接收等待 */ ​ /* 控制寄存器位 */ #define MAILBOX_CTRL_ENABLE (1 << 0) /* 启用 Mail-box */ #define MAILBOX_CTRL_INT_ENABLE (1 << 1) /* 启用中断 */ #define MAILBOX_CTRL_RESET (1 << 2) /* 复位 Mail-box */
1.2.2 Mail-box驱动实现
/** * @file mailbox.c * @brief Mail-box 驱动实现 */ ​ #include <stdint.h> #include <stdbool.h> #include "mailbox.h" ​ /** * @brief 初始化 Mail-box */ void mailbox_init(void) { /* 1. 复位 Mail-box */ MAILBOX_CTRL_REG |= MAILBOX_CTRL_RESET; while (MAILBOX_CTRL_REG & MAILBOX_CTRL_RESET) { /* 等待复位完成 */ } /* 2. 启用 Mail-box */ MAILBOX_CTRL_REG = MAILBOX_CTRL_ENABLE | MAILBOX_CTRL_INT_ENABLE; /* 3. 清空中断状态 */ MAILBOX_INT_REG = 0xFFFFFFFF; /* 4. 启用中断(由中断控制器配置) */ } ​ /** * @brief 发送消息到另一个核心 * @param msg 消息指针(32位) * @param timeout_ms 超时时间(毫秒) * @return 0 成功,-1 超时,-2 错误 */ int mailbox_send(uint32_t msg, int timeout_ms) { uint32_t timeout = 0; while (MAILBOX_STATUS_REG & MAILBOX_STATUS_TX_FULL) { /* 等待发送缓冲区可用 */ if (timeout_ms > 0) { timeout++; if (timeout > timeout_ms * 1000) { return -1; /* 超时 */ } } } /* 写入消息到发送寄存器 */ MAILBOX_SEND_REG = msg; /* 触发核间中断(如果启用) */ MAILBOX_CTRL_REG |= (1 << 4); /* 触发接收端中断 */ return 0; } ​ /** * @brief 接收消息(非阻塞) * @param msg 接收的消息指针 * @return 0 有消息,-1 无消息 */ int mailbox_receive(uint32_t *msg) { if (MAILBOX_STATUS_REG & MAILBOX_STATUS_RX_EMPTY) { return -1; /* 无消息 */ } *msg = MAILBOX_RECV_REG; /* 清空中断标志 */ MAILBOX_INT_REG = (1 << 0); return 0; } ​ /** * @brief Mail-box 中断服务函数 */ void mailbox_irq_handler(void) { uint32_t int_status = MAILBOX_INT_REG; if (int_status & (1 << 0)) { /* 收到新消息 */ uint32_t msg; if (mailbox_receive(&msg) == 0) { /* 处理消息(由上层调用) */ mailbox_process_message(msg); } /* 清空中断 */ MAILBOX_INT_REG = (1 << 0); } } ​ /** * @brief 处理接收到的消息(示例) * @param msg 消息内容 */ void mailbox_process_message(uint32_t msg) { /* 消息格式: [8位命令][8位源ID][16位数据] */ uint8_t cmd = (msg >> 24) & 0xFF; uint8_t src_id = (msg >> 16) & 0xFF; uint16_t data = msg & 0xFFFF; switch (cmd) { case 0x01: /* 安全请求 */ mailbox_handle_secure_request(src_id, data); break; case 0x02: /* 密钥请求 */ mailbox_handle_key_request(src_id, data); break; case 0x03: /* 状态查询 */ mailbox_handle_status_query(src_id); break; default: /* 未知命令 */ break; } }

1.3 多核安全信息交互实现

多核之间传递安全信息时,需要对消息进行加密和签名,防止中间人攻击。

1.3.1 安全消息结构
/** * @file secure_ipc.h * @brief 安全核间通信消息结构 */ ​ #define SECURE_IPC_MAGIC 0x5A5A5A5A #define SECURE_IPC_VERSION 0x02 ​ typedef struct { uint32_t magic; /* 魔数 */ uint32_t version; /* 版本 */ uint32_t sequence; /* 序列号 */ uint32_t timestamp; /* 时间戳 */ uint8_t src_core; /* 源核心 ID */ uint8_t dst_core; /* 目标核心 ID */ uint8_t cmd; /* 命令 */ uint8_t reserved; /* 保留 */ uint32_t payload_len; /* 载荷长度 */ uint8_t payload[256]; /* 载荷数据 */ uint8_t signature[256]; /* RSA 签名 */ } secure_ipc_msg_t; ​ typedef struct { uint8_t key_id; /* 密钥 ID */ uint8_t key_type; /* 密钥类型 (AES/RSA/ECC) */ uint8_t key_len; /* 密钥长度 */ uint8_t key_data[64]; /* 密钥数据 (加密后) */ } ipc_key_msg_t;
1.3.2 安全消息发送与接收
/** * @file secure_ipc.c * @brief 安全核间通信实现 */ ​ #include "secure_ipc.h" #include "crypto_rsa.h" #include "crypto_sha.h" #include "trng.h" ​ static uint32_t g_ipc_sequence = 0; ​ /** * @brief 发送安全消息到另一个核心 * @param dst_core 目标核心 ID * @param cmd 命令 * @param payload 载荷数据 * @param len 载荷长度 * @return 0 成功,-1 失败 */ int secure_ipc_send(uint8_t dst_core, uint8_t cmd, const uint8_t *payload, uint32_t len) { secure_ipc_msg_t msg; uint8_t hash[32]; /* 1. 构造消息 */ memset(&msg, 0, sizeof(msg)); msg.magic = SECURE_IPC_MAGIC; msg.version = SECURE_IPC_VERSION; msg.sequence = ++g_ipc_sequence; msg.timestamp = get_system_time(); msg.src_core = get_current_core_id(); msg.dst_core = dst_core; msg.cmd = cmd; msg.payload_len = len; if (len > 256) { return -1; } memcpy(msg.payload, payload, len); /* 2. 计算消息哈希 (不包括签名) */ crypto_sha256_hw((uint8_t *)&msg, sizeof(msg) - 256, hash); /* 3. 用发送核心的私钥签名 */ uint8_t priv_key[256]; secure_storage_read(PRIV_KEY_ID, priv_key, &len); rsa_sign_hw(priv_key, 256, hash, 32, msg.signature); /* 4. 通过 Mail-box 发送 */ uint32_t *msg_words = (uint32_t *)&msg; for (int i = 0; i < sizeof(msg) / 4; i++) { if (mailbox_send(msg_words[i], 1000) != 0) { return -1; } } return 0; } ​ /** * @brief 接收并验证安全消息 * @param msg 接收的消息结构 * @return 0 成功,-1 验证失败,-2 序列号错误 */ int secure_ipc_receive(secure_ipc_msg_t *msg) { uint32_t *msg_words = (uint32_t *)msg; /* 1. 从 Mail-box 接收 */ for (int i = 0; i < sizeof(secure_ipc_msg_t) / 4; i++) { if (mailbox_receive(&msg_words[i]) != 0) { return -1; } } /* 2. 验证魔数和版本 */ if (msg->magic != SECURE_IPC_MAGIC || msg->version != SECURE_IPC_VERSION) { return -1; } /* 3. 验证序列号 (防重放) */ static uint32_t last_seq[4] = {0}; /* 每个核心的序列号 */ if (msg->sequence <= last_seq[msg->src_core]) { return -2; /* 重放攻击 */ } last_seq[msg->src_core] = msg->sequence; /* 4. 验证签名 */ uint8_t hash[32]; crypto_sha256_hw((uint8_t *)msg, sizeof(secure_ipc_msg_t) - 256, hash); uint8_t pub_key[256]; secure_storage_read(PUB_KEY_ID + msg->src_core, pub_key, &len); int ret = rsa_verify_hw(pub_key, 256, hash, 32, msg->signature); if (ret != 1) { return -1; } return 0; }

1.4 安全引擎 BOOTROM 开发

BOOTROM 是芯片复位后执行的第一段代码,它必须足够小、不可修改,并且能够验证后续固件。

1.4.1 BOOTROM 启动流程
[芯片上电复位] -> [BOOTROM 入口] | +-> 1. 初始化 CPU 基本状态 (栈指针、中断向量) | +-> 2. 检查 OTP 状态 (锁定标志、公钥哈希) | +-> 3. 从 Flash 读取第一级引导固件头部 | +-> 4. 验证固件签名 (RSA-2048) | +-> 验证通过: 跳转到固件入口 | +-> 验证失败: 进入安全故障状态 | +-> 5. 如果验证通过,跳转到固件入口 | +-> 固件执行,继续加载后续代码 | +-> 6. 安全故障状态: +-> 停止 CPU,发送错误指示(LED/GPIO)
1.4.2 BOOTROM 代码实现(汇编 + C)
/** * @file bootrom.s * @brief BOOTROM 汇编启动代码 */ ​ /* RISC-V BOOTROM 启动代码 */ .section .bootrom, "ax" .globl _start ​ _start: /* 1. 设置栈指针 (使用内部 SRAM) */ li sp, 0x20004000 /* 2. 初始化中断向量 */ la t0, _start csrw mtvec, t0 /* 3. 清空缓存 */ li t0, 0 csrw mstatus, t0 /* 4. 调用 C 主函数 */ call bootrom_main /* 5. 如果返回,进入安全故障 */ li a0, 0xDEADBEEF j secure_fault ​ /* 安全故障处理 */ secure_fault: /* 亮红灯、停止 CPU */ li t0, 0x10000000 /* GPIO 基址 */ li t1, 0x80000000 sw t1, 0(t0) /* 进入无限循环 */ wfi j secure_fault
/** * @file bootrom.c * @brief BOOTROM C 代码实现 */ ​ #include <stdint.h> #include <string.h> ​ /* BOOTROM 常量和结构 */ #define BOOTROM_MAGIC 0x5AFE5AFE #define BOOTROM_HEADER_SIZE 64 #define BOOTROM_SIGNATURE_SIZE 256 ​ /* OTP 基址 */ #define OTP_BASE 0x10000000 #define OTP_ROOT_HASH (OTP_BASE + 0x100) ​ /* Flash 基址 */ #define FLASH_BASE 0x20000000 #define FW_HEADER_ADDR FLASH_BASE ​ /* 固件头部结构 */ typedef struct __attribute__((packed)) { uint32_t magic; uint32_t header_size; uint32_t payload_size; uint32_t version; uint32_t boot_address; uint8_t reserved[16]; uint8_t fw_hash[32]; uint8_t signature[256]; } fw_header_t; ​ /* 硬件抽象函数 (由 BOOTROM 实现) */ int otp_read(uint32_t addr, uint8_t *buf, uint32_t len) { /* OTP 硬件读取 */ for (uint32_t i = 0; i < len; i++) { buf[i] = *((uint8_t *)(OTP_BASE + addr + i)); } return 0; } ​ int flash_read(uint32_t addr, uint8_t *buf, uint32_t len) { /* Flash 硬件读取 */ for (uint32_t i = 0; i < len; i++) { buf[i] = *((uint8_t *)(FLASH_BASE + addr + i)); } return 0; } ​ void sha256_hw(const uint8_t *data, uint32_t len, uint8_t *digest) { /* 调用硬件 SHA-256 引擎 */ /* 实际代码需要配置 SHA 引擎寄存器 */ /* 这里使用软件模拟 */ extern void sha256_sw(const uint8_t *, uint32_t, uint8_t *); sha256_sw(data, len, digest); } ​ int rsa_verify_hw(const uint8_t *pubkey, const uint8_t *hash, const uint8_t *signature) { /* 调用硬件 RSA 验签引擎 */ /* 实际代码需要配置 RSA 引擎寄存器 */ /* 返回 1 成功,0 失败 */ return 1; /* 模拟成功 */ } ​ /** * @brief BOOTROM 主函数 (从汇编跳转进入) */ void bootrom_main(void) { fw_header_t header; uint8_t otp_root_hash[32]; uint8_t fw_hash[32]; uint8_t pubkey[256]; /* 1. 读取 OTP 根公钥哈希 */ if (otp_read(OTP_ROOT_HASH, otp_root_hash, 32) != 0) { goto secure_fault; } /* 2. 读取固件头部 */ if (flash_read(0, (uint8_t *)&header, sizeof(header)) != 0) { goto secure_fault; } /* 3. 验证魔数 */ if (header.magic != BOOTROM_MAGIC) { goto secure_fault; } /* 4. 读取公钥 (从 OTP 或 Flash) */ if (otp_read(OTP_BASE + 0x200, pubkey, 256) != 0) { goto secure_fault; } /* 5. 计算固件哈希 */ uint8_t *fw_data = (uint8_t *)(FLASH_BASE + sizeof(header)); sha256_hw(fw_data, header.payload_size, fw_hash); /* 6. 验证固件哈希 */ if (memcmp(fw_hash, header.fw_hash, 32) != 0) { goto secure_fault; } /* 7. RSA 验签 */ if (rsa_verify_hw(pubkey, fw_hash, header.signature) != 1) { goto secure_fault; } /* 8. 验证通过,跳转到固件入口 */ void (*entry)(void) = (void (*)(void))(FLASH_BASE + header.boot_address); entry(); /* 不会执行到这里 */ return; ​ secure_fault: /* 进入安全故障状态 */ while (1) { __asm__ volatile ("wfi"); } }

1.5 OTP 驱动开发与密钥存储

1.5.1 OTP 驱动实现(包括写保护)
/** * @file otp_driver.c * @brief OTP 驱动实现 (带写保护) */ ​ #include <stdint.h> #include <stdbool.h> ​ /* OTP 控制器寄存器 (假设基址 0x20000000) */ #define OTP_CTRL (*(volatile uint32_t *)(0x20000000)) #define OTP_STATUS (*(volatile uint32_t *)(0x20000004)) #define OTP_ADDR (*(volatile uint32_t *)(0x20000008)) #define OTP_WDATA (*(volatile uint32_t *)(0x2000000C)) #define OTP_RDATA (*(volatile uint32_t *)(0x20000010)) #define OTP_LOCK (*(volatile uint32_t *)(0x20000014)) ​ /* OTP 控制位 */ #define OTP_CTRL_READ (1 << 0) #define OTP_CTRL_WRITE (1 << 1) #define OTP_CTRL_ERASE (1 << 2) #define OTP_CTRL_LOCK (1 << 3) #define OTP_CTRL_BUSY (1 << 4) ​ /* OTP 状态位 */ #define OTP_STATUS_READY (1 << 0) #define OTP_STATUS_ERROR (1 << 1) ​ /* OTP 锁定区域 (每 4 字节一个锁定位) */ #define OTP_LOCK_OFFSET(addr) ((addr) / 4) ​ /** * @brief 等待 OTP 控制器就绪 */ static void otp_wait_ready(void) { while (OTP_CTRL & OTP_CTRL_BUSY) { /* 等待完成 */ } } ​ /** * @brief 检查 OTP 地址是否已锁定 * @param addr OTP 地址 (字节偏移) * @return 1 已锁定,0 未锁定 */ int otp_is_locked(uint32_t addr) { uint32_t lock_word = OTP_LOCK >> (OTP_LOCK_OFFSET(addr) & 31); return (lock_word & 1) ? 1 : 0; } ​ /** * @brief 从 OTP 读取数据 * @param addr OTP 地址 (字节偏移) * @param buf 输出缓冲区 * @param len 读取长度 (字节) * @return 0 成功,-1 失败 */ int otp_read(uint32_t addr, uint8_t *buf, uint32_t len) { otp_wait_ready(); for (uint32_t i = 0; i < len; i += 4) { OTP_ADDR = addr + i; OTP_CTRL = OTP_CTRL_READ; otp_wait_ready(); uint32_t data = OTP_RDATA; for (int j = 0; j < 4 && i + j < len; j++) { buf[i + j] = (data >> (j * 8)) & 0xFF; } } return 0; } ​ /** * @brief 写入 OTP (一次性操作) * @param addr OTP 地址 (4 字节对齐) * @param data 要写入的数据 (4 字节) * @return 0 成功,-1 失败 */ int otp_write(uint32_t addr, uint32_t data) { if ((addr & 3) != 0) { return -1; /* 地址必须 4 字节对齐 */ } if (otp_is_locked(addr)) { return -1; /* 已锁定 */ } otp_wait_ready(); OTP_ADDR = addr; OTP_WDATA = data; OTP_CTRL = OTP_CTRL_WRITE; otp_wait_ready(); if (OTP_STATUS & OTP_STATUS_ERROR) { return -1; } return 0; } ​ /** * @brief 锁定 OTP 地址 (永久禁止写入) * @param addr OTP 地址 * @return 0 成功,-1 失败 */ int otp_lock_region(uint32_t addr) { if ((addr & 3) != 0) { return -1; } otp_wait_ready(); OTP_ADDR = addr; OTP_CTRL = OTP_CTRL_LOCK; otp_wait_ready(); if (OTP_STATUS & OTP_STATUS_ERROR) { return -1; } return 0; }

1.6 数字签名解密与验证流程

数字签名解密(即签名验签)是安全启动、安全升级、安全通信的核心。完整流程如下:

1.6.1 数字签名验证流程
[签名数据] -> [SHA-256 哈希计算] -> [RSA-2048 验签] -> [验证结果] | | | | | +-> [签名有效] -> 允许执行 | | +-> [签名无效] -> 拒绝执行 | | | +-> [使用公钥解密密文] | +-> [从 OTP 读取根公钥]
1.6.2 数字签名验证完整代码
/** * @file sig_verify.c * @brief 数字签名验证完整实现 */ ​ #include <stdint.h> #include <string.h> #include "crypto_sha.h" #include "crypto_rsa.h" #include "otp_driver.h" ​ #define SIGNATURE_SIZE 256 #define HASH_SIZE 32 #define RSA_KEY_SIZE 256 ​ /** * @brief 验证数字签名 (完整流程) * @param data 原始数据 * @param data_len 数据长度 * @param signature 签名 (256 字节) * @param key_id 公钥 ID (从 OTP 或安全存储读取) * @return 1 有效,0 无效,-1 错误 */ int verify_signature(const uint8_t *data, uint32_t data_len, const uint8_t *signature, uint32_t key_id) { uint8_t hash[HASH_SIZE]; uint8_t pubkey[RSA_KEY_SIZE]; int ret; /* 1. 计算数据哈希 */ ret = crypto_sha256_hw(data, data_len, hash); if (ret != 0) { return -1; } /* 2. 从 OTP 或安全存储读取公钥 */ if (key_id < 16) { /* 从 OTP 读取 */ ret = otp_read(OTP_BASE + 0x200 + key_id * 256, pubkey, RSA_KEY_SIZE); } else { /* 从安全存储读取 */ ret = secure_storage_read(key_id, pubkey, &len); } if (ret != 0) { return -1; } /* 3. RSA 验签 */ ret = rsa_verify_hw(pubkey, RSA_KEY_SIZE, hash, HASH_SIZE, signature); return ret; /* 1 有效,0 无效 */ } ​ /** * @brief 加密数据并签名 (用于安全通信) * @param plaintext 明文 * @param pt_len 明文长度 * @param ciphertext 输出密文 * @param signature 输出签名 * @param key_id 用于签名的私钥 ID * @return 0 成功,-1 失败 */ int sign_and_encrypt(const uint8_t *plaintext, uint32_t pt_len, uint8_t *ciphertext, uint8_t *signature, uint32_t key_id) { uint8_t hash[HASH_SIZE]; uint8_t priv_key[RSA_KEY_SIZE]; uint8_t aes_key[32]; int ret; /* 1. 生成随机 AES 密钥 */ trng_get_random(aes_key, 32); /* 2. 使用 AES-GCM 加密数据 */ uint8_t iv[12]; trng_get_random(iv, 12); uint8_t tag[16]; ret = aes_gcm_encrypt_hw(aes_key, 32, iv, 12, plaintext, pt_len, ciphertext + 12 + 16, tag); if (ret != 0) { return -1; } /* 3. 计算加密数据的哈希 */ ret = crypto_sha256_hw(ciphertext + 12 + 16, pt_len, hash); if (ret != 0) { return -1; } /* 4. 使用私钥签名哈希 */ ret = secure_storage_read(key_id, priv_key, &len); if (ret != 0) { return -1; } ret = rsa_sign_hw(priv_key, RSA_KEY_SIZE, hash, HASH_SIZE, signature); if (ret != 1) { return -1; } /* 5. 构造输出:IV + Tag + 密文 + 签名 */ memcpy(ciphertext, iv, 12); memcpy(ciphertext + 12, tag, 16); memcpy(ciphertext + 12 + 16 + pt_len, signature, 256); return 0; }

1.7 安全模块固件开发中的常见问题与调试

问题现象调试方法
BOOTROM 无法启动芯片复位后无响应1. 检查 BOOTROM 是否被错误擦除 2. 检查 CPU 复位向量是否正确 3. 使用 JTAG 读取 BOOTROM 前几条指令
OTP 写入失败编程后回读全 01. 检查 OTP 编程电压和时序 2. 确认地址和数据类型是否对齐 3. 检查 OTP 是否已锁定
Mail-box 消息丢失发送后接收端收不到消息1. 检查 Mail-box 中断是否启用 2. 检查接收缓冲区是否溢出 3. 增加发送等待超时
签名验证失败固件无法通过安全启动1. 检查公钥是否匹配 OTP 存储 2. 确认签名算法类型 (RSA/ECDSA) 3. 验证哈希计算是否正确
多核通信异常核间消息校验失败1. 检查序列号是否重复 (防重放) 2. 验证消息签名是否正确 3. 检查核心 ID 映射是否正确
安全存储数据损坏读取数据完整性校验失败1. 检查 Flash 存储区域的 CRC 2. 确认加密密钥是否正确 3. 检查 HMAC 计算是否一致

第二部分 开源安全组件分析与总结

2.1 MCUboot 文件树与功能分析

MCUboot 是用于微控制器的安全启动加载程序,支持双分区、签名验证、回滚保护等。以下是其文件树结构及功能分析。

2.1.1 MCUboot 文件树
mcuboot/ ├── boot/ │ ├── bootutil/ # 启动工具库 │ │ ├── include/ # 头文件 │ │ │ ├── bootutil/bootutil.h # 启动工具主接口 │ │ │ ├── bootutil/encrypted.h # 固件加密支持 │ │ │ └── bootutil/crc.h # CRC 校验函数 │ │ ├── src/ # 源码 │ │ │ ├── bootutil.c # 启动逻辑 (查找分区、验证镜像) │ │ │ ├── crypto_common.c # 加密抽象层 │ │ │ ├── encryption_*.c # 加密具体实现 │ │ │ └── loader.c # 镜像加载和引导 │ │ └── README │ ├── zephyr/ # Zephyr OS 移植 │ │ ├── prj.conf # 配置 │ │ ├── CMakeLists.txt │ │ └── src/ │ │ └── main.c # Zephyr 入口 │ ├── mynewt/ # Mynewt OS 移植 │ └── mbed/ # Mbed OS 移植 ├── docs/ # 文档 │ ├── design.md # 设计文档 │ ├── encrypted_images.md # 固件加密文档 │ ├── porting.md # 移植指南 │ └── signed_images.md # 签名镜像指南 ├── samples/ # 示例 │ └── blinky/ # 示例应用 ├── scripts/ # 工具脚本 │ ├── imgtool.py # 镜像签名工具 (Python) │ ├── imgtool_rsa.py # RSA 签名 │ ├── imgtool_ecdsa.py # ECDSA 签名 │ ├── keygen.py # 密钥生成工具 │ └── flash_map.py # Flash 分区映射 ├── ext/ # 外部依赖 │ └── mbedtls/ # Mbed TLS (用于加密) ├── include/ # 公共头文件 │ ├── bootutil_flash.h # Flash 操作抽象 │ └── bootutil_public.h # 公共 API ├── CMakeLists.txt ├── Kconfig └── README.md
2.1.2 MCUboot 关键文件功能详解
文件功能常修改的地方
bootutil.c启动核心逻辑:查找分区、验证签名、选择启动镜像bootutil_verify_sig函数(签名验证算法)、bootutil_choose_image(分区选择策略)
loader.c镜像加载器:从 Flash 复制镜像到 SRAM/DRAMboot_copy_image函数(复制策略)、boot_swap(双分区切换)
crypto_common.c加密抽象层:定义bootutil_sha256bootutil_rsa_verify添加新的加密算法(如 SM2/SM3)
encryption_*.c固件加密实现:AES-128/256 加密镜像boot_encrypt_imageboot_decrypt_image(加密/解密逻辑)
imgtool.py镜像签名工具:命令行签名、生成公钥添加新的签名格式或密钥类型
flash_map.cFlash 分区映射:定义分区布局flash_map结构(根据芯片 Flash 布局修改)
Kconfig配置选项:启用加密、调试、回滚等MCUBOOT_ENCRYPT,MCUBOOT_SIGN_EC256
2.1.3 MCUboot 集成示例(Zephyr)
/** * @file mcuboot_integrate.c * @brief MCUboot 集成到 Zephyr 示例 */ ​ /* 1. 初始化 MCUboot */ int mcuboot_init(void) { int ret = bootutil_init(); if (ret != 0) { return -1; } /* 2. 选择启动镜像 */ int boot_result = bootutil_choose_image(); if (boot_result != 0) { /* 所有镜像无效,进入恢复模式 */ return -2; } /* 3. 加载镜像 */ ret = bootutil_load_image(); if (ret != 0) { return -3; } return 0; } ​ /** * @brief 验证镜像签名 (自定义实现) * @param img_addr 镜像地址 * @param size 镜像大小 * @param pubkey 公钥 (从 OTP 读取) * @return 0 成功,-1 失败 */ int mcuboot_verify_custom(uint32_t img_addr, uint32_t size, const uint8_t *pubkey) { /* 计算哈希 */ uint8_t hash[32]; crypto_sha256_hw((uint8_t *)img_addr, size, hash); /* 读取签名 (镜像末尾 256 字节) */ uint8_t signature[256]; flash_read(img_addr + size - 256, signature, 256); /* RSA 验签 */ return rsa_verify_hw(pubkey, 256, hash, 32, signature); }

2.2 TFM (Trusted Firmware-M) 文件树与功能分析

TFM 是 Arm 为 Cortex-M 处理器提供的安全固件框架,实现了 PSA 安全标准。

2.2.1 TFM 文件树
tfm/ ├── docs/ # 文档 │ ├── security/ # 安全设计文档 │ ├── user_guides/ # 用户指南 │ └── platform/ # 平台文档 ├── platform/ # 平台移植 │ ├── arm/ # Arm 平台 (Cortex-M) │ ├── nxp/ # NXP 平台 │ ├── stm32/ # STM32 平台 │ └── boards/ # 开发板配置 ├── secure_fw/ # 安全固件 │ ├── core/ # 核心服务 │ │ ├── spm.h # 安全分区管理器 │ │ ├── psa_crypto.h # PSA 加密接口 │ │ └── psa_attestation.h # PSA 认证服务 │ ├── partitions/ # 安全分区 │ │ ├── crypto/ # 加密服务 │ │ ├── attestation/ # 认证服务 │ │ ├── internal_trusted_storage/ # 内部安全存储 │ │ └── protected_storage/ # 受保护存储 │ └── services/ # 安全服务 │ ├── tfm_crypto_api.c # 加密 API │ ├── tfm_attestation_api.c # 认证 API │ └── tfm_secure_storage.c # 安全存储 API ├── interface/ # 安全/非安全接口 │ ├── include/ # 头文件 │ │ ├── psa/ # PSA 标准头文件 │ │ └── tfm_veneers.h # 安全呼叫 veneer │ └── src/ # 接口实现 │ └── tfm_veneers.c # veneer 函数 ├── non_secure/ # 非安全应用 │ ├── CMakeLists.txt │ └── src/ │ └── main_ns.c # 非安全主程序 ├── build/ # 构建目录 ├── CMakeLists.txt ├── Kconfig └── README.md
2.2.2 TFM 关键文件功能详解
文件功能常修改的地方
spm.h安全分区管理器:定义分区配置、内存隔离spm_partition_config(添加新分区)、spm_memory_isolation(内存隔离策略)
psa_crypto.hPSA 加密接口:算法定义、密钥管理添加自定义加密算法(如 SM2/SM3)
tfm_veneers.c安全呼叫 veneer:非安全世界调用安全服务的入口添加新的安全服务函数(tfm_veneer_new_service
tfm_crypto_api.c加密 API 实现:AES、RSA、SHA 等替换底层加密引擎(硬件加速/软件实现)
tfm_secure_storage.c安全存储 API:读写、完整性保护修改存储后端(Flash/OTP/SRAM)
platform/*平台移植:Flash、串口、中断配置根据芯片硬件修改 Flash 驱动、OTP 驱动
2.2.3 TFM 集成示例
/** * @file tfm_integrate.c * @brief TFM 集成示例 */ ​ #include "psa/crypto.h" #include "tfm_veneers.h" ​ /** * @brief TFM 初始化 (安全启动后调用) */ void tfm_init(void) { psa_status_t status; /* 1. 初始化 PSA 加密 */ status = psa_crypto_init(); if (status != PSA_SUCCESS) { tfm_fault_handler(status); } /* 2. 初始化安全存储 */ status = psa_its_init(); if (status != PSA_SUCCESS) { tfm_fault_handler(status); } /* 3. 初始化认证服务 */ status = psa_attestation_init(); if (status != PSA_SUCCESS) { tfm_fault_handler(status); } } ​ /** * @brief 使用 TFM 安全存储写入数据 * @param uid 存储 ID * @param data 数据指针 * @param len 数据长度 * @return 0 成功,-1 失败 */ int tfm_secure_storage_write(uint32_t uid, const uint8_t *data, uint32_t len) { psa_status_t status; /* 1. 检查 UID 合法性 */ if (uid >= 0x1000) { return -1; } /* 2. 调用 TFM 安全存储 API (通过 veneer) */ status = tfm_psa_its_set(uid, len, data, 0); if (status != PSA_SUCCESS) { return -1; } return 0; } ​ /** * @brief 使用 TFM 加密服务 (AES-GCM) * @param key 密钥 * @param key_len 密钥长度 * @param plain 明文 * @param pt_len 明文长度 * @param cipher 输出密文 * @param tag 输出认证标签 * @return 0 成功,-1 失败 */ int tfm_aes_gcm_encrypt(const uint8_t *key, size_t key_len, const uint8_t *plain, size_t pt_len, uint8_t *cipher, uint8_t *tag) { psa_status_t status; psa_key_handle_t key_handle; psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; size_t out_len; /* 1. 设置密钥属性 */ psa_set_key_type(&attributes, PSA_KEY_TYPE_AES); psa_set_key_algorithm(&attributes, PSA_ALG_GCM); psa_set_key_bits(&attributes, key_len * 8); /* 2. 导入密钥 */ status = psa_import_key(&attributes, key, key_len, &key_handle); if (status != PSA_SUCCESS) { return -1; } /* 3. AES-GCM 加密 */ uint8_t iv[12] = {0}; /* 实际应使用随机 IV */ status = psa_aead_encrypt(key_handle, PSA_ALG_GCM, iv, 12, NULL, 0, plain, pt_len, cipher, pt_len + 16, &out_len); if (status != PSA_SUCCESS) { psa_destroy_key(key_handle); return -1; } /* 4. 提取 Tag */ memcpy(tag, cipher + pt_len, 16); psa_destroy_key(key_handle); return 0; }

2.3 TLS/SSL/mTLS 安全通信方案树形对比

特性TLS 1.2TLS 1.3mTLS (双向认证)DTLS (UDP)
协议版本RFC 5246RFC 8446基于 TLS 1.2/1.3RFC 6347
握手轮数2 轮 (4 个消息)1 轮 (2 个消息)1 轮 (2 个消息)1 轮 (2 个消息)
支持算法RSA、ECDHE、DHEECDHE 必须,RSA 可选同 TLS同 TLS 1.3
加密套件多种组合5 种标准套件同 TLS同 TLS 1.3
证书验证可配置强制验证双向验证同 TLS
性能2 RTT 握手1 RTT 握手 (0-RTT 可用)略高略高
嵌入式支持mbedTLS, wolfSSLmbedTLS 3.0+需额外配置mbedTLS 支持
2.3.1 在嵌入式中的性能对比
设备TLS 1.2 内存使用TLS 1.3 内存使用握手时间 (1KB 数据)
Cortex-M3 (100MHz)8KB RAM6KB RAM800ms
Cortex-M4 (200MHz)10KB RAM8KB RAM400ms
Cortex-M7 (400MHz)12KB RAM10KB RAM200ms
RISC-V (500MHz)10KB RAM8KB RAM250ms

2.4 整体架构评审(SWOT 分析)

维度内容
优势 (Strengths)- 完整的信任链:BOOTROM -> 固件 -> 应用 - 硬件安全模块:OTP、PMP、加密引擎 - 安全存储加密和完整性保护 - 多核安全通信
劣势 (Weaknesses)- BOOTROM 固定且不可更新,一旦漏洞无法修补 - OTP 编程是一次性,无法更改配置 - 依赖外部工具签名(imgtool) - PMP 实现需要手动配置
机会 (Opportunities)- 支持更多加密算法(SM2/SM3/SM4) - 集成 MCUboot 提高灵活性 - 使用 TEE/TrustZone 增强隔离 - 支持更高速接口(PCIe/USB3.0)
威胁 (Threats)- 侧信道攻击(功耗、电磁) - 故障注入攻击(电压、时钟) - 物理探针攻击(解密密钥) - 后门漏洞

2.5 未来演进路线

2.5.1 短期
项目目标技术方案预计提升
支持更多加密算法满足各国标准集成 SM2/SM3/SM4扩展认证范围
硬件加速集成减少 CPU 占用使用 FPGA/DMA 加速加密性能 3-5 倍
OTA 压缩减少传输带宽集成 lz4/zlib升级速度 2-3 倍
远程认证设备身份验证实现 RFC 8472 (DICE)增强安全性
2.5.2 中期
项目目标技术方案预计提升
物理防攻击抵抗侧信道攻击使用掩蔽、随机化提高安全性
区块链集成设备身份溯源在链上存储设备哈希防止伪造
自愈机制从攻击中恢复自动备份和恢复增加容错
量子安全抗量子计算攻击集成 PQC (如 FALCON, Dilithium)长期安全

2.6 持续集成与测试策略

2.6.1 CI/CD 流水线
# .gitlab-ci.yml stages: - build - test - security - deploy ​ build-job: stage: build script: - make clean - make all - make bootrom - make fw_signed artifacts: paths: - build/bootrom.bin - build/fw_signed.bin ​ test-job: stage: test script: - make test-unit - make test-integration - make test-fault-injection coverage: /Coverage: \d+\.\d+%/ ​ security-job: stage: security script: - make security-scan - make sonarqube - make sbom variables: SONAR_TOKEN: $SONAR_TOKEN ​ deploy-job: stage: deploy script: - make sign-firmware - make upload-firmware only: - tags
2.6.2 测试覆盖率要求
测试类型覆盖率要求测试用例数量
单元测试80% 行覆盖500+
集成测试90% 功能覆盖200+
安全测试100% 安全功能100+
故障注入90% 故障路径50+
渗透测试所有已知漏洞50+
硬件测试100% 寄存器访问100+

2.7 研发路线图

季度主要任务交付物里程碑
Q1- 实现 SM2/SM3/SM4 支持 - 集成 MCUboot 双分区- 算法实现 - 固件签名工具完成国密支持
Q2- 硬件加速集成(DMA + AES) - 固件压缩- 高效加密 API - lz4 压缩库加密性能提升 3 倍
Q3- 远程认证 (DICE) - 侧信道防护- 设备身份验证 - 掩蔽实现通过 PSA Level 2
Q4- 整体文档整理 - 开源发布- 技术白皮书 - 开发板支持通过 CE/CCC 认证

2.8 总结

安全芯片固件开发是一个综合性极强的领域,涉及密码学、硬件设计、嵌入式软件、系统架构等多个学科。

核心设计原则:

  1. 信任根不可篡改:BOOTROM + OTP 构建不可绕过的安全起点。

  2. 最小化信任:逐级验证,每级仅信任下级一级。

  3. 分层防御:硬件隔离 + 加密 + 签名 + 认证。

  4. 可恢复性:双分区 + 回滚,防止升级失败导致设备变砖。

  5. 可观测性:统计和日志,便于调试和监控。

推荐进阶路径:

  1. 先精通 MCUboot 和 TFM 的基础用法。

  2. 学习硬件加密引擎的驱动开发。

  3. 熟悉 OTP 和安全存储的设计。

  4. 掌握安全调试和认证流程。

  5. 参与 PSA 和 CCC/CE/FCC 认证项目。

http://www.cnnetsun.cn/news/2755429.html

相关文章:

  • 拆解低空智联:四位一体架构、落地场景与行业瓶颈|《低空智联技术与应用白皮书 2026》深度复盘
  • 提升qorder开发效率:用快马AI一键生成智能订单计价与优惠核销模块
  • CodeForge v26.0.0 里程碑式更新:进化为轻量编辑器,内置 AI 助手!
  • 告别模拟器卡顿:APK Installer让Windows直接安装安卓应用的完整指南
  • GPT-4o结构化输出100%准确:JSON Schema生成稳定性实战指南
  • 3个技巧:用Draw.io Mermaid插件实现代码驱动图表设计
  • 大模型长期记忆同步:多 Agent 间的消息路由机制设计
  • IPXWrapper技术方案:为现代Windows系统重构IPX/SPX兼容层,重温经典游戏网络对战
  • YOLOv5视觉瞄准系统架构剖析:基于深度学习的目标检测与实时控制技术实现
  • 2026 论文降AI率工具终极测评:真实体验分享,毕业党生存手册
  • 告别死记硬背:用‘小树’和‘铃儿’轻松搞定三十六计(附110位数字编码表)
  • AI工具链如何接管企业搜索?3步实现语义理解→意图识别→精准召回的闭环升级
  • 【金融级AI质押架构设计指南】:基于FISCO BCOS+LangChain+TEE的三重可信验证体系(附压测QPS 12,800实测报告)
  • HR总监紧急通知:下季度起所有请假系统必须通过ISO/IEC 23894 AI治理认证,你准备好了吗?
  • 别再手动整理了!用WPS宏一键提取汉字拼音首字母,批量处理通讯录超省心
  • Agent“活”起来!企业级动态RAG的可靠记忆与知识进化之路
  • 如何在5分钟内为Windows 11 24H2 LTSC恢复微软应用商店:新手完整指南
  • Qt Quick Canvas 画布实战:手把手教你用QML打造一个可复用的汽车仪表盘组件
  • SuperPNG终极指南:如何用免费插件彻底优化Photoshop PNG导出
  • 从航拍到成图:一次讲透无人机测绘中比例尺、GSD与航高设计的完整工作流(以1:1000地形图为例)
  • Kimi K2.6 AI Agent实战解析:任务拆解、工具调用与自主反思
  • 【仅限Q3开放】AI融资整合能力成熟度测评(含17项技术适配指标+3类企业定制路径),测完即生成金融机构认可的接入资质预评估报告
  • AI Agent(智能体)应用工程师:年薪50W+的AI风口,零基础也能入行
  • 3大突破重构ESP32物联网开发:从零到精通的完整指南
  • 从峰会实践看科技女性职业发展:架构、策略与可持续影响
  • Moneta Markets亿汇:聚焦细节,看看风控思路的关键细节
  • 9V电池转±5V双电源:线性稳压器与电荷泵的工程实践
  • 电路设计入门:从核心概念到实战项目,掌握硬件开发基础
  • 3分钟掌握:告别网盘限速困扰的浏览器脚本终极指南
  • 面试官:agent的三层记忆系统是啥