2026-09-21 11:00:37 +08:00
2026-09-21 11:00:37 +08:00
2026-09-21 11:00:37 +08:00
2026-09-21 11:00:37 +08:00
2026-09-21 11:00:37 +08:00

chongming-license

机器码授权共享包:硬件指纹采集、license 载荷格式、Ed25519 验签与插件白名单判定。 网关与厂商侧签发工具共用同一份实现 —— 尤其是规范化 JSON 只有一处实现, 避免"自己签的自己验不过"。

设计要点

  • 纯离线:设备用内置公钥验签,运行期零联网。与现有 air-gapped 部署形态 (Zenoh localhost、Caddy tls internal、无 phone-home)一致。
  • 非对称:Ed25519。注意根仓 resources/*.key 那套 .mbank 验签是 HMAC 对称且密钥与银行同目录发布,只能算防篡改/混淆,不能作为厂商 信任根 —— 授权必须用非对称,公钥可安全内置。
  • N-of-M 容错:license 里存各来源的原始指纹,校验按"命中数达阈值"判定, 而非把所有来源哈希成一个值 —— 否则换一块网卡就直接失效。 展示给客户的仍是单个 machine_code。
  • weak 来源:/etc/machine-id 在同镜像批量刷机场景下所有机器相同, 故标记 weak 且不参与判定阈值(只作诊断参考),避免它给攻击者白送一票。

采集来源

来源 位置 说明
board_serial /proc/device-tree/serial-number、DMI board_serial 逐机唯一,最稳定
emmc_cid /sys/block/mmcblk*/device/cid 芯片出厂唯一,不随系统重装变化
cpu_serial /proc/cpuinfo 的 Serial ARM 常见;部分型号全 0(会被剔除)
mac /sys/class/net/*/address 取字典序最小者:插入/移除其它网卡不改变它
product_uuid /sys/class/dmi/id/product_uuid x86 有效,ARM 通常缺失
machine_id /etc/machine-id ⚠ weak,见上

文件格式

{
  "payload": {
    "v": 1,
    "lic_id": "L2026-0001",
    "customer": "某某科技",
    "machine_code": "A3F9-1B77-9E04-2C8D-6F31-0A55",
    "sources": {"board_serial": "...", "emmc_cid": "...", "mac": "..."},
    "plugins": ["aibox_sophon_adapter", "ip_sound_column"],
    "not_before": "2026-09-01",
    "expires_at": "2027-09-01",
    "issued_at": "2026-09-01T10:00:00Z",
    "note": ""
  },
  "alg": "ed25519",
  "kid": "vendor-2026",
  "sig": "<base64,覆盖 payload 的规范化 JSON>"
}

签名覆盖 payload 原始字节的规范化形式(canonical_json:键排序、无空白), 因此载荷内不允许浮点数(float 文本表示存在多种合法写法)。校验顺序是 先验签、后解析模型 —— 反过来会让默认值填充/字段顺序改变字节导致验签失败。

用法

网关侧:

from chongming_license import LicenseManager

mgr = LicenseManager(
    license_path="license.lic",
    public_key=config["license"]["public_key"],
    clock_store=cache,          # chongming_cache.Cache,存时间高水位
    enforce=is_packaged(),      # 打包产物强制校验;开发/测试放行
)
decision = mgr.check_plugin("aibox_sophon_adapter")
if not decision.allowed:
    ...                          # 不加载该插件

厂商侧(chongming-cli,私钥只在这边):

uv run chongming-license keygen -o license_private.pem   # 一次性生成密钥对
uv run chongming-license issue --machine-code <码> --sources-json <采集导出> \
    --plugins aibox_sophon_adapter,ip_sound_column \
    --customer 某某科技 --expires 2027-09-01 -k license_private.pem -o license.lic

诚实的边界

离线 + root 的天花板是阻止随手拷贝,不是阻止逆向:有 root 者可改二进制 跳过校验,或 LD_PRELOAD 伪造指纹读取。clock 模块的时间回拨检测同理 —— 删掉缓存文件即失效,它只是抬高随手改时间的门槛。

真正难以绕过的是签名:伪造 license 需要厂商私钥,而公钥可明文放置 (换公钥只会验签失败,无法据以伪造)。

S
Description
No description provided
Readme
66 KiB
Languages
Python 100%