2. 固件签名与验证机制
固件签名这事儿,说白了就是给固件贴个「防伪标签」。你想想看,如果设备随便刷个固件就能跑,那黑客改点代码塞进去,设备就成别人的了。Matter 作为智能家居的通用语言,签名验证是它的底线。
我个人习惯把签名机制拆成三块来看:密码学原理、签名格式、验证流程。下面咱们一个一个聊。
2.1 固件签名的密码学原理
签名用的不是对称加密,而是非对称加密。简单说就是:私钥签名,公钥验签。私钥只有厂商自己知道,公钥可以公开。
具体流程是这样的:
- 对固件做哈希运算(比如 SHA-256),得到一个固定长度的摘要。
- 用私钥对这个摘要加密,生成签名。
- 设备端用公钥解密签名,拿到摘要,再和自己算的摘要对比。
- 一致就通过,不一致就拒绝。
核心要点:哈希保证完整性,非对称加密保证真实性。两者缺一不可。
我在项目中遇到过一种情况:有人只做了哈希校验,没做签名。结果攻击者把固件和哈希一起换了,设备照样认。嗯,这就是典型的「只防君子不防小人」。
2.2 Matter 固件签名格式解析
Matter 的签名格式不是随便拼的,它有严格的规范。我直接拿一个实际解析过的例子来说。
Matter 固件签名通常包含以下几个字段:
| 字段 | 长度 | 说明 |
|---|---|---|
| 签名算法标识 | 2 字节 | 0x0001 表示 ECDSA with SHA-256 |
| 签名值 R | 32 字节 | ECDSA 签名的 R 分量 |
| 签名值 S | 32 字节 | ECDSA 签名的 S 分量 |
| 公钥 | 65 字节 | 未压缩格式,0x04 + X + Y |
| 证书链 | 可变 | DER 编码的 X.509 证书链 |
解析的时候,我建议按顺序读,别跳字段。曾经有个厂商把公钥和签名值的顺序搞反了,结果设备死活验不过。后来查了半天才发现是格式问题。
下面是一个用 Python 解析签名头的示例:
import struct
def parse_matter_signature(data):
# 前2字节是算法标识
algo_id = struct.unpack('>H', data[0:2])[0]
if algo_id != 0x0001:
raise ValueError(f"不支持的签名算法: {algo_id}")
# 接下来32字节是R
r = data[2:34]
# 再32字节是S
s = data[34:66]
# 然后65字节是公钥
pubkey = data[66:131]
return {
'algorithm': 'ECDSA-SHA256',
'r': r.hex(),
's': s.hex(),
'pubkey': pubkey.hex()
}
小技巧:解析时先校验魔数和长度,避免解析到畸形数据导致崩溃。我习惯在解析前加一个「长度门限检查」。
2.3 签名验证流程与工具链
验证流程其实不复杂,但步骤不能省。我画了一张流程图,你看一眼就明白了。
工具链方面,我常用的有这几样:
- OpenSSL:命令行验签、解析证书、转换格式。最基础也最可靠。
- Python + cryptography 库:适合写自动化脚本,批量验证固件。
- Matter SDK 自带的 chip-tool:官方工具,支持完整的 OTA 验证流程。
- Hex 编辑器(如 010 Editor):手动查看签名结构,调试时很有用。
注意:千万不要在生产环境里用「跳过签名验证」的调试开关。我曾经见过一个团队,为了测试方便把验证关了,结果发布时忘了打开。那批设备全部无法通过 OTA 升级,只能返厂。
最后说一个我踩过的坑。有一次验证固件时,发现签名总是失败。查了两天,最后发现是固件里多了一个 4 字节的尾部填充。Matter 规范里明确要求签名前要去掉填充,但那个厂商的构建脚本没做。所以我的建议是:验签前先确认固件边界,多一个字节都不行。