generated from nathanwoodburn/python-webserver-template
This commit is contained in:
154
tools.py
154
tools.py
@@ -55,74 +55,84 @@ def check_ssl(domain: str):
|
||||
certificates = [cert[cert.find("-----BEGIN CERTIFICATE-----"):] for cert in certificates]
|
||||
|
||||
if not certificates:
|
||||
returns["message"] = "No certificate found on remote webserver"
|
||||
return returns
|
||||
|
||||
cert = certificates[0]
|
||||
returns["cert"] = {"cert": cert}
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_cert_file:
|
||||
temp_cert_file.write(cert)
|
||||
temp_cert_file.seek(0)
|
||||
|
||||
tlsa_command = ["openssl","x509","-in",temp_cert_file.name,"-pubkey","-noout","|","openssl","pkey","-pubin","-outform","der","|","openssl","dgst","-sha256","-binary",]
|
||||
|
||||
tlsa_process = subprocess.Popen(" ".join(tlsa_command), shell=True, stdout=subprocess.PIPE)
|
||||
tlsa_output, _ = tlsa_process.communicate()
|
||||
|
||||
tlsa_server = "3 1 1 " + binascii.hexlify(tlsa_output).decode("utf-8")
|
||||
|
||||
|
||||
returns["tlsa"] = {
|
||||
"server": tlsa_server,
|
||||
"nameserver": "",
|
||||
"match": False
|
||||
}
|
||||
|
||||
|
||||
# Get domains
|
||||
cert_obj = x509.load_pem_x509_certificate(cert.encode("utf-8"), default_backend())
|
||||
|
||||
domains = []
|
||||
for ext in cert_obj.extensions:
|
||||
if ext.oid == x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME:
|
||||
san_list = ext.value.get_values_for_type(x509.DNSName)
|
||||
domains.extend(san_list)
|
||||
|
||||
# Extract the common name (CN) from the subject
|
||||
common_name = cert_obj.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
|
||||
if common_name:
|
||||
if common_name[0].value not in domains:
|
||||
domains.append(common_name[0].value)
|
||||
|
||||
|
||||
if domains:
|
||||
cert_domains = []
|
||||
for cn in domains:
|
||||
cert_domains.append(cn)
|
||||
if cn == domain:
|
||||
domain_check = True
|
||||
elif cn.startswith("*."):
|
||||
if domain.endswith(cn[1:]):
|
||||
domain_check = True
|
||||
|
||||
returns["cert"]["domains"] = cert_domains
|
||||
returns["cert"]["domain"] = domain_check
|
||||
|
||||
expiry_date = cert_obj.not_valid_after_utc
|
||||
# Check if expiry date is past
|
||||
if expiry_date < datetime.datetime.now(datetime.timezone.utc):
|
||||
returns["cert"]["expired"] = True
|
||||
returns["cert"]["valid"] = False
|
||||
returns["cert"] = {
|
||||
"cert":"",
|
||||
"domains": [],
|
||||
"domain": False,
|
||||
"expired": False,
|
||||
"valid": False,
|
||||
"expiry_date": ""
|
||||
}
|
||||
returns["tlsa"] = {
|
||||
"server": "",
|
||||
"nameserver": "",
|
||||
"match": False
|
||||
}
|
||||
|
||||
else:
|
||||
returns["cert"]["expired"] = False
|
||||
returns["cert"]["valid"] = True if domain_check else False
|
||||
|
||||
cert = certificates[0]
|
||||
returns["cert"] = {"cert": cert}
|
||||
|
||||
with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_cert_file:
|
||||
temp_cert_file.write(cert)
|
||||
temp_cert_file.seek(0)
|
||||
|
||||
returns["cert"]["expiry_date"] = expiry_date.strftime("%d %B %Y %H:%M:%S")
|
||||
tlsa_command = ["openssl","x509","-in",temp_cert_file.name,"-pubkey","-noout","|","openssl","pkey","-pubin","-outform","der","|","openssl","dgst","-sha256","-binary",]
|
||||
|
||||
tlsa_process = subprocess.Popen(" ".join(tlsa_command), shell=True, stdout=subprocess.PIPE)
|
||||
tlsa_output, _ = tlsa_process.communicate()
|
||||
|
||||
tlsa_server = "3 1 1 " + binascii.hexlify(tlsa_output).decode("utf-8")
|
||||
|
||||
|
||||
returns["tlsa"] = {
|
||||
"server": tlsa_server,
|
||||
"nameserver": "",
|
||||
"match": False
|
||||
}
|
||||
|
||||
|
||||
# Get domains
|
||||
cert_obj = x509.load_pem_x509_certificate(cert.encode("utf-8"), default_backend())
|
||||
|
||||
domains = []
|
||||
for ext in cert_obj.extensions:
|
||||
if ext.oid == x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME:
|
||||
san_list = ext.value.get_values_for_type(x509.DNSName)
|
||||
domains.extend(san_list)
|
||||
|
||||
# Extract the common name (CN) from the subject
|
||||
common_name = cert_obj.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
|
||||
if common_name:
|
||||
if common_name[0].value not in domains:
|
||||
domains.append(common_name[0].value)
|
||||
|
||||
|
||||
if domains:
|
||||
cert_domains = []
|
||||
for cn in domains:
|
||||
cert_domains.append(cn)
|
||||
if cn == domain:
|
||||
domain_check = True
|
||||
elif cn.startswith("*."):
|
||||
if domain.endswith(cn[1:]):
|
||||
domain_check = True
|
||||
|
||||
returns["cert"]["domains"] = cert_domains
|
||||
returns["cert"]["domain"] = domain_check
|
||||
|
||||
expiry_date = cert_obj.not_valid_after_utc
|
||||
# Check if expiry date is past
|
||||
if expiry_date < datetime.datetime.now(datetime.timezone.utc):
|
||||
returns["cert"]["expired"] = True
|
||||
returns["cert"]["valid"] = False
|
||||
|
||||
else:
|
||||
returns["cert"]["expired"] = False
|
||||
returns["cert"]["valid"] = True if domain_check else False
|
||||
|
||||
returns["cert"]["expiry_date"] = expiry_date.strftime("%d %B %Y %H:%M:%S")
|
||||
|
||||
try:
|
||||
# Check for TLSA record
|
||||
@@ -131,18 +141,12 @@ def check_ssl(domain: str):
|
||||
for record in response:
|
||||
tlsa_records.append(str(record))
|
||||
|
||||
if not tlsa_records:
|
||||
returns["message"] = "No TLSA record found on DNS"
|
||||
return returns
|
||||
|
||||
returns["tlsa"]["nameserver"] = tlsa_records[0]
|
||||
if tlsa_server == tlsa_records[0]:
|
||||
returns["tlsa"]["match"] = True
|
||||
|
||||
|
||||
if tlsa_records:
|
||||
returns["tlsa"]["nameserver"] = tlsa_records[0]
|
||||
if tlsa_server == tlsa_records[0]:
|
||||
returns["tlsa"]["match"] = True
|
||||
except:
|
||||
returns["message"] = "No TLSA record found on DNS"
|
||||
return returns
|
||||
returns["tlsa"]["error"] = "No TLSA record found on DNS"
|
||||
|
||||
# Check if valid
|
||||
if returns["cert"]["valid"] and returns["tlsa"]["match"] and returns["dnssec"]["valid"]:
|
||||
@@ -164,6 +168,6 @@ def validate_dnssec(domain):
|
||||
command = f"delv @{resolverIP} -a hsd-ksk {domain} A +rtrace +vtrace"
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||
if "; fully validated" in result.stdout:
|
||||
return {"valid": True, "message": "DNSSEC is valid", "output": result.stdout, "errors": result.stderr}
|
||||
return {"valid": True, "message": "DNSSEC is valid", "output": result.stderr + result.stdout}
|
||||
else:
|
||||
return {"valid": False, "message": "DNSSEC is not valid", "output": result.stdout, "errors": result.stderr}
|
||||
return {"valid": False, "message": "DNSSEC is not valid", "output": result.stderr + result.stdout}
|
||||
Reference in New Issue
Block a user