1. 项目概述
作为一名嵌入式开发工程师,我最近在STM32MP15x系列芯片上实现了安全启动功能。这个功能对于保护嵌入式系统的安全性至关重要,但官方文档确实存在一些晦涩难懂的地方。通过实际项目实践,我总结出了一套完整的实现方案,希望能帮助更多开发者快速上手。
安全启动的核心目的是确保只有经过授权的软件才能在设备上运行。在STM32MP15x平台上,这主要通过数字签名验证机制来实现。整个过程涉及密钥生成、OTP编程、固件签名等多个环节,每个步骤都需要特别注意细节。
2. 安全启动基础概念
2.1 安全启动的核心原理
安全启动主要包含两个层面的安全保证:
-
签名验证:确保运行在设备上的软件是被特定用户授权过的。任何未经签名的软件或调试工具都无法在设备上运行。这是STM32MP15x目前支持的主要安全机制。
-
加密保护:更高阶的安全机制,不仅验证签名,还对软件进行加密保护,防止逆向工程。目前STM32MP15x暂不支持此功能。
提示:签名验证基于非对称加密算法(ECDSA),使用私钥签名、公钥验证的方式确保固件完整性。
2.2 硬件支持情况
并非所有STM32MP15x芯片都支持安全启动功能。根据我的实测经验,只有STM32MP15xC/F系列的芯片才具备完整的OTP(One-Time Programmable)区域和安全启动ROM代码支持。
在选型时,务必确认芯片型号后缀是否为C或F。例如:
- 支持型号:STM32MP157C、STM32MP153F
- 不支持型号:STM32MP157A、STM32MP153D
3. 硬件准备与环境搭建
3.1 所需硬件清单
在开始前,请确保准备好以下硬件:
- 支持安全启动的STM32MP15x开发板(如STM32MP157C-DK2)
- 调试器(ST-LINK/V2或V3)
- 串口转USB模块(用于控制台输出)
- 至少8GB的microSD卡(用于系统镜像烧录)
3.2 软件工具准备
需要安装以下开发工具:
- STM32CubeProgrammer(最新版本)
- OpenSTLinux Developer Package
- 交叉编译工具链(arm-ostl-linux-gnueabi-)
- Git(用于获取mbedTLS源码)
安装STM32CubeProgrammer时,建议选择完整安装,这样会自动包含KeyGen工具:
bash复制sudo dpkg -i stm32cubeprog_*.deb
4. 密钥生成与管理
4.1 生成认证密钥对
安全启动的基础是一对非对称密钥。使用STM32MP_KeyGen_CLI工具生成ECDSA密钥对:
bash复制STM32MP_KeyGen_CLI -pubk ./public.pem -prvk ./private.pem -hash ./pubKeyHash.bin -pwd YourStrongPassword
参数说明:
-pubk:指定公钥输出路径-prvk:指定私钥输出路径-hash:输出公钥的SHA256哈希值-pwd:设置密钥保护密码(至少8位,包含大小写字母和数字)
重要:生成的私钥和密码必须妥善保管!一旦丢失,将无法为后续固件签名。
4.2 密钥安全存储建议
在实际项目中,我建议采用以下密钥管理方案:
- 私钥存储在加密的USB Key中
- 密码使用密码管理器保存
- 开发环境与签名环境物理隔离
- 定期轮换密钥(虽然STM32MP15x的OTP是一次性编程的)
5. OTP编程与配置
5.1 烧录公钥哈希到OTP
公钥哈希(PKH)需要烧录到芯片的OTP区域。有几种方法可以实现:
方法一:使用U-Boot命令行
bash复制stm32key read // 读取当前OTP状态
stm32key write <pubKeyHash.bin>
方法二:使用STM32CubeProgrammer
- 连接开发板并进入UART/USB DFU模式
- 打开STM32CubeProgrammer
- 导航到OTP配置页面
- 加载pubKeyHash.bin文件
- 点击"Program"按钮
注意:OTP编程是不可逆操作!建议在最终确认前先保持OTP开放状态(不烧写关闭位)。
5.2 OTP区域详解
STM32MP15x的OTP包含多个重要区域:
- PKH区域:存储公钥哈希(256位)
- 关闭位:控制芯片安全状态
- 调试控制位:控制JTAG/SWD访问权限
典型的安全启动配置:
code复制OTP Word 57: PKH[255:224]
OTP Word 58: PKH[223:192]
...
OTP Word 64: PKH[31:0]
OTP Word 65: Close device bit
6. 带签名固件的生成
6.1 编译mbedTLS库
签名过程依赖mbedTLS加密库。获取方式有两种:
方法一:从GitHub直接获取
bash复制git clone https://github.com/Mbed-TLS/mbedtls -b mbedtls-2.28.1
cd mbedtls
mkdir build && cd build
cmake -DUSE_SHARED_MBEDTLS_LIBRARY=ON ..
make -j$(nproc)
sudo make install
方法二:通过Yocto获取(适用于OpenSTLinux)
bash复制devtool modify mbedtls
devtool build mbedtls
6.2 编译带签名的TF-A
- 首先设置环境变量:
bash复制export MBEDTLS_DIR=/path/to/mbedtls
export FIP_DEPLOYDIR_ROOT=/path/to/deploy
- 编译TF-A:
bash复制make -f ../Makefile.sdk TRUSTED_BOARD_BOOT=1 \
TF_A_DEVICETREE=stm32mp157c-dk2 \
TF_A_CONFIG="optee sdcard emmc usb" \
DEPLOYDIR=$FIP_DEPLOYDIR_ROOT/arm-trusted-firmware stm32
- 生成签名镜像:
bash复制STM32_SigningTool_CLI -pubk public.pem -prvk private.pem \
-pwd YourStrongPassword -t fsbl \
-bin tf-a-stm32mp157c-dk2-sdcard.stm32 \
-o tf-a-stm32mp157c-dk2-sdcard_Signed.stm32
6.3 验证TF-A签名
烧录签名后的TF-A镜像到开发板,串口输出应包含类似信息:
code复制BL2: Secure boot enabled
BL2: Verifying signature...
BL2: Signature verified successfully
如果看到"Authentication failed"错误,请检查:
- OTP中的PKH是否与公钥匹配
- 签名使用的私钥是否与公钥配对
- 固件编译选项是否正确
7. FIP镜像的签名与验证
7.1 生成证书工具
从TF-A v2.8开始,需要手动编译cert_create工具:
bash复制cd <TF-A_source>
make OPENSSL_DIR=$OECORE_NATIVE_SYSROOT/bin PLAT=stm32mp1 DEBUG=1 V=1 certtool
7.2 创建证书链
使用以下脚本生成必要的证书:
bash复制./tools/cert_create/cert_create \
-n --rot-key build/stm32mp1/debug/rot_key.pem \
--tfw-nvctr 0 \
--ntfw-nvctr 0 \
--key-alg ecdsa --hash-alg sha256 \
--tos-fw build/stm32mp1/debug/tos_fw_content.crt \
--tos-fw-key build/stm32mp1/debug/tos_fw_key.pem \
--tos-fw-cert build/stm32mp1/debug/tos_fw_cert.pem \
--nt-fw build/stm32mp1/debug/nt_fw_content.crt \
--nt-fw-key build/stm32mp1/debug/nt_fw_key.pem \
--nt-fw-cert build/stm32mp1/debug/nt_fw_cert.pem \
--trusted-key-cert build/stm32mp1/debug/trusted_key_cert.pem \
--fw-config build/stm32mp1/debug/fw_config.crt \
--hw-config build/stm32mp1/debug/hw_config.crt
7.3 生成签名的FIP镜像
使用fiptool工具创建最终镜像:
bash复制./tools/fiptool/fiptool create \
--tos-fw build/stm32mp1/debug/tos_fw_cert.pem \
--nt-fw build/stm32mp1/debug/nt_fw_cert.pem \
--trusted-key-cert build/stm32mp1/debug/trusted_key_cert.pem \
--fw-config build/stm32mp1/debug/fw_config.crt \
--hw-config build/stm32mp1/debug/hw_config.crt \
fip.bin
8. 设备关闭与最终验证
8.1 关闭设备安全状态
在所有测试通过后,可以永久关闭设备:
- 使用STM32CubeProgrammer连接开发板
- 导航到OTP编程界面
- 设置OTP Word 65的bit 0为1
- 点击"Program"按钮
警告:此操作不可逆!关闭后,将无法再修改OTP内容或降级安全级别。
8.2 最终验证步骤
- 尝试烧录未签名的固件 - 应该失败
- 验证调试接口访问 - 应该被禁用
- 检查启动日志中的安全状态
- 测试正常功能是否受影响
9. 常见问题与解决方案
9.1 签名验证失败
现象:启动时出现"Authentication failed"错误
可能原因:
- OTP中的PKH与当前公钥不匹配
- 签名使用的私钥与公钥不配对
- 固件被修改过
解决方案:
- 使用
stm32key read确认OTP内容 - 重新生成密钥对并更新OTP
- 确保签名工具和流程正确
9.2 OTP编程错误
现象:无法写入OTP或写入后验证失败
可能原因:
- 芯片已关闭
- 电压不稳定
- 编程时序不正确
解决方案:
- 更换新的开发板
- 确保供电稳定
- 使用最新版STM32CubeProgrammer
9.3 性能下降
现象:启用安全启动后系统变慢
可能原因:
- 签名验证增加了启动时间
- 加密操作消耗CPU资源
解决方案:
- 优化启动流程
- 考虑使用更高效的算法(如SHA256替代SHA512)
- 评估硬件加速选项
10. 进阶技巧与优化建议
- 批量生产方案:开发自动化签名流水线,集成到CI/CD流程中
- 密钥轮换策略:设计多阶段密钥方案,即使主密钥泄露也能限制损失
- 安全审计:定期检查系统安全状态,确保没有安全漏洞
- 性能优化:利用STM32MP15x的硬件加密引擎加速签名验证过程
在实际项目中,我发现安全启动虽然增加了开发复杂度,但对于保护知识产权和防止恶意软件攻击至关重要。特别是在工业控制和物联网应用中,这项功能已经成为必备的安全措施。