SSL时获取证书信息:certificate_verify_failed

时间:2018-09-04 23:13:10

标签: python ssl

我需要从一堆带有自签名证书的设备中读取颁发者CN。有些人有一个错误,以致发行人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格式的证书。

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

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

2 个答案:

答案 0 :(得分:3)

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

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)

编辑更简单,但仍会写入文件

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

答案 1 :(得分: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来保存/解析证书,这是想到的最简单的方法,它可以快速地抓住发卡行并以您喜欢的任何方法对其进行解析。