def test_min_eq_max(self): it = structured_random_iter(1, min_length=16, max_length=16, step=16) ret = [i for i in it] self.assertEqual(len(ret), 1) self.assertIsInstance(ret[0], StructuredRandom) self.assertEqual(len(ret[0].data), 16)
def test_min_and_max(self): for _ in range(100): it = structured_random_iter(1, min_length=16, max_length=256, step=16) ret = [i for i in it] self.assertIn(len(ret), [1]) for r in ret: self.assertIsInstance(r, StructuredRandom) self.assertIn(len(r.data), range(16, 257, 16)) if r.vals[0][1] is not None: self.assertEqual(r.data[0], r.vals[0][1])
def main(): """check if incorrect padding is rejected by server""" host = "localhost" port = 4433 num_limit = 800 run_exclude = set() argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:", ["help"]) for opt, arg in opts: if opt == '-h': host = arg elif opt == '-p': port = int(arg) elif opt == '-e': run_exclude.add(arg) elif opt == '-n': num_limit = int(arg) elif opt == '--help': help_msg() sys.exit(0) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None conversations = {} conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateRequest()) fork = node node = node.add_child(ExpectServerHelloDone()) node = node.add_child(CertificateGenerator()) # handle servers which ask for client certificates fork.next_sibling = ExpectServerHelloDone() join = ClientKeyExchangeGenerator() fork.next_sibling.add_child(join) node = node.add_child(join) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child(ApplicationDataGenerator(b"GET / HTTP/1.0\r\n\r\n")) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["sanity"] = \ conversation # block size is 16 bytes for AES_128, 2**14 is the TLS protocol max for data in structured_random_iter(num_limit, min_length=16, max_length=2**14, step=16): conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateRequest()) fork = node node = node.add_child(ExpectServerHelloDone()) node = node.add_child(CertificateGenerator()) # handle servers which ask for client certificates fork.next_sibling = ExpectServerHelloDone() join = ClientKeyExchangeGenerator() fork.next_sibling.add_child(join) node = node.add_child(join) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( replace_plaintext( ApplicationDataGenerator( b"I'm ignored, only type is important"), data.data)) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.bad_record_mac)) node = node.add_child(ExpectClose()) conversations["encrypted plaintext of {0}".format(data)] = \ conversation # run the conversation good = 0 bad = 0 failed = [] if not num_limit: num_limit = len(conversations) # make sure that sanity test is run first and last # to verify that server was running and kept running throught sanity_test = ('sanity', conversations['sanity']) ordered_tests = chain([sanity_test], islice( filter(lambda x: x[0] != 'sanity', conversations.items()), num_limit), [sanity_test]) for c_name, c_test in ordered_tests: if run_only and c_name not in run_only or c_name in run_exclude: continue print("{0} ...".format(c_name)) runner = Runner(c_test) res = True try: runner.run() except Exception: print("Error while processing") print(traceback.format_exc()) res = False if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad)) failed_sorted = sorted(failed, key=natural_sort_keys) print(" {0}".format('\n '.join(repr(i) for i in failed_sorted))) if bad > 0: sys.exit(1)
def main(): """Check if incorrect padding and MAC is rejected by server.""" host = "localhost" port = 4433 num_limit = 1024 rand_limit = None run_exclude = set() expected_failures = {} last_exp_tmp = None dhe = False cipher = None splitting = None argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:x:X:n:dC:", ["help", "random=", "1/n-1", "0/n"]) for opt, arg in opts: if opt == '-h': host = arg elif opt == '-p': port = int(arg) elif opt == '-e': run_exclude.add(arg) elif opt == '-x': expected_failures[arg] = None last_exp_tmp = str(arg) elif opt == '-X': if not last_exp_tmp: raise ValueError("-x has to be specified before -X") expected_failures[last_exp_tmp] = str(arg) elif opt == '-n': num_limit = int(arg) elif opt == '--random': rand_limit = int(arg)//2 elif opt == '-d': dhe = True elif opt == '--1/n-1': splitting = 1 elif opt == '--0/n': splitting = 0 elif opt == '-C': if arg[:2] == '0x': cipher = int(arg, 16) else: try: cipher = getattr(CipherSuite, arg) except AttributeError: cipher = int(arg) elif opt == '--help': help_msg() sys.exit(0) else: raise ValueError("Unknown option: {0}".format(opt)) if dhe and cipher is not None: raise ValueError("-C and -d are mutually exclusive") if cipher is None: if dhe: cipher = CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA else: cipher = CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA block_size = 16 if cipher in CipherSuite.tripleDESSuites: block_size = 8 if rand_limit is None: if block_size == 16: rand_limit = 4096 else: assert block_size == 8 rand_limit = 8192 dhe = cipher in CipherSuite.ecdhAllSuites or \ cipher in CipherSuite.dhAllSuites if args: run_only = set(args) else: run_only = None # if we are to execute only some tests, we need to not filter the # static ones if run_only: num_limit = None conversations = {} conversation = Connect(host, port) node = conversation if dhe: ext = {} add_dhe_extensions(ext) else: ext = None ciphers = [cipher, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectCertificate()) if dhe: node = node.add_child(ExpectServerKeyExchange()) # handle servers that ask for client certificates node = node.add_child(ExpectCertificateRequest()) fork = node node = node.add_child(ExpectServerHelloDone()) node = node.add_child(CertificateGenerator()) # handle servers that don't ask for client certificates fork.next_sibling = ExpectServerHelloDone() # join both paths join = ClientKeyExchangeGenerator() fork.next_sibling.add_child(join) node = node.add_child(join) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( ApplicationDataGenerator(b"GET / HTTP/1.0\r\n\r\n")) if splitting is not None: node = node.add_child(ExpectApplicationData(size=splitting)) node = node.add_child(ExpectApplicationData()) node = node.add_child(AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["sanity"] = \ conversation # test all combinations of lengths and values for plaintexts up to 256 # bytes long with uniform content (where every byte has the same value) mono_tests = [(length, value) for length in range(block_size, 257, block_size) for value in range(256)] if not num_limit: mono_iter = mono_tests rand_len_to_generate = rand_limit else: # we want to speed up generation, so generate only as many conversations # as necessary to meet num_limit, but do that uniformely between # random payloads, mono payloads, application_data tests and handshake # tests ratio = rand_limit * 1.0 / len(mono_tests) # `num_limit / 2` because of handshake and application_data tests mono_len_to_generate = min(len(mono_tests), int(ceil((num_limit / 2) * (1 - ratio)))) rand_len_to_generate = int(ceil((num_limit) / 2 * ratio)) mono_iter = sample(mono_tests, mono_len_to_generate) mono = (StructuredRandom([(length, value)]) for length, value in mono_iter) # 2**14 is the TLS protocol max rand = structured_random_iter(rand_len_to_generate, min_length=block_size, max_length=2**14, step=block_size) if not run_only: for data in chain(mono, rand): add_app_data_conversation(conversations, host, port, cipher, dhe, data) else: for conv in run_only: if "Application Data" in conv: params = parse_structured_random_params(conv) data = StructuredRandom(params) add_app_data_conversation(conversations, host, port, cipher, dhe, data) # do th same thing but for handshake record # (note, while the type is included in the MAC, we are never # sending a valid MAC, so the server has only the record layer header to # deduce if the message needs special handling, if any) # test all combinations of lengths and values for plaintexts up to 256 # bytes long with uniform content (where every byte has the same value) mono_tests = [(length, value) for length in range(block_size, 257, block_size) for value in range(256)] if not num_limit: mono_iter = mono_tests rand_len_to_generate = rand_limit else: # we want to speed up generation, so generate only as many conversations # as necessary to meet num_limit, but do that uniformely between # random payloads, mono payloads, application_data tests and handshake # tests ratio = rand_limit * 1.0 / len(mono_tests) # `num_limit / 2` because of handshake and application_data tests mono_len_to_generate = min(len(mono_tests), int(ceil((num_limit / 2) * (1 - ratio)))) rand_len_to_generate = int(ceil((num_limit) / 2 * ratio)) mono_iter = sample(mono_tests, mono_len_to_generate) mono = (StructuredRandom([(length, value)]) for length, value in mono_iter) # 2**14 is the TLS protocol max rand = structured_random_iter(rand_len_to_generate, min_length=block_size, max_length=2**14, step=block_size) if not run_only: for data in chain(mono, rand): add_handshake_conversation(conversations, host, port, cipher, dhe, data) else: for conv in run_only: if "Handshake" in conv: params = parse_structured_random_params(conv) data = StructuredRandom(params) add_handshake_conversation(conversations, host, port, cipher, dhe, data) # run the conversation good = 0 bad = 0 xfail = 0 xpass = 0 failed = [] xpassed = [] if not num_limit: num_limit = len(conversations) # make sure that sanity test is run first and last # to verify that server was running and kept running throughout sanity_tests = [('sanity', conversations['sanity'])] regular_tests = [(k, v) for k, v in conversations.items() if k != 'sanity'] sampled_tests = sample(regular_tests, min(num_limit, len(regular_tests))) ordered_tests = chain(sanity_tests, sampled_tests, sanity_tests) for c_name, c_test in ordered_tests: if run_only and c_name not in run_only or c_name in run_exclude: continue print("{0} ...".format(c_name)) runner = Runner(c_test) res = True exception = None try: runner.run() except Exception as exp: exception = exp print("Error while processing") print(traceback.format_exc()) res = False if c_name in expected_failures: if res: xpass += 1 xpassed.append(c_name) print("XPASS: expected failure but test passed\n") else: if expected_failures[c_name] is not None and \ expected_failures[c_name] not in str(exception): bad += 1 failed.append(c_name) print("Expected error message: {0}\n" .format(expected_failures[c_name])) else: xfail += 1 print("OK-expected failure\n") else: if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) print("Tester for de-padding and MAC verification\n") print("Generates plaintexts that can be incorrectly handled by de-padding") print("and MAC verification algorithms and verifies that they are handled") print("correctly and consistently.\n") print("Should be executed with multiple ciphers (especially regarding the") print("HMAC used) and TLS versions. Note: test requires CBC mode") print("ciphers.\n") print("TLS 1.0 servers should require enabling BEAST workaround, see") print("help message.\n") print("version: {0}\n".format(version)) print("Test end") print(20 * '=') print("TOTAL: {0}".format(len(sampled_tests) + 2*len(sanity_tests))) print("SKIP: {0}".format(len(run_exclude.intersection(conversations.keys())))) print("PASS: {0}".format(good)) print("XFAIL: {0}".format(xfail)) print("FAIL: {0}".format(bad)) print("XPASS: {0}".format(xpass)) print(20 * '=') sort = sorted(xpassed ,key=natural_sort_keys) if len(sort): print("XPASSED:\n\t{0}".format('\n\t'.join(repr(i) for i in sort))) sort = sorted(failed, key=natural_sort_keys) if len(sort): print("FAILED:\n\t{0}".format('\n\t'.join(repr(i) for i in sort))) if bad > 0: sys.exit(1)
def main(): host = "localhost" port = 4433 num_limit = 20 run_exclude = set() expected_failures = {} last_exp_tmp = None ext_exclude = set() exp_sup_groups = False individual_ext = [] argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:x:X:n:", ["help", "exc=", "supgroup", "separate="]) for opt, arg in opts: if opt == '-h': host = arg elif opt == '-p': port = int(arg) elif opt == '-e': run_exclude.add(arg) elif opt == '-x': expected_failures[arg] = None last_exp_tmp = str(arg) elif opt == '-X': if not last_exp_tmp: raise ValueError("-x has to be specified before -X") expected_failures[last_exp_tmp] = str(arg) elif opt == '-n': num_limit = int(arg) elif opt == '--exc': ext_exclude.add(int(arg)) elif opt == '--supgroup': exp_sup_groups = True elif opt == "--separate": individual_ext.append(int(arg)) elif opt == '--help': help_msg() sys.exit(0) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None conversations = {} conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create(key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectEncryptedExtensions()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation expect_exts_sh = { ExtensionType.key_share: None, ExtensionType.supported_versions: None } expect_exts_ee = {} if exp_sup_groups: expect_exts_ee[ExtensionType.supported_groups] = None unassigned_ext_id = [] unassigned_ext_id.extend(range(2, 5)) unassigned_ext_id.extend(range(6, 10)) unassigned_ext_id.extend([11, 12, 17]) unassigned_ext_id.extend(range(22, 28)) unassigned_ext_id.extend(range(29, 41)) unassigned_ext_id.extend([46]) unassigned_ext_id.extend(range(52, 65536)) # Exclude extensions from a list of unassigned ones unassigned_ext_id = [ ext for ext in unassigned_ext_id if ext not in ext_exclude ] chunk_size = 4096 for ext_chunk in (unassigned_ext_id[j:j + chunk_size] for j in range(0, len(unassigned_ext_id), chunk_size)): conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = OrderedDict() for ext_id in ext_chunk: ext[ext_id] = AutoEmptyExtension() if ExtensionType.renegotiation_info in ext: ext[ExtensionType.renegotiation_info] = None groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(extensions=expect_exts_sh)) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child( ExpectEncryptedExtensions(extensions=expect_exts_ee)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations[ "empty unassigned extensions, ids in range from {0} to {1}".format( ext_chunk[0], ext_chunk[-1])] = conversation chunk_size = 1024 for ext_chunk in (unassigned_ext_id[j:j + chunk_size] for j in range(0, len(unassigned_ext_id), chunk_size)): conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] random_payload = structured_random_iter(max_length=2**6, count=len(ext_chunk)) ext = OrderedDict() for ext_id in ext_chunk: ext[ext_id] = TLSExtension(extType=ext_id).create( next(random_payload).data) if ExtensionType.renegotiation_info in ext: ext[ExtensionType.renegotiation_info] = None groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(extensions=expect_exts_sh)) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child( ExpectEncryptedExtensions(extensions=expect_exts_ee)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations[ "unassigned extensions with random payload, ids in range from {0} to {1}" .format(ext_chunk[0], ext_chunk[-1])] = conversation # test the special one user asked for for ext_id in individual_ext: conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = OrderedDict() if ExtensionType.renegotiation_info in ext: ext[ExtensionType.renegotiation_info] = None groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) ext[ext_id] = AutoEmptyExtension() node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(extensions=expect_exts_sh)) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child( ExpectEncryptedExtensions(extensions=expect_exts_ee)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["empty unassigned extension id {0}".format( ext_id)] = conversation # and now with random payload conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = OrderedDict() if ExtensionType.renegotiation_info in ext: ext[ExtensionType.renegotiation_info] = None groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) random_payload = structured_random_iter(max_length=2**6, count=1) ext[ext_id] = TLSExtension(extType=ext_id)\ .create(next(random_payload).data) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(extensions=expect_exts_sh)) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child( ExpectEncryptedExtensions(extensions=expect_exts_ee)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["unassigned extension with random payload, id {0}". format(ext_id)] = conversation # run the conversation good = 0 bad = 0 xfail = 0 xpass = 0 failed = [] xpassed = [] if not num_limit: num_limit = len(conversations) # make sure that sanity test is run first and last # to verify that server was running and kept running throughout sanity_tests = [('sanity', conversations['sanity'])] if run_only: if num_limit > len(run_only): num_limit = len(run_only) regular_tests = [(k, v) for k, v in conversations.items() if k in run_only] else: regular_tests = [(k, v) for k, v in conversations.items() if (k != 'sanity') and k not in run_exclude] sampled_tests = sample(regular_tests, min(num_limit, len(regular_tests))) ordered_tests = chain(sanity_tests, sampled_tests, sanity_tests) for c_name, c_test in ordered_tests: print("{0} ...".format(c_name)) runner = Runner(c_test) res = True exception = None try: runner.run() except Exception as exp: exception = exp print("Error while processing") print(traceback.format_exc()) res = False if c_name in expected_failures: if res: xpass += 1 xpassed.append(c_name) print("XPASS-expected failure but test passed\n") else: if expected_failures[c_name] is not None and \ expected_failures[c_name] not in str(exception): bad += 1 failed.append(c_name) print("Expected error message: {0}\n".format( expected_failures[c_name])) else: xfail += 1 print("OK-expected failure\n") else: if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) print("Test with large number of unassigned extensions in TLS 1.3") print("Verify that server does not reply to any of these extensions") print("and establish regular session.\n") print("Test end") print(20 * '=') print("version: {0}".format(version)) print(20 * '=') print("TOTAL: {0}".format(len(sampled_tests) + 2 * len(sanity_tests))) print("SKIP: {0}".format( len(run_exclude.intersection(conversations.keys())))) print("PASS: {0}".format(good)) print("XFAIL: {0}".format(xfail)) print("FAIL: {0}".format(bad)) print("XPASS: {0}".format(xpass)) print(20 * '=') sort = sorted(xpassed, key=natural_sort_keys) if len(sort): print("XPASSED:\n\t{0}".format('\n\t'.join(repr(i) for i in sort))) sort = sorted(failed, key=natural_sort_keys) if len(sort): print("FAILED:\n\t{0}".format('\n\t'.join(repr(i) for i in sort))) if bad > 0: sys.exit(1)
def main(): host = "localhost" port = 4433 num_limit = None run_exclude = set() ext_exclude = set() exp_sup_groups = False argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:", ["help", "exc=", "supgroup"]) for opt, arg in opts: if opt == '-h': host = arg elif opt == '-p': port = int(arg) elif opt == '-e': run_exclude.add(arg) elif opt == '-n': num_limit = int(arg) elif opt == '--exc': ext_exclude.add(int(arg)) elif opt == '--supgroup': exp_sup_groups = True elif opt == '--help': help_msg() sys.exit(0) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None conversations = {} conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create(key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectEncryptedExtensions()) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation expect_exts_sh = { ExtensionType.key_share: None, ExtensionType.supported_versions: None } expect_exts_ee = {} if exp_sup_groups: expect_exts_ee[ExtensionType.supported_groups] = None unassigned_ext_id = [] unassigned_ext_id.extend(range(2, 5)) unassigned_ext_id.extend(range(6, 10)) unassigned_ext_id.extend([11, 12, 17]) unassigned_ext_id.extend(range(22, 28)) unassigned_ext_id.extend(range(29, 41)) unassigned_ext_id.extend([46]) unassigned_ext_id.extend(range(52, 65536)) # Exclude extensions from a list of unassigned ones unassigned_ext_id = [ ext for ext in unassigned_ext_id if ext not in ext_exclude ] chunk_size = 4096 for ext_chunk in (unassigned_ext_id[j:j + chunk_size] for j in range(0, len(unassigned_ext_id), chunk_size)): conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = OrderedDict() for ext_id in ext_chunk: ext[ext_id] = AutoEmptyExtension() if ExtensionType.renegotiation_info in ext: ext[ExtensionType.renegotiation_info] = None groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(extensions=expect_exts_sh)) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child( ExpectEncryptedExtensions(extensions=expect_exts_ee)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations[ "empty unassigned extensions, ids in range from {0} to {1}".format( ext_chunk[0], ext_chunk[-1])] = conversation chunk_size = 1024 for ext_chunk in (unassigned_ext_id[j:j + chunk_size] for j in range(0, len(unassigned_ext_id), chunk_size)): conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] random_payload = structured_random_iter(max_length=2**6, count=len(ext_chunk)) ext = OrderedDict() for ext_id in ext_chunk: ext[ext_id] = TLSExtension(extType=ext_id).create( next(random_payload).data) if ExtensionType.renegotiation_info in ext: ext[ExtensionType.renegotiation_info] = None groups = [GroupName.secp256r1] key_shares = [] for group in groups: key_shares.append(key_share_gen(group)) ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT]) ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) sig_algs = [ SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_pss_sha256 ] ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\ .create(sig_algs) ext[ExtensionType.signature_algorithms_cert] = SignatureAlgorithmsCertExtension()\ .create(RSA_SIG_ALL) node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(extensions=expect_exts_sh)) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child( ExpectEncryptedExtensions(extensions=expect_exts_ee)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectCertificateVerify()) node = node.add_child(ExpectFinished()) node = node.add_child(FinishedGenerator()) node = node.add_child( ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n"))) # This message is optional and may show up 0 to many times cycle = ExpectNewSessionTicket() node = node.add_child(cycle) node.add_child(cycle) node.next_sibling = ExpectApplicationData() node = node.next_sibling.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations[ "unassigned extensions with random payload, ids in range from {0} to {1}" .format(ext_chunk[0], ext_chunk[-1])] = conversation # run the conversation good = 0 bad = 0 failed = [] if not num_limit: num_limit = len(conversations) # make sure that sanity test is run first and last # to verify that server was running and kept running throught sanity_test = ('sanity', conversations['sanity']) ordered_tests = chain([sanity_test], islice( filter(lambda x: x[0] != 'sanity', conversations.items()), num_limit), [sanity_test]) for c_name, c_test in ordered_tests: if run_only and c_name not in run_only or c_name in run_exclude: continue print("{0} ...".format(c_name)) runner = Runner(c_test) res = True try: runner.run() except Exception: print("Error while processing") print(traceback.format_exc()) res = False if res: good += 1 print("OK\n") else: bad += 1 failed.append(c_name) print("Test with large number of unassigned extensions in TLS 1.3") print("Verify that server does not reply to any of these extensions") print("and establish regular session.\n") print("version: {0}\n".format(version)) print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad)) failed_sorted = sorted(failed, key=natural_sort_keys) print(" {0}".format('\n '.join(repr(i) for i in failed_sorted))) if bad > 0: sys.exit(1)