hivefans

check_ssl.py

Dec 8th, 2020
410
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.00 KB | None | 0 0
  1. # -*- encoding: utf-8 -*-
  2. # requires a recent enough python with idna support in socket
  3. # pyopenssl, cryptography and idna
  4.  
  5. from OpenSSL import SSL
  6. from cryptography import x509
  7. from cryptography.x509.oid import NameOID
  8. import idna
  9.  
  10. from socket import socket
  11. from collections import namedtuple
  12.  
  13. HostInfo = namedtuple(field_names='cert hostname peername', typename='HostInfo')
  14.  
  15. HOSTS = [
  16.     ('damjan.softver.org.mk', 443),
  17.     ('expired.badssl.com', 443),
  18.     ('wrong.host.badssl.com', 443),
  19.     ('ca.ocsr.nl', 443),
  20.     ('faß.de', 443),
  21.     ('самодеј.мкд', 443),
  22. ]
  23.  
  24. def verify_cert(cert, hostname):
  25.     # verify notAfter/notBefore, CA trusted, servername/sni/hostname
  26.     cert.has_expired()
  27.     # service_identity.pyopenssl.verify_hostname(client_ssl, hostname)
  28.     # issuer
  29.  
  30. def get_certificate(hostname, port):
  31.     hostname_idna = idna.encode(hostname)
  32.     sock = socket()
  33.  
  34.     sock.connect((hostname, port))
  35.     peername = sock.getpeername()
  36.     ctx = SSL.Context(SSL.SSLv23_METHOD) # most compatible
  37.     ctx.check_hostname = False
  38.     ctx.verify_mode = SSL.VERIFY_NONE
  39.  
  40.     sock_ssl = SSL.Connection(ctx, sock)
  41.     sock_ssl.set_connect_state()
  42.     sock_ssl.set_tlsext_host_name(hostname_idna)
  43.     sock_ssl.do_handshake()
  44.     cert = sock_ssl.get_peer_certificate()
  45.     crypto_cert = cert.to_cryptography()
  46.     sock_ssl.close()
  47.     sock.close()
  48.  
  49.     return HostInfo(cert=crypto_cert, peername=peername, hostname=hostname)
  50.  
  51. def get_alt_names(cert):
  52.     try:
  53.         ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
  54.         return ext.value.get_values_for_type(x509.DNSName)
  55.     except x509.ExtensionNotFound:
  56.         return None
  57.  
  58. def get_common_name(cert):
  59.     try:
  60.         names = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
  61.         return names[0].value
  62.     except x509.ExtensionNotFound:
  63.         return None
  64.  
  65. def get_issuer(cert):
  66.     try:
  67.         names = cert.issuer.get_attributes_for_oid(NameOID.COMMON_NAME)
  68.         return names[0].value
  69.     except x509.ExtensionNotFound:
  70.         return None
  71.  
  72.  
  73. def print_basic_info(hostinfo):
  74.     s = '''» {hostname} « … {peername}
  75.    \tcommonName: {commonname}
  76.    \tSAN: {SAN}
  77.    \tissuer: {issuer}
  78.    \tnotBefore: {notbefore}
  79.    \tnotAfter:  {notafter}
  80.    '''.format(
  81.             hostname=hostinfo.hostname,
  82.             peername=hostinfo.peername,
  83.             commonname=get_common_name(hostinfo.cert),
  84.             SAN=get_alt_names(hostinfo.cert),
  85.             issuer=get_issuer(hostinfo.cert),
  86.             notbefore=hostinfo.cert.not_valid_before,
  87.             notafter=hostinfo.cert.not_valid_after
  88.     )
  89.     print(s)
  90.  
  91. def check_it_out(hostname, port):
  92.     hostinfo = get_certificate(hostname, port)
  93.     print_basic_info(hostinfo)
  94.  
  95.  
  96. import concurrent.futures
  97. if __name__ == '__main__':
  98.     with concurrent.futures.ThreadPoolExecutor(max_workers=4) as e:
  99.         for hostinfo in e.map(lambda x: get_certificate(x[0], x[1]), HOSTS):
  100.             print_basic_info(hostinfo)
Add Comment
Please, Sign In to add comment