1. ARM ATF验签机制概述
ARM Trusted Firmware(ATF)的安全启动流程中,验签机制是确保固件完整性和真实性的核心环节。ATF采用分层信任链设计,每一级镜像(BL1/BL2/BL31等)在加载下一级镜像前,都会通过密码学手段验证其数字签名。这种机制能有效防御固件被篡改或替换的攻击场景。
典型验签流程包含三个关键步骤:
- 哈希校验:使用SHA-256等算法计算镜像内容的哈希值
- 签名验证:用预置的公钥验证镜像附带的ECDSA/RSA签名
- 防回滚检查:比对镜像中的版本号与硬件安全计数器(NV Counter)
关键点:ATF默认使用mbedTLS密码库实现验签操作,通过REGISTER_CRYPTO_LIB宏注册验签函数指针,形成模块化的安全服务架构。
2. 验签核心数据结构解析
2.1 证书链描述符(CoT)
在include/drivers/auth/auth_common.h中定义的auth_img_desc_t结构体描述了验证链中每个镜像的验证参数:
c复制typedef struct auth_img_desc_s {
const char *img_name;
const struct auth_img_desc_s *parent;
img_type_t img_type;
const auth_method_desc_t *const img_auth_methods;
const auth_param_desc_t *const authenticated_data;
} auth_img_desc_t;
各字段作用:
img_name:镜像标识符(如"BL2")parent:指向父镜像描述符的指针,形成信任链img_type:镜像格式(IMG_RAW/IMG_PLAT/IMG_CERT)img_auth_methods:验证方法数组authenticated_data:用于验证下级镜像的参数
2.2 验证方法描述
auth_method_desc_t定义了具体的验证手段:
c复制typedef struct auth_method_desc_s {
auth_method_type_t type; // 验证类型
union {
auth_method_param_hash_t hash; // 哈希验证参数
auth_method_param_sig_t sig; // 签名验证参数
auth_method_param_nv_ctr_t nv_ctr; // 计数器验证
} param;
} auth_method_desc_t;
验证类型枚举值:
c复制typedef enum auth_method_type_enum {
AUTH_METHOD_NONE = 0,
AUTH_METHOD_HASH, // 哈希匹配验证
AUTH_METHOD_SIG, // 数字签名验证
AUTH_METHOD_NV_CTR, // 防回滚计数器验证
AUTH_METHOD_NUM
} auth_method_type_t;
2.3 签名验证参数
对于签名验证(AUTH_METHOD_SIG),需要配置以下参数:
c复制typedef struct auth_method_param_sig_s {
auth_param_type_desc_t *pk; // 公钥参数描述符
auth_param_type_desc_t *sig; // 签名参数描述符
auth_param_type_desc_t *alg; // 签名算法描述符
auth_param_type_desc_t *data; // 被签名的数据
} auth_method_param_sig_t;
典型配置示例:
c复制static const auth_method_param_sig_t sig_param = {
.pk = &rotpk_key,
.sig = &sig,
.alg = &sig_alg,
.data = &content_pk
};
3. 验签流程深度剖析
3.1 镜像加载阶段
当BL1加载BL2镜像时,执行以下操作:
- 从存储介质(如Flash)读取镜像到内存
- 检查镜像头部魔数(Magic Number)
- 验证镜像长度不超过预定义限制
- 分配临时缓冲区存储验证参数
关键代码路径:
code复制bl1_main() → bl1_load_bl2() → load_image() → auth_mod_verify_img()
3.2 证书解析流程
对于采用X.509证书链的镜像,解析过程如下:
- 证书链定位:通过
REGISTER_COT宏注册的证书链描述符定位各级证书 - 完整性检查:调用
check_integrity()验证证书结构有效性 - 参数提取:通过
get_auth_param()获取公钥、签名等验证要素
c复制// 证书解析器注册示例
REGISTER_IMG_PARSER_LIB(IMG_CERT, "mbedTLS X.509 Parser",
mbedtls_x509_parser_init,
mbedtls_x509_cert_verify,
mbedtls_x509_get_auth_param);
3.3 签名验证实现
实际签名验证在mbedtls_crypto.c中实现:
c复制int verify_signature(void *data_ptr, unsigned int data_len,
void *sig_ptr, unsigned int sig_len,
void *sig_alg_ptr, unsigned int sig_alg_len,
void *pk_ptr, unsigned int pk_len)
{
mbedtls_pk_context pk;
int ret;
mbedtls_pk_init(&pk);
ret = mbedtls_pk_parse_public_key(&pk, pk_ptr, pk_len);
if (ret != 0)
goto exit;
ret = mbedtls_pk_verify(
&pk,
MBEDTLS_MD_SHA256,
data_ptr, data_len,
sig_ptr, sig_len);
exit:
mbedtls_pk_free(&pk);
return (ret == 0) ? CRYPTO_SUCCESS : CRYPTO_ERR_SIGNATURE;
}
踩坑记录:mbedTLS要求公钥格式必须为DER编码,直接使用PEM格式会导致解析失败。建议使用
openssl rsa -pubin -in key.pem -outform DER -out key.der转换格式。
4. 典型问题排查指南
4.1 签名验证失败(Error Code: -0x4E00)
现象:
code复制ERROR: BL1: Failed to load BL2 (-3)
NOTICE: BL1: Booting BL31
排查步骤:
- 确认使用的签名私钥与ATF编译时配置的公钥匹配
- 检查镜像签名工具是否与mbedTLS兼容(推荐使用
cert_create工具) - 验证镜像未在签名后被修改(可通过
sha256sum比对) - 检查硬件安全计数器是否已递增到最新值
根本原因:
- 90%的案例是由于密钥不匹配导致
- 5%是签名算法配置错误(如SHA256 vs SHA384)
- 5%是镜像填充(Padding)问题
4.2 防回滚检查失败
错误日志:
code复制WARN: NV Counter: 0x5 < Image Counter: 0x6
解决方案:
- 更新硬件安全计数器:
bash复制tools/cert_create/cert_create -n -f -b 0x6
- 或修改平台代码中的默认计数器值(仅开发阶段):
c复制#define PLAT_NV_COUNTERS_MAX_VAL 0xFFFFFFFF
4.3 证书链验证中断
典型表现:
code复制ERR: Failed to get parent auth param: 0x10
调试方法:
- 使用
print_auth_param()打印各级证书参数 - 确认证书链注册顺序正确:
c复制static const auth_img_desc_t *const cot_desc[] = {
&cot_bl2,
&cot_bl31,
&cot_bl32,
NULL
};
- 检查每个证书的
parent指针是否指向正确的上级证书
5. 高级配置与优化
5.1 多密钥轮换方案
在include/drivers/auth/mbedtls/mbedtls_config.h中配置密钥槽:
c复制#define MBEDTLS_PK_MAX_KEY_SLOTS 3
#define MBEDTLS_PK_KEY_SLOT_ROT 0 // 根密钥
#define MBEDTLS_PK_KEY_SLOT_OTA 1 // OTA更新密钥
#define MBEDTLS_PK_KEY_SLOT_DBG 2 // 调试密钥
密钥切换API:
c复制int mbedtls_pk_switch_key_slot(unsigned int slot);
5.2 验签性能优化
通过启用硬件加速提升验签速度:
- ARM CryptoCell:
c复制#define MBEDTLS_CC310_SUPPORT
#define MBEDTLS_SHA256_ALT
- CAAM加速(NXP平台):
makefile复制CRYPTO_LIB := caam
实测性能对比(RSA-2048验签):
| 平台 | 纯软件 | 硬件加速 | 提升倍数 |
|---|---|---|---|
| Cortex-A53 | 78ms | 9ms | 8.6x |
| Cortex-A72 | 45ms | 6ms | 7.5x |
5.3 调试日志增强
在验签失败时获取详细日志:
c复制// 启用mbedTLS调试
#define MBEDTLS_DEBUG_C
// 设置调试级别(0-5)
mbedtls_debug_set_threshold(4);
// 注册调试回调
mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
典型调试输出:
code复制verify_signature:498 | PK verify: SHA-256 with RSA
verify_signature:512 | Input hash: 3a6fed5fc11392b3...
verify_signature:523 | Signature: 89ab3cd4e0f12345...
verify_signature:537 | Verification failed (-0x4E00)
6. 安全加固建议
6.1 密钥保护方案
- HSM集成:
c复制#define PLAT_ROTPK_LOCATION HSM_PROVISIONED
- eFuse烧录(以NXP为例):
bash复制efuse_program -a 0x100 -v 0xA5A5A5A5
- 白盒密码保护:
c复制static int whitebox_decrypt_key(uint8_t *out, const uint8_t *in)
{
// 实现白盒解密逻辑
...
}
6.2 抗侧信道防护
- 恒定时间比较:
c复制int mbedtls_safer_memcmp(const void *a, const void *b, size_t n)
{
volatile int diff = 0;
for (size_t i = 0; i < n; i++)
diff |= ((const uint8_t*)a)[i] ^ ((const uint8_t*)b)[i];
return diff;
}
- RSA盲化签名:
c复制#define MBEDTLS_RSA_BLINDING
6.3 安全审计要点
- 定期检查以下关键配置:
bash复制grep -r "MBEDTLS_" plat/ | grep -i "weak\|insecure"
- 验证镜像保护范围:
bash复制tools/fiptool/fiptool info --secure boot build/fip.bin
- 检查编译器加固选项:
makefile复制TF_CFLAGS += -fstack-protector-strong -D_FORTIFY_SOURCE=2
