Python新ASN.1 API预览:高性能与现代化解析方案

本文介绍了Trail of Bits团队基于Rust开发的新ASN.1 API,旨在解决Python生态中ASN.1解析的性能、差异性和现代化问题。该库将集成到PyCA Cryptography,提供接近原生性能的解析能力,并采用声明式数据类接口。

Python新ASN.1 API预览

如果您曾使用Python处理密码学、PKI方案或低级网络,很可能遇到过ASN.1。ASN.1支撑着每个TLS握手(通过X.509路径验证),为LDAP、SNMP和3GPP等核心互联网协议提供序列化层,并作为密码原语和协议表示的通用语言。

ASN.1的关键作用与其丰富的安全历史相辅相成:ASN.1编码规则的实现历来是内存损坏和拒绝服务漏洞的丰富来源。同样,ASN.1在互联网协议最底层的存在使得性能和无解析差异成为关键要求。

Python有多个优秀的ASN.1实现(如pyasn1、asn1和asn1tools),但这些通常属于后一类:纯Python编写使得性能成为问题,集成到使用其他ASN.1解析器的堆栈(例如在X.509层)会引入差异风险。

我们正在改变这一点:在Alpha-Omega的资助下,我们正在为PyCA Cryptography构建一个ASN.1 API,解决Python生态系统当前的三个关键缺陷:

  • 性能:新API将使用纯Rust ASN.1解析器,提供接近原生的解析性能。
  • 差异减少:上述解析器已用于PyCA Cryptography的X.509 API。这将减少“混合匹配”ASN.1解析方法的需求,从而减少差异漏洞。
  • 现代化:新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"..."

这项工作是我们之前由Sovereign Tech Fund资助的X.509路径验证工作的逻辑延续。它反映了我们持续改进Python生态系统的承诺,特别是在密码学和供应链安全领域。

如果您有兴趣了解更多或资助类似工作,请联系我们!

ASN.1快速背景

ASN.1,或抽象语法记法一,是一种接口描述语言(IDL)。这是一种花哨的说法,表示它是一种以语言和平台无关的方式描述数据结构的语法。

令人困惑的是,ASN.1本身不是序列化格式。相反,它定义编码规则,这些规则进而定义在不同设置中ASN.1结构的序列化和反序列化。在实践中,ASN.1与可分辨编码规则(DER)同义。

我们将在这篇文章中互换使用“ASN.1”和“DER”。与其深入探讨两者的复杂性(Let’s Encrypt有很好的覆盖),我们将专注于使DER几十年来保持相关性的属性:

  • DER是规范编码:在DER中编码给定ASN.1结构只有一种方式。换句话说,ASN.1结构在DER中的编码是确定性的,并且可以在保留逐位相等性的情况下往返。
  • DER相对紧凑:DER定义二进制格式,并且由于是规范的,禁止整数、布尔值和时间的非最小编码。
  • DER是自描述和自定界编码:给定的DER消息可以完全且健全地解析,无需事先参考模式或格式描述,除了DER本身的编码规则。

这些属性自然适用于Web开发人员所称的“渐进增强”:使用DER的应用程序可以解码它关心的特定结构,同时跳过它不关心的结构,仅解码它们的长度以跳转到下一个。

DER支持任意精度整数:DER中的INTEGER类型在功能上大小不受限制,这使得它适合表示密码学设置中经常出现的大数字(例如素数)。

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

更准确地说,它在这些设置的内部非常流行:ASN.1用于保护世界TLS流量的X.509证书,广泛用于PEM编码格式,并为互联网的许多低级协议层提供描述和序列化。

为Python开发ASN.1库的动机

您可能会合理地问:为什么Python需要这个?

毕竟,大多数Python开发人员不会每天接触ASN.1,而那些接触的人大多以预定义的方式(如X.509证书)进行。为什么生态系统需要对ASN.1的通用支持?

答案在于,无论好坏,有许多情况下Python开发人员需要在X.509和其他知名格式和协议的“标准”形状之外进行ASN.1编码和解码。

这可以在Sigstore生态系统中看到:Sigstore主要是一个普通的RFC 5280风格PKI,但它也包括一些自定义X.509扩展用于其自身目的。例如,Sigstore日志条目的摘录显示以下扩展:

1
2
3
4
5

Runner Environment: github-hosted
Source Repository URI: https://github.com/pypa/sampleproject
Source Repository Ref: refs/heads/main
Source Repository Owner URI: https://github.com/pypa

如果我们想从Python使用这些(例如,为了根据策略验证Sigstore证书),我们需要提取它们:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from cryptography import x509

raw_cert = b"""
-----BEGIN CERTIFICATE-----
MIIGoTCCBiigAwIBAgITFai+PDKak1xA1HLq0mskqhDV5zAKBggqhkjOPQQDAzA3
MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxHjAcBgNVBAMTFXNpZ3N0b3JlLWludGVy
bWVkaWF0ZTAeFw0yNDExMDYyMjM3MDdaFw0yNDExMDYyMjQ3MDdaMAAwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAARbx1Fse2Ln00On5aFaL+lHNGFYLaqeKDduplZD
PJS+w2PjYfNPL0g/n4sDWEQFZfyIExEWKulZ2GKNzAc0+SmUo4IFSDCCBUQwDgYD
VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBT/uSEI
XmQzuRkppWXrTKVkfZFJbzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhk
PzBhBgNVHREBAf8EVzBVhlNodHRwczovL2dpdGh1Yi5jb20vcHlwYS9zYW1wbGVw
cm9qZWN0Ly5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sQHJlZnMvaGVhZHMv
bWFpbjA5BgorBgEEAYO/MAEBBCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVi
dXNlcmNvbnRlbnQuY29tMBIGCisGAQQBg78wAQIEBHB1c2gwNgYKKwYBBAGDvzAB
AwQoNjIxZTQ5NzRjYTI1Y2U1MzE3NzNkZWY1ODZiYTNlZDhlNzM2YjNmYzAVBgor
BgEEAYO/MAEEBAdSZWxlYXNlMCAGCisGAQQBg78wAQUEEnB5cGEvc2FtcGxlcHJv
amVjdDAdBgorBgEEAYO/MAEGBA9yZWZzL2hlYWRzL21haW4wOwYKKwYBBAGDvzAB
CAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVi
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计