-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcipher_enum.py
More file actions
127 lines (104 loc) · 4 KB
/
cipher_enum.py
File metadata and controls
127 lines (104 loc) · 4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import sys
import ssl
import socket
import json
import subprocess
def test_tls12_ciphers(host, port, allowed_ciphers_tls12):
print("=== TLSv1.2 ===")
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.minimum_version = ssl.TLSVersion.TLSv1_2
context.maximum_version = ssl.TLSVersion.TLSv1_2
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
for cipher in allowed_ciphers_tls12:
try:
context.set_ciphers(cipher)
except ssl.SSLError:
print(f"Invalid cipher for TLSv1.2: {cipher}")
continue
try:
with socket.create_connection((host, port), timeout=3) as sock:
with context.wrap_socket(sock, server_hostname=host):
print(f"Supported: {cipher}")
except Exception:
print(f"Not supported: {cipher}")
def test_tls13_cipher_openssl(host, port, cipher):
cmd = [
"openssl", "s_client",
"-connect", f"{host}:{port}",
"-tls1_3",
"-ciphersuites", cipher,
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
output = result.stdout + result.stderr
# Uncomment below for debug output if needed
# print(f"Debug output for cipher {cipher}:\n{output}\n{'-'*60}")
if ("handshake failure" in output.lower() or
"alert" in output.lower() or
"error" in output.lower()):
return False
for line in output.splitlines():
if line.strip().startswith("Cipher :"):
if cipher in line:
return True
else:
return False
return False
except Exception:
return False
def test_tls13_ciphers(host, port, allowed_ciphers_tls13):
print("\n=== TLSv1.3 ===")
for cipher in allowed_ciphers_tls13:
if test_tls13_cipher_openssl(host, port, cipher):
print(f"Supported: {cipher}")
else:
print(f"Not supported: {cipher}")
def get_server_supported_ciphers(host, port, min_version, max_version):
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.minimum_version = min_version
context.maximum_version = max_version
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
ciphers = [c['name'] for c in context.get_ciphers()]
supported = []
for cipher in ciphers:
try:
context.set_ciphers(cipher)
except ssl.SSLError:
continue
try:
with socket.create_connection((host, port), timeout=3) as sock:
with context.wrap_socket(sock, server_hostname=host):
supported.append(cipher)
except Exception:
pass
return supported
def main():
if len(sys.argv) != 4:
print(f"Usage: {sys.argv[0]} <host> <port> <allowed_ciphers_json>")
sys.exit(1)
host = sys.argv[1]
port = int(sys.argv[2])
allowed_ciphers_file = sys.argv[3]
try:
with open(allowed_ciphers_file, 'r') as f:
allowed_ciphers = json.load(f)
except Exception as e:
print(f"Error loading allowed ciphers JSON file: {e}")
sys.exit(1)
print(f"Testing ciphers on {host}:{port}\n")
allowed_tls12 = allowed_ciphers.get("TLSv1.2", [])
allowed_tls13 = allowed_ciphers.get("TLSv1.3", [])
test_tls12_ciphers(host, port, allowed_tls12)
test_tls13_ciphers(host, port, allowed_tls13)
print("\n=== Checking for ciphers supported by server but NOT in allowed list ===")
server_tls12 = get_server_supported_ciphers(host, port, ssl.TLSVersion.TLSv1_2, ssl.TLSVersion.TLSv1_2)
disallowed_tls12 = [c for c in server_tls12 if c not in allowed_tls12]
print("\n-- TLSv1.2 unexpected supported ciphers --")
for c in disallowed_tls12:
print(c)
# Note: Detailed TLS 1.3 ciphers enumeration via Python ssl not possible;
# We tested TLS 1.3 ciphers with openssl s_client already.
if __name__ == "__main__":
main()