Skip to content

License XML 如何工作 ​

License XML 使用 Ed25519 数字签名保护许可证载荷。许可证是可读的 XML 文件;签名用于验证载荷是否由可信签发方签署,以及签发后是否被修改。签名本身不加密许可证内容,也不负责在线激活或用量计量。

参与方与密钥 ​

参与方持有内容职责
签发方Ed25519 私钥、许可证记录校验授权信息并签发许可证
应用一个或多个可信公钥严格解析许可证、验证签名和授权条件
用户许可证 XML 文件保存并向应用提供许可证

私钥只保存在签发系统中,绝不能嵌入客户端或分发给用户。应用使用 keyId 从可信公钥集合中选择验证密钥。轮换密钥时,可在应用中增加新公钥,并按产品版本策略决定是否继续信任旧公钥。

签发流程 ​

text
签发方 / 许可证系统
        │
        ├─ 1. 创建载荷
        │     licenseId、产品、客户、有效期、
        │     功能、数量限制、机器绑定
        ▼
   校验载荷结构与字段
        │ 失败 → 拒绝签发
        ▼
   序列化为 XML <payload>
        ▼
   Canonical XML 1.0(不含注释)
        ▼
   使用 Ed25519 私钥签名 UTF-8 字节
        ▼
   Base64 编码签名,附加 algorithm 与 keyId
        ▼
   输出许可证 XML ───────────────→ 分发给用户
                                      (只分发许可证,不分发私钥)

签名只覆盖 <payload>。许可证 ID、产品、客户、有效期、功能、限制和机器绑定等字段都在签名范围内;签名元素和根元素不在范围内。规范化后的载荷字节相同,签名才可验证。XML 属性顺序等词法差异可能不影响签名,但载荷文本中的空白属于签名内容。

离线验证流程 ​

text
用户提供许可证 XML
        │
        ▼
检查 XML 大小、语法与安全限制
(拒绝 DTD、实体声明、命名空间等)
        │ 失败 → INVALID_FORMAT
        ▼
检查许可证结构、字段与签名编码
        │ 失败 → INVALID_FORMAT
        ▼
读取 signature.keyId
        │
        ├─ 未知 keyId / 不支持算法
        │       → INVALID_SIGNATURE
        ▼
规范化原始 <payload> 并验证 Ed25519 签名
        │ 失败 → INVALID_SIGNATURE
        ▼
检查调用方提供的产品 ID / 版本
        │ 不匹配 → PRODUCT_MISMATCH
        ▼
检查 issuedAt 与 expiresAt
        ├─ 尚未生效 → NOT_YET_VALID
        └─ 已过期   → EXPIRED
        ▼
检查机器绑定
        └─ 指纹缺失或不匹配 → MACHINE_MISMATCH
        ▼
VALID:将已签名的功能和限制交给应用层执行

验证顺序很重要:只有签名有效后,应用才能信任载荷中的授权声明。若机器类型为 none,验证器不会进行机器指纹比较;若为 fingerprint,集成应用必须提供当前指纹。指纹采集、稳定性及防伪均由应用负责。

verifyLicense 执行本地格式、签名、产品、时间和机器指纹检查。产品 ID、版本及机器指纹由调用方传入;未传产品参数时不会检查对应匹配项。返回 VALID 只代表许可证通过这些验证,不代表应用已经强制执行功能开关或用量上限。

可选的在线激活与撤销 ​

完全离线时,客户端没有服务器状态,无法判断许可证是否已被撤销,也无法阻止同一文件被复制到多台未绑定设备。若业务要求限制重复激活、设备席位或远程撤销,需要由集成应用另外实现服务端流程。下面是一个非本协议定义的示意;本项目不提供激活/撤销 API 或服务端状态数据库。

text
首次启动 / 定期联网
        │
        ▼
客户端先执行本地签名及授权检查
        │ 无效 → 拒绝使用
        ▼
向应用服务端提交 licenseId 与设备标识
(具体认证与设备标识由应用设计)
        │
        ▼
服务端查许可证状态与已激活设备
        │
        ├─ 已撤销 / 已过期 → 拒绝
        ├─ 超出设备席位     → 拒绝或要求解绑
        └─ 可激活           → 原子地登记或更新设备
                                  │
                                  ▼
                           返回应用定义的结果

服务端应将许可证状态与设备席位作为权威状态,并妥善处理并发激活、重复请求、换机和解绑。licenseId 是许可证标识符,不是秘密或防复制凭证。只要客户端可以被修改,在线检查也无法从根本上保证应用一定执行检查;需结合应用自身的防篡改和业务策略评估风险。

安全边界 ​

  • 有效签名证明载荷与签发时一致,并证明签名由对应私钥产生;它不证明许可证尚未撤销。
  • 离线验证无法获知服务端状态,也无法保证系统时钟可信。
  • 许可证明文可读;签名不提供保密性。
  • 机器绑定不能代替签名验证;设备标识的采集与可靠性属于应用层。
  • 功能权限和用量限制需要由应用实际执行。客户端可被 Patch 或调试,许可证格式本身无法阻止此事。