Python:如何获取过期的 SSL 证书日期?

问题描述 投票:0回答:2

我创建了一个简单的Python程序来获取SSL证书的到期日期,参考互联网上的内容。对于尚未过期的证书,它可以正常工作。但是对于已经过期的证书,由于证书过期,在套接字握手期间会引发错误。

由于连接被拒绝,如何获取过期的证书信息以提取过期日期。有没有办法强制建立套接字连接,即使证书可能已过期?

代码:

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 格式的证书,但对于已经过期的证书出现证书验证错误。

python python-3.x ssl
2个回答
7
投票

我设法创建了一个可行的解决方案。在这里查看我的 Github 要点:https://gist.github.com/sharuzzaman/8827ef0d9fff89e4e937579b2b01653f

这里还有逐字代码以供快速参考

#!/bin/env python3

# check_ssl_cert.py - python get info for expired SSL cert
# Copyright 2022 Sharuzzaman Ahmat Raslan <[email protected]>

# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License along with this program. If not, see https://www.gnu.org/licenses/.

from cryptography import x509
import socket
import ssl
import sys

hostname = sys.argv[1]

# create default context
context = ssl.create_default_context()

# override context so that it can get expired cert
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE

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()

        # get cert in DER format
        data = ssock.getpeercert(True)
        print("Data:", data)
        print()

        # convert cert to PEM format
        pem_data = ssl.DER_cert_to_PEM_cert(data)
        print("PEM cert:", pem_data)

        # pem_data in string. convert to bytes using str.encode()
        # extract cert info from PEM format
        cert_data = x509.load_pem_x509_certificate(str.encode(pem_data))

        # show cert expiry date
        print("Expiry date:", cert_data.not_valid_after)
        print()

0
投票

我使用这样的脚本...

root@script:~# cat /root/bin/check-cert-mattila.eu.sh

#!/bin/bash
clear
echo "SERVER CERTIFICATE EXPIRATION DATES:"
echo "------------------------------------"
server=mail.mattila.eu
echo ""
echo "server = ${server}"
echo ""
echo ""
echo "#### WWW port (client2server) ####"
echo "------------------------------------"
echo " SSL certificate on port 443"
echo |openssl s_client -showcerts -connect $server:443 2>/dev/null | openssl x509 -dates | grep After | sed 's/notAfter=/ Expires = /'
echo ""
echo ""
echo "#### SMTP ports (server2server) ####"
echo "------------------------------------"
echo " TLS certificate on port 25"
echo |openssl s_client -showcerts -connect $server:25 2>/dev/null -starttls smtp | openssl x509 -dates | grep After | sed 's/notAfter=/ Expires = /'
echo ""
echo " SSL certificate on port 465"
echo |openssl s_client -showcerts -connect $server:465 2>/dev/null | openssl x509 -dates | grep After | sed 's/notAfter=/ Expires = /'
echo ""
echo " TLS certificate on port 587"
echo |openssl s_client -showcerts -connect $server:587 2>/dev/null -starttls smtp | openssl x509 -dates | grep After | sed 's/notAfter=/ Expires = /'
echo ""
echo ""
echo "#### IMAP ports (client2server) ####"
echo "------------------------------------"
echo " SSL certificate on port 143"
echo |openssl s_client -showcerts -connect $server:143 2>/dev/null -starttls imap | openssl x509 -dates | grep After | sed 's/notAfter=/ Expires = /'
echo ""
echo " SSL certificate on port 993"
echo |openssl s_client -showcerts -connect $server:993 2>/dev/null | openssl x509 -dates | grep After | sed 's/notAfter=/ Expires = /'
echo ""
echo ""

它会给你类似这样的东西(如果你的脚本主机有最新的CA)。

SERVER CERTIFICATE EXPIRATION DATES:
------------------------------------

server = mail.mattila.eu


#### WWW port (client2server) ####
------------------------------------
 SSL certificate on port 443
 Expires = May  4 23:33:17 2023 GMT


#### SMTP ports (server2server) ####
------------------------------------
 TLS certificate on port 25
 Expires = May  4 23:33:17 2023 GMT

 SSL certificate on port 465
 Expires = May  4 23:33:17 2023 GMT

 TLS certificate on port 587
 Expires = May  4 23:33:17 2023 GMT


#### IMAP ports (client2server) ####
------------------------------------
 SSL certificate on port 143
 Expires = May  4 23:33:17 2023 GMT

 SSL certificate on port 993
 Expires = May  4 23:33:17 2023 GMT

这还显示正确过期的(LetsEncrypt/Certbot)证书(证书)。您还可以修改它以嗅探 SQL/LDAP 端口。

© www.soinside.com 2019 - 2024. All rights reserved.