Skip to content

[Bug] 动态签发的叶子证书 authorityKeyIdentifier 为空 SEQUENCE,导致 Python 3.13+ X509_STRICT 校验失败 #712

Description

@HWWX5

Ⅰ. 说明操作系统及DS的版本号:

  1. 操作系统:Linux(Debian/Ubuntu 系),kernel 7.0.0-15-generic
  2. DS 版本号:v2.2.0(DevSidecar-2.2.0-linux-x86_64.deb)
  3. 相关环境:Python 3.14.4

根证书已正常安装到系统信任库(复制到 /usr/local/share/ca-certificates/ 并执行 update-ca-certificates,openssl verify 通过)。

Ⅱ. 问题描述:

dev-sidecar 代理动态签发的叶子证书中,authorityKeyIdentifier(OID 2.5.29.35)是一个空的 SEQUENCE(DER 为 30 00),不符合 RFC 5280 §4.2.1.1 —— 该节要求 keyIdentifier 必须存在。

开启严格模式校验的客户端会直接拒绝该证书。Python 3.13 起 ssl.create_default_context() 默认启用 VERIFY_X509_STRICT(本报告在 Python 3.14.4 上实测复现),因此所有走 dev-sidecar 代理的 Python 程序(requests / pip / urllib 等)在访问被拦截的域名时都会 CERTIFICATE_VERIFY_FAILED。

注意:这与根证书是否安装无关 —— 根证书安装完全正确时问题依然存在,重装根证书无法解决。

实测受影响的域名:github.com、api.github.com、raw.githubusercontent.com、www.google.com、registry.npmjs.org
(codeload.github.com 另表现为 TLS 握手超时,未深究是否同源)

对照:pypi.org / files.pythonhosted.org 正常 —— 因为它们未被 dev-sidecar 拦截,走的是真实证书。

补充:dev-sidecar 自身日志中没有报错,因为失败发生在客户端证书校验环节,代理侧看不到异常。

Ⅲ. 期望的结果:

动态签发的叶子证书中,authorityKeyIdentifier 应填入签发 CA 的 subjectKeyIdentifier 字节
(本机 CA 的 SKI 为 99:68:0C:BF:3D:59:31:C5:2F:9F:71:81:A3:D8:90:D1:99:38:A8:8F),
而不是留下一个空 SEQUENCE。

若使用 node-forge,对应写法是传入 keyIdentifier: true,使其从签发者证书派生。

修复后可用以下命令验证:

$ openssl verify -x509_strict -CAfile dev-sidecar.ca.crt leaf.pem
leaf.pem: OK          # 应返回 OK

Ⅳ. 如何复现问题?

  1. 启动 dev-sidecar 并开启系统代理(默认 127.0.0.1:31181)
  2. 用 Python 3.13+ 访问任意被 dev-sidecar 拦截的域名:
import ssl, socket
ctx = ssl.create_default_context()          # 3.13+ 默认含 VERIFY_X509_STRICT
s = socket.create_connection(('127.0.0.1', 31181), timeout=15)
s.sendall(b'CONNECT github.com:443 HTTP/1.1\r\nHost: github.com:443\r\n\r\n')
s.recv(200)
ctx.wrap_socket(s, server_hostname='github.com')

结果:

SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED]
certificate verify failed: Missing Authority Key Identifier
  1. 不依赖 Python,用 openssl 同样可复现:
$ openssl verify -CAfile dev-sidecar.ca.crt leaf.pem
leaf.pem: OK

$ openssl verify -x509_strict -CAfile dev-sidecar.ca.crt leaf.pem
CN=*.github.com, C=CN, ST=GuangDong, L=ShenZhen, O=dev-sidecar, ...
error 85 at 0 depth lookup: Missing Authority Key Identifier
error /tmp/leaf.pem: verification failed

error 85 与 Python 报的是同一个错误,可确认问题在证书本身而非 Python 配置。

Ⅴ. 请提供相关的错误日志,尽可能的详细:

dev-sidecar 自身日志无报错,以下为证书本身的证据。

1. 原始 DER:AKI 是空 SEQUENCE

dev-sidecar 签发的叶子证书:

06 03 55 1d 23   OID 2.5.29.35 (authorityKeyIdentifier)
04 02            OCTET STRING, 长度 2
30 00            SEQUENCE, 长度 0        ← 空

正常证书(同一台机器抓到的 PyPI 真实证书)作为对照:

06 03 55 1d 23   OID 2.5.29.35
04 18            OCTET STRING, 长度 24
30 16            SEQUENCE, 长度 22
80 14 b0 43 9e…  keyIdentifier, 长度 20 + 实际 keyid

openssl x509 -ext authorityKeyIdentifier 输出:

# dev-sidecar 叶子证书
X509v3 Authority Key Identifier:
    0.                                    ← 无法解析

# PyPI 真实证书
X509v3 Authority Key Identifier:
    B0:43:9E:30:70:F6:DE:FD:54:1E:12:3A:1D:E0:F7:61:CB:FB:20:C7

2. 可能的根因代码路径(推测)

在 resources/app.asar 中可见如下逻辑:

else if ("authorityKeyIdentifier" === e.name && t.cert) {
    e.value = a.create(UNIVERSAL, SEQUENCE, true, []);   // 先建空 SEQUENCE
    l = e.value.value;
    if (e.keyIdentifier) {                               // 仅当传入才填充
        // push keyId ...
    }
}

即:AKI 扩展先被初始化为空 SEQUENCE,只有在 keyIdentifier 有值时才写入内容。
若当前签发路径未提供 keyIdentifier,产出的正是上述 30 00。

(说明:从打包产物中只能看到该填充逻辑,无法确认调用方传入了什么参数,
因此本节为推测,供定位参考。)

3. 已排除的因素

  • 叶子证书为运行时内存生成,磁盘上无证书缓存(~/.dev-sidecar/ 下仅有 CA 的 key/crt)
  • 连续两次连接签发的证书字节一致,AKI 均为 30 00,行为确定,非偶发
  • 根证书安装正确:不加 strict 时 openssl verify 返回 OK,CA 的 SKI 正常
  • 与 Devsidecar v2.2.0 的 Bug 清单 #667 提到的「根证书无法正常安装」是不同问题:本问题在根证书安装正确的前提下依然复现

4. 影响范围

  • 受影响:Python ≥ 3.13,以及任何显式启用 X509_STRICT 的客户端
  • 不受影响:curl、Node.js、Python ≤ 3.12(它们不做该项检查)

该 bug 属于长期存在、近期才被现代工具链暴露的问题。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugSomething isn't workingGood first issueGood for newcomersknown issues确认存在的问题

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions