Go crypto/x509.ParseRevocationList 怎样读取 CRL 撤销条目
来源:17golang原创
时间:2026-11-10 23:01:57 471浏览 收藏
处理证书吊销列表(CRL)时,真正传给 x509.ParseRevocationList 的不是整段 PEM 文本,而是去掉 PEM 外壳后的 ASN.1 DER 字节。解析成功后得到 *x509.RevocationList,可以读取签发者、更新时间和被撤销证书条目。
最容易混淆的地方有三个:PEM 与 DER 是两层格式;解析 CRL 不等于验证签名;旧的 ParseDERCRL 返回 pkix.CertificateList,新代码应优先使用 ParseRevocationList。
- 先用
pem.Decode取出block.Bytes,再传给ParseRevocationList。 - 读取条目时优先看
RevokedCertificateEntries,可得到序列号、撤销时间和原因码。 - 解析只说明编码结构可读;需要确认签发者时,再单独调用
CheckSignatureFrom。
一、先把 PEM 外壳和 DER 内容分开
CRL 文件经常以 -----BEGIN X509 CRL----- 开头。这个文本外壳便于传输,但标准库解析函数接收的是 DER 内容。若把整段 PEM 字符串直接转成字节传入,通常会得到 ASN.1 解析错误。

func decodeCRL(data []byte) ([]byte, error) {
// PEM 只是编码外壳,先取出其中真正的 DER 字节。
block, rest := pem.Decode(data)
if block == nil {
return nil, errors.New("没有找到 PEM 数据块")
}
// 允许调用方检查文件中是否意外拼接了第二段内容。
if len(bytes.TrimSpace(rest)) != 0 {
return nil, errors.New("CRL 后仍有未处理的数据")
}
if block.Type != "X509 CRL" {
return nil, fmt.Errorf("不是 X509 CRL: %s", block.Type)
}
return block.Bytes, nil
}
如果上游已经提供 DER 文件,就不需要 pem.Decode,直接把文件字节交给解析函数即可。输入层完成后,后面的代码不应再关心文件是 PEM 还是 DER。
二、用 ParseRevocationList 得到结构化 CRL
ParseRevocationList 解析的是 X.509 v2 CRL 的 ASN.1 DER 数据,返回 *x509.RevocationList。它能提供 Issuer、ThisUpdate、NextUpdate、编号以及撤销条目等结构化字段。
func parseCRL(data []byte) (*x509.RevocationList, error) {
// 解析阶段只负责确认 DER 结构可读,不代表签名已经可信。
der, err := decodeCRL(data)
if err != nil {
return nil, err
}
list, err := x509.ParseRevocationList(der)
if err != nil {
return nil, fmt.Errorf("解析 CRL 失败: %w", err)
}
return list, nil
}
旧代码可能还在使用已弃用的 ParseDERCRL。迁移时不要只把函数名替换掉就结束:返回对象的字段模型也应改为 x509.RevocationList,并明确后续是读取条目还是做签名检查。
三、读取撤销条目的序列号、时间和原因
一张 CRL 可以包含多个被撤销证书。对每个条目,最常用的信息是证书序列号和撤销时间;如果发布方带有原因码,还可以读取 ReasonCode。Go 1.21 起,RevocationListEntry 提供了更适合新代码使用的条目类型。

func summarize(list *x509.RevocationList) []string {
result := make([]string, 0, len(list.RevokedCertificateEntries))
for _, entry := range list.RevokedCertificateEntries {
// 序列号用于和待检查证书建立对应关系,时间用于判断撤销发生时点。
result = append(result, fmt.Sprintf(
"serial=%s revoked_at=%s reason=%d",
entry.SerialNumber.Text(16),
entry.RevocationTime.Format(time.RFC3339),
entry.ReasonCode,
))
}
return result
}
不要把 RevokedCertificateEntries 当成“当前仍然有效的黑名单”直接长期缓存。它表达的是这张 CRL 发布时包含的撤销记录,业务还需要结合 ThisUpdate、NextUpdate 和自己的缓存刷新策略判断新鲜度。
四、解析、签名和旧字段要分别处理
解析成功只代表 DER 结构符合标准库能识别的格式。要确认 CRL 是由预期的签发者发布的,应取得对应的 *x509.Certificate,再调用 list.CheckSignatureFrom(issuer)。这个调用仍然不是完整的证书路径验证,它只处理 CRL 签名与签发者之间的关系。
| 目标 | 使用方式 | 不要混淆 |
|---|---|---|
| 从文件获得 DER | pem.Decode | PEM 外壳不是 ASN.1 内容 |
| 读取 CRL 字段 | ParseRevocationList | 解析成功不等于可信 |
| 读取被撤销证书 | RevokedCertificateEntries | 条目不是完整证书对象 |
| 确认签发者 | CheckSignatureFrom | 不替代整条证书链验证 |
如果需要兼容旧数据结构,可暂时读取已弃用的 RevokedCertificates 字段,但新代码应优先围绕 RevocationListEntry 组织结果。这样后续处理原因码和扩展字段时,边界更清楚。
相关问题
DER 文件还需要调用 pem.Decode 吗?
不需要。只有输入带 PEM 文本外壳时才先解码;已经是 DER 的字节可以直接传给 ParseRevocationList。
ParseRevocationList 成功后就能信任 CRL 吗?
不能。它只完成格式解析;需要确认来源时,还要用预期签发者调用 CheckSignatureFrom,并按业务要求处理 CRL 新鲜度。
为什么不继续使用 ParseDERCRL?
ParseDERCRL 已被官方标记为弃用,推荐迁移到 ParseRevocationList,以使用新的 RevocationList 与条目模型。
-
237 收藏
-
125 收藏
-
322 收藏
-
349 收藏
-
394 收藏
-
485 收藏
-
272 收藏
-
337 收藏
-
161 收藏
-
497 收藏
-
190 收藏
-
119 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习