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 9import sys 10 11def 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 70if __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