def test_run(): test_session = shared.TLSNClientSession(server='www.mozilla.org') sckt = shared.create_sock(test_session.server_name,test_session.ssl_port) test_session.start_handshake(sckt) test_session.set_auditee_secret() test_session.set_auditor_secret() test_session.extract_mod_and_exp() test_session.set_enc_first_half_pms() test_session.set_enc_second_half_pms() test_session.set_encrypted_pms() test_session.set_master_secret_half() test_session.do_key_expansion() test_session.client_key_exchange = shared.tlsn_ssl.TLSClientKeyExchange(serialized=None,encryptedPMS=test_session.enc_pms) test_session.change_cipher_spec = shared.tlsn_ssl.TLSChangeCipherSpec() test_session.handshake_messages[4] = test_session.client_key_exchange.serialized test_session.handshake_messages[5] = test_session.change_cipher_spec.serialized test_session.set_handshake_hashes() verify_data = test_session.get_verify_data_for_finished() test_session.client_finished = shared.tlsn_ssl.TLSFinished(serialized=None, verify_data=verify_data) test_session.handshake_messages[6] = test_session.client_finished.serialized print ("We are about to send the final three handshake messages,") print ("They are: ") print ([binascii.hexlify(x) for x in test_session.handshake_messages[4:7]]) #Note that the three messages cannot be packed into one record; #change cipher spec is *not* a handshake message shared.tlsn_ssl.tls_sender(sckt,test_session.handshake_messages[4],shared.tlsn_ssl.hs) shared.tlsn_ssl.tls_sender(sckt,test_session.handshake_messages[5],shared.tlsn_ssl.chcis) #client finished must be sent encrypted #print ('We are about to send finished.') #print ('The handshake messages are: ', self.handshake_messages[:5]) shared.tlsn_ssl.tls_sender(sckt,test_session.handshake_messages[6],shared.tlsn_ssl.hs, conn=test_session.client_connection_state) records=[] while len(records) < 2: rspns = shared.recv_socket(sckt,True) x, remaining = shared.tlsn_ssl.tls_record_decoder(rspns) assert not remaining, "Server sent spurious non-TLS response" records.extend(x) test_session.server_ccs = [x for x in records if x.content_type == shared.tlsn_ssl.chcis][0] print ("We got this server ccs: ", binascii.hexlify(test_session.server_ccs.fragment)) sf = [x for x in records if x.content_type == shared.tlsn_ssl.hs][0] print ("Cipher suite chosen was: ", test_session.chosen_cipher_suite) print ("Server finished is: ", binascii.hexlify(sf.fragment)) print ("We got rspns: ", binascii.hexlify(rspns)) with open('testharness','wb') as f: f.write(test_session.dump()) test_session.server_finished = \ shared.tlsn_ssl.tls_record_fragment_decoder(shared.tlsn_ssl.hs,sf.fragment, \ conn=test_session.server_connection_state, \ ignore_bad_mac=True)[0] #store the IV immediately after decrypting Finished; this will be needed #by auditor in order to replay the decryption test_session.IV_after_finished = test_session.server_connection_state.IV sha_verify, md5_verify = test_session.set_handshake_hashes(server=True) verify_data_check = test_session.get_verify_data_for_finished(sha_verify=sha_verify,\ md5_verify=md5_verify, is_for_client=False) print ("Got this from server: ", binascii.hexlify(test_session.server_finished.verify_data)) print ("Got this from check: ",binascii.hexlify(verify_data_check))
def prepare_pms(tlsn_session, session_id): n = shared.bi2ba(tlsn_session.server_modulus) rs_choice = random.choice(shared.reliable_sites.keys()) print("ramdom choice:", rs_choice) for i in range(10): #keep trying until reliable site check succeeds try: pms_session = shared.TLSNClientSession( rs_choice, shared.reliable_sites[rs_choice][0], ccs=53, tlsver=global_tlsver) if not pms_session: raise Exception( "Client session construction failed in prepare_pms") tls_sock = shared.create_sock(pms_session.server_name, pms_session.ssl_port) pms_session.start_handshake(tls_sock) # 1# message exchange with auditor reply = send_and_recv( 'rcr_rsr_rsname_n', pms_session.client_random + pms_session.server_random + rs_choice[:5] + n, session_id) if reply[0] != 'success': raise Exception( 'Failed to receive a reply for rcr_rsr_rsname_n:') if not reply[1] == 'rrsapms_rhmac_rsapms': raise Exception('bad reply. Expected rrsapms_rhmac_rsapms:') reply_data = reply[2] rrsapms2 = reply_data[:256] pms_session.p_auditor = reply_data[256:304] rsapms2 = reply_data[304:] response = pms_session.complete_handshake(tls_sock, rrsapms2) tls_sock.close() if not response: print("PMS trial failed") continue #judge success/fail based on whether a properly encoded #Change Cipher Spec record is returned by the server (we could #also check the server finished, but it isn't necessary) if not response.count( shared.TLSRecord(shared.chcis, f='\x01', tlsver=global_tlsver).serialized): print("PMS trial failed, retrying. (", binascii.hexlify(response), ")") continue tlsn_session.auditee_secret = pms_session.auditee_secret tlsn_session.auditee_padding_secret = pms_session.auditee_padding_secret tlsn_session.enc_second_half_pms = shared.ba2int(rsapms2) tlsn_session.set_enc_first_half_pms() tlsn_session.set_encrypted_pms() return except shared.TLSNSSLError: shared.ssl_dump(pms_session, fn='preparepms_ssldump') shared.ssl_dump(tlsn_session) raise raise Exception ('Could not prepare PMS with ', rs_choice, ' after 10 tries. Please '+\ 'double check that you are using a valid public key modulus for this site; '+\ 'it may have expired.')
def probe_server_modulus(server): probe_session = shared.TLSNClientSession(server, tlsver=global_tlsver) print('ssl port is: ', probe_session.ssl_port) tls_sock = shared.create_sock(probe_session.server_name, probe_session.ssl_port) try: probe_session.start_handshake(tls_sock) except Exception as e: print("tls 1.1 not support") old_tlsver = bytearray('\x03\x01') probe_session = shared.TLSNClientSession(server, tlsver=old_tlsver) tls_sock = shared.create_sock(probe_session.server_name, probe_session.ssl_port) probe_session.start_handshake(tls_sock) server_mod, server_exp = probe_session.extract_mod_and_exp() tls_sock.close() return shared.bi2ba(server_mod)
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
oracle_ba_modulus = bytearray('').join(map(chr, oracle_modulus)) oracle_int_modulus = shared.ba2int(oracle_ba_modulus) shared.load_program_config() if int(shared.config.get("General", "gzip_disabled")) == 1: 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) + 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']: