第4章:公钥基础设施(PKI)在启动链中的应用

聊到安全启动链,就绕不开PKI。说白了,PKI就是一套管理密钥和证书的体系。在工业安全芯片里,它负责回答三个问题:你是谁?你凭什么启动?你的代码有没有被篡改?

我个人习惯把PKI比作一个「信任传递链」。你想想看,芯片上电后谁都不认识,它怎么知道加载的Bootloader是官方的?靠的就是证书链一层层往上追溯,最终追溯到芯片里预置的那个根证书。

4.1 证书链结构:信任是怎么传递的

证书链,也叫证书层级。典型的工业安全芯片会用三级结构:

  • 根证书(Root CA):自签名,芯片出厂时预置,不可更改
  • 中间证书(Intermediate CA):由根证书签发,用于签发最终实体证书
  • 实体证书(End Entity):签发给具体的Bootloader、固件镜像

我在项目中遇到过一种情况:客户为了省事,直接把根证书签发给固件。结果根证书泄露,整个产品线的安全全部崩塌。嗯,这里要注意——根证书必须离线保存,永远不要直接用于日常签名。

证书链的验证流程是这样的:

  1. 芯片读取固件附带的证书链
  2. 从实体证书开始,逐级向上验证签名
  3. 最终比对根证书是否与芯片内部预置的一致
  4. 全部通过,信任建立;否则启动失败

核心原则:信任不能凭空产生,只能传递。芯片只信任预置的根证书,其他一切证书都必须能追溯到它。

4.2 根证书的预置:芯片的「出厂烙印」

根证书预置是安全启动的第一步,也是最关键的一步。一旦根证书被篡改,整个信任链就崩塌了。

预置方式通常有三种:

方式 安全性 灵活性 我见过的坑
OTP熔丝 最高 低(一次性写入) 曾经有客户写错了哈希值,整批芯片报废
eFuse 中(可部分编程) 电流冲击可能导致位翻转,需要ECC保护
安全Flash 高(可更新) 容易被物理攻击读取,需要加扰存储

我个人推荐OTP熔丝方案。虽然灵活性差,但安全性最高。你想想看,根证书一旦写入,连芯片厂商自己都改不了,这才是真正的「信任锚点」。

经验之谈:预置的不是根证书本身,而是根证书的哈希值。证书本体可以放在固件里,芯片只存256位的哈希。这样既节省空间,又保证安全性。

4.3 密钥生命周期管理:从生到死

密钥不是永久的。它和人一样,有出生、有使用、有退休、有销毁。我见过太多项目只关注「怎么生成密钥」,却忽略了「密钥死了怎么办」。

完整的生命周期包括六个阶段:

  1. 生成:必须在安全环境中(HSM或安全芯片内部)生成
  2. 分发:通过安全通道传输,避免中间人攻击
  3. 存储:私钥必须加密存储,最好有硬件保护
  4. 使用:签名操作在安全环境中完成,私钥不出芯片
  5. 轮换:定期更换,降低单点泄露风险
  6. 销毁:彻底擦除,包括所有备份和缓存

我曾经帮一家工控厂商做安全审计。发现他们的密钥轮换策略是「三年换一次」。三年啊!中间证书泄露了都不知道。后来我建议他们改成「每批次生产换一次根证书,每季度换一次中间证书」。

警告:密钥销毁不是简单的「删除文件」。在Flash里,删除只是标记为无效,数据还在。必须执行物理擦除或多次覆写。对于OTP,一旦写入就无法销毁,所以根证书的轮换要靠「版本号」机制来实现。

4.4 证书链验证的代码实现

下面是一个简化的证书链验证流程。实际项目中会复杂得多,但核心逻辑不变:

// 伪代码:证书链验证
int verify_chain(cert_chain_t *chain, uint8_t *root_hash) {
    // 1. 从叶子证书开始
    for (int i = chain->length - 1; i >= 0; i--) {
        cert_t *cert = &chain->certs[i];
        
        // 2. 验证签名
        if (!verify_signature(cert, cert->issuer_pubkey)) {
            return ERR_SIGNATURE_INVALID;
        }
        
        // 3. 检查有效期
        if (cert->expiry < current_time) {
            return ERR_CERT_EXPIRED;
        }
        
        // 4. 检查是否被吊销
        if (is_revoked(cert->serial)) {
            return ERR_CERT_REVOKED;
        }
    }
    
    // 5. 最后比对根证书哈希
    uint8_t computed_hash[SHA256_LEN];
    sha256(chain->root_cert, sizeof(chain->root_cert), computed_hash);
    
    if (memcmp(computed_hash, root_hash, SHA256_LEN) != 0) {
        return ERR_ROOT_MISMATCH;
    }
    
    return SUCCESS;
}

避坑指南:我曾经在验证时忘了检查证书有效期。结果生产线上用了过期的测试证书,整批产品启动失败。从那以后,我把「时间检查」写进了验证流程的第一步。

4.5 证书链结构图

下面这张图展示了典型的工业安全芯片证书链结构。从根证书到固件签名,信任是一层层传递的:

工业安全芯片证书链结构 根证书 (Root CA) 自签名 · 预置在OTP中 签发 中间证书 (Intermediate CA) 由根证书签发 · 可轮换 签发 实体证书 (End Entity) 签发给Bootloader/固件 签名 固件镜像 信任验证方向 固件 → 实体证书 → 中间证书 → 根证书 → 芯片OTP哈希比对 ⚠ 私钥必须存储在 HSM或安全芯片内

这张图里,信任是从下往上验证的。芯片先拿到固件和证书链,然后从实体证书开始,逐级向上验证签名,最终比对根证书哈希。任何一个环节失败,启动就终止。

4.6 密钥生命周期管理流程图

下面这张图展示了密钥从生成到销毁的完整流程。每个阶段都有对应的安全措施:

密钥生命周期管理流程 生成 HSM内生成 分发 安全通道 存储 加密+硬件保护 使用 私钥不出芯片 轮换 定期更换 销毁 物理擦除 关键安全措施 • 生成阶段:必须在HSM或安全芯片内部完成,避免私钥暴露 • 销毁阶段:必须执行物理擦除或多次覆写,不能只删除文件 • 轮换周期:根证书按批次换,中间证书按季度换,实体证书按需换

这个流程看起来简单,但每个阶段都有坑。我见过最离谱的是:某厂商把私钥生成在普通服务器上,然后通过邮件发送给产线。嗯,这相当于把家门钥匙贴在门上。

4.7 总结

PKI在安全启动链中的作用,说白了就是建立和管理信任。根证书是信任的起点,证书链是信任的传递,密钥生命周期管理是信任的保障。

我个人觉得,做安全启动最忌讳的就是「一次性思维」。密钥不是写进去就完事了,要考虑它怎么轮换、怎么销毁、怎么应对泄露。你想想看,如果根证书泄露了,整个产品线的安全就全完了。所以,从一开始就要把生命周期管理纳入设计。

一句话记住:PKI不是一套静态的证书体系,而是一套动态的信任管理机制。从根证书预置到密钥销毁,每个环节都要有预案。


公众号:蓝海资料掘金营,微信deep3321