在Python中获取或构建PEM证书链

2023-12-02

是否可以使用 ssl 和 Python 获取 PEM 格式的整个证书链?我可以通过以下方式获得具体的:

import ssl
addr = '192.0.2.1'
cert_str = ssl.get_server_certificate((addr, 443))

这给了我类似的东西:

-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----

但我想要:

-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----

我很确定这是可能的,因为我可以从我的网络浏览器下载它。任何想法 ?

(我已经查过使用Python 3.3 SSL模块获取证书链但我不确定这就是我想要的......)

EDIT:我尝试过之后帕特里克·梅夫泽克回答 :

from OpenSSL import SSL
import socket
dst = ('192.0.2.1', 443)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.set_alpn_protos([b'http/1.1'])
if sock.connect_ex(dst) == 0:
    connection = SSL.Connection(ctx, sock)
    cert_str = connection.get_peer_cert_chain()

但 cert_str 是 None 。我认为这是因为我在使用 OpenSSL 时遗漏了一些东西。


如果您使用OpenSSLPython 中的库,你有get_peer_cert_chain您可以在连接对象上应用该证书,它将为您提供服务器发送的证书列表,因此如果需要,最终证书以及所有中间证书都是一个。

See https://pyopenssl.org/en/stable/api/ssl.html#connection-objects :

获取对等证书链()

检索对方的证书(如果有)

返回: 提供对等方证书链的 X509 实例列表,如果没有,则返回 None。

这是一个粗略的示例(没有任何错误处理):

from OpenSSL import SSL
import socket

dst = ('www.google.com', 443)
ctx = SSL.Context(SSL.SSLv23_METHOD)
s = socket.create_connection(dst)
s = SSL.Connection(ctx, s)
s.set_connect_state()
s.set_tlsext_host_name(dst[0])

s.sendall('HEAD / HTTP/1.0\n\n')
s.recv(16)

certs = s.get_peer_cert_chain()
for pos, cert in enumerate(certs):
   print "Certificate #" + str(pos)
   for component in cert.get_subject().get_components():
       print "Subject %s: %s" % (component)
   print "notBefore:" + cert.get_notBefore()
   print "notAfter:" + cert.get_notAfter()
   print "version:" + str(cert.get_version())
   print "sigAlg:" + cert.get_signature_algorithm()
   print "digest:" + cert.digest('sha256')

这使:

Certificate #0
Subject C: US
Subject ST: California
Subject L: Mountain View
Subject O: Google LLC
Subject CN: www.google.com
notBefore:20180612133452Z
notAfter:20180821121300Z
version:2
sigAlg:sha256WithRSAEncryption
digest:06:C5:12:EB:3C:B1:7F:AB:18:E0:D5:22:E4:25:12:A7:30:AA:27:16:0B:3A:99:CB:3D:11:CF:12:EF:95:2E:41
Certificate #1
Subject C: US
Subject O: Google Trust Services
Subject CN: Google Internet Authority G3
notBefore:20170615000042Z
notAfter:20211215000042Z
version:2
sigAlg:sha256WithRSAEncryption
digest:BE:0C:CD:54:D4:CE:CD:A1:BD:5E:5D:9E:CC:85:A0:4C:2C:1F:93:A5:22:0D:77:FD:E8:8F:E9:AD:08:1F:64:1B

这样您就拥有了证书的完整详细内容,请参阅https://pyopenssl.org/en/stable/api/crypto.html#x509-objects获取可用信息。 那么你就有了to_cryptography()能够通过以下方式获取其 PEM 版本:cert.to_cryptography().public_bytes(serialization.Encoding.PEM)

但还要考虑到:

  • 最好使用回调,请参阅set_info_callback()方法,以便在适当的时间运行诊断(甚至键入SSL.SSL_CB_HANDSHAKE_DONE)
  • 我发现您需要先交换一些流量(发送/接收)才能调用get_peer_cert_chain()(如果你之前移动它sendall()在我的示例中,它返回None)

从您问题中的链接来看,您似乎拥有与getpeercertchain()刚使用时ssl并不是OpenSSL;然而,这似乎仍然被记录为一个错误,有一些补丁可用,并且可能不会发布。 事实上最新的文档位于https://docs.python.org/3.8/library/ssl.html未列出getpeercertchain().

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在Python中获取或构建PEM证书链 的相关文章

随机推荐