4. Secure DFU核心概念
Secure DFU 与早期 Legacy DFU 最大的区别,是把“升级包”拆成了两个在语义上完全不同的对象:Init Packet 和 Firmware Image。前者描述“这次升级是什么、能不能升”,后者才是真正要写进 Flash 的固件数据。理解这两个对象以及它们携带的签名、CRC、版本信息,是排查 DFU 失败、设计自定义升级流程的基础。
Init Packet:升级的“元数据信封”
Init Packet 是一个独立的小数据包,在固件数据真正传输之前先发送给 Bootloader。它不包含可执行代码,而是携带本次升级的元信息,典型字段包括:
- 固件类型:SoftDevice、Bootloader、Application 或它们的组合。
- 固件大小:Firmware Image 的字节数,用于后续接收校验。
- 固件版本:如 0x00000002,用于版本比较。
- CRC32:对 Firmware Image 整体计算的校验值。
- 签名:对上述字段的 ECDSA(P-256)签名,Secure DFU 的核心安全凭证。
Bootloader 收到 Init Packet 后,会先用公钥验证签名,再检查版本、CRC 等条件。只有 Init Packet 校验通过,Bootloader 才会进入接收 Firmware Image 的状态。因此 Init Packet 相当于“先验票、后入场”。
Firmware Image:真正写入 Flash 的数据
Firmware Image 是编译产物经过打包后的二进制数据,通常由 nrfutil pkg generate 生成,内部包含固件本体以及必要的元数据。它被分片传输,每片写入 Flash 的升级区。传输完成后,Bootloader 会重新计算整包 CRC32,并与 Init Packet 中声明的 CRC 比对,一致才认为数据完整。
签名、CRC 与版本校验的分工
这三者常被混为一谈,但职责完全不同:
| 机制 | 作用 | 失败后果 |
|---|---|---|
| ECDSA 签名 | 证明升级包来源可信、未被篡改 | 拒绝升级,返回签名错误 |
| CRC32 | 检测传输或存储过程中的数据损坏 | 拒绝激活,返回 CRC 错误 |
| 版本校验 | 防止降级或重复升级 | 拒绝升级,返回版本错误 |
签名解决“是不是我信任的人给的”,CRC 解决“数据有没有坏”,版本解决“该不该升”。三者缺一不可。
升级状态机
Secure DFU 在 Bootloader 内部维护一个状态机,典型状态迁移如下:
IDLE
│ 收到 Init Packet
▼
VALIDATING_INIT
│ 签名/版本/CRC 校验通过
▼
RECEIVING_IMAGE
│ 分片接收完成
▼
VALIDATING_IMAGE
│ 整包 CRC 通过
▼
ACTIVATING
│ 写入目标区域并复位
▼
DONE / 回到 IDLE
任一校验失败,状态机会回到 IDLE 并返回对应错误码,例如 NRF_DFU_ERR_EXT_API、NRF_DFU_ERR_CRC、NRF_DFU_ERR_SIGNATURE。理解状态机有助于定位问题发生在“验票”还是“入场”阶段。
实际打包与校验示例
以 nRF5 SDK 为例,生成一个带签名的升级包通常使用如下命令(参数为示例值):
nrfutil pkg generate \
--hw-version 52 \
--sd-req 0x00B6 \
--application-version 2 \
--application app.hex \
--key-file private.pem \
app_dfu_package.zip
其中 --application-version 2 会写入 Init Packet 的版本字段,--key-file 用于生成 ECDSA 签名。Bootloader 端使用对应的公钥(烧录在 Bootloader 中)验证签名。若版本号小于等于当前固件版本,Bootloader 会拒绝升级并返回版本错误。
private.pem 一旦丢失,已烧录对应公钥的设备将无法再接受新固件升级。生产环境应妥善备份密钥,并避免在多个产品线复用同一密钥。
常见错误与定位思路
- 签名错误:检查私钥与设备公钥是否匹配,确认
--key-file正确。 - CRC 错误:检查传输链路是否丢包,确认 Firmware Image 未被截断或修改。
- 版本错误:确认
--application-version大于设备当前版本。 - 状态机卡在 VALIDATING_INIT:多为 Init Packet 字段不完整或签名格式错误。
掌握 Init Packet、Firmware Image、签名、CRC、版本校验与状态机之间的关系,就能在 DFU 失败时快速判断问题出在“验票”还是“入场”,而不是盲目重试。