本文声明 FMO 数字证书体系中 根证书(Root CA)中间证书(Intermediate CA) 的开放格式,供实现互通的设备、服务器与第三方开发者参考。格式与官方证书工具 fmo-certificate-tools 的签发实现保持一致。

1. 证书体系

FMO 的身份体系建立在三层信任链之上:

Root CA(根机构) → Intermediate CA(中间机构) → User Cert(用户证书)
证书 职责 由谁签发
Root CA 信任锚,只负责签发中间证书;全网唯一的认证源头 自签名
Intermediate CA 负责审核真实操作证材料,签发用户证书 Root CA
User Cert 声明"这个呼号、这个 UID、这把公钥"属于被认可用户 Intermediate CA

核心原则:

  • 证书是公开对象。呼号、UID、公钥、序列号、有效期都可以被公开缓存、转发和再分发;证书本身不属于秘密数据。
  • 私钥永不进入证书。证书只承载公钥,签发方私钥与持有方私钥都不出现在任何证书字段中。
  • 信任是逐级传递的Root CA 的公钥 验证 中间证书中间证书的公钥 验证 用户证书,直至把某条广播、某次连接绑定到一个具体呼号。

2. 通用约定

2.1 编码与时间

  1. 所有证书 JSON 使用 UTF-8 编码。
  2. 时间戳统一使用 UTC Unix 时间戳,单位为秒。
  3. 二进制字段(公钥、签名等)在 JSON 中统一使用 不带 padding 的 base64url 编码;进入签名时使用原始字节。
  4. 所有大小写敏感字段必须精确匹配。

2.2 签名算法

  1. 证书签名算法固定为 Ed25519
  2. 签名的输入不是 JSON 文本,而是按协议字段顺序构造的固定顺序语义值数组,再对该数组做确定性 CBOR 编码后得到的原始字节串。
  3. 确定性 CBOR 编码不允许 indefinite length,不允许同一语义值存在多种编码形式;不同实现的 JSON 缩进、空格、字段排序差异不影响签名结果。
  4. signature 字段本身永远不进入被签名数组

2.3 域分离

所有证书签名结构必须显式包含以下前缀字段,避免不同对象之间误验签:

["FMO", 4, "messageType", ...]
  • protocol 固定为 "FMO"
  • version 固定为整数 4
  • messageType 为当前对象类型,如 rootCAintermediateCAuserCert

接收端必须在完全一致的 protocolversionmessageType 条件下重建签名数组,再做确定性 CBOR 编码后验签。

2.4 字段类型规则

语义 签名数组中的表示
snissuerSnuidiatexpuidRange.start/end CBOR integer
isCA CBOR boolean(不是 1/0 文本)
publicKey 原始 32 字节的 CBOR byte string
nameemailkeyIdcrllicense CBOR text string
issuingCountries 先全部转为两位大写国家码,再按字典序升序排序,作为嵌套 text string array

3. 根证书(Root CA)格式

3.1 职责与特性

  1. Root CA 是整条信任链的信任锚,私钥离线保存,不得在线使用
  2. Root CA 为自签名证书,用自身 subject.publicKey 对应的私钥签发。
  3. 完整 Root 自签名证书通过 OTA 写入设备信任存储;设备运行时以其中的 Root 公钥作为信任锚,Root 不通过 APRS 广播,也不在激活响应中下发。
  4. 默认有效期为 10 年

3.2 JSON 结构

{
  "sn": 1,
  "type": "rootCA",
  "issuer": {
    "name": "BG5ESN",
    "email": "xifengzui@yeah.net"
  },
  "subject": {
    "name": "BG5ESN",
    "publicKey": "root_public_key_base64url"
  },
  "extensions": {
    "isCA": true,
    "pathLen": 1,
    "crl": "https://bg5esn.com/share/ca/root_crl.json",
    "license": "https://bg5esn.com/share/ca/license.md",
    "keyId": "1"
  },
  "iat": 1780876683,
  "exp": 2096495883,
  "signatureAlgorithm": "Ed25519",
  "signature": "root_self_signature_base64url"
}

3.3 字段定义

字段 说明
sn 根证书序列号,全局唯一
type 固定为 rootCA
issuer.name 签发机构名称
issuer.email 签发机构联系邮箱
subject.name 主体名称(默认同签发机构)
subject.publicKey Root 公钥,32 字节 base64url
extensions.isCA 固定为 true
extensions.pathLen 固定为 1,允许签发一级中间 CA
extensions.crl Root CRL 可下载地址
extensions.license 使用许可声明地址
extensions.keyId 根密钥标识
iat 生效时间(UTC Unix 秒)
exp 过期时间(UTC Unix 秒)
signatureAlgorithm 固定为 Ed25519
signature Root 自签名,64 字节 base64url

3.4 签名数组(15 元素)

["FMO", 4, "rootCA", sn, issuerName, issuerEmail, subjectName, subjectPublicKeyBytes, isCA, pathLen, crl, license, keyId, iat, exp]

说明:

  1. Root 虽为自签名证书,签名数组仍按 issuersubject 逻辑字段分别展开,不做省略。
  2. subjectPublicKeyBytes 为 Root 公钥的原始 32 字节。
  3. isCA 进入数组时为 CBOR boolean truepathLen 为整数 1
  4. signature 字段本身不进入该数组。

4. 中间证书(Intermediate CA)格式

4.1 职责与特性

  1. Intermediate CA 由 Root CA 签发,负责审核真实操作证材料并签发用户证书。
  2. 证书通过 extensions 声明授权边界:可签发的 UID 范围(uidRange)与可签发的国家码范围(issuingCountries)。
  3. pathLen 固定为 0,表示不允许继续下发下级 CA
  4. 默认有效期为 5 年,且不得超出签发给它的 Root 证书的有效期。

4.2 JSON 结构

{
  "sn": 1001,
  "type": "intermediateCA",
  "issuer": {
    "sn": 1,
    "name": "BG5ESN",
    "publicKey": "root_public_key_base64url"
  },
  "subject": {
    "name": "BD4WPW",
    "email": "bd4wpw@example.com",
    "publicKey": "intermediate_public_key_base64url"
  },
  "extensions": {
    "isCA": true,
    "pathLen": 0,
    "keyId": "1",
    "crl": "https://bd4wpw.example.com/crl.json",
    "license": "https://bd4wpw.example.com/license.md",
    "uidRange": {
      "start": 5000,
      "end": 10000
    },
    "issuingCountries": [
      "CN"
    ]
  },
  "iat": 1780876801,
  "exp": 1938643203,
  "signatureAlgorithm": "Ed25519",
  "signature": "signed_by_root_base64url"
}

4.3 字段定义

字段 说明
sn 中间证书序列号,全局唯一
type 固定为 intermediateCA
issuer.sn 签发它的 Root 证书序列号
issuer.name Root 的主体名称
issuer.publicKey Root 公钥(与 Root 证书 subject.publicKey 一致)
subject.name 中间机构名称
subject.email 中间机构联系邮箱
subject.publicKey 中间 CA 公钥,32 字节 base64url
extensions.isCA 固定为 true
extensions.pathLen 固定为 0,禁止签发下级 CA
extensions.keyId 中间密钥标识
extensions.crl 该中间 CA 的 Intermediate CRL 可下载地址
extensions.license 使用许可声明地址
extensions.uidRange.start 可签发 UID 下限(含)
extensions.uidRange.end 可签发 UID 上限(含)
extensions.issuingCountries 可签发国家码列表,两位大写
iat 生效时间(UTC Unix 秒)
exp 过期时间(UTC Unix 秒)
signatureAlgorithm 固定为 Ed25519
signature Root 私钥签名,64 字节 base64url

4.4 签名数组(20 元素)

["FMO", 4, "intermediateCA", sn, issuerSn, issuerName, issuerPublicKeyBytes, subjectName, subjectEmail, subjectPublicKeyBytes, isCA, pathLen, keyId, crl, license, uidRangeStart, uidRangeEnd, [countryCode1, countryCode2, ...], iat, exp]

说明:

  1. issuerPublicKeyBytessubjectPublicKeyBytes 都使用原始公钥字节,不是 base64url 展示文本。
  2. issuingCountries 作为已按字典序升序排序的嵌套数组整体进入签名数组;任一实现排序结果不同都会导致签名不一致,因此排序规则必须严格一致。
  3. isCA 为 CBOR boolean truepathLen 为整数 0
  4. signature 字段本身不进入该数组。

4.5 签发约束

Root 签发中间证书时必须满足以下条件,任何一项不满足即为非法证书:

约束 规则
issuer 身份 issuer.sn == root.snissuer.name == root.subject.nameissuer.publicKey == root.subject.publicKey
时间窗口 iat ≥ root.iatexp ≤ root.exp
授权边界 uidRange.start ≤ uidRange.endissuingCountries 非空

5. 证书链校验

接收端校验证书链时按自顶向下顺序执行:

1. 用本地信任存储中的 Root 公钥,验证 Intermediate CA 证书签名
2. 核对 Intermediate 的 issuer 三要素与 Root 一致(sn / name / publicKey)
3. 检查时间窗口:root.iat ≤ intermediate.iat,intermediate.exp ≤ root.exp
4. 用 Intermediate 的 subject.publicKey,验证 User Cert 签名
5. 核对 User Cert 的 issuerSn == intermediate.sn
6. 检查用户证书时间窗口:intermediate.iat ≤ user.iat,user.exp ≤ intermediate.exp
7. 检查 user.uid 落在 intermediate.uidRange 范围内
8. 检查从 callsign 推断的国家码落在 intermediate.issuingCountries 范围内(可推断时)

说明:User Certificate 只承载呼号、UID、公钥与有效期,是其后续 APRS 广播与业务报文签名的根绑定材料。其完整格式与 APRS 紧凑表示将另行声明。

6. 吊销(CRL)

证书吊销遵循"上级吊销下级"的原则:

CRL 吊销对象 命中规则
Root CRL Intermediate CA sn + certFingerprint 双命中
Intermediate CRL User Cert uid + certFingerprint 双命中

certFingerprint 为被吊销证书的 SHA-256 指纹,计算规则:

certFingerprint = SHA-256( 该证书签名数组的确定性 CBOR 编码字节串 )

说明:

  1. 不允许对证书 JSON 文本直接做 SHA-256。
  2. 不允许把 signature 字段并入指纹计算输入。
  3. sn/uid 命中而指纹不匹配时不算吊销命中,这通常意味着证书重签发或缓存混乱。

CRL 是公开、带 Ed25519 签名、可独立下载与验签的对象;吊销明细格式将另行声明。

7. 工具与参考

本文档定义的帧结构与签名规则由 FMO 项目方主导,不接受外部 PR 变更申请;演进建议请通过 FMO 项目方渠道提出,保证全网互操作性。