Python全新ASN.1 API:高性能密码学解析革新

本文深入解析Trail of Bits为Python开发的全新ASN.1 API,该库基于Rust实现,显著提升解析性能,减少差分漏洞风险,并采用现代化数据类接口设计,适用于TLS握手、X.509证书等密码学场景。

Python全新ASN.1 API前瞻

ASN.1快速背景

ASN.1(Abstract Syntax Notation One)是一种接口描述语言(IDL),用于以语言和平台无关的方式描述数据结构。ASN.1本身不是序列化格式,而是定义编码规则,这些规则在不同设置下定义ASN.1结构的序列化和反序列化。实践中,ASN.1通常与可分辨编码规则(DER)同义。

DER具有以下关键特性:

  • 规范编码:给定ASN.1结构只有一种DER编码方式,编码是确定性的,可以往返并保持比特级相等。
  • 相对紧凑:DER定义二进制格式,并由于规范性而禁止整数、布尔值和时间的非最小编码。
  • 自描述和自定界编码:无需模式或格式描述即可完全解析DER消息。
  • 支持任意精度整数:DER的INTEGER类型在大小上功能无约束,适用于表示密码学中的大数。

这些特性使DER在密码学、网络和电信设置中非常流行。

为Python开发ASN.1库的动机

尽管大多数Python开发者不日常接触ASN.1,但许多情况下需要在X.509和其他知名格式和协议之外进行ASN.1编码和解码。例如,在Sigstore生态系统中,自定义X.509扩展需要从Python中提取和解析。

示例代码展示了如何从X.509证书中提取自定义扩展值:

1
2
3
4
5
6
from cryptography import x509

raw_cert = b"""..."""
cert = x509.load_pem_x509_certificate(raw_cert)
ext = cert.extensions.get_extension_for_oid(x509.ObjectIdentifier("1.3.6.1.4.1.57264.1.16")).value
ext.value  # => b'\x0c\x17https://github.com/pypa'

扩展值本身是DER编码的,PyCA Cryptography的API留给我们解释。因此,需要DER解析器,如pyasn1:

1
2
3
4
5
from pyasn1.codec.der.decoder import decode
from pyasn1.type.char import UTF8String

ext_value = decode(ext.value, UTF8String)[0].decode()
ext_value  # => 'https://github.com/pypa'

为何需要新库?

现有Python ASN.1实现(如pyasn1、asn1和asn1tools)存在三个关键问题:

  1. 性能:纯Python实现性能受限。新API使用纯Rust ASN.1解析器,提供接近本机的解析性能。
  2. 差分减少:ASN.1生态系统异构,实现差异导致协议演进和安全问题。新库使用PyCA Cryptography已有的rust-asn1解析器,减少独立解析器数量。
  3. 现代化:新API暴露声明性数据类样式接口,充满类型提示,使其熟悉、符合习惯且与类型检查器兼容。

示例ASN.1定义:

1
2
3
4
5
6
7
Doohickies ::= SEQUENCE {
    tschotchkes       OCTET STRING,
    baubles           INTEGER,
    knickknacks       UTF8String,
    whatchamacallits  SEQUENCE OF OBJECT IDENTIFIER,
    gizmos            SET OF GeneralizedTime OPTIONAL
}

对应Python代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from datetime import datetime
from cryptography.hazmat import asn1

@asn1.sequence
class Doohickies:
    tschotchkes: bytes
    baubles: int
    knickknacks: str
    whatchamacallits: list[asn1.ObjectIdentifier]
    gizmos: set[datetime] | None

doohickies = Doohickies.from_der(b"...")
print(doohickies.tschotchkes)
doohickies.to_der()  # b"..."

更多内容敬请期待

这只是前瞻;请关注更新!开发计划如下:

  1. 构建初始版本,支持@asn1.sequence@asn1.enum装饰器,以及ASN.1基本类型和修饰符(如OPTIONAL、DEFAULT、IMPLICIT和EXPLICIT)。
  2. 将版本集成到PyCA Cryptography中,可能作为cryptography.asn1cryptography.hazmat.asn1,并尽可能去重类型。
  3. 随PyCA Cryptography主要版本发布!

感谢Alpha-Omega资助此工作,以及PyCA Cryptography维护者的支持和设计审查。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计