【发布时间】:2022-02-17 14:52:55
【问题描述】:
我创建了一个简单的 Python 程序来获取 SSL 证书的到期日期,来自 Internet 上的参考。它适用于仍未过期的证书。但是对于已经过期的证书,由于证书过期,在套接字握手期间引发了错误。
由于连接被拒绝,我如何获取过期证书信息以提取过期日期。即使证书可能已过期,是否有办法强制建立套接字连接?
代码:
import ssl
from cryptography import x509
import sys
import socket
hostname = sys.argv[1]
context = ssl.create_default_context()
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
print("SSL/TLS version:",ssock.version())
print()
data = ssock.getpeercert()
print("Data:",data)
print()
notafter_date = data["notAfter"]
print("Expiry date:",notafter_date)
print()
未过期证书的输出:
$ python check_ssl_cert.py badssl.com
SSL/TLS version: TLSv1.2
Data: {'subject': ((('countryName', 'US'),), (('stateOrProvinceName', 'California'),), (('localityName', 'Walnut Creek'),), (('organizationName', 'Lucas Garron Torres'),), (('commonName', '*.badssl.com'),)), 'issuer': ((('countryName', 'US'),), (('organizationName', 'DigiCert Inc'),), (('commonName', 'DigiCert SHA2 Secure Server CA'),)), 'version': 3, 'serialNumber': '0AF06CDA37A60B641342F0A1EB1D59FD', 'notBefore': 'Mar 23 00:00:00 2020 GMT', 'notAfter': 'May 17 12:00:00 2022 GMT', 'subjectAltName': (('DNS', '*.badssl.com'), ('DNS', 'badssl.com')), 'OCSP': ('http://ocsp.digicert.com',), 'caIssuers': ('http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt',), 'crlDistributionPoints': ('http://crl3.digicert.com/ssca-sha2-g6.crl', 'http://crl4.digicert.com/ssca-sha2-g6.crl')}
Expiry date: May 17 12:00:00 2022 GMT
过期证书的输出:
$ python check_ssl_cert.py expired.badssl.com
Traceback (most recent call last):
File "check_ssl_cert.py", line 11, in <module>
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
File "/usr/lib/python3.7/ssl.py", line 423, in wrap_socket
session=session
File "/usr/lib/python3.7/ssl.py", line 870, in _create
self.do_handshake()
File "/usr/lib/python3.7/ssl.py", line 1139, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate has expired (_ssl.c:1091)
按照其他解决方案的建议,它不能解决问题。
我试过换行
data = ssock.getpeercert()
到
data = ssock.getpeercert(True)
对于未过期的证书,返回一个 DER 格式的证书,但是对于已经过期的证书,出现证书验证错误。
【问题讨论】:
-
不,它没有。我尝试输入 ssock.getpeercert(True),并显示相同的错误。我可以尝试添加 ssl.get_server_certificate 命令并通过 try..except 调用它。仍然希望只使用 ssock.getpeercert() 命令
-
"但是对于已经过期的证书,由于证书过期,在套接字握手期间引发了错误。"按设计。如果您使用高级库,它会为您进行所有有效性检查,因此如果出现问题,它将中止 TLS 握手。在 Python 中查看 PyOpenSSL 模块而不是内部的
ssl模块,它可以让您更好地控制正在发生的事情(参见set_verify()) -
是的,SSL(真的是 TLS)套接字创建在所有高级库中都被抽象出来了,这里的设计目标是当有问题时连接会严重失败。您需要使用可以进行半次握手的低级库。
-
插入
ssl.get_server_certificate()是我重复链接的重点。很明显,其他的东西都不起作用。 -
create_default_context创建一个上下文 with 证书验证,这就是它失败的原因。请参阅Python getting common name from URL using ssl.getpeercert(),了解如何实现您的目标。
标签: python python-3.x ssl