【问题标题】:Get certificate information when SSL: certificate_verify_failed [duplicate]SSL时获取证书信息:certificate_verify_failed [重复]
【发布时间】:2019-02-10 00:09:17
【问题描述】:

我需要从一堆具有自签名证书的设备中读取颁发者 CN。有些人有一个错误,即发行人 CN 在应该是唯一的时候并不是唯一的,我希望确定哪些人有这种情况。找到了一个代码片段here,稍作修改:

import ssl, socket

myhostname = 'some_host'
myctx = ssl.create_default_context()
myctx.check_hostname = False
myctx.verify_mode = ssl.CERT_NONE # ssl.CERT_OPTIONAL
s = myctx.wrap_socket(socket.socket(), server_hostname=myhostname)
s.connect((hostname, 443))
cert = s.getpeercert()

当 verify_mode 为 CERT_NONE 时,连接建立但证书被丢弃;当 CERT_OPTIONAL 连接失败时,因为验证失败。

如何在不使用 openssl 的情况下连接并读取错误证书的详细信息?

这是一个一次性的问题解决脚本;我只需要输出 some_host 和 issuer CN。 Openssl 在此系统上不可用。

编辑 1 遵循 Patrick 的 PyOpenSSL 建议(也不在此系统上)this post 表示 cert = s.getpeercert(binary_form=True) 以 DER 格式返回证书。

EDIT 2重复还是不重复?最终我认为是的,它是重复的,但不是指定的“重复”,因为我的系统上没有 Openssl。我相信还是有用的。下面的工作解决方案使用来自几个 other posts 的信息以及沿途的其他几个。整洁的一点是使用 ssl.get_server_certificate (感谢 Steffen,不需要 getpeercert;返回 pem 不是 der),而丑陋的一点是将证书存储到文件中,然后使用未记录的方法获取详细信息。它不使用 getpeercert 也不使用 openssl。

如果有一种更简洁的方法来处理收到的 pem 证书以阅读我很想知道的详细信息,但这对我来说已经足够了。

【问题讨论】:

  • 您可能需要使用PyOpenSSL 库,您可以在其中在 TLS 握手的各个步骤中注入各种回调,从而访问交换的证书。

标签: python ssl


【解决方案1】:

以下内容完成工作,但将证书写入文件。是否可以直接解码证书并避免将其保存到文件中?

import ssl, socket

myhostname = 'some_host'
myctx = ssl.create_default_context()
myctx.check_hostname = False
myctx.verify_mode = ssl.CERT_NONE
s = myctx.wrap_socket(socket.socket(), server_hostname=myhostname)
s.connect((myhostname, 443))

bcert = s.getpeercert(binary_form=True)
cert = ssl.DER_cert_to_PEM_cert(bcert)
# workaround, ssl._ssl._test_decode_cert method expects a filename
f = open('mycert.pem','w')
f.write(cert)
f.close()
cert_dict = ssl._ssl._test_decode_cert('mycert.pem')   # expects a filename?

subject = dict(x[0] for x in cert_dict['subject'])
issued_to = subject['commonName']
issuer = dict(x[0] for x in cert_dict['issuer'])
issued_by = issuer['commonName']
print(issued_to)
print(issued_by)

EDIT 更简单,但仍写入文件

import ssl
myhostname = 'some_host'
cert = ssl.get_server_certificate((myhostname, 443))
[..]

【讨论】:

    【解决方案2】:

    既然您说这是一个一次性的问题解决脚本,并且您缺少许多在 python 中本地执行此操作的组件。可以接受 shell 脚本(或使用 python 执行和读取 shell/系统命令)吗?如果是这样并且 curl 可用,您可以尝试使用它:

        curl -vvI https://www.google.com
    
    * About to connect() to www.google.com port 443 (#0)
    *   Trying 172.217.197.103...
    * Connected to www.google.com (172.217.197.103) port 443 (#0)
    * Initializing NSS with certpath: sql:/etc/pki/nssdb
    *   CAfile: /etc/pki/tls/certs/ca-bundle.crt
      CApath: none
    * SSL connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    * Server certificate:
    *   subject: CN=www.google.com,O=Google LLC,L=Mountain View,ST=California,C=US
    *   start date: Aug 14 07:44:35 2018 GMT
    *   expire date: Oct 23 07:38:00 2018 GMT
    *   common name: www.google.com
    *   issuer: CN=Google Internet Authority G3,O=Google Trust Services,C=US
    > HEAD / HTTP/1.1
    > User-Agent: curl/7.29.0
    > Host: www.google.com
    > Accept: */*
    

    没有 openssl 运行 s_client 来保存/解析证书,这是最简单的方法,可以快速获取颁发者并以您喜欢的任何方法解析它。

    【讨论】:

    • MS Windows,没有 curl :( 但我喜欢这个解决方案,太棒了。欢迎 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 2015-09-25
    • 1970-01-01
    • 2014-06-16
    • 2018-07-07
    • 2021-09-28
    • 2021-10-08
    相关资源
    最近更新 更多