如何使用python检索远程主机的TLS/SSL对等证书?

问题描述:

我需要扫描IP列表并从该IP上的证书检索公用名称(对于每个允许端口443连接的IP)。我已经能够成功地使用套接字和ssl模块来做到这一点。它适用于具有有效签名证书的所有IP,但不适用于自签名证书。如何使用python检索远程主机的TLS/SSL对等证书?

如果我用这个方法,它需要由我的CA-束验证的有效证书:

from socket import socket 
import ssl 

s = socket() 
c = ssl.wrap_socket(s,cert_reqs=ssl.CERT_REQUIRED, ca_certs='ca-bundle.crt') 
c.connect(('127.0.0.1', 443)) 

print c.getpeercert() 

如果我删除cert_reqs=ssl.CERT_REQUIRED然后它连接但没有拿到证书都没有。

如何在IP上检索证书的公用名称,而不管它是否针对ca-bundle进行验证?

python的ssl库似乎只是解析出你的证书,如果它有一个有效的签名。

"""Returns a formatted version of the data in the 
    certificate provided by the other end of the SSL channel. 
    Return None if no certificate was provided, {} if a 
    certificate was provided, but not validated.""" 

你仍然可以得到与ssl.get_server_certificate()功能的服务器证书,但它在PEM格式返回。 (或者,你可以调用c.getpeercert(True),它返回二进制DER格式的证书,无论是验证或不。)

>>> print ssl.get_server_certificate(('server.test.com', 443)) 
-----BEGIN CERTIFICATE----- 
MIID4zCCAsugAwIBA..... 

从这里,我会用M2Crypto或OpenSSL的阅读证书,并获得价值:

# M2Crypto 
cert = ssl.get_server_certificate(('www.google.com', 443)) 
x509 = M2Crypto.X509.load_cert_string(cert) 
x509.get_subject().as_text() 
# 'C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com' 

# OpenSSL 
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) 
x509.get_subject().get_components() 
#[('C', 'US'), 
# ('ST', 'California'), 
# ('L', 'Mountain View'), 
# ('O', 'Google Inc'), 
# ('CN', 'www.google.com')] 
+1

另外值得注意的是,如果您通过ssl.getpeercert(True)提取证书,则需要使用OpenSSL.crypto.FILETYPE_ASN1而不是FILETYPE_PEM来加载它 –

+3

由于SSLv3中的“Poodle”漏洞许多Web服务器已禁用它。如果您看到类似“sslv3警报握手故障”的类似信息,则可能需要将'ssl_version = ssl.PROTOCOL_TLSv1'添加到您的'get_server_certificate(..)'调用中。 –

+0

M2Crypto调用SocketServer,它在python3下更改为socketserver。 M2Crypto将在python3下破解。 – mootmoot

在Mac上,您需要安装痛饮和M2Crypto

在终端运行:

brew install swig 

然后:

sudo pip install m2crypto 

然后你可以运行上面的代码:

from socket import socket 
import ssl 
import M2Crypto 
import OpenSSL 

# M2Crypto 
cert = ssl.get_server_certificate(('www.google.com', 443)) 
x509 = M2Crypto.X509.load_cert_string(cert) 
print x509.get_subject().as_text() 
# 'C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com' 

# OpenSSL 
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) 
print x509.get_subject().get_components() 
#[('C', 'US'), 
# ('ST', 'California'), 
# ('L', 'Mountain View'), 
# ('O', 'Google Inc'), 
# ('CN', 'www.google.com')] 

如果有人与SNI(服务器名称指示)挣扎(由@mootmoot提到)是指我的答案在这里https://*.com/a/49132495/8370670