Python使用asn1tools解码X.509证书报错的问题排查咨询
纯Python实现X.509证书全信息提取问题排查
已完成前置工作
- 参考Python官方ssl模块文档,实现了支持IPv4/IPv6双栈的套接字客户端,加载了www.python.org对应的证书bundle;参考本地证书颁发者校验报错的解决方案,下载证书链拆分保存为独立文件,添加
context.load_verify_locations('path/to/cabundle.pem')配置后客户端可正常运行,所用证书均合法有效。 - 参考X.509公钥证书信息打印方案,计划使用如下代码实现解码:
该代码逻辑依赖对应的X.509 ASN.1定义文件。import asn1tools foo = asn1tools.compile_files("x509.asn") output = foo.decode("Certificate", cert) - 从ITU官方下载了ITU-T X.509 (08/1997)标准规范压缩包,解压得到三个文件:
AlgorithmObjectIdentifiers.asn、AuthenticationFramework.asn、CertificateExtensions.asn。最初误将AlgorithmObjectIdentifiers.asn作为顶层定义文件传入编译函数,执行代码如下:foo = asn1tools.compile_files("AlgorithmObjectIdentifiers.asn") output = foo.decode("Certificate", cert) print("Cert output: ", output)
运行报错信息
File ".../test-print-ssl.py", line 47, in cert_print_asn1 output = foo.decode("Certificate", cert) File "...\lib\site-packages\asn1tools\compiler.py", line 161, in decode "Type '{}' not found in types dictionary.".format(name)) asn1tools.errors.DecodeError: Type 'Certificate' not found in types dictionary.
待解决疑问
- 从哪里可以获取适用于上述代码的有效ASN.1文件?
- 已经下载的三个ASN.1文件应如何正确使用?是否需要合并文件?如果需要合并应如何操作?
- 应当如何进一步调试排查该问题?
补充说明
- 已验证
openssl x509 -in website.com.pem -text命令可正常打印同一份证书文件的内容,知晓可以通过os.system()调用openssl命令实现需求,但希望获得纯Python实现的证书解码打印方案。 - 已查阅过asn1tools编译ASN.1失败的相关问题,本次报错发生在解码阶段,与编译失败的场景并不相同。
解决方案
1. 有效ASN.1文件获取
你从ITU官方下载的三个1997版X.509规范文件本身就是合法有效的ASN.1定义源,不需要额外找其他零散的x509.asn文件。网上流传的单文件x509.asn大多是开发者提前合并好依赖的版本,反而容易出现OID缺失、扩展定义不全的问题。
2. 三个ASN.1文件的使用方法
不需要手动合并文件。asn1tools.compile_files本身支持传入文件路径列表,会自动解析处理文件间的依赖引用。
三个文件的层级关系如下:
AlgorithmObjectIdentifiers.asn:存储通用算法对象标识符(OID)定义,为最底层依赖CertificateExtensions.asn:存储X.509 v3证书的扩展字段定义,依赖算法OID文件AuthenticationFramework.asn:包含Certificate类型的顶层定义,依赖前两个文件
正确的编译写法如下:
import asn1tools # 直接传入所有ASN.1文件即可,工具会自动处理依赖顺序 compiler = asn1tools.compile_files([ "AlgorithmObjectIdentifiers.asn", "CertificateExtensions.asn", "AuthenticationFramework.asn" ])
如果确实需要合并为单文件,按照「算法OID文件→证书扩展文件→认证框架文件」的顺序,把三个文件的内容依次拼接为同一个.asn文件即可,注意删除重复的模块声明头部。
3. 调试排查步骤
- 第一步校验编译后的可用类型:编译完成后执行
print(compiler.types.keys()),即可看到当前编译产出的所有支持解析的ASN.1类型。你之前的报错核心原因就是只传入了算法OID定义文件,该文件内根本没有定义Certificate类型,自然会提示类型不存在。 - 第二步校验证书输入格式:如果是读取PEM格式证书,需要先去掉
-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----的头尾标记,将剩余内容做base64解码得到DER格式的二进制字节串,再传入decode方法,直接传入PEM文本会导致解码失败。 - 第三步适配编码兼容性:如果遇到部分扩展字段解码报错,可以在编译时添加
numeric_enums=True参数,解码时指定encoding='der',适配不同CA签发证书时的编码实现差异。
额外纯Python实现方案
如果不想手动维护ASN.1定义文件,可以直接使用纯Python实现的cryptography库加载解析证书,不需要调用外部openssl命令,直接访问对象属性即可拿到所有证书信息,示例代码:
from cryptography import x509 from cryptography.hazmat.backends import default_backend with open("website.com.pem", "rb") as f: cert_data = f.read() cert = x509.load_pem_x509_certificate(cert_data, default_backend()) # 可直接访问subject、issuer、extensions、public_key、serial_number等所有证书字段 print(cert)
内容的提问来源于stack exchange,提问作者minghua
相关产品推荐
相关产品推荐

