问题描述
我正在尝试获取证书颁发者信息(通用名称),但链接中的代码不适用于某些 URL.
I am trying to get Certificate issuer information (Common Name), but the code in the link doesn't work with some URLs.
import ssl, socket
hostname = 'google.com'
ctx = ssl.create_default_context()
s = ctx.wrap_socket(socket.socket(), server_hostname=hostname)
s.connect((hostname, 443))
cert = s.getpeercert()
subject = dict(x[0] for x in cert['subject'])
issued_to = subject['commonName']
>>> issued_to
u'*.google.com'
例如,我试过主机名cds.ca",它说
For example, I tried hostname "cds.ca", it says
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)
但我仍然可以使用 Internet Explorer (*.cds.ca) 获取通用名称
but I could still get the Common name using Internet Explorer (*.cds.ca)
所以我认为我应该使用我自己的证书(.cer)而不是使用 getpeercert(),那么我应该如何更改该行?
So I think I should use my own certificate(.cer) instead of using getpeercert(), then how should I change that line?
或者,有没有其他办法用我自己的证书文件实现CN?
Or, is there any other way to achieve CN with my own certificate file?
推荐答案
如果无论证书验证成功与否,您只想获取 CN 或其他证书详细信息,则必须禁用验证.不幸的是,如果证书验证被禁用,一个简单的 sock.getpeercert()
在设计上只会返回一个空字典.这就是为什么必须使用 sock.getpeercert(True)
来获取证书的二进制表示并使用 OpenSSL.crypto 从中提取 CN:
If you just want to get the CN or other certificate details no matter if certificate validation succeeds or not, you have to disable the verification. Unfortunately a simple sock.getpeercert()
will by design only return an empty dictionary if certificate validation is disabled. That's why one has to use sock.getpeercert(True)
to get the binary representation of the certificate and extract the CN using OpenSSL.crypto from it:
import socket
import ssl
import OpenSSL.crypto as crypto
dst = ('cds.ca',443)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(dst)
# upgrade the socket to SSL without checking the certificate
# !!!! don't transfer any sensitive data over this socket !!!!
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
s = ctx.wrap_socket(s, server_hostname=dst[0])
# get certificate
cert_bin = s.getpeercert(True)
x509 = crypto.load_certificate(crypto.FILETYPE_ASN1,cert_bin)
print("CN=" + x509.get_subject().CN)
这篇关于Python 使用 ssl.getpeercert() 从 URL 获取通用名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!