Skip to content

实现原理:CRL 生成与编码

对应代码:pkg/crlgen.go · 入口 GenerateCRL(req)

CRL 是 CA 签名的"已吊销证书清单",规范在 RFC 5280 §5.3.1。本页讲 reason code 编码、serial 双试解析与一个容易被忽略的省略惯例。

reason code 映射

严格按 RFC 5280 §5.3.1:

原因名备注
unspecified0默认
key-compromise1私钥泄露
ca-compromise2CA 私钥泄露
affiliation-changed3
superseded4
cessation-of-operation5
certificate-hold6暂时挂起
7RFC 5280 未分配,缺省
remove-from-crl8
privilege-withdrawn9
aa-compromise10

码 7 是空的

RFC 5280 没分配值 7,cert-skills 的 revocationReasons 映射表里也没有 7。反向映射 reasonCodeToString 遇未知码返回 "unknown (%d)"

关键惯例:unspecified 时省略扩展

go
if reasonCode > 0 {
    rle.ReasonCode = reasonCode  // 仅 >0 时设置
}

为什么省略? RFC 5280 规定 unspecified 是默认值,"SHOULD NOT" 显式携带——写了 0 反而不合规。cert-skills 遵守这条惯例。

reasonCode 来源:优先 entry.ReasonCode;若为 0 且 entry.Reason != "" 才查 revocationReasons map。

序列号双试解析

每条 RevokedEntry 的 serial 用 big.Int.SetString 双试(L139-145):

这样 --serials 123456(十进制)和 --serials 0x1E240(十六进制)都能解析。

revocationTime 默认

entry.RevocationTime.IsZero() 时用 time.Now().UTC()(L155-158)。

CRL 模板与签名

Number 类型是 *big.IntThisUpdate 默认 time.Now().UTC()NextUpdate = ThisUpdate + NextUpdate天

默认值

参数默认值位置
NextUpdate30 天L62-64
Number1L65-67
OutputPath"crl.pem"L68-70
PEM block type"X509 CRL"L114

CRLGenerateRequest 字段

go
type CRLGenerateRequest struct {
    CACertPath    string
    CAKeyPath     string
    RevokedCerts  []RevokedEntry
    NextUpdate    int    // 天
    Number        int64
    OutputPath    string
}

type RevokedEntry struct {
    SerialNumber    string
    RevocationTime  time.Time
    Reason          string   // 字符串原因名
    ReasonCode      int      // 数字码(优先)
}

keyMatchesCert 三算法支持

loadCertAndSigner(caissuer.go L354-377)按 cert.PublicKey.(type) 分发:

go
switch pub := cert.PublicKey.(type) {
case *rsa.PublicKey:
    sp := priv.(*rsa.PrivateKey).PublicKey
    return pub.N.Cmp(sp.N) == 0 && pub.E == sp.E
case *ecdsa.PublicKey:
    sp := priv.(*ecdsa.PrivateKey).PublicKey
    return pub.X.Cmp(sp.X) == 0 && pub.Y.Cmp(sp.Y) == 0
case ed25519.PublicKey:
    sp := priv.(ed25519.PrivateKey).Public().(ed25519.PublicKey)
    return pub.Equal(sp)
default:
    return false
}

配套能力

  • ParseCRL(L177-202):先尝试 PEM(block type 必须为 "X509 CRL"),否则按 DER;x509.ParseRevocationList;CRLInfo.Number = crl.Number.String()
  • VerifyCRLSignaturecrl.CheckSignatureFrom(caCert)
  • CheckCertRevokedByCRL(L327-369):按 cert.SerialNumber.String() 与每个 crlInfo.RevokedCerts[i].SerialNumber 字符串相等比较

前置条件回顾

生成 CA 时 --is-ca 会自动带上 CRLSign,所以用 cert-skills 自建的 CA 直接能签 CRL。

下一步