如何使用x509.CertificateBuilder为证书添加信任链?
如何将CA证书加入用cryptography.x509.CertificateBuilder生成的证书链中?
我正在使用cryptography.x509.CertificateBuilder生成证书,代码如下:
from pathlib import Path from cryptography import x509 from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.serialization import Encoding private_key: rsa.RSAPrivateKey ca_cert: x509.Certificate ca_cert_private_key: rsa.RSAPrivateKey cert = ( x509.CertificateBuilder() .subject_name(x509.Name.from_rfc4514_string(f"CN={workstation_name}")) .issuer_name(ca_cert.subject) .public_key(private_key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(today) .not_valid_after(today + timedelta(days=60)) .add_extension(subject_alt_name, critical=False) .sign(ca_cert_private_key) ) Path("workstation.crt").write_bytes(cert.public_bytes(Encoding.PEM))
现在我想把ca_cert添加到生成的证书的证书链中。比如Stack Overflow的证书链包含3个证书:
$ openssl s_client -connect stackoverflow.com:443 CONNECTED(00000003) depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1 verify return:1 depth=1 C = US, O = Let's Encrypt, CN = R3 verify return:1 depth=0 CN = *.stackexchange.com verify return:1 --- Certificate chain 0 s:CN = *.stackexchange.com i:C = US, O = Let's Encrypt, CN = R3 a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 v:NotBefore: Dec 18 14:08:17 2022 GMT; NotAfter: Mar 18 14:08:16 2023 GMT 1 s:C = US, O = Let's Encrypt, CN = R3 i:C = US, O = Internet Security Research Group, CN = ISRG Root X1 a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256 v:NotBefore: Sep 4 00:00:00 2020 GMT; NotAfter: Sep 15 16:00:00 2025 GMT 2 s:C = US, O = Internet Security Research Group, CN = ISRG Root X1 i:O = Digital Signature Trust Co., CN = DST Root CA X3 a:PKEY: rsaEncryption, 4096 (bit); sigalg: RSA-SHA256 v:NotBefore: Jan 20 19:14:03 2021 GMT; NotAfter: Sep 30 18:14:03 2024 GMT ---
但我生成的证书链里只有1个证书:
$ openssl s_client -connect localhost:443 CONNECTED(00000003) Can't use SSL_get_servername depth=1 CN = [Redacted CA Cert Name] verify return:1 depth=0 CN = [Redacted Workstation Name] verify return:1 --- Certificate chain 0 s:CN = [Redacted Workstation Name] i:CN = [Redacted CA Cert Name] ---
请问怎么把ca_cert作为第2个证书加入到证书链中?
解决方法
证书链本质是将多个PEM格式的证书按顺序拼接成一个文件,核心规则是:终端实体证书(你的工作站证书)放在最前面,之后依次添加签发它的中间CA证书、根CA证书(如果需要)。
只需要修改代码,把工作站证书和CA证书的PEM内容合并后写入同一个文件即可:
from pathlib import Path from cryptography import x509 from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.serialization import Encoding from datetime import timedelta private_key: rsa.RSAPrivateKey ca_cert: x509.Certificate ca_cert_private_key: rsa.RSAPrivateKey workstation_name = "你的工作站名称" today = x509.utcnow() subject_alt_name = x509.SubjectAlternativeName([x509.DNSName("localhost")]) # 示例SAN,根据实际情况调整 # 生成工作站证书 cert = ( x509.CertificateBuilder() .subject_name(x509.Name.from_rfc4514_string(f"CN={workstation_name}")) .issuer_name(ca_cert.subject) .public_key(private_key.public_key()) .serial_number(x509.random_serial_number()) .not_valid_before(today) .not_valid_after(today + timedelta(days=60)) .add_extension(subject_alt_name, critical=False) .sign(ca_cert_private_key) ) # 拼接证书链:工作站证书 + CA证书(注意中间加换行分隔) cert_chain_pem = cert.public_bytes(Encoding.PEM) + b"\n" + ca_cert.public_bytes(Encoding.PEM) # 写入带证书链的文件 Path("workstation_chain.crt").write_bytes(cert_chain_pem)
验证效果
修改后,用openssl s_client连接服务时,就能看到证书链包含两个证书:
$ openssl s_client -connect localhost:443 CONNECTED(00000003) # ... 省略其他输出 ... --- Certificate chain 0 s:CN = [你的工作站名称] i:CN = [CA证书名称] 1 s:CN = [CA证书名称] i:CN = [CA的签发者名称] ---
额外说明
- 如果你的CA证书还有上层根CA,可以继续把根CA的PEM内容追加到文件末尾,形成完整的信任链。
- 务必保证证书顺序正确:终端证书在前,后续CA证书按"子CA在前、父CA在后"排列,否则客户端无法正常验证信任关系。
内容的提问来源于Stack Exchange,提问作者Gary van der Merwe
相关产品推荐
相关产品推荐

