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