diff --git a/src/pytds/tls.py b/src/pytds/tls.py index 81c40ae..b4db564 100644 --- a/src/pytds/tls.py +++ b/src/pytds/tls.py @@ -81,6 +81,18 @@ def shutdown(self): def verify_cb(conn, cert, err_num, err_depth, ret_code): return ret_code == 1 +def is_san_matching(san: str, host_name: str) -> bool: + for item in san.split(','): + dnsentry = item.lstrip('DNS:').strip() + # SANs are usually have form like: DNS:hostname + if dnsentry == host_name: + return True + if dnsentry[0:2] == "*.": # support for wildcards, but only at the first position + afterstar_parts = dnsentry[2:] + afterstar_parts_sname = '.'.join(host_name.split('.')[1:]) # remove first part of dns name + if afterstar_parts == afterstar_parts_sname: + return True + return False def validate_host(cert, name): """ @@ -105,11 +117,10 @@ def validate_host(cert, name): ext = cert.get_extension(i) if ext.get_short_name() == b'subjectAltName': s = str(ext) - # SANs are usually have form like: DNS:hostname - if s.startswith('DNS:') and s[4:] == s_name: + if is_san_matching(s, s_name): return True - # TODO handle wildcards + # TODO check if wildcard is needed in CN as well return False diff --git a/tests/tls_san_test.py b/tests/tls_san_test.py new file mode 100644 index 0000000..e44345a --- /dev/null +++ b/tests/tls_san_test.py @@ -0,0 +1,10 @@ +from pytds.tls import is_san_matching + +def test_san(): + assert not is_san_matching("", "host.com") + assert is_san_matching("database.com", "database.com") + assert not is_san_matching("notdatabase.com", "database.com") + assert not is_san_matching("*.database.com", "database.com") + assert is_san_matching("*.database.com", "test.database.com") + assert not is_san_matching("database.com", "*.database.com") + assert not is_san_matching("test.*.database.com", "test.subdomain.database.com") # That star should be at first position \ No newline at end of file