嵌入式安全启动详解:从信任根、镜像签名到量产实践
1. 嵌入式安全启动概述
嵌入式设备已经深度融入工业控制、汽车电子、智能家居、医疗设备、通信基站和物联网终端等场景。随着设备联网率不断提高,固件成为攻击者最关注的目标之一。一旦引导阶段的校验缺失,攻击者可以在设备上电启动时植入恶意代码、替换内核、修改启动参数或关闭安全机制,而且这类攻击往往发生在操作系统安全能力建立之前,传统的杀毒软件、运行时防护都难以生效。
安全启动(Secure Boot)解决的核心问题是:保证设备从第一行 ROM 代码开始,到最终加载操作系统和应用的整个过程中,每一级被加载的代码都是可信的、未被篡改的、并来自合法发布者。它的本质不是“防止设备被攻击”,而是“保证启动链路中每一步的代码来源可信、内容完整”。如果某一级校验失败,设备可以选择拒绝启动、进入恢复模式或回退到安全状态。
与传统的“引导加载”相比,安全启动增加了一系列密码学校验动作。它通常需要依赖植入芯片内部且不可修改的信任根(Root of Trust,RoT),然后通过逐级验签的方式延伸信任链。信任根一旦被硬件固化,攻击者即使拿到了完整固件镜像,也无法伪造一个能够通过校验的启动镜像,除非攻破了密钥体系本身。
需要特别说明的是,安全启动不等于“设备绝对安全”。它解决的是启动阶段的代码完整性与来源可信问题,并不能自动解决运行时内存破坏、逻辑漏洞、侧信道攻击等问题。一个完整的安全体系通常需要把安全启动、安全升级、安全存储、远程认证、安全通信等能力结合起来。
2. 安全启动的核心概念与信任链
2.1 信任根、信任链与信任边界
信任根是安全启动体系中第一个被无条件信任的组件。它可以是固化在芯片内部的引导 ROM(Boot ROM)、存储在 eFuse/OTP 中的公钥哈希、安全元件中的初始密钥等。信任根必须满足两个条件:一是无法在设备出厂后被修改;二是其正确性经过芯片设计和制造过程的验证。
信任链(Chain of Trust)是指从信任根开始,逐级验证下一级软件的过程。典型的嵌入式启动链路如下:
Boot ROM(硬件信任根)
-> 验证并加载 FSBL(第一级引导程序)
-> 验证并加载 SSBL(第二级引导程序,如 U-Boot)
-> 验证并加载内核 Kernel
-> 验证并加载根文件系统 RootFS / 应用镜像
每一级加载器在把控制权交给下一级之前,都需要先验证下一级镜像的签名。信任之所以能够从硬件传递到最后的应用,是因为每一级“被信任的代码”都在执行“验证下一级”的动作。任何一个环节如果跳过了验签,后续的信任链就断裂了,攻击者就可以从这个薄弱点注入恶意代码。
信任边界(Trust Boundary)则用来划分“可信区域”和“不可信区域”。例如 Boot ROM 内部执行的环境是可信的,外部 SPI NOR Flash 中存储的固件是不可信的,必须经过验证才能加载到内存执行。明确信任边界有助于判断哪些数据必须校验、哪些代码必须隔离、哪些外设访问必须受控。
2.2 静态信任链与动态信任链
静态信任链(Static Root of Trust)是当前嵌入式安全启动最常见的形式,从 Boot ROM 开始逐级验证,启动过程中每一级的验证动作都是串行发生的。它的优点是实现简单、边界清晰、硬件依赖较小;缺点是启动时间会随着镜像体积增大而增加,而且如果某级引导程序自身存在漏洞,信任链可能被破坏。
动态信任链(Dynamic Root of Trust for Measurement,DRTM,动态信任根测量)则是在系统运行到某个时刻后,通过 CPU 的特殊指令重新建立一个隔离且可信的执行环境,例如 Intel TXT、AMD SVM、ARM 的某些可信执行环境能力。动态信任链更适合复杂系统,但在资源受限的嵌入式平台上实现成本较高,目前主要出现在高端 SoC 和可信计算场景中。
2.3 安全启动的常见实现层次
从工程实践看,嵌入式安全启动通常涉及四个层次:
- 第一层:芯片硬件级。包括 Boot ROM、eFuse/OTP、硬件哈希引擎、硬件密码引擎、安全熔丝和生命周期控制等。
- 第二层:引导固件级。包括厂商提供的 FSBL、开放源码的 U-Boot、TF-A(Trusted Firmware-A)、OP-TEE 等。
- 第三层:操作系统级。包括 Linux 内核模块签名、内核镜像验签、rootfs 完整性校验、dm-verity/dm-crypt 等。
- 第四层:应用与升级级。包括 OTA 升级包签名、A/B 分区回滚保护、应用签名、安全存储凭据等。
3. 嵌入式系统的攻击面与威胁模型
3.1 为什么要做威胁建模
安全启动的设计离不开威胁模型。不同产品的攻击者能力、攻击成本、防护目标差异巨大。例如消费级路由器需要防止远程固件篡改,汽车 ECU 需要防止物理接入总线的攻击,支付终端则需要对抗具备芯片级逆向能力的攻击者。只有明确“保护什么、防谁、在什么条件下”,才能选择合适的安全启动方案,避免过度设计导致成本失控,也避免设计不足留下明显漏洞。
常见的威胁建模维度包括:攻击者的技术能力、是否具备物理接触条件、是否拥有调试接口权限、是否能获取固件、是否能进行芯片逆向、攻击目标是偷取密钥还是植入后门、攻击是一次性还是批量性等。
3.2 固件篡改与恶意代码注入
攻击者通过 JTAG、UART、SPI 编程器、芯片夹等方式直接读写外部 Flash,修改其中的启动镜像,或者在固件更新时劫持升级流程并植入恶意代码。安全启动应对该威胁的手段是对每一级镜像进行数字签名验证,使被篡改的镜像无法通过验签。对于没有安全启动的设备,攻击者只需修改一个跳转指令,就能让设备执行任意代码。
3.3 回滚攻击
回滚攻击是指攻击者保存了厂商早期发布的、含有已知漏洞的合法签名镜像,然后将设备软件降级到旧版本,再利用旧漏洞攻击设备。由于旧镜像的签名是合法的,单纯验签无法阻止回滚。安全启动体系通常需要配合版本计数、单调计数器、安全版本号(Security Version Number)或防回滚熔丝来对抗此类攻击。
常见的防回滚实现包括:在 OTP/eFuse 中保存最低安全版本号,每次启动时比较镜像版本和芯片中记录的安全版本;或者使用硬件单调计数器,只允许增加不允许减少;在 OTA 场景中使用版本链和 A/B 分区的安全元数据保护。
3.4 调试接口滥用与生命周期管理
JTAG、SWD、UART 等调试接口是开发阶段的必需品,但如果量产后仍然完全开放,攻击者就可以通过这些接口读写内存、提取固件、注入代码,甚至绕过安全启动。成熟方案通常引入芯片生命周期(Lifecycle)管理,把芯片状态划分为开发、量产、封闭、失效等阶段。例如量产完成后关闭 JTAG,或者写入一个安全密钥后才允许有限调试。部分芯片还支持“授权调试”,即用证书临时解锁调试功能。
3.5 侧信道攻击与故障注入
侧信道攻击通过功耗、电磁辐射、时间差等信息推断密钥或内部状态。故障注入通过电压毛刺、时钟毛刺、电磁脉冲、激光等手段让芯片在执行关键校验时产生错误,例如跳过签名校验、强制校验结果返回成功。高端安全芯片会通过随机延迟、掩码、双轨逻辑、故障检测电路等方式抵抗这些攻击。普通嵌入式 MCU 通常难以完全防御,因此在威胁建模中需要评估攻击者是否具备这类实验室级能力。
3.6 供应链与密钥泄露威胁
安全启动的强度和密钥管理的强度是一致的。如果私钥在生产服务器、构建主机、代码仓库或代工厂中泄露,攻击者就能签发任意恶意镜像。更隐蔽的攻击发生在供应链环节:构建工具被植入后门、第三方库带有恶意代码、交付的固件在运输中被替换。因此在设计安全启动体系时,必须把密钥生命周期管理、签名环境隔离、构建可审计性纳入统一考虑。
4. 密码学基础:哈希、签名与验签
4.1 哈希函数的作用
哈希函数把任意长度的数据映射为固定长度的摘要。安全启动中的哈希主要用于两个目的:一是快速检测镜像是否被篡改;二是作为数字签名算法的输入。常用算法包括 SHA-256、SHA-384、SHA-512,以及部分资源受限设备上的 SHA-1 历史实现。现代安全启动体系应尽量避免使用已被证明存在碰撞风险的 MD5 和 SHA-1。
#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>
int main(void)
{
unsigned char digest[SHA256_DIGEST_LENGTH];
const char *data = "Embedded secure boot payload";
SHA256((unsigned char *)data, strlen(data), digest);
printf("SHA-256: ");
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
printf("%02x", digest[i]);
printf("\n");
return 0;
}
上述代码使用 OpenSSL 计算数据的 SHA-256 摘要。实际芯片中通常会提供硬件哈希引擎,避免在 Boot ROM 中实现完整软件哈希库,同时也能提高启动速度。
4.2 非对称签名与验签原理
数字签名解决了两个问题:镜像确实来自持有私钥的发布者,以及镜像内容未被修改。签名方使用私钥对镜像哈希进行签名,验签方使用公钥验证签名是否有效。常用算法包括 RSA、ECDSA,以及近年来更受青睐的 Ed25519。其中 ECDSA 和 Ed25519 在相同安全强度下密钥更短、签名更小、计算更快,非常适合嵌入式场景。
流程图描述整个签名与验签过程如下:
flowchart TD
A[读取镜像文件] --> B[计算 SHA-256 哈希]
B --> C[使用发布者私钥对哈希签名]
C --> D[生成签名文件]
E[设备启动读取镜像] --> F[再次计算镜像哈希]
E --> G[读取签名文件]
F --> H[使用公钥验证签名]
G --> H
H -->|签名有效| I[允许加载执行]
H -->|签名无效| J[拒绝启动并进入安全策略]
验签时最重要的原则是:必须同时验证签名值和镜像哈希。如果只比较哈希而不验证签名,攻击者可以同时替换镜像和哈希值;如果只验证签名而不检查签名针对的哈希是否与当前镜像一致,攻击者可能重放旧签名。
4.3 公钥基础设施与密钥层级
在大规模量产场景下,通常不会直接使用一个根私钥签署所有镜像。工程上更推荐密钥分层:根密钥(Root Key)只用于签发下级密钥证书,镜像密钥(Image Signing Key)用于实际签署固件。这样当镜像密钥泄露或需要更换时,只需吊销旧密钥并分发新密钥证书,而无需更换烧录在芯片中的根公钥。
密钥层级通常包括:根密钥(Root of Trust Key)、固件签名密钥、升级包签名密钥、调试授权密钥、安全存储密钥等。不同类型的密钥用途分离,可以降低单点泄露造成的影响。
4.4 对称加密在安全启动中的角色
严格意义上的安全启动主要解决完整性和来源认证,不一定要求机密性。因此非对称验签是核心。但在很多方案中,启动镜像还需要加密,防止攻击者提取固件进行逆向分析。此时会引入对称加密,例如 AES-CBC、AES-CTR、AES-GCM 等。加密密钥通常由芯片内部唯一密钥派生,或者通过安全引导流程解密后加载,避免直接存储在普通 Flash 中。
加密与签名是两件事:加密解决“看不到”,签名解决“改不了、赖不掉”。一个完善的固件保护方案往往同时包含“先加密、再签名”或“签名后再加密”的组合。需要注意的是,如果镜像被加密,验签动作必须在解密后执行,或者在加密前签署的是明文镜像,设备需要先解密再验签,顺序设计要非常谨慎。
5. 硬件信任根与密钥存储
5.1 Boot ROM 与不可变启动代码
Boot ROM 是芯片出厂时固化在内部只读存储器中的第一段代码,通常由芯片厂商编写并经过严格审查。CPU 上电后首先从 Boot ROM 开始执行。Boot ROM 的职责包括初始化最小硬件环境、确定启动介质、读取外部启动镜像、验证签名、解密、加载并跳转执行。Boot ROM 本身是不可修改的,因此它是天然的可信起点。
由于 Boot ROM 无法在出厂后修复,任何 Boot ROM 中的漏洞都可能是永久性的,只能通过后续软件补丁、外置安全策略或芯片生命周期控制来缓解。这也是为什么安全启动设计强调 Boot ROM 应尽量简单、减少可被攻击的代码路径。
5.2 OTP 与 eFuse 存储
一次可编程存储器(One-Time Programmable,OTP)或电子熔丝(eFuse)用于存储不可修改的安全配置。典型内容包括:根公钥的哈希、公钥本身、安全版本号、设备唯一密钥、生命周期状态、调试锁定标志、启动配置等。OTP 一旦写入就不能擦除,这正好满足信任根的不可篡改需求。
在实践中,为了节省 OTP 空间,往往不烧录完整公钥,而是烧录公钥的 SHA-256 哈希。Boot ROM 在启动时读取被签名的公钥证书,计算其哈希并与 OTP 中的值比对;一致后才信任该公钥。这种“公钥哈希锁定”方式允许在量产阶段灵活管理多把密钥,同时保持硬件成本可控。
5.3 TPM、安全元件与安全区域的对比
| 方案 | 主要能力 | 典型场景 | 优缺点 |
|---|---|---|---|
| TPM 可信平台模块 | 平台配置寄存器、密钥生成、加密存储、远程证明 | X86 平台、工控机、边缘服务器 | 生态成熟、功能丰富;成本较高,低端 MCU 较少采用 |
| Secure Element 安全元件 | 防篡改密钥存储、密码运算、安全认证 | 支付、SIM、车规安全芯片 | 抗物理攻击强;存储和算力有限 |
| 芯片内置安全子系统 | Boot ROM、eFuse、硬件密码引擎、安全岛 | 主流嵌入式 SoC、车规 MCU | 集成度高、启动路径短;依赖芯片厂商设计质量 |
| PUF 物理不可克隆函数 | 从芯片物理特性派生唯一密钥 | 需要设备专属密钥的高安全场景 | 密钥不落盘、抗克隆;实现和稳定性要求高 |
5.4 PUF 与设备唯一密钥
物理不可克隆函数(Physically Unclonable Function,PUF)利用芯片制造过程中的随机物理差异,在每次上电时派生出一致的设备唯一密钥,但不以明文形式长期存储。即使攻击者打开芯片,也很难读取到密钥。PUF 常用于包裹固件加密密钥、设备身份密钥和安全存储主密钥。
相比把固定密钥直接烧在 OTP 中,PUF 的优势是没有静态存储的密钥可供提取,但 PUF 的稳定性、误码率、温度电压特性需要芯片设计保证,通常需要配合纠错算法使用。
5.5 生命周期管理与调试锁定
生命周期管理把芯片状态划分为若干阶段,典型流程为:空白(Blank)到开发(Development)到量产(Production)到封闭(Closed)到失效(Return/End of Life)。不同阶段对调试接口、密钥烧录、安全特性的开放程度不同。例如在开发阶段允许 JTAG 完全访问;进入量产后关闭 JTAG 或仅允许授权调试;设备退市时需要根据业务策略决定是否永久关闭关键安全能力。
工程落地中,生命周期切换通常通过写 OTP 完成,而且是单向的,避免攻击者把已经封闭的芯片退回开发状态。
6. 安全启动的完整流程
6.1 从上电到内核的通用环节
一个典型 SoC 的安全启动完整流程可以拆解为以下步骤:
- 芯片上电,CPU 从 Boot ROM 开始执行。
- Boot ROM 初始化时钟、内存控制器和启动介质控制器。
- 读取 OTP/eFuse,确认生命周期状态。若处于封闭状态,则禁止非授权调试。
- 从启动介质读取公钥证书或根公钥哈希,校验其与 OTP 中记录是否一致。
- 读取 FSBL 镜像及其签名,使用公钥验证签名。
- 可选地使用设备唯一密钥解密 FSBL。
- 验证通过后,Jump 到 FSBL 执行。
- FSBL 初始化 DDR、电源、外设,再验证并加载 SSBL。
- SSBL 完成更复杂的硬件初始化、设备树加载、启动参数准备。
- SSBL 验证并加载内核镜像、设备树、initramfs。
- 内核启动后,通过 dm-verity 等方式校验根文件系统;而后启动 init 进程。
整个流程中,每一级“下一级镜像验证”动作都必须在加载到执行之前完成,否则会出现“先执行后验证”的时序窗口,被攻击者利用。
6.2 镜像封装格式与签名文件组织
早期的裸二进制镜像没有统一的封装格式,签名文件常常单独存放,容易出现文件与签名不匹配、字段错位等问题。现代方案普遍使用带签名头的镜像容器,把版本、算法、密钥、签名、载荷等元数据统一封装。常见格式包括 U-Boot 的 FIT Image、Android 的 Boot Image Header、厂商私有的签名镜像格式、OP-TEE 的 signed header 等。
一个简化的镜像签名头部可能包含如下字段:
| 字段 | 作用 |
|---|---|
| Magic | 标识镜像格式版本 |
| Version | 安全版本号,用于防回滚 |
| Hash Algorithm | 镜像摘要算法,如 SHA-256 |
| Signature Algorithm | 签名算法,如 ECDSA P-256 |
| Key Identifier | 标识使用哪把密钥验证 |
| Payload Offset/Size | 载荷位置与大小 |
| Payload Hash | 载荷哈希值 |
| Signature | 对头部摘要进行签名的结果 |
6.3 启动时间与性能优化
安全启动引入的验签开销主要来自哈希计算和签名验证,以及从慢速 Flash 读取大镜像的时间。对于启动时间敏感的设备,可以采用以下优化策略:
- 使用硬件密码引擎加速 SHA 和 ECDSA/RSA 运算。
- 选择密钥小、运算快的算法,如 ECDSA P-256 或 Ed25519。
- 对镜像采用分块哈希、并行计算,减少整体延迟。
- 只在安全版本变化时执行全量校验,正常启动使用缓存的摘要。
- 把 bootloader、内核、rootfs 分别签名,支持独立加载和并行校验。
需要注意的是,任何“为速度而跳过校验”的优化都必须经过安全评审,不能牺牲安全性换取启动速度。
7. U-Boot 安全启动实战
7.1 U-Boot Verified Boot 简介
U-Boot 是嵌入式领域使用最广泛的引导加载程序。U-Boot Verified Boot 通过 FIT Image 和签名验证实现安全启动。它支持 RSA 和 ECDSA 签名,支持多镜像打包、多配置选择、内核、设备树、ramdisk 等组件的独立校验。
FIT(Flattened Image Tree)是 U-Boot 的一种镜像描述格式,内部使用设备树结构描述镜像分区的节点、加载地址、压缩方式、哈希值和签名信息。一个典型 FIT 镜像可以同时包含多个内核、多个设备树和多个配置,设备在启动时根据硬件信息选择合适的配置。
7.2 生成密钥与签名工具链
首先需要生成签名密钥。这里以 RSA 2048 为例:
mkdir -p keys
openssl genrsa -F4 -out keys/dev.key 2048
openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt
然后准备镜像签名描述文件(.its)。下面是一个简化的 fitImage 描述:
/dts-v1/;
/ {
description = "Secure boot fitImage";
#address-cells = <1>;
images {
kernel {
description = "Linux kernel";
data = /incbin/("zImage");
type = "kernel";
arch = "arm";
os = "linux";
compression = "none";
load = <0x80008000>;
entry = <0x80008000>;
hash-1 {
algo = "sha256";
};
};
fdt {
description = "Device tree";
data = /incbin/("board.dtb");
type = "flat_dt";
arch = "arm";
compression = "none";
hash-1 {
algo = "sha256";
};
};
};
configurations {
default = "conf-1";
conf-1 {
description = "Boot Linux with device tree";
kernel = "kernel";
fdt = "fdt";
signature-1 {
algo = "sha256,rsa2048";
key-name-hint = "dev";
};
};
};
};
使用 mkimage 工具生成带签名的 FIT 镜像:
mkimage -f image.its -K u-boot.dtb -k keys -r image.fit
其中 -k 指定密钥目录,-K 把公钥写入 U-Boot 设备树用于验签,-r 表示必须校验成功。
7.3 U-Boot 配置与验签流程
启用 U-Boot Verified Boot 需要在配置文件中打开相关选项。典型配置片段如下:
CONFIG_FIT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_FIT_VERBOSE=y
CONFIG_FIT_ENABLE_SHA256=y
CONFIG_RSA=y
CONFIG_RSA_VERIFY=y
设备启动后,U-Boot 在执行 bootm 命令加载 FIT 镜像时,会读取镜像签名节点,找到公钥并用其验证镜像哈希。如果签名无效,启动流程终止。为了在生产环境中强制验签,建议在板级代码或环境变量中禁止无签名启动,防止攻击者通过修改环境变量绕过校验。
7.4 ECDSA 与 Ed25519 实践
RSA 虽然通用,但密钥长度较大,签名校验较慢。U-Boot 也支持 ECDSA。生成 ECDSA 密钥的示例:
openssl ecparam -name prime256v1 -genkey -noout -out keys/ecdsa.key
openssl req -batch -new -x509 -key keys/ecdsa.key -out keys/ecdsa.crt
在 FIT 描述中,签名算法可写为 sha256,ecdsa256。对于资源紧张的启动阶段,Ed25519 由于运算简单且没有椭圆曲线点乘中的复杂逻辑,正逐渐被更多方案采纳。选用哪种算法应结合实际硬件密码引擎支持情况决定。
8. 主流嵌入式平台安全启动方案
8.1 ARM TrustZone 与 TF-A
ARM TrustZone 把 CPU 执行环境划分为安全世界(Secure World)和普通世界(Normal World)。安全启动可以利用安全世界执行敏感验证、密钥管理和安全监控,普通操作系统无法直接访问这些资源。TF-A(Trusted Firmware-A)是 ARM 平台通用的安全启动固件,常见启动层级包括 BL1、BL2、BL31、BL32、BL33 等。
典型 ARMv8 平台启动顺序为:BL1 从 Boot ROM 加载并验证,BL2 初始化安全世界相关硬件,BL31 作为 EL3 运行时提供安全服务,BL32 通常运行 OP-TEE,BL33 则为 U-Boot 等普通世界引导器。每一级的镜像都通过签名校验,保证从安全世界到普通世界的启动路径可信。
8.2 OP-TEE 与安全执行环境
OP-TEE 是一个开源的可信执行环境(Trusted Execution Environment,TEE),运行在安全世界中。它提供可信应用(Trusted Application,TA)加载、安全存储、密码运算、密钥管理等功能。OP-TEE 自身的镜像和可信应用都可以配置签名校验,从而把安全启动延伸到了应用级别。
OP-TEE 的安全启动通常分为两个部分:一是 TEE 核心镜像在 BL2/BL32 阶段被验证;二是每个可信应用在加载前验证其签名。通过组合 OP-TEE 的 secure storage 和安全时钟,还可以实现抗回滚的版本管理。
8.3 NXP、TI、ST、瑞萨等厂商方案概述
| 厂商 | 代表平台 | 安全启动特点 |
|---|---|---|
| NXP | i.MX 8/9 系列 | Boot ROM 加 HAB/CAAM 安全子系统,支持 SRK 密钥哈希熔丝、镜像签名和加密 |
| TI | AM62x、AM64x、CC 系列 | R5 核负责初始安全启动,支持设备专属密钥、安全版本号、授权调试 |
| ST | STM32MP1/MP2 系列 | Boot ROM 加安全工程支持,公钥哈希熔丝、签名校验、生命周期管理 |
| 瑞萨 | RZ、RA 系列 | 硬件安全模块、唯一 ID,支持认证启动与固件加密 |
| Microchip | SAMA5、SAM9 系列 | 安全 Boot ROM、OTP、加密引擎,适合工业控制场景 |
8.4 Android Verified Boot 与 AVB
Android Verified Boot 系列机制可以看作嵌入式安全启动在消费电子上的成熟实践。AVB 2.0 使用 vbmeta 结构描述启动分区和校验信息,支持链式分区描述、带版本号的防回滚、基于 dm-verity 的只读文件系统完整性校验。AVB 的设计思想对嵌入式 Linux 方案同样有借鉴意义,尤其是分区版本管理与启动链描述方式。
AVB 的 vbmeta 中可以记录每个分区的哈希、公钥索引、安全版本和回滚保护要求。设备启动时逐分区校验,任何不匹配都会导致启动失败。这种“元数据驱动”的启动校验方式非常适合需要灵活管理多分区和多升级策略的产品。
9. Linux 内核与根文件系统安全
9.1 内核镜像签名与模块签名
即使引导加载程序只加载合法内核,如果攻击者能够修改内核或插入恶意内核模块,仍然可以控制整个系统。Linux 内核支持模块签名机制,通过 CONFIG_MODULE_SIG 开启后,只有经过合法签名的模块才能被加载。内核镜像本身的完整性可以由引导器验签保证,也可以使用 UEFI Secure Boot 或 FIT 镜像签名保证。
模块签名启用的关键配置包括:
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y
CONFIG_MODULE_SIG_SHA256=y
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
当 MODULE_SIG_FORCE 打开时,未签名或签名无效的模块会被拒绝加载。对于不允许用户插入第三方模块的封闭产品,建议打开强制签名。
9.2 dm-verity 与根文件系统完整性
dm-verity 是 Linux 内核中的设备映射目标,用于对块设备实施透明完整性校验。它使用一棵 Merkle 哈希树覆盖整个只读文件系统。每次读取数据时,内核会根据树节点逐级验证读取内容的哈希,如果发现不一致就返回读取错误。dm-verity 通常与只读的 squashed-fs 根文件系统配合使用,从而保证系统分区无法被篡改。
构建 dm-verity 的典型步骤包括:先生成只读根文件系统,再使用 veritysetup 工具生成哈希树,把根哈希写入安全启动链或 vbmeta。设备启动时通过内核命令行传入哈希设备、数据设备和根哈希信息。
9.3 dm-crypt 与加密根文件系统
dm-crypt 提供块设备加密能力,保护数据机密性。它不直接解决完整性验证,但可以与 dm-verity 组合使用:先加密再验证,或者对不同分区分别处理。对嵌入式产品而言,是否加密根文件系统取决于固件逆向风险;对于带有商业算法或用户数据的设备,加密通常是必要的。
9.4 initramfs 验证与私有数据保护
initramfs 在挂载真正根文件系统之前运行,常用于负载解密密钥、提供恢复功能等。由于 initramfs 运行在早期启动阶段,其安全性直接影响后续启动。应把 initramfs 纳入引导器验签范围,并避免把明文密钥写进 initramfs。私有数据分区可以使用 dm-crypt 加设备绑定,密钥由 TEE 或安全元件保存。
10. OTA 升级与安全启动的结合
10.1 升级包签名与双重验证
安全启动解决的是当前已安装镜像的可信性,OTA 升级解决的是新镜像如何安全地进入设备。升级包同样需要数字签名,否则攻击者可以绕过启动校验,直接通过升级通道把恶意镜像刷入设备。OTA 客户端在收到升级包后,先用升级公钥验证签名,通过后才写入备用分区或执行安装。
升级包签名和启动镜像签名最好使用不同密钥,这样即使某个升级密钥泄露,也不影响已经烧录的启动镜像验签体系;反之亦然。升级包签名还应可配置有效期和适用范围,支持批量吊销。
10.2 A/B 分区与无缝升级
A/B 分区方案保留两套系统分区,设备升级时把新镜像写入非活动分区,校验通过后切换启动标志。下次启动时引导器选择新分区启动;如果新版本启动失败或运行中崩溃次数过多,则回退到旧分区。A/B 方案天然增强了对升级风险的容错能力,但在资源受限的嵌入式设备上会增加 Flash 占用。
A/B 分区与安全启动结合的关键点在于:每个分区独立签名、独立维护安全版本,切换逻辑本身也需要保护,避免攻击者修改启动标志或把设备强制指向不安全的旧分区。
10.3 防回滚策略落地
在 OTA 场景中,防回滚通常需要记录当前设备允许的最低安全版本号。安全版本号可以存储在 OTP/eFuse 中,也可以存储在受签名保护的安全元数据分区中,还可以由 TEE 安全存储维护。每次升级时,升级包中携带新版本号;安装成功后更新设备记录。启动时,引导器比较镜像版本与设备记录的最低版本,低于该版本则拒绝启动。
需要避免的常见错误是:防回滚版本只保存在普通文件中、可以随意修改;或者每个分区各自为政,导致攻击者只回滚某一个旧分区就能绕过整体防护。
10.4 差分升级与可靠写入
差分升级只传输新旧版本之间的差异,对带宽受限设备非常重要。但差分补丁的结果必须与预期镜像完全一致,才能通过后续签名验证。工程上通常先计算目标镜像哈希,再对补丁后的结果进行哈希比对,最后写入安全版本信息。写入过程中要处理突然掉电的原子性问题,防止设备停留在“版本已更新但镜像未写完”的状态。
11. 量产密钥管理与签名流程
11.1 密钥生成的安全环境要求
生产密钥必须与开发测试密钥彻底隔离。密钥生成建议在离线的、经过加固的专用主机上完成,或者使用硬件安全模块(HSM)生成并保存私钥。保存私钥的介质应加密、受控访问,并进行审计记录。不要在普通开发服务器、共享 CI 机器或个人笔记本上生成量产密钥。
最小权限原则同样适用于密钥:开发工程师只应接触开发密钥;量产签名操作由受限的签名服务执行;私钥永不导出;签名日志保留以便追溯。对于高安全产品,还应支持密钥轮换、吊销和多签机制。
11.2 离线签名与在线签名的选择
离线签名通常在隔离网络中完成,私钥不接触外部网络,安全性最高,适合根密钥和低频固件签名。在线签名服务集成在 CI/CD 中,效率高,但攻击面更大,适合使用独立镜像密钥并配合 HSM 保护。大规模量产环境中常见“根密钥离线、镜像密钥在线并定期轮换”的混合模式。
11.3 工厂烧录与设备初始化
量产阶段需要完成根公钥哈希熔丝烧写、设备唯一密钥注入、生命周期切换到量产或封闭状态、关闭调试接口等操作。烧录流程本身必须经过严格管理,避免在工厂环境中泄露密钥或留下调试后门。
一种常见做法是:安全服务器为每台设备生成唯一的烧录包,工厂扫码后一次性烧录;烧录完成后芯片自动进入封闭状态;烧录数据包含设备公钥证书,用于后续设备认证。这样可以保证每台设备的密钥互不相同,即使单台设备被攻破,也不会波及整批设备。
11.4 密钥轮换与吊销
安全启动体系运行多年后,可能遇到根密钥到期、算法迁移、疑似泄露等情况。由于根公钥哈希已烧录在 OTP 中且不可修改,直接换根密钥通常意味着芯片无法再验证新根。因此设计时要预留多密钥槽、密钥版本或二级密钥机制,让设备能够安全地接受新密钥,同时拒绝旧密钥签发的镜像,防止攻击者利用吊销前的旧签名。
12. 调试、故障排查与常见问题
12.1 安全启动失败的典型表现
安全启动校验失败时,设备通常表现为:上电后无输出、启动停在 Boot ROM 阶段、引导器打印签名错误并复位、反复重启、进入恢复模式等。不同厂商对失败的处理策略不同:有的会直接停止启动,有的会点亮特定错误灯,有的会通过 UART 输出错误码。
排查第一步是区分“镜像损坏”“签名不匹配”“公钥不匹配”“安全版本错误”“熔丝未正确烧写”等不同原因。多数厂商调试工具会输出比较明确的校验失败原因,例如 hash mismatch、signature verification failed、key hash mismatch、version rollback detected 等。
12.2 常见配置错误与规避
- 公钥未正确写入:镜像签名使用的私钥与设备中的公钥不是一对。应核对密钥版本和公钥哈希。
- FIT 描述与签名节点错位:data 路径、load 地址、签名节点名不一致,导致哈希计算范围错误。
- 校验范围覆盖不全:只签了部分镜像,未覆盖设备树或启动参数,攻击者仍可修改未校验部分。
- 安全版本号设置过低或未更新:量产时安全版本配置错误,导致防回滚失效或正常升级被拒绝。
- 调试接口未关闭:量产设备仍开放 JTAG,安全启动形同虚设。
12.3 使用日志与单向验签测试
开发阶段可以在 U-Boot 中打开 CONFIG_FIT_VERBOSE,查看每次验签使用的密钥、算法和结果;也可以使用 mkimage 的 verify 功能在宿主机上先验证镜像签名是否正确。对于启动失败的现场设备,如果还保留有限调试接口,应记录完整错误日志,而不是反复盲目重烧。
12.4 现场恢复与售后策略
生产设备一旦进入封闭状态,常规 JTAG 无法使用,现场修复需要设计安全的恢复通道。常见方案包括:进入专用恢复模式后只加载厂商签名的恢复镜像、通过 TEE 授权临时解锁调试、使用安全通信通道下发修复固件等。恢复机制必须具备与正常启动同等级别的安全校验,否则很容易被攻击者利用。
13. 安全启动的局限与高级威胁
13.1 安全启动无法覆盖的运行时威胁
安全启动通过校验镜像来保证启动时代码可信,但对于运行时的内存溢出、释放后使用、逻辑绕过、权限提升等漏洞无能为力。攻击者可以通过利用内核或应用漏洞,在系统启动完成后获得代码执行权限,而不需要修改启动镜像。因此安全启动必须与运行时防护结合。
13.2 供应链攻击与后门风险
如果供应商提供的 Boot ROM 或引导固件本身存在后门,设备层安全启动无法发现。更现实的情况是,第三方驱动、开源组件或构建工具被植入恶意行为。企业应建立 SBOM(软件物料清单)、漏洞跟踪机制和代码审计流程,尽量降低供应链风险。
13.3 芯片级攻击能力评估
对于具备高价值攻击目标的产品,攻击者可能会进行开盖、微探针、故障注入等芯片级攻击。普通 MCU 通常难以完全防御此类攻击,因此在威胁建模中需要评估:攻击者是否可能为了设备中的秘密付出芯片级分析成本。对于真正需要高强度对抗的场景,应选择具备防篡改设计的安全芯片或安全元件。
13.4 安全启动与隐私、合规的关系
安全启动在保护设备的同时,也可能被用于限制用户自由运行第三方软件。在开放设备与封闭设备之间存在产品定位和政策合规的权衡。对于消费类设备,部分法规要求提供开放接口或维修权利;对于关键基础设施和特定行业设备,封闭启动链可能是合规要求。产品设计时应同时评估技术安全和合规要求。
14. 总结与最佳实践
嵌入式安全启动不是某一个工具或算法,而是一整套贯穿芯片、固件、签名体系、量产流程和售后策略的系统工程。一个真正有效的安全启动体系至少应该满足以下条件:硬件信任根不可修改;信任链每一级都验证下一级;密钥管理安全且支持轮换;具备防回滚能力;调试接口在量产后受控;升级通道与启动验签同等安全;失败处理策略清晰且不会泄露更多信息。
结合全篇内容,落地方案时建议遵循以下最佳实践:
- 从芯片选型开始考虑安全启动,优先选择 Boot ROM、eFuse、硬件密码引擎和生命周期管理完善的平台。
- 信任根最小化,Boot ROM 保持简单,减少不可修复的攻击面。
- 完整覆盖启动链,从 FSBL 到内核、设备树、initramfs、rootfs 都纳入校验。
- 算法与密钥面向未来,优先 ECDSA/Ed25519,预留密钥槽和版本号。
- 量产密钥与开发密钥严格隔离,使用 HSM 或离线签名环境。
- A/B 分区与安全版本号配合,既支持可靠升级,又防止回滚攻击。
- 把调试接口纳入生命周期管理,量产后关闭或授权访问。
- 建立完整的自测与审计机制,对签名流程、密钥使用和启动失败日志进行持续跟踪。
最后需要记住:安全启动的目标不是让设备永远不失败,而是在攻击发生时,让设备能够识别异常、拒绝运行不可信代码、保护关键资产,并为进一步的恢复和安全事件响应赢得空间。安全设计本身也没有终点,需要根据新攻击技术、法规变化和产品演进持续迭代。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)