meow_sign — MeowOS .mpk 产签/验签工具(宿主端)
定位:离线维护者侧工具,给
.mpk包打 Ed25519 签名,供设备端meow_verify(固件/usr/bin/meow_verify) 验签。本工具不落设备、不入库私钥。设计依据:devdocs/plan/MPK_SIGNATURE_DESIGN.md(§4.2 产签流程 / §3.1 块格式 / §5.1 挂点)。
0. 安全模型(先读,诚实标注)
| 项 | 说明 |
|---|---|
| 算法 | Ed25519(非对称)。私钥仅在离线维护机,设备只持公钥(固化进 meow_sign 的 meow_signing_pub.h)。 |
| 私钥 | .keys/signing.key(0600)——绝不入库(.gitignore 已忽略 .keys/)、绝不落设备;全网唯一,务必单独备份。 |
| 设备验证 | meow_verify(固件)只读内嵌公钥数组验签;os.meow.* 包必须有有效签名,否则 nyai/launcher 拒装(防伪造系统包名)。 |
| 签名覆盖 | payload_sha256(整个 tar.gz 前缀,含二进制/资源/app.json)+ 显式 package(包名)。改内容/改包名 → 验签失败。 |
| 诚实天花板 | 签名 + IPC 鉴权是防误装/防伪造包名/防沿途篡改,不是真安全边界:有 shell 的 root 用户可直接建目录/换 meow_verify。它挡住第三方 App 的「无意识越权」,挡不住 root 有意攻击(见 MPK_SIGNATURE_DESIGN §8)。 |
1. 用法
meow_sign keygen <priv_path> # 生成密钥对:priv(0600) + <priv>.pub(32B raw) + stdout 打印 pub_hex
meow_sign sign <pkg>.mpk <priv> [--v1] # 给纯 tar.gz 追加签名 footer(默认 v2 含时间戳;--v1=2A 旧版无 ts)
meow_sign verify <mpk> <pub|hex> # 用公钥(.pub 文件或 64 位 hex)验签指定 .mpk(产签后自测)
sign的<pkg>.mpk文件名茎必须等于包名(app.json.package),这是三重绑定①(meow_verify会二次校验)。- 默认产出 v2 块(184B):含被签时间戳
ts,验签端做「未来宽限」校验(超出now+86400拒)。 如需兼容旧固件(2A 的meow_verify只认 180B 的 v1)可加--v1产旧版。新固件meow_verifyv1/v2 都读。 verify是宿主侧镜像(产签后、分发前确认签名有效);设备侧真正把关的是meow_verify。
2. 产签流程(给新系统 App 签名)
以新增 os.meow.xxx 为例。
2.1 首次:生成/备份密钥(仅一次)
./patch_v2/meow_sign/meow_sign keygen .keys/signing.key
# 私钥 .keys/signing.key(0600) 请离线备份;公钥 .keys/signing.key.pub 可入库/固化进固件。
若已存在
.keys/signing.key(本仓库 2A 已生成),直接复用,勿覆盖(覆盖会令旧包全部失效)。
2.2 打包(不含签名;.mpk = 纯 tar.gz)
mkdir -p <build>/os.meow.xxx
# 放入 app.json + meow 二进制 + 资源;app.json 的 package 必须 == 目录名 == 文件名茎;version 单调递增(禁降级)
tar czf os.meow.xxx.mpk os.meow.xxx
app.json要点:package(=os.meow.xxx)、exec(指向MeowAPPs/os.meow.xxx/内二进制)、version(≥ 已装,禁止降级)。
2.3 签名(默认 v2)
./patch_v2/meow_sign/meow_sign sign os.meow.xxx.mpk .keys/signing.key
# => sign ok (v2): ... package=os.meow.xxx ts=<unix> block_len=184 ...
2.4 产签后自测(可选但推荐)
./patch_v2/meow_sign/meow_sign verify os.meow.xxx.mpk .keys/signing.key.pub # 用自己公钥确认
./patch_v2/meow_verify/meow_verify_host os.meow.xxx.mpk # 用固件内嵌公钥确认(与设备同口径)
2.5 装到设备 / 分发
- 把
os.meow.xxx.mpk放到卡上(如MeowOS/opt/nyai/或目标目录),用nyai install安装。 - 安装期由 nyai/launcher 调
meow_verify:验签通过 + 三重绑定(footer.package==文件名茎==app.json.package +os.meow.*前缀)才落盘;否则拒装并回滚。 os.meow.*无签名/验签失败 → 一律拒装(防伪造系统包名);第三方包无签可直接装(但建议也签名防篡改)。
3. 三重绑定(三方各司其职)
| 绑定 | 校验方 | 校验点 |
|---|---|---|
| ① footer.package == 文件名茎 | meow_verify(--package/推导) |
防「把 os.meow.xxx.mpk 改名为 evil.mpk」 |
② footer.package == 解包 app.json.package |
nyai / launcher 安装流 | 防「改 app.json 的 package」 |
③ os.meow.* 前缀 + 必须验签过 |
nyai / launcher 安装流 | 防「无签名冒充系统包」 |
4. 多公钥 / 密钥轮换(2B)
固件 meow_verify 内嵌公钥数组(meow_signing_pub.h),验签时任一公钥通过即放行。轮换 = 加钥/去钥 + 重编 meow_verify(随固件更新):
#define MEOW_PUB_KEY_COUNT 2
static const uint8_t g_meow_pub[MEOW_PUB_KEY_COUNT][32] = {
{ /* key #0:旧主钥(保留做跨代兼容) */ ... },
{ /* key #1:新钥 */ ... },
};
- 加钥:新钥
meow_sign keygen后追加到数组尾部、MEOW_PUB_KEY_COUNT+1、重编meow_verify→ 旧钥签的包(新固件仍内嵌旧钥)与新旧包都放行(平滑过渡)。 - 去钥:从数组移除 + 重编 → 原钥签的包在新固件拒装。去钥必须与包重签协同(先用新钥重签所有在维护的系统包)。
- 私钥更新(新钥签新包)时,务必保证新私钥离线备份,且旧私钥在轮换期内保留(否则旧钥签的包失效)。
5. v1 / v2 块与兼容
| v1(2A 旧版) | v2(2B 加固) | |
|---|---|---|
| 总长 | 180B | 184B |
| 时间戳 | 无 | 有(ts,unix 秒,被签名) |
| 被签消息 | "MEOWSIG1"‖alg‖pkg_len‖package‖sha256 |
v1 msg ‖ ts(4B,LE) |
meow_verify |
读取(不检 ts) | 读取(校验 ts 未来宽限,超 now+86400 拒;ts==0 视为畸形拒) |
- 新
meow_verify(2B 固件)v1/v2 都读 → 旧 2A 签的包仍可装/可导出复验。 --v1产出的包在旧 2A 固件可装;v2 包需 2B+ 固件(旧固件meow_verify只认 180B,会把 184B 块误判为无签 →os.meow.*拒装)。固件与工具链同版本发布即可避免此坑。
6. 明确不做(诚实)
- 防重放 / 密钥过期 / CRL / 在线验证:需网络+后端,超出「单机 + 卡分发」模型(
MPK_SIGNATURE_DESIGN §8)。 - 时间戳只做「未来异常」宽限拒绝(防错误时钟/手工伪造未来 ts),不做「旧包过期拒装」。
- 签名是防误装/防伪造包名/防篡改,不是安全边界。
7. 相关文件
| 文件 | 作用 |
|---|---|
meow_sign.c |
产签/验签工具源码(复用 ../meow_verify 的 tweetnacl.c + sha256.c + meow_sig.h) |
build_sign.sh |
宿主编译(./build_sign.sh / ./build_sign.sh static) |
../meow_verify/meow_verify.c |
设备侧校验器(固件 /usr/bin/meow_verify) |
../meow_verify/meow_signing_pub.h |
固件内嵌公钥数组(仅公钥,可入库) |
../meow_verify/meow_sig.h |
签名块格式 + 被签消息构造(verifier/signer 共用) |
.keys/ |
私钥目录(已 gitignore,绝不入库) |