Check a host, print the progress
authorRalf Jung <post@ralfj.de>
Mon, 21 Jul 2014 08:53:37 +0000 (10:53 +0200)
committerRalf Jung <post@ralfj.de>
Mon, 21 Jul 2014 08:53:37 +0000 (10:53 +0200)
ssl-check

index a93a4bf16d8eee8666c6a28c3e40306983804a29..ae3d26fb934e88245c182473592e6e7bbba233b4 100755 (executable)
--- a/ssl-check
+++ b/ssl-check
@@ -1 +1,79 @@
 #!/usr/bin/python3
 #!/usr/bin/python3
+import subprocess, sys
+from collections import OrderedDict
+from enum import Enum
+
+# progress bar
+def terminal_size():
+    import fcntl, termios, struct
+    try:
+        result = fcntl.ioctl(1, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0))
+    except OSError:
+        # this is not a terminal
+        return 0, 0
+    h, w, hp, wp = struct.unpack('HHHH', result)
+    assert w > 0 and h > 0, "Empty terminal...??"
+    return w, h
+
+def compute_frac(fracs):
+    frac = 0.0
+    last_frac = 1.0
+    for complete, total in fracs:
+        frac += (complete*last_frac/total)
+        last_frac *= 1/total
+    return frac
+
+def print_progress(state, fracs):
+    STATE_WIDTH = 30
+    w, h = terminal_size()
+    if w < STATE_WIDTH+10: return # not a (wide enough) terminal
+    bar_width = w-STATE_WIDTH-3
+    hashes = int(bar_width*compute_frac(fracs))
+    sys.stdout.write('\r{0} [{1}{2}]'.format(state[:STATE_WIDTH].ljust(STATE_WIDTH), '#'*hashes, ' '*(bar_width-hashes)))
+    sys.stdout.flush()
+def finish_progress():
+    w, h = terminal_size()
+    sys.stdout.write('\r'+(' '*w)+'\r')
+    sys.stdout.flush()
+
+# cipher check
+def list_ciphers():
+    ciphers = subprocess.check_output(["openssl", "ciphers", "ALL:COMPLEMENTOFALL"]).decode('UTF-8').strip()
+    return ciphers.split(':')
+
+def test_cipher(host, port, protocol, cipher = None, options=[]):
+    try:
+        if cipher is not None:
+            options = ["-cipher", cipher]+options
+        subprocess.check_call(["openssl", "s_client", "-"+protocol, "-connect", host+":"+str(port)]+options,
+                              stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
+    except subprocess.CalledProcessError:
+        return False
+    else:
+        return True
+
+def test_protocol(host, port, protocol, ciphers, base_frac, options=[]):
+    if test_cipher(host, port, protocol, options=options):
+        # the protocol is supported
+        results = OrderedDict()
+        for i in range(len(ciphers)):
+            cipher = ciphers[i]
+            print_progress(protocol+" "+cipher, base_frac+[(i, len(ciphers))])
+            results[cipher] = test_cipher(host, port, protocol, cipher, options)
+        return results
+    else:
+        # it is not supported
+        return None
+
+def test_host(host, port, options=[]):
+    ciphers = list_ciphers()
+    results = OrderedDict()
+    protocols = ('ssl2', 'ssl3', 'tls1', 'tls1_1', 'tls1_2')
+    for i in range(len(protocols)):
+        protocol = protocols[i]
+        print_progress(protocol, [(i, len(protocols))])
+        results[protocol] = test_protocol(host, port, protocol, ciphers, [(i, len(protocols))], options)
+    finish_progress()
+    return results
+
+print(test_host('ralfj.de', 443))