我正在写一个监控服务器证书过期的工具。我正在使用python3 ssl和套接字模块来获取服务器证书,使用的是一个非常基本的方法:创建默认上下文,禁用主机名验证和证书验证,调用SSLSocket.connect(),然后调用SSLSocket.getpeercert(),唯一的目的就是获取服务器证书,仅此而已。
这一切都是在私有网络中进行的,我不关心验证。
我有一些设备需要由私有CA签名的客户端证书(我的工具没有),因此在SSLSocket.connect()上握手失败,使得SSLSocket.getpeercert()不可能实现。
我知道在握手期间,服务器证书确实被提供给了我的客户端(连同那个令人讨厌的证书请求)。我可以在数据包捕获中看到它,也可以只使用openssl s_client命令行。
这是我的代码。
def get_cert(self, host, port):
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
with ctx.wrap_socket(socket.socket(), server_hostname=host) as s:
s.settimeout(10)
s.connect((host, port))
binary_cert = s.getpeercert(True)
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, binary_cert)
pem_cert = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert).decode()
return pem_cert有没有办法在握手消息中降低一点,以获得服务器证书,即使握手最终失败了?
我目前的解决方案是在发生ssl.SSLError的情况下使用subprocess.run()运行openssl s_client -connect host:port。
发布于 2020-08-31 22:03:24
您可以捕获do_handshake()产生的异常,然后继续处理服务器证书。
import OpenSSL
import socket
dst = ('10.10.10.10', 443)
sock = socket.create_connection(dst)
context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
connection = OpenSSL.SSL.Connection(context, sock)
connection.set_connect_state()
try:
connection.do_handshake()
except:
print(connection.get_peer_cert_chain())在python 2.7.17和3.8.5上测试
发布于 2021-10-20 09:17:36
不幸的是,在低于3.10的版本中,python的ssl模块似乎无法做到这一点。在这些版本中,获取我能看到的对等证书的唯一方法是通过低级_ssl.SSLSocket.getpeercert()方法,如果握手没有完成,它会立即抛出异常。
从Python3.10开始,有了一个新的_ssl.SSLSocket.get_unverified_chain()方法,它不做握手检查,所以也许像这样令人讨厌的东西可以工作?
ssock = context.wrap_socket(sock, do_handshake_on_connect=False)
try:
ssock.do_handshake()
except ssl.SSLError as e:
pass
certs = ssock._sslobj._sslobj.get_unverified_chain()..。但我还没有测试过。
https://stackoverflow.com/questions/61737856
复制相似问题