3. 密钥体系设计:密钥分层结构与用途分离原则
做安全启动,第一件事不是选算法,也不是写代码。
是先把密钥体系想清楚。
我见过太多团队,上来就一把密钥签到底。产品出了,想换密钥?改固件?加个新功能?全得推倒重来。说白了,密钥体系设计得不好,后面每一步都是坑。
这一章,我们就聊聊怎么搭一个靠谱的密钥分层结构,以及为什么要把不同用途的密钥分开管。
3.1 为什么需要密钥分层?
想象一下,你公司大门只有一把钥匙。前台一把,CEO一把,保洁阿姨也一把。丢了任何一把,整栋楼都得换锁。
密钥管理也是这个道理。
如果所有签名都用同一把密钥,那这把密钥一旦泄露,整个产品线的信任体系就崩了。更麻烦的是,你没法做权限隔离——做驱动的工程师不该能签 bootloader,做应用的工程师不该能签内核。
密钥分层,就是为了解决两个核心问题:
- 风险隔离:某一层密钥泄露,不影响其他层。
- 权限控制:不同角色只能使用自己权限范围内的密钥。
核心原则:根密钥永远离线,中间密钥做策略控制,代码签名密钥用于日常操作。三层分离,各司其职。
3.2 经典的三层密钥结构
我个人习惯用三层结构。不是拍脑袋定的,是这些年踩坑踩出来的。
这三层分别是:
- 根密钥(Root Key)—— 信任的起点
- 中间密钥(Intermediate Key)—— 策略执行层
- 代码签名密钥(Code Signing Key)—— 日常干活用的
下面这张图,把三层的关系和流转画清楚了。
3.3 各层密钥的职责与保护要求
3.3.1 根密钥(Root Key)
根密钥是整个信任链的锚点。它只做一件事:签发中间密钥证书。
根密钥一旦泄露,整个产品线的安全就归零了。所以它的保护级别是最高的。
- 存储位置:硬件安全模块(HSM),或者离线保险柜里的专用加密机。
- 使用频率:极低。一年可能就用一两次,只在发布新中间密钥时才动用。
- 访问权限:不超过3个人能接触到。我建议是安全官 + 技术负责人 + 备份保管人。
⚠ 我曾经见过一个团队:把根密钥的私钥文件放在共享网盘上,还设了个弱密码。结果被内部员工拷走,整个产品线的信任体系被迫重建。那次教训,直接让公司损失了两个月的人力。
3.3.2 中间密钥(Intermediate Key)
中间密钥是策略执行层。它由根密钥签发,负责给代码签名密钥授权。
为什么要多这一层?直接让根密钥签代码不行吗?
行,但不灵活。你想想看:
- 如果根密钥签了所有代码,那每次换签名策略(比如增加版本号约束),都得动用根密钥。
- 中间密钥可以设多个,按产品线、按安全等级、按部门来分。
- 中间密钥泄露了,可以吊销,重新签发一个就行,不用动根密钥。
| 属性 | 根密钥 | 中间密钥 | 代码签名密钥 |
|---|---|---|---|
| 用途 | 签发中间密钥 | 签发代码签名密钥 | 签名固件/镜像 |
| 存储方式 | HSM / 离线保险柜 | HSM / 专用服务器 | 构建服务器 / CI系统 |
| 使用频率 | 极低(年/次) | 低(月/次) | 高(日/次) |
| 泄露影响 | 全产品线信任崩塌 | 该产品线信任崩塌 | 该版本镜像信任崩塌 |
| 访问人数 | ≤3人 | ≤10人 | 按需授权 |
3.3.3 代码签名密钥(Code Signing Key)
这是真正干活用的密钥。开发工程师、CI系统、构建服务器,每天都要用它来签名固件。
代码签名密钥由中间密钥签发,可以按产品线、按版本、按模块来生成多个。
举个例子:
- 产品A的bootloader用密钥K1
- 产品A的内核用密钥K2
- 产品B的全部镜像用密钥K3
这样,即使K1泄露了,也只影响产品A的bootloader,其他部分不受影响。
💡 我的建议:代码签名密钥最好用短期证书,比如有效期设3个月或6个月。到期自动轮换,减少长期泄露的风险。我在一个车载项目里就是这么做的,效果很好。
3.4 密钥用途分离原则
密钥用途分离,说白了就是:一把密钥只干一件事。
这个原则听起来简单,但实际执行中经常被忽视。我见过有人用代码签名密钥去加密通信,用根密钥去签测试镜像——这都是坏习惯。
分离原则具体包括:
- 签名密钥 vs 加密密钥:签名密钥只用于签名验证,加密密钥只用于加解密。不要混用。
- 生产密钥 vs 测试密钥:生产环境用的密钥,绝对不能出现在开发或测试环境中。测试密钥可以随便用,但生产密钥必须严格管控。
- 不同产品线的密钥分离:产品A的密钥不能用来签产品B的固件。哪怕两个产品用的是同一套芯片方案。
- 不同安全等级的密钥分离:安全启动的密钥和OTA升级的密钥,建议分开。万一OTA密钥泄露,至少安全启动还能兜底。
核心原则总结:密钥分层 + 用途分离 = 最小化泄露影响。每一层、每一把密钥,都只做它该做的事。出了事,也能把损失控制在最小范围内。
3.5 实际项目中的密钥体系设计示例
拿一个典型的IoT网关项目来说吧。
这个网关有bootloader、Linux内核、应用程序三个镜像需要签名。我们当时的设计是这样的:
密钥体系设计(IoT网关示例)
├── 根密钥(Root Key)
│ └── 存储在离线HSM中,仅用于签发中间密钥
│
├── 中间密钥(Intermediate Key)
│ ├── 产品线中间密钥(用于签发所有代码签名密钥)
│ └── 存储在专用HSM中,每月使用一次
│
├── 代码签名密钥(Code Signing Key)
│ ├── bootloader签名密钥(K_bl)
│ ├── 内核签名密钥(K_kernel)
│ ├── 应用签名密钥(K_app)
│ └── 存储在构建服务器的加密分区中
│
└── 测试密钥(Test Key)
├── 测试用bootloader密钥
├── 测试用内核密钥
└── 测试用应用密钥
└── 存储在开发环境的本地密钥库中
这个设计的好处是:
- 根密钥一年只用一两次,安全风险极低。
- 中间密钥控制了整个产品线的签名策略,但泄露了也能快速吊销。
- 代码签名密钥按模块分离,一个泄露不影响其他模块。
- 测试密钥和生产密钥完全隔离,开发人员随便折腾也不影响生产。
⚠ 注意:测试密钥的证书链和生产密钥的证书链必须分开。也就是说,测试密钥不能由生产环境的根密钥签发。否则,测试环境泄露的密钥,理论上也能签出被生产设备信任的固件。
3.6 密钥轮换与吊销策略
密钥不是永久的。再好的保护措施,也架不住时间。
我个人建议:
- 根密钥:5-10年轮换一次。如果没出安全问题,甚至可以更久。
- 中间密钥:1-2年轮换一次。配合产品线的更新节奏。
- 代码签名密钥:3-6个月轮换一次。最好做成自动轮换。
吊销呢?一旦发现密钥泄露,必须立即吊销对应的证书,并发布新的密钥。
吊销列表(CRL)要放在固件里,或者通过OTA下发。设备在启动时,先检查签名密钥是否在吊销列表中。如果在,直接拒绝启动。
💡 一个小技巧:在中间密钥证书里,可以加上一个「仅用于签发代码签名密钥」的扩展字段。这样即使中间密钥被偷了,攻击者也没法用它去签发新的中间密钥,只能签代码签名密钥。这叫「密钥用途约束」,是X.509证书标准里就有的功能,别浪费了。
好了,密钥体系设计的核心思路就这些。记住:分层、分离、轮换、吊销。把这四个词刻在脑子里,你的密钥体系就不会出大问题。