def review(audit_filename): review_result = "" try: ok, result = extract_audit_data(audit_filename) if not ok: # print(result) review_result += "Valid proof file format: False\n" return False, review_result, None else: review_result += "Valid Proof File Format: True\n" audit_data = result except Exception as e: review_result += "Valid proof file format: False\n" return False, review_result, None #1. Verify TLS Server's pubkey # to-do: verify cert signed by trusted root CA # to-do: extrct pubkey from ca certificate, compare with pubkey in pgsg try: audit_session = shared.TLSNClientSession( ccs=audit_data['cipher_suite'], tlsver=audit_data['tlsver']) first_cert_len = shared.ba2int(audit_data['certs'][:3]) cert_bi = audit_data['certs'][3:3 + first_cert_len] cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, cert_bi) cert_cn = cert.get_subject().CN print(cert.get_subject().get_components()) print("cert CN:", cert.get_subject().commonName) # server_name = cert.get_subject().CN print("audit_data server:", audit_data['host']) server_name = audit_data['host'] # print("is rsapublickey:",isinstance(cert.get_pubkey().to_cryptography_key(), cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKey)) server_mod = cert.get_pubkey().to_cryptography_key().public_numbers().n # print("extrct public_key mod:", server_mod) if cert_cn.startswith("*."): cert_cn = cert_cn[2:] if cert_cn.endswith(".cn"): cert_cn = cert_cn[:-3] if cert_cn.startswith("www."): cert_cn = cert_cn[4:] print("cert CN:", cert_cn) if "." in cert_cn: cert_cn_arrays = cert_cn.split(".") cert_cn = cert_cn_arrays[-2] print("cert CN:", cert_cn) # if not server_name.endswith(cert_cn): # if cert_cn not in server_name: # review_result += "Valid Host name: False\n" # return False, review_result, None # else: # review_result += "Valid Host name: True\n" print('Processing data for server:', server_name) # if server_name.strip() != audit_data['host'].strip(): # return False, "host name not match" public_hex = binascii.hexlify(shared.bi2ba(server_mod)) # if server_name.startswith("*."): # short = server_name[2:] # url_openssl = "free-api."+short # print ('Processing data for server:', server_name) cipher_key = audit_data['cipher_suite'] cipher_suites = shared.tlsn_cipher_suites chosen_cipher = cipher_suites[cipher_key][0] print("chosen cipher suite:", chosen_cipher) tls_ver = "-tls1_1" if audit_data['tlsver'] == bytearray('\x03\x01'): tls_ver = "-tls1" print("tls ver:", tls_ver) cmd = "echo |openssl s_client " + tls_ver + " -cipher " + chosen_cipher + " -connect " + server_name + ":443 2>&1 | openssl x509 -pubkey -modulus -noout 2>&1 | grep 'Modulus' | sed 's/Modulus=//g' " print("cmd:", cmd) import subprocess public_openssl = subprocess.check_output(cmd, shell=True).strip('\n') print("hex:" + public_hex.upper().lower()) print("openssl:" + public_openssl.upper().lower()) if public_hex.upper().lower() == public_openssl.upper().lower(): review_result += "Valid server pub key: True\n" else: review_result += "Valid server pub key: False\n" return False, review_result, None except Exception as e: review_result += "Valid server pub key: False\n" return False, review_result, None try: check_cert = os.system("echo |openssl s_client " + tls_ver + " -cipher " + chosen_cipher + " -connect " + server_name + ":443") print("check_cert result:", check_cert) if check_cert == 0: review_result += "Valid server certificate chain: True\n" else: review_result += "Valid server certificate chain: False\n" return False, review_result, None except Exception as e: review_result += "Valid server certificate chain: False\n" return False, review_result, None # to-do check if openssl cmd return 0 #2. Verify Proof from the Auditor Side # the partial proof from auditor is signed by auditor #First, extract the cert in DER form from the notarization file #Then, extract from the cert the modulus and server name (common name field) #To do this, we need to initialise the TLSNClientSession try: audit_session = shared.TLSNClientSession( ccs=audit_data['cipher_suite'], tlsver=audit_data['tlsver']) first_cert_len = shared.ba2int(audit_data['certs'][:3]) # server_mod, server_exp = audit_session.extract_mod_and_exp(certDER=audit_data['certs'][3:3+first_cert_len], sn=True) data_to_be_verified = audit_data['commit_hash'] + audit_data[ 'pms2'] + shared.bi2ba(server_mod) + audit_data['audit_time'] data_to_be_verified = sha256(data_to_be_verified).digest() if not shared.verify_signature(data_to_be_verified, audit_data['signature'], oracle_int_modulus): review_result += "Valid Auditor Signature: False\n" return False, review_result, None else: review_result += "Valid Auditor Signature: True\n" #3. Verify commitment hash. if not sha256(audit_data['response'] + audit_data['certs']).digest( ) == audit_data['commit_hash']: review_result += "Valid server response: False\n" return False, review_result, None else: review_result += "Valid encrypted server response: True\n" except Exception as e: review_result += "Valid server response: False\n" print(e) return False, review_result, None #4 Decrypt html and check for mac errors. Response data and MAC code from auditee will be checked by the MAC key from Auditor try: audit_session.unexpected_server_app_data_count = shared.ba2int( audit_data['response'][0]) audit_session.tlsver = audit_data['tlsver'] audit_session.client_random = audit_data['client_random'] audit_session.server_random = audit_data['server_random'] audit_session.pms1 = audit_data['pms1'] audit_session.pms2 = audit_data['pms2'] audit_session.p_auditee = shared.tls_10_prf( 'master secret' + audit_session.client_random + audit_session.server_random, first_half=audit_session.pms1)[0] audit_session.p_auditor = shared.tls_10_prf( 'master secret' + audit_session.client_random + audit_session.server_random, second_half=audit_session.pms2)[1] audit_session.set_master_secret_half() audit_session.do_key_expansion() audit_session.store_server_app_data_records(audit_data['response'][1:]) audit_session.IV_after_finished = (map(ord,audit_data['IV'][:256]),ord(audit_data['IV'][256]), \ ord(audit_data['IV'][257])) if audit_data['cipher_suite'] in [4,5] else audit_data['IV'] print("start to decrypt") plaintext, bad_mac = audit_session.process_server_app_data_records( is_for_auditor=True) print("decrypt done") if bad_mac: review_result += "Valid decrypted response content: False\n" return False, review_result, None plaintext = shared.dechunk_http(plaintext) plaintext = shared.gunzip_http(plaintext) if plaintext == audit_data['html']: review_result += "Valid decrypted response content: True\n" else: review_result += "Valid decrypted response content: False\n" return False, review_result, None except Exception as e: review_result += "Valid decrypted response content: False\n" return False, review_result, None #5 Display html + success. # with open(join(current_session_dir,'audited.html'),'wb') as f: # f.write(plaintext) #print out the info about the domain # n_hexlified = binascii.hexlify(shared.bi2ba(server_mod)) # print("pubkey string:"+n_hexlified) # #pubkey in the format 09 56 23 .... # n_write = " ".join(n_hexlified[i:i+2] for i in range(0, len(n_hexlified), 2)) # with open(join(current_session_dir,'domain_data.txt'), 'wb') as f: # f.write('Server name: '+audit_session.server_name + '\n\n'+'Server pubkey:' + '\n\n' + n_write+'\n') return True, review_result, plaintext
def start_generate(server_name, headers, server_modulus): global global_tlsver global global_use_gzip global global_use_slowaes print("server_name:", server_name) session_id = ''.join( random.choice(string.ascii_lowercase + string.digits) for x in range(10)) tlsn_session = shared.TLSNClientSession(server_name, tlsver=global_tlsver) tlsn_session.server_modulus = shared.ba2int(server_modulus) tlsn_session.server_mod_length = shared.bi2ba(len(server_modulus)) print('Preparing encrypted pre-master secret') prepare_pms(tlsn_session, session_id) for i in range(10): try: print('Performing handshake with server') tls_sock = shared.create_sock(tlsn_session.server_name, tlsn_session.ssl_port) tlsn_session.start_handshake(tls_sock) retval = negotiate_crippled_secrets(tlsn_session, tls_sock, session_id) if not retval == 'success': raise shared.TLSNSSLError('Failed to negotiate secrets: ' + retval) print('Getting data from server') # response = make_tlsn_request(headers, tlsn_session, tls_sock) #prefix response with number of to-be-ignored records, #note: more than 256 unexpected records will cause a failure of audit. Just as well! response = shared.bi2ba( tlsn_session.unexpected_server_app_data_count, fixed=1) + response break except shared.TLSNSSLError: shared.ssl_dump(tlsn_session) raise except Exception as e: print( 'Exception caught while getting data from server, retrying...', e) if i == 9: raise Exception('Notarization failed') continue # commit its own hash, get auditor's secrets ok, commit_hash, pms2, signature, audit_time = commit_session( tlsn_session, response, session_id) if not ok: return ok, "commit hash to auditor failed" # no need to verify signatures msg = sha256(commit_hash + pms2 + shared.bi2ba(tlsn_session.server_modulus) + audit_time).digest() oracle_ba_modulus = binascii.unhexlify(oracle_modulus) oracle_int_modulus = shared.ba2int(oracle_ba_modulus) print(msg) print(signature) if not shared.verify_signature(msg, signature, oracle_int_modulus): raise Exception("Notarization FAILED, notary signature invalid.") ok, result = decrypt_html(pms2, tlsn_session) if not ok: return ok, result html = result print('Verified OK') host_line = "host: " + server_name + "\r\n" readable = host_line b = """""" "" b = """<meta[ ]+http-equiv=["']?content-type["']?[ ]+content=["']?text/html;[ ]*charset=([0-9-a-zA-Z]+)["']?""" B = re.compile(b, re.IGNORECASE) encodings = B.search(html) # print("encoding:") if encodings != None: encoding = encodings.group(1) if encoding.lower() == 'gb231' or encoding.lower() == 'gb2312': html = html.decode('gb18030') # print(html) else: html = html.decode(encoding) else: html.decode('utf-8') print("html len:", len(html)) html = "response:\r\n" + html + '\r\n-----PROOF BINARY DATA-----\r\n' # print(html) # readable += html.decode().encode('utf-8') readable += html # chosen_cipher_suite audit_data = shared.bi2ba(tlsn_session.chosen_cipher_suite, fixed=2) # 2 bytes # client_random, server_random audit_data += tlsn_session.client_random + tlsn_session.server_random # 64 bytes # pre_master_key, two parts, each generated by auditee or auditor audit_data += tlsn_session.pms1 + pms2 #48 bytes # length of server_cert, sent by TLS Server, why fix 3 ? audit_data += shared.bi2ba(len(tlsn_session.server_certificate.certs), fixed=3) # server_certs, it's very hard to verify these babies on-chain. audit_data += tlsn_session.server_certificate.certs # tls version audit_data += tlsn_session.tlsver #2 bytes # proposed tls version in ClientHello? # audit_data += tlsn_session.initial_tlsver #2 bytes # length of response audit_data += shared.bi2ba(len(response), fixed=8) #8 bytes # response data audit_data += response #note that it includes unexpected pre-request app data, 10s of kB # IV_after_finished used by RC4, necessory to authenticate response IV = tlsn_session.IV_after_finished if tlsn_session.chosen_cipher_suite in [47,53] \ else shared.rc4_state_to_bytearray(tlsn_session.IV_after_finished) # length of IV, should be before IV ? audit_data += shared.bi2ba(len(IV), fixed=2) #2 bytes # IV audit_data += IV #16 bytes or 258 bytes for RC4. # length of auditor's public key, in modulus formate audit_data += shared.bi2ba(len(oracle_ba_modulus), fixed=2) # auditor's signature audit_data += signature #512 bytes RSA PKCS 1 v1.5 padding # hash that auditee commits to auditor audit_data += commit_hash #32 bytes sha256 hash # auditor's public key audit_data += oracle_ba_modulus # timestamp used to make signature unique audit_data += audit_time # audit_data = bytearray(readable.encode('utf-8')) + audit_data date = time_str = time.strftime('%d-%b-%Y-%H-%M-%S-', time.gmtime()) filename = date + session_id + ".pgsg" # print("proof file name:",filename) proofpath = join(PROOF_DIR, filename) with open(proofpath, "w") as f: f.write(readable) f.write(audit_data) return True, filename
global_use_gzip = False audit_data = extract_audit_data(audit_filename) #1. Verify notary pubkey - done in extract_audit_data print ('Notary pubkey OK') #2. Verify signature #First, extract the cert in DER form from the notarization file #Then, extract from the cert the modulus and server name (common name field) #To do this, we need to initialise the TLSNClientSession audit_session = shared.TLSNClientSession(ccs=audit_data['cipher_suite'],tlsver=audit_data['initial_tlsver']) first_cert_len = shared.ba2int(audit_data['certs'][:3]) server_mod, server_exp = audit_session.extract_mod_and_exp(certDER=audit_data['certs'][3:3+first_cert_len], sn=True) print ('Processing data for server: ', audit_session.server_name) data_to_be_verified = audit_data['commit_hash'] + audit_data['pms2'] + shared.bi2ba(server_mod) data_to_be_verified = sha256(data_to_be_verified).digest() if not shared.verify_signature(data_to_be_verified, audit_data['signature'],oracle_int_modulus): print ('Audit FAILED. Signature is not verified.') exit() print ('Notary signature OK') #3. Verify commitment hash. if not sha256(audit_data['response']).digest() == audit_data['commit_hash']: print ('Audit FAILED. Commitment hash does not match encrypted server response.') exit() print ('Commitment hash OK') #4 Decrypt html and check for mac errors. audit_session.unexpected_server_app_data_count = shared.ba2int(audit_data['response'][0]) audit_session.tlsver = audit_data['tlsver'] audit_session.client_random = audit_data['client_random'] audit_session.server_random = audit_data['server_random'] audit_session.pms1 = audit_data['pms1'] audit_session.pms2 = audit_data['pms2']
#1. Verify notary pubkey - done in extract_audit_data print('Notary pubkey OK') #2. Verify signature #First, extract the cert in DER form from the notarization file #Then, extract from the cert the modulus and server name (common name field) #To do this, we need to initialise the TLSNClientSession audit_session = shared.TLSNClientSession( ccs=audit_data['cipher_suite'], tlsver=audit_data['initial_tlsver']) first_cert_len = shared.ba2int(audit_data['certs'][:3]) server_mod, server_exp = audit_session.extract_mod_and_exp( certDER=audit_data['certs'][3:3 + first_cert_len], sn=True) print('Processing data for server: ', audit_session.server_name) data_to_be_verified = audit_data['commit_hash'] + audit_data[ 'pms2'] + shared.bi2ba(server_mod) + audit_data['audit_time'] data_to_be_verified = sha256(data_to_be_verified).digest() if not shared.verify_signature( data_to_be_verified, audit_data['signature'], oracle_int_modulus): print('Audit FAILED. Signature is not verified.') exit() print('Notary signature OK') #3. Verify commitment hash. if not sha256( audit_data['response']).digest() == audit_data['commit_hash']: print( 'Audit FAILED. Commitment hash does not match encrypted server response.' ) exit() print('Commitment hash OK') #4 Decrypt html and check for mac errors. audit_session.unexpected_server_app_data_count = shared.ba2int( audit_data['response'][0]) audit_session.tlsver = audit_data['tlsver']