From 4743ae9ca362ea19812281d4314a6849c0b5c126 Mon Sep 17 00:00:00 2001 From: beu Date: Wed, 4 Jul 2018 18:12:38 +0200 Subject: [PATCH] First commit --- README.md | 5 +++ index.py | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 README.md create mode 100644 index.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c5ab66 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# API of HTTPS+ Checker + +It's a CGI API write in python3. + +The only one dependance is **dnspython** diff --git a/index.py b/index.py new file mode 100644 index 0000000..d773310 --- /dev/null +++ b/index.py @@ -0,0 +1,130 @@ +#!/usr/bin/python3 +#-*- coding: utf-8 -*- + +# IMPORTATION +import cgi +import json +import urllib.request +import ssl +import hashlib +import dns.query +import dns.message +import socket + +from cryptography import x509 +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.serialization import Encoding +from cryptography.hazmat.primitives.serialization import PublicFormat + +# MODULES +def dnssec_validation(DOMAIN): + qm = dns.message.make_query(DOMAIN, dns.rdatatype.A,want_dnssec=True) + response = dns.query.udp(qm,"1.1.1.1") + dnssec = dns.flags.to_text(response.flags) + + if "AD" in dnssec: + return(True) + else: + return(False) + + +def tlsa_validation(DOMAIN): + def compute_hash(func, string): + """compute hash of string using given hash function""" + h = func() + h.update(string) + return h.hexdigest() + + qm = dns.message.make_query('_443._tcp.' + DOMAIN, dns.rdatatype.TLSA) + response = dns.query.udp(qm,"1.1.1.1") + if len(response.answer) is 0: + return(False) + else: + tlsaanswer = str(response.answer[-1]) + tlsatable = tlsaanswer.split() + selector = str(tlsatable[5]) + mtype = str(tlsatable[6]) + hexdata1 = str(tlsatable[7]) + + conn = ssl.create_connection((DOMAIN , 443)) + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + sock = context.wrap_socket(conn, server_hostname=DOMAIN) + cert = ssl.DER_cert_to_PEM_cert(sock.getpeercert(True)) + cert = cert.encode('ascii') + + if selector == "0": + certdata = cert.as_der() + elif selector == "1": + cert = x509.load_pem_x509_certificate(cert, default_backend()) + certdata = cert.public_key().public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo) + else: + raise ValueError("selector type %d not recognized" % selector) + + if mtype == "0": + hexdata2 = hexdump(certdata) + elif mtype == "1": + hexdata2 = compute_hash(hashlib.sha256, certdata) + elif mtype == "2": + hexdata2 = compute_hash(hashlib.sha512, certdata) + else: + raise ValueError("matchtype %d not recognized" % matchtype) + + if hexdata1 == hexdata2: + return True + else: + return False + +def headers_validation(DOMAIN): + url = "https://" + DOMAIN + "/" + try: + headers = urllib.request.urlopen(url,timeout=3).info() + except: + return("NO HTTPS") + + + if "public-key-pins" in str(headers).lower(): + RESULT="HPKP_TRUE" + else: + RESULT="HPKP _FALSE" + + if "strict-transport-security" in str(headers).lower(): + RESULT = RESULT + " HSTS_TRUE" + else: + RESULT = RESULT + " HSTS_FALSE" + + return(RESULT) + +# MAIN + + +print("Content-Type: text/html") +print("") +fs = cgi.FieldStorage() + +JSON_RESULT= '{"DNSSEC": false,"DANE": false,"HSTS": false,"HPKP": false}' +JSON_DATA = json.loads(JSON_RESULT) + +if "domain" not in fs: + print("{ERROR}") + cgi.sys.exit(0) + +domain = cgi.escape(fs["domain"].value) + +if dnssec_validation(domain) is True: + JSON_DATA["DNSSEC"] = True + +if tlsa_validation(domain) is True: + JSON_DATA["DANE"] = True + +headers = headers_validation(domain) +if "HSTS_TRUE" in headers: + JSON_DATA["HSTS"] = True + +if "HPKP_TRUE" in headers: + JSON_DATA["HPKP"] = True + + +JSON_RESULT = json.dumps(JSON_DATA) +print(JSON_RESULT) + +