Home | History | Annotate | Download | only in ssl
      1 #!/usr/bin/env python

      2 #

      3 # fetch the certificate that the server(s) are providing in PEM form

      4 #

      5 # args are HOST:PORT [, HOST:PORT...]

      6 #

      7 # By Bill Janssen.

      8 
      9 import sys
     10 
     11 def fetch_server_certificate (host, port):
     12 
     13     import re, tempfile, os, ssl
     14 
     15     def subproc(cmd):
     16         from subprocess import Popen, PIPE, STDOUT
     17         proc = Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True)
     18         status = proc.wait()
     19         output = proc.stdout.read()
     20         return status, output
     21 
     22     def strip_to_x509_cert(certfile_contents, outfile=None):
     23         m = re.search(r"^([-]+BEGIN CERTIFICATE[-]+[\r]*\n"
     24                       r".*[\r]*^[-]+END CERTIFICATE[-]+)$",
     25                       certfile_contents, re.MULTILINE | re.DOTALL)
     26         if not m:
     27             return None
     28         else:
     29             tn = tempfile.mktemp()
     30             fp = open(tn, "w")
     31             fp.write(m.group(1) + "\n")
     32             fp.close()
     33             try:
     34                 tn2 = (outfile or tempfile.mktemp())
     35                 status, output = subproc(r'openssl x509 -in "%s" -out "%s"' %
     36                                          (tn, tn2))
     37                 if status != 0:
     38                     raise OperationError(status, tsig, output)
     39                 fp = open(tn2, 'rb')
     40                 data = fp.read()
     41                 fp.close()
     42                 os.unlink(tn2)
     43                 return data
     44             finally:
     45                 os.unlink(tn)
     46 
     47     if sys.platform.startswith("win"):
     48         tfile = tempfile.mktemp()
     49         fp = open(tfile, "w")
     50         fp.write("quit\n")
     51         fp.close()
     52         try:
     53             status, output = subproc(
     54                 'openssl s_client -connect "%s:%s" -showcerts < "%s"' %
     55                 (host, port, tfile))
     56         finally:
     57             os.unlink(tfile)
     58     else:
     59         status, output = subproc(
     60             'openssl s_client -connect "%s:%s" -showcerts < /dev/null' %
     61             (host, port))
     62     if status != 0:
     63         raise OSError(status)
     64     certtext = strip_to_x509_cert(output)
     65     if not certtext:
     66         raise ValueError("Invalid response received from server at %s:%s" %
     67                          (host, port))
     68     return certtext
     69 
     70 if __name__ == "__main__":
     71     if len(sys.argv) < 2:
     72         sys.stderr.write(
     73             "Usage:  %s HOSTNAME:PORTNUMBER [, HOSTNAME:PORTNUMBER...]\n" %
     74             sys.argv[0])
     75         sys.exit(1)
     76     for arg in sys.argv[1:]:
     77         host, port = arg.split(":")
     78         sys.stdout.write(fetch_server_certificate(host, int(port)))
     79     sys.exit(0)
     80