固件分发全流程
固件从开发到设备、再到后续空中升级的完整流程。角色分工与每步的约束以本文为准。
相关仓库:sign https://github.com/ffffxxxjjj/sign ;gateway https://github.com/ffffxxxjjj/gateway ;firmware-tool https://github.com/ffffxxxjjj/firmware-tool 。
包格式:GWPK v3(共用包,包头 312 字节、格式 3,格式 2 直接拒绝;版本块仍是格式 2,偏移 0x1000,228 字节)。权威定义见 sign 仓 docs/package-format.md;服务端端点见 sign 仓 docs/sign-server-api.md;固件 provisioning 见 gateway 仓 docs/provisioning.md;写入工具设计见 firmware-tool 仓 docs/固件写入工具设计.md。
总览
- 开发人员打包(出原始固件)
- 运营人员上传包到管理后台(后端签名+加密一次,出共用包)
- 现场实施人员从网站下载固件包与写入工具
- 现场实施人员写入固件到设备(出发前准备区,批量准备)
- 客户现场安装、上电、验在线
- 后续空中升级(云端推共用包+按设备包密钥包)
第 1 步:开发人员打包
- 开发人员打出原始固件,带版本块(版本块在偏移 0x1000,含型号、固件名、版本、日期、时间;时间精确到秒)。
- 原始固件只有版本块一处身份,无签名、无加密、无设备钥匙;签名与加密由管理后台做(第 2 步),不在开发侧做。
- 初始镜像不走签名打包工具:初始镜像不验签,由写入工具经串行线调试接口直写。
第 2 步:运营人员上传包到管理后台
- 运营人员把原始固件上传到管理后台的固件发布区。
- 后端签名+加密一次,出共用包(v3):同一版本所有设备共用同一份包文件;包密钥每版本随机新生成、后端按版本存,各版本互不通用。
- 包密钥包按设备单独包:后端按版本+序列号取包密钥包(80 字节:临时公钥 32 +包装后包密钥 48),设备用私钥解出包密钥再解固件、验签。
- 共用包与包密钥包严格区分:共用包公开分发无妨(没包密钥解不开);包密钥包只给对应设备(经推送命令或取接口),不公开。
第 3 步:现场实施人员从网站下载固件包与写入工具
- 网站做一个专门供下载的首页,不需要登录,供下载固件和写入工具。
- 写入工具本身也放在网站上供下载;事先下载好也行。
- 下载的固件是初始镜像(写给新设备)或共用包(空中升级用,见第 6 步);初始镜像只含公开钥匙、无私钥,可公开。
第 4 步:写入固件到设备(出发前准备区)
这一步不是到了客户现场才做:去客户现场前就准备好(领号、分发、下载包、写入固件都在出发前完成)。
前置:批量领号
- 出发前从管理后台批量领号,领的是设备序列号(发号系统去重、标记已领出防重领)。
- 序列号格式:
GW{YYYYMMDD}{序号:04}(按天计数,不重复);领号接口 POST /devices/allocate(管理员会话,数量 1–1000)。
工具
- 固件写入工具:带图形界面、给现场实施人员用;跨平台(Windows、Linux、macOS),Rust + egui + probe-rs。
- 调试器用 DAPLink,一根线:烧写与串口对话走同一根线(DAPLink 自带虚拟串口)。
- 写入工具不管签名钥匙(全局跟固件走),不管空中升级打包(管理后台的事)。
单台流程
- 联网检查(写入必须联网,无网不能写)。
- 操作员登录:写入工具用操作员账号(用户名密码)登录管理后台。
- 取密钥:工具向后台上报设备序列号、型号等,后台分发密钥对并绑定到该序列号(
POST /devices/issue,只走操作员会话;公钥私钥都存后台,记操作时间、操作人等审计);重发须 reissue=true,返回存量密钥不轮换。
- DAPLink 连接。
- 串行线调试接口写初始固件并校验。
- 串口命令把私钥和序列号发给固件,固件写进一次性可编程存储区,读回确认(
PROV BEGIN → PROV SERIAL → PROV KEY → PROV COMMIT → OK PROVISIONED;回复永不输出私钥)。
- 读回序列号显示,人工记录台账(纸面台账作核对用;系统记录以后的台分发记录为准,不靠人工登记)。
- 完成,换下一台。
- 任一步失败停下,不放行;分发没成功、写进没确认,不算完成。
约束
- 写入必须联网,无网不能写;不做离线写,不做后期补录,不做补录入口。
- 分发只接受操作员会话上报;序列号须在已领出批次内,重复分发按重发规则(不带
reissue=true 拒绝)。
- 序列号写入时读出,由人工记录(现场人工台账,作核对用)。
- 固件不再自己产生密钥对:密钥对由后台生成、绑定序列号;写入工具只接收后台分发的私钥与序列号。
第 5 步:客户现场
第 6 步:后续空中升级
- 云端按型号推送,每个型号单独的下载地址;包名见 GWPK 条;本地升级(人手挑文件)那条路的型号兜底靠包头型号字段。
- 升级包是共用包(第 2 步出的那份);包密钥按设备各包一遍(80 字节包密钥包),随推送命令或取接口给设备。
- 型号、固件名、版本、日期、时间只从签名的包头与版本块里读,不从文件名解析。
- 云端主动推为主,设备状态上报作兜底,不单独轮询;没收到回执重推;设备重连后首次上报状态时云端再比对版本补推;客户端点检查更新也是云端推(触发人是客户)。
- 手动推送:管理员可手动向设备推升级命令(单个
POST /devices/{序列号}/push,批量 POST /devices/push-batch,按型号等筛选、上限 500);设备列表显示当前版本与最新版本,支持手动单个与手动批量推送。
- 设备收到
firmware_update(版本号+包下载地址+80 字节包密钥包)后:解包密钥、解固件、验签、安装;先验后装,验不过不装。
- 包密钥安全模型:包密钥每版本随机新生成;一台设备私钥泄漏,只影响该版本的包密钥(该版本固件可解),换版本即换包密钥,其他版本不受影响;设备钥匙不可轮换,泄漏只能单台收敛(换新设备或重发号)。
- 信任区与签名钥匙轮换:走信任区机制,文档待后续(见遗留)。
角色与工具
- 开发人员:出原始固件。
- 运营人员:上传包到管理后台。
- 现场实施人员:下载、写入、登记、安装验在线。
- 固件写入工具:操作员登录、分发取密钥、写入与确认。
- 管理后台:设备登记表(设备列表)、批量领号、操作员账号、固件发布、包密钥记录、公开下载首页、手动推送。
- 签名打包工具:共用包打包(后端)与包密钥包包装。
关键规则
- 设备 = 一台独立物理设备,以自定义序列号区分,不是型号、批次、规格。
- 设备钥匙一机一对,后台分发、后台先存着,私钥存一次性可编程存储区,不可轮换;泄漏只能单台收敛。
- 云端签名钥匙全局一对(平时)+ 2 个备用;轮换走信任区机制(文档待后续)。
- 初始镜像的可信来自管理后台下载链路;空中升级验签的前提是初始镜像里的信任锚正确。
遗留
- 信任区与轮换消息文档(待后续)。
- 设备端
firmware_update 处理(收命令、解包密钥、解固件、验签、安装、回执)——固件侧待实现。
- 回执配对跟踪(命令发出即返回,不等回执;后续工作)。
- 管理台推送按钮界面(推送现阶段只走接口)。