2 import subprocess, sys, argparse
3 from collections import OrderedDict
8 import fcntl, termios, struct
10 result = fcntl.ioctl(1, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0))
12 # this is not a terminal
14 h, w, hp, wp = struct.unpack('HHHH', result)
15 assert w > 0 and h > 0, "Empty terminal...??"
18 def compute_frac(fracs):
21 for complete, total in fracs:
22 frac += (complete*last_frac/total)
26 def print_progress(state, fracs):
28 w, h = terminal_size()
29 if w < STATE_WIDTH+10: return # not a (wide enough) terminal
30 bar_width = w-STATE_WIDTH-3
31 hashes = int(bar_width*compute_frac(fracs))
32 sys.stdout.write('\r{0} [{1}{2}]'.format(state[:STATE_WIDTH].ljust(STATE_WIDTH), '#'*hashes, ' '*(bar_width-hashes)))
34 def finish_progress():
35 w, h = terminal_size()
36 sys.stdout.write('\r'+(' '*w)+'\r')
41 ciphers = subprocess.check_output(["openssl", "ciphers", "ALL:COMPLEMENTOFALL"]).decode('UTF-8').strip()
42 return ciphers.split(':')
44 def test_cipher(host, port, protocol, cipher = None, options=[]):
46 if cipher is not None:
47 options = ["-cipher", cipher]+options
48 subprocess.check_call(["openssl", "s_client", "-"+protocol, "-connect", host+":"+str(port)]+options,
49 stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
50 except subprocess.CalledProcessError:
55 def test_protocol(host, port, protocol, ciphers, base_frac, options=[]):
56 if test_cipher(host, port, protocol, options=options):
57 # the protocol is supported
58 results = OrderedDict()
59 for i in range(len(ciphers)):
61 print_progress(protocol+" "+cipher, base_frac+[(i, len(ciphers))])
62 results[cipher] = test_cipher(host, port, protocol, cipher, options)
68 def test_host(host, port, options=[]):
69 ciphers = list_ciphers()
70 results = OrderedDict()
71 protocols = ('ssl2', 'ssl3', 'tls1', 'tls1_1', 'tls1_2')
72 for i in range(len(protocols)):
73 protocol = protocols[i]
74 print_progress(protocol, [(i, len(protocols))])
75 results[protocol] = test_protocol(host, port, protocol, ciphers, [(i, len(protocols))], options)
79 if __name__ == "__main__":
80 parser = argparse.ArgumentParser(description='Check SSL ciphers supported by a host')
81 parser.add_argument("host", metavar='HOST[:PORT]',
82 help="The host to check")
83 args = parser.parse_args()
87 host, port = args.host.split(':')
93 results = test_host(host, port)
94 for protocol, ciphers in results.items():
97 print(" Is not supported by client or server")
99 for cipher, supported in ciphers.items():