def test_parse(self): parser = Parser(bytearray(b'\x01\x00')) ext = ECPointFormatsExtension() self.assertIsNone(ext.formats) ext.parse(parser) self.assertEqual(ext.formats, [ECPointFormat.uncompressed])
def test_parse_with_empty_data(self): parser = Parser(bytearray(0)) ext = ECPointFormatsExtension() ext.parse(parser) self.assertIsNone(ext.formats)
def test_write(self): ext = ECPointFormatsExtension() ext.create([ECPointFormat.ansiX962_compressed_prime]) self.assertEqual(bytearray( b'\x00\x0b' + # type of extension b'\x00\x02' + # overall length b'\x01' + # length of list b'\x01'), ext.write())
def test_write(self): ext = ECPointFormatsExtension() ext.create([ECPointFormat.ansiX962_compressed_prime]) self.assertEqual( bytearray(b'\x00\x0b' + # type of extension b'\x00\x02' + # overall length b'\x01' + # length of list b'\x01'), ext.write())
def __init__(self): """Set the configuration to Firefox 42.""" super(Firefox_42, self).__init__() self._name = "Firefox 42" self.version = (3, 3) self.record_version = (3, 1) self.ciphers = [ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA ] ext = self.extensions = [] ext.append(SNIExtension()) ext.append( TLSExtension(extType=ExtensionType.renegotiation_info).create( bytearray(1))) ext.append(SupportedGroupsExtension().create( [GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1])) ext.append(ECPointFormatsExtension().create( [ECPointFormat.uncompressed])) ext.append(TLSExtension(extType=ExtensionType.session_ticket)) ext.append(NPNExtension()) ext.append( TLSExtension(extType=ExtensionType.alpn).create( bytearray(b'\x00\x15' + b'\x02' + b'h2' + b'\x08' + b'spdy/3.1' + b'\x08' + b'http/1.1'))) ext.append( TLSExtension(extType=ExtensionType.status_request).create( bytearray(b'\x01' + b'\x00\x00' + b'\x00\x00'))) sig_algs = [] for alg in ['sha256', 'sha384', 'sha512', 'sha1']: sig_algs.append((getattr(HashAlgorithm, alg), SignatureAlgorithm.rsa)) for alg in ['sha256', 'sha384', 'sha512', 'sha1']: sig_algs.append((getattr(HashAlgorithm, alg), SignatureAlgorithm.ecdsa)) for alg in ['sha256', 'sha1']: sig_algs.append((getattr(HashAlgorithm, alg), SignatureAlgorithm.dsa)) ext.append(SignatureAlgorithmsExtension().create(sig_algs))
def main(): host = "localhost" port = 4433 num_limit = None run_exclude = set() expected_failures = {} last_exp_tmp = None argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:x:X: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 == '-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 == '--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, (3, 3)]) 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 test_groups = { GroupName.x25519: X25519_ORDER_SIZE, GroupName.x448: X448_ORDER_SIZE, } # check if server will negotiate x25519/x448 - sanity check for test_group, group_size in test_groups.items(): for compression_format in [ ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, ECPointFormat.uncompressed ]: conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} ext[ExtensionType.ec_point_formats] = ECPointFormatsExtension( ).create([compression_format]) groups = [test_group] 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, (3, 3)]) 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 {0} with compression {1}".format( GroupName.toRepr(test_group), ECPointFormat.toRepr(compression_format))] = conversation # check if server will reject an all-zero key share for x25519/x448 # (it should result in all-zero shared secret) conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [ KeyShareEntry().create(test_group, bytearray(group_size)) ] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) 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( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["all zero {0} key share".format( GroupName.toRepr(test_group))] = conversation # check if server will reject a key share or 1 for x25519/x448 # (it should result in all-zero shared secret) conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [ KeyShareEntry().create(test_group, numberToByteArray(1, group_size, "little")) ] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) 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( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["{0} key share of \"1\"".format( GroupName.toRepr(test_group))] = conversation # check if server will reject too small x25519/x448 share # (one with too few bytes in the key share) conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [ KeyShareEntry().create(test_group, bytearray([55] * (group_size - 1))) ] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) 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( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["too small {0} key share".format( GroupName.toRepr(test_group))] = conversation # check if server will reject empty x25519/x448 share # no compression conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [KeyShareEntry().create(test_group, bytearray())] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) 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( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["empty {0} key share".format( GroupName.toRepr(test_group))] = conversation # check if server will reject too big x25519/x448 share # (one with too many bytes in the key share) conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] ext = {} groups = [test_group] key_shares = [ KeyShareEntry().create(test_group, bytearray([55] * (group_size + 1))) ] ext[ExtensionType.key_share] = ClientKeyShareExtension().create( key_shares) ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([TLS_1_3_DRAFT, (3, 3)]) 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( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["too big {0} key share".format( GroupName.toRepr(test_group))] = 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'])] 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("Basic test to verify that server selects same ECDHE parameters") print("and ciphersuites when x25519 or x448 curve is an option\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(): """Verify correct ECDHE shared secret handling.""" host = "localhost" port = 4433 num_limit = None run_exclude = set() min_zeros = 1 record_split = True argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:z", ["help", "min-zeros="]) 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 == '-z': record_split = False elif opt == '--help': help_msg() sys.exit(0) elif opt == '--min-zeros': min_zeros = int(arg) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None collected_premaster_secrets = [] variables_check = \ {'premaster_secret': collected_premaster_secrets} groups = [ GroupName.x25519, GroupName.x448, GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1 ] conversations = {} conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] groups_ext = SupportedGroupsExtension().create(groups) points_ext = ECPointFormatsExtension().create([ECPointFormat.uncompressed]) exts = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: groups_ext, ExtensionType.ec_point_formats: points_ext } node = node.add_child(ClientHelloGenerator(ciphers, extensions=exts)) exts = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=exts)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(CopyVariables(variables_check)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation for prot in [(3, 0), (3, 1), (3, 2), (3, 3)]: for ssl2 in [True, False]: for group in groups: # with SSLv2 compatible or with SSLv3 we can't advertise # curves so do just one check if (ssl2 or prot == (3, 0)) and group != groups[0]: continue conversation = Connect(host, port, version=(0, 2) if ssl2 else (3, 0)) node = conversation ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] if ssl2 or prot == (3, 0): exts = None else: groups_ext = SupportedGroupsExtension().create([group]) exts = { ExtensionType.supported_groups: groups_ext, ExtensionType.ec_point_formats: points_ext } node = node.add_child( ClientHelloGenerator(ciphers, version=prot, extensions=exts, ssl2=ssl2)) if prot > (3, 0): if ssl2: ext = {ExtensionType.renegotiation_info: None} else: ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } else: ext = None node = node.add_child( ExpectServerHello(extensions=ext, version=prot)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(CopyVariables(variables_check)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) if prot < (3, 2) and record_split: # 1/n-1 record splitting node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["Protocol {0}{1}{2}".format( prot, "" if ssl2 or prot < (3, 1) else " with {0} group".format(GroupName.toStr(group)), " in SSLv2 compatible ClientHello" if ssl2 else "")] = \ 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 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 i = 0 break_loop = False while True: # don't hog the memory unnecessairly collected_premaster_secrets[:] = [] print("\"{1}\" repeat {0}...".format(i, c_name)) i += 1 if c_name == 'sanity': break_loop = True 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 if collected_premaster_secrets[-1][:min_zeros] == \ bytearray(min_zeros): print("Got premaster secret with {0} most significant " "bytes equal to zero.".format(min_zeros)) break_loop = True print("OK\n") else: bad += 1 failed.append(c_name) break if break_loop: break print('') print("Check if the connections work when the calculated ECDH shared") print("secret must be padded on the left with zeros") 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)
def test_repr(self): ext = ECPointFormatsExtension().create([ECPointFormat.uncompressed]) self.assertEqual("ECPointFormatsExtension(formats=[0])", repr(ext))
def main(): host = "localhost" port = 4433 num_limit = None run_exclude = set() expected_failures = {} last_exp_tmp = None dhe = False ocsp = False argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:x:X:n:d", ["help", "ocsp-enabled"]) 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 == '-d': dhe = True elif opt == '--ocsp-enabled': ocsp = 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 if dhe: ext = {} groups = [GroupName.secp256r1, GroupName.ffdhe2048] ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) ext[ExtensionType.signature_algorithms] = \ SignatureAlgorithmsExtension().create(SIG_ALL) ext[ExtensionType.signature_algorithms_cert] = \ SignatureAlgorithmsCertExtension().create(SIG_ALL) ciphers = [ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] else: ext = None ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(description="first")) node = node.add_child(ExpectCertificate()) if dhe: node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(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()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation # sanity renegotiation test case conversation = Connect(host, port) node = conversation ext = OrderedDict() # TODO add session_ticket ext[ExtensionType.signature_algorithms] = \ SignatureAlgorithmsExtension().create(SIG_ALL) ext[ExtensionType.signature_algorithms_cert] = \ SignatureAlgorithmsCertExtension().create(SIG_ALL) groups = [GroupName.secp256r1, GroupName.ffdhe2048] ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) ext[ExtensionType.extended_master_secret] = AutoEmptyExtension() ext[ExtensionType.key_share] = key_share_ext_gen([GroupName.secp256r1]) ext[ExtensionType.alpn] = \ ALPNExtension().create([bytearray(b'http/1.1')]) ext[ExtensionType.ec_point_formats] = \ ECPointFormatsExtension().create([ ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, ECPointFormat.uncompressed]) # 18 - signed_certificate_timestamp ext[18] = AutoEmptyExtension() ext[ExtensionType.status_request] = \ StatusRequestExtension().create() ext[ExtensionType.post_handshake_auth] = AutoEmptyExtension() # yes, don't include TLS 1.3, as we want to be able to renegotiate... ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([(3, 3), (3, 2)]) ext[ExtensionType.psk_key_exchange_modes] = \ PskKeyExchangeModesExtension().create( [PskKeyExchangeMode.psk_dhe_ke, PskKeyExchangeMode.psk_ke]) psk_settings = [(b'test', b'pre-shared key', 'sha256')] ext[ExtensionType.pre_shared_key] = psk_ext_gen(psk_settings) mods = [] mods.append(psk_ext_updater(psk_settings)) if dhe: ciphers = [ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] else: ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child( ClientHelloGenerator(ciphers, extensions=ext, modifiers=mods)) node = node.add_child(ExpectServerHello(description="first handshake")) node = node.add_child(ExpectCertificate()) if ocsp: node = node.add_child(ExpectCertificateStatus()) if dhe: node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child(ResetHandshakeHashes()) renego_exts = OrderedDict(ext) # use None for autogeneration of the renegotiation_info with correct # payload renego_exts[ExtensionType.renegotiation_info] = None if ExtensionType.pre_shared_key in renego_exts: # make sure the PSK is the last extension tmp = renego_exts[ExtensionType.pre_shared_key] del renego_exts[ExtensionType.pre_shared_key] renego_exts[ExtensionType.pre_shared_key] = tmp renego_ciphers = list(ciphers) renego_ciphers.remove(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) node = node.add_child( ClientHelloGenerator(renego_ciphers, extensions=renego_exts, session_id=bytearray(0), modifiers=mods)) node = node.add_child(ExpectServerHello(description="second handshake")) node = node.add_child(ExpectCertificate()) if dhe: node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(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()) node.next_sibling = ExpectClose() conversations["sanity - renegotiation"] = conversation # drop specific extensions in the renegotiated client hello # signature_algorithms and signature_algorithms_cert are covered # by the test-sig-algs-renegotiation-resumption.py for drop_ext, exp_result in [ (ExtensionType.supported_groups, None), (ExtensionType.extended_master_secret, AlertDescription.handshake_failure), (ExtensionType.key_share, None), (ExtensionType.alpn, None), (ExtensionType.ec_point_formats, None), (18, None), # signed_certificate_timestamp (ExtensionType.status_request, None), (ExtensionType.post_handshake_auth, None), (ExtensionType.supported_versions, None), (ExtensionType.psk_key_exchange_modes, None), (ExtensionType.pre_shared_key, None) ]: conversation = Connect(host, port) node = conversation ext = OrderedDict() ext[ExtensionType.signature_algorithms] = \ SignatureAlgorithmsExtension().create(SIG_ALL) ext[ExtensionType.signature_algorithms_cert] = \ SignatureAlgorithmsCertExtension().create(SIG_ALL) groups = [GroupName.secp256r1, GroupName.ffdhe2048] ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\ .create(groups) ext[ExtensionType.extended_master_secret] = AutoEmptyExtension() ext[ExtensionType.key_share] = key_share_ext_gen([GroupName.secp256r1]) ext[ExtensionType.alpn] = \ ALPNExtension().create([bytearray(b'http/1.1')]) ext[ExtensionType.ec_point_formats] = \ ECPointFormatsExtension().create([ ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, ECPointFormat.uncompressed]) # 18 - signed_certificate_timestamp ext[18] = AutoEmptyExtension() ext[ExtensionType.status_request] = \ StatusRequestExtension().create() ext[ExtensionType.post_handshake_auth] = AutoEmptyExtension() # yes, don't include TLS 1.3, as we want to be able to renegotiate... ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\ .create([(3, 3), (3, 2)]) ext[ExtensionType.psk_key_exchange_modes] = \ PskKeyExchangeModesExtension().create( [PskKeyExchangeMode.psk_dhe_ke, PskKeyExchangeMode.psk_ke]) ext[ExtensionType.pre_shared_key] = psk_ext_gen([(b'test', b'pre-shared key')]) if dhe: ciphers = [ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] else: ciphers = [ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(description="first handshake")) node = node.add_child(ExpectCertificate()) if ocsp: node = node.add_child(ExpectCertificateStatus()) if dhe: node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child(ResetHandshakeHashes()) renego_exts = OrderedDict(ext) del renego_exts[drop_ext] # use None for autogeneration of the renegotiation_info with correct # payload renego_exts[ExtensionType.renegotiation_info] = None if ExtensionType.pre_shared_key in renego_exts: # make sure the PSK is the last extension tmp = renego_exts[ExtensionType.pre_shared_key] del renego_exts[ExtensionType.pre_shared_key] renego_exts[ExtensionType.pre_shared_key] = tmp renego_ciphers = list(ciphers) renego_ciphers.remove(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) node = node.add_child( ClientHelloGenerator(renego_ciphers, extensions=renego_exts, session_id=bytearray(0))) if exp_result is not None: node = node.add_child(ExpectAlert(AlertLevel.fatal, exp_result)) node.add_child(ExpectClose()) else: node = node.add_child( ExpectServerHello(description="second handshake")) node = node.add_child(ExpectCertificate()) if dhe: node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(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()) node.next_sibling = ExpectClose() conversations["drop {0} in renegotiation".format( ExtensionType.toStr(drop_ext))] = 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 how server behaves when the renegotiation Client Hello is") print("changed compared to the initial ClientHello.\n") print("If the renegotiation is supposed to be disabled use the") print("test-renegotiation-disabled.py or") print("test-renegotiation-disabled-client-cert.py scripts to verify") print("that.\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 test___init__(self): ext = ECPointFormatsExtension() self.assertIsNotNone(ext) self.assertEqual(ext.extData, bytearray(0)) self.assertEqual(ext.extType, 11)
def main(): host = "localhost" port = 4433 run_exclude = set() argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:", ["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 == '--help': help_msg() sys.exit(0) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None """Test if server supports the ECDHE_RSA key exchange""" conversations = {} conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension().create( [GroupName.secp256r1, GroupName.secp384r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension().create([ECPointFormat.uncompressed]) } node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] node = node.add_child( ClientHelloGenerator( ciphers, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child( ExpectServerHello(extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node.add_child(Close()) conversations["ECDHE w/o extension"] = conversation good = 0 bad = 0 failed = [] # 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'] shuffled_tests = sample(regular_tests, len(regular_tests)) ordered_tests = chain(sanity_tests, shuffled_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 try: runner.run() except: print("Error while processing") print(traceback.format_exc()) res = False if res: good += 1 print("OK") 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(): """Test if server supports the ECDHE_RSA key exchange""" conversations = {} conversation = Connect("localhost", 4433) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1, GroupName.secp384r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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( bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child(AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity check ECDHE_RSA_AES_128"] = conversation good = 0 bad = 0 for conversation_name, conversation in conversations.items(): print("{0} ...".format(conversation_name)) runner = Runner(conversation) res = True try: runner.run() except: print("Error while processing") print(traceback.format_exc()) print("") res = False if res: good += 1 print("OK\n") else: bad += 1 print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad)) if bad > 0: sys.exit(1)
def main(): """Check handling of malformed ECDHE_RSA client key exchange messages""" host = "localhost" port = 4433 num_limit = None run_exclude = set() expected_failures = {} last_exp_tmp = None argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:x:X:", ["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 == '-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 == '--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_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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( bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child(AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation # invalid ecdh_Yc value conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) subst = dict((i, 0x00) for i in range(-1, -65, -1)) subst[-1] = 0x01 node = node.add_child(fuzz_message(ClientKeyExchangeGenerator(), substitutions=subst)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["invalid point (0, 1)"] = conversation # invalid ecdh_Yc value conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # point at infinity doesn't have a defined encoding, but some libraries # encode it as 0, 0, check if it is rejected subst = dict((i, 0x00) for i in range(-1, -65, -1)) node = node.add_child(fuzz_message(ClientKeyExchangeGenerator(), substitutions=subst)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["invalid point (0, 0)"] = conversation # invalid ecdh_Yc value conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(fuzz_message(ClientKeyExchangeGenerator(), substitutions=dict((i, 0x00) for i in range(-1, -33, -1)))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["invalid point (self-inconsistent, y all zero)"] = conversation # invalid ecdh_Yc value conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(fuzz_message(ClientKeyExchangeGenerator(), xors={-1:0xff})) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["invalid point (self-inconsistent)"] = conversation # truncated Client Key Exchange conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(truncate_handshake(ClientKeyExchangeGenerator(), 1)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error)) node = node.add_child(ExpectClose()) conversations["truncated ecdh_Yc value"] = conversation # padded Client Key Exchange conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(pad_handshake(ClientKeyExchangeGenerator(), 1)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error)) node = node.add_child(ExpectClose()) conversations["padded Client Key Exchange"] = 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: 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("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(): """Test if server provides unique ECDHE_RSA key shares.""" host = "localhost" port = 4433 num_limit = None run_exclude = set() repeats = 32 argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:", ["help", "repeat="]) 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) elif opt == '--repeat': repeats = int(arg) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None collected_randoms = [] collected_key_shares = [] collected_session_ids = [] variables_check = \ {'ServerHello.random': collected_randoms, 'ServerKeyExchange.key_share': collected_key_shares, 'ServerHello.session_id': collected_session_ids} groups = [ GroupName.x25519, GroupName.x448, GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1 ] conversations = {} conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] groups_ext = SupportedGroupsExtension().create(groups) points_ext = ECPointFormatsExtension().create([ECPointFormat.uncompressed]) exts = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: groups_ext, ExtensionType.ec_point_formats: points_ext } node = node.add_child(ClientHelloGenerator(ciphers, extensions=exts)) exts = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=exts)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(CopyVariables(variables_check)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation for prot in [(3, 0), (3, 1), (3, 2), (3, 3)]: for ssl2 in [True, False]: for group in groups: # with SSLv2 compatible or with SSLv3 we can't advertise # curves so do just one check if (ssl2 or prot == (3, 0)) and group != groups[0]: continue conversation = Connect(host, port, version=(0, 2) if ssl2 else (3, 0)) node = conversation ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] if ssl2 or prot == (3, 0): exts = None else: groups_ext = SupportedGroupsExtension().create([group]) exts = { ExtensionType.supported_groups: groups_ext, ExtensionType.ec_point_formats: points_ext } node = node.add_child( ClientHelloGenerator(ciphers, version=prot, extensions=exts, ssl2=ssl2)) if prot > (3, 0): if ssl2: ext = {ExtensionType.renegotiation_info: None} else: ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } else: ext = None node = node.add_child( ExpectServerHello(extensions=ext, version=prot)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(CopyVariables(variables_check)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) if prot < (3, 2): # 1/n-1 record splitting node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["Protocol {0}{1}{2}".format( prot, "" if ssl2 or prot < (3, 1) else " with {0} group".format(GroupName.toStr(group)), " in SSLv2 compatible ClientHello" if ssl2 else "")] = \ 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 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 for i in range(repeats): print("\"{1}\" repeat {0}...".format(i, 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) failed_tests = uniqueness_check(variables_check, good + bad) if failed_tests: print("\n".join(failed_tests)) else: print("\n".join("{0} values: OK".format(i) for i in variables_check)) print('') print("Check if the server provided random values are unique") print("Checks random and session_id from Server Hello and ECDHE key share") print("Note: not supporting ECDHE in SSLv3 or with SSLv2 Client Hello is") print("valid behaviour, as the client can't advertise groups it supports") print("there.") print("version: {0}\n".format(version)) print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad + len(failed_tests))) failed_sorted = sorted(failed, key=natural_sort_keys) print(" {0}".format('\n '.join(repr(i) for i in failed_sorted))) if bad > 0 or failed_tests: sys.exit(1)
def main(): """Check handling of malformed ECDHE_RSA client key exchange messages""" conversations = {} conversation = Connect("localhost", 4433) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension().create( [GroupName.secp256r1, GroupName.secp384r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension().create([ECPointFormat.uncompressed]) } node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity check ECDHE_RSA_AES_128"] = conversation # invalid ecdh_Yc value conversation = Connect("localhost", 4433) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension().create( [GroupName.secp256r1, GroupName.secp384r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension().create([ECPointFormat.uncompressed]) } node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child( fuzz_message(ClientKeyExchangeGenerator(), xors={-1: 0xff})) node = node.add_child(ChangeCipherSpecGenerator()) # node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectAlert()) node = node.add_child(ExpectClose()) conversations["invalid point (self-inconsistent)"] = conversation # truncated Client Key Exchange conversation = Connect("localhost", 4433) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension().create( [GroupName.secp256r1, GroupName.secp384r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension().create([ECPointFormat.uncompressed]) } node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(truncate_handshake(ClientKeyExchangeGenerator(), 1)) # node = node.add_child(ChangeCipherSpecGenerator()) # node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectAlert()) node = node.add_child(ExpectClose()) conversations["truncated ecdh_Yc value"] = conversation # padded Client Key Exchange conversation = Connect("localhost", 4433) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension().create( [GroupName.secp256r1, GroupName.secp384r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension().create([ECPointFormat.uncompressed]) } node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(pad_handshake(ClientKeyExchangeGenerator(), 1)) # node = node.add_child(ChangeCipherSpecGenerator()) # node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectAlert()) node = node.add_child(ExpectClose()) conversations["padded Client Key Exchange"] = conversation good = 0 bad = 0 for conversation_name, conversation in conversations.items(): print("{0} ...".format(conversation_name)) runner = Runner(conversation) res = True try: runner.run() except: print("Error while processing") print(traceback.format_exc()) print("") res = False if res: good += 1 print("OK\n") else: bad += 1 print("Test end") print("successful: {0}".format(good)) print("failed: {0}".format(bad)) if bad > 0: sys.exit(1)
def main(): host = "localhost" port = 4433 run_exclude = set() argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:", ["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 == '--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 = {} # check if server selects ECDHE when fully specified conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) cipher = CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA node = node.add_child(ExpectServerHello(version=(3, 3), cipher=cipher)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["sanity"] = conversation # check if server selects compatible group if none is selected conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) cipher = CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA node = node.add_child(ExpectServerHello(version=(3, 3), cipher=cipher)) node = node.add_child(ExpectCertificate()) groups = [GroupName.secp256r1] node = node.add_child(ExpectServerKeyExchange(valid_groups=groups)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["default to P-256 when no groups specified"] = conversation # check if server selects compatible group and hash when none specified conversation = Connect(host, port) node = conversation ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers)) cipher = CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA node = node.add_child(ExpectServerHello(version=(3, 3), cipher=cipher)) node = node.add_child(ExpectCertificate()) groups = [GroupName.secp256r1] node = node.add_child(ExpectServerKeyExchange(valid_groups=groups)) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations[ "default to P-256/sha-1 when no extensions specified"] = conversation # check if server will fallback to to other cipher when no groups # are acceptable conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.sect163k1] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) cipher = CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA node = node.add_child(ExpectServerHello(version=(3, 3), cipher=cipher)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["only secp163k1 group - fallback to DHE"] = conversation # check if server will fallback to to other cipher when no groups # are defined conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [11200] # unknown ECDHE group ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) cipher = CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA node = node.add_child(ExpectServerHello(version=(3, 3), cipher=cipher)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["only unknown group - fallback to DHE"] = conversation # check if server will abort if no group is acceptable and no fallback # is possible conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [11200] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.handshake_failure)) node = node.add_child(ExpectClose()) conversations["only unknown group - no fallback to DHE"] = conversation # check if server will not negotiate x25519 conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519, GroupName.x448] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations[ "only x25519 and x448 groups - allow for DHE fallback"] = conversation # check if server will abort if x25519 is not support conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519, GroupName.x448] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations[ "only x25519 and x448 groups - no fallback to DHE possible"] = conversation # check if server will negotiate X25519 with compression supported conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } ext[ExtensionType.ec_point_formats] = \ ECPointFormatsExtension().create([ECPointFormat.ansiX962_compressed_prime, ECPointFormat.ansiX962_compressed_char2, ECPointFormat.uncompressed]) groups = [GroupName.x25519] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["EC point format - all types - x25519"] = conversation # check if server will negotiate X25519 with typical EC point format ext conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } ext[ExtensionType.ec_point_formats] = \ ECPointFormatsExtension().create([ECPointFormat.uncompressed]) groups = [GroupName.x25519] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations[ "EC point format - only uncompressed - x25519"] = conversation # check if server will negotiate X25519 conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["sanity - negotiate x25519"] = conversation # check if server will negotiate X448 conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x448] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node = node.add_child(ExpectClose()) conversations["sanity - negotiate x448"] = conversation # check if server will reject too small x25519 share # (one with too few bytes in the key share) conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator(ecdh_Yc=bytearray([55] * (X25519_ORDER_SIZE - 1)))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["too small x25519 key share"] = conversation # check if server will reject empty x25519 share conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child(ClientKeyExchangeGenerator(ecdh_Yc=bytearray())) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) # since the ECPoint is defined as <1..2^8-1>, zero length value is an # incorrect encoding node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error)) node = node.add_child(ExpectClose()) conversations["empty x25519 key share"] = conversation # check if server will reject too big x25519 share # (one with too many bytes in the key share) conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator(ecdh_Yc=bytearray([55] * (X25519_ORDER_SIZE + 1)))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["too big x25519 key share"] = conversation # check if server will reject x25519 share with high order bit set # per draft-ietf-tls-rfc4492bis: # # Since there are some implementation of the X25519 function that # impose this restriction on their input and others that don't, # implementations of X25519 in TLS SHOULD reject public keys when the # high-order bit of the final byte is set conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519] # ecdh_x25519 ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator( ecdh_Yc=bytearray([55] * (X25519_ORDER_SIZE - 1) + [0x80]))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) # Because we are sending a key exchange with a public value for which # we do not know the private valye, the Finished message will be encrypted # using incorrect keys, so expect a failure that shows that node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.bad_record_mac)) node = node.add_child(ExpectClose()) conversations["x25519 key share with high bit set"] = conversation # check if server will reject empty x448 share conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x448] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child(ClientKeyExchangeGenerator(ecdh_Yc=bytearray())) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) # since the ECPoint is defined as <1..2^8-1>, zero length value is an # incorrect encoding node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error)) node = node.add_child(ExpectClose()) conversations["empty x448 key share"] = conversation # check if server will reject too small x448 share conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x448] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator(ecdh_Yc=bytearray([55] * (X448_ORDER_SIZE - 1)))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["too small x448 key share"] = conversation # check if server will reject too big x448 share conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x448] # ecdh_x448 ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator(ecdh_Yc=bytearray([55] * (X448_ORDER_SIZE + 1)))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["too big x448 key share"] = conversation # check if server will reject an all-zero key share for x25519 # (it should result in all-zero shared secret) conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator(ecdh_Yc=bytearray(X25519_ORDER_SIZE))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["all zero x25519 key share"] = conversation # check if server will reject an all-zero key share for x448 # (it should result in all-zero shared secret) conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x448] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator(ecdh_Yc=bytearray(X448_ORDER_SIZE))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["all zero x448 key share"] = conversation # check if server will reject a key share or 1 for x25519 # (it should result in all-zero shared secret) conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x25519] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator( ecdh_Yc=numberToByteArray(1, X25519_ORDER_SIZE, "little"))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["x25519 key share of \"1\""] = conversation # check if server will reject a key share of 1 for x448 # (it should result in all-zero shared secret) conversation = Connect(host, port) node = conversation sigs = [(HashAlgorithm.sha512, SignatureAlgorithm.rsa), (HashAlgorithm.sha384, SignatureAlgorithm.rsa), (HashAlgorithm.sha256, SignatureAlgorithm.rsa), (HashAlgorithm.sha1, SignatureAlgorithm.rsa)] ext = { ExtensionType.signature_algorithms: SignatureAlgorithmsExtension().create(sigs), ExtensionType.signature_algorithms_cert: SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL) } groups = [GroupName.x448] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ciphers = [ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV ] node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) node = node.add_child( ClientKeyExchangeGenerator( ecdh_Yc=numberToByteArray(1, X448_ORDER_SIZE, "little"))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(TCPBufferingDisable()) node = node.add_child( ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["x448 key share of \"1\""] = conversation # run the conversation good = 0 bad = 0 failed = [] # 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], filter(lambda x: x[0] != 'sanity', conversations.items()), [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: 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("Basic test to verify that server selects sane ECDHE parameters and") print("ciphersuites when x25519 curve is an option\n") 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 handling of malformed ECDHE_RSA client key exchange messages""" host = "localhost" port = 4433 run_exclude = set() argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:", ["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 == '--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_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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( bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child(AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation # invalid ecdh_Yc value conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) subst = dict((i, 0x00) for i in range(-1, -65, -1)) subst[-1] = 0x01 node = node.add_child(fuzz_message(ClientKeyExchangeGenerator(), substitutions=subst)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["invalid point (0, 1)"] = conversation # invalid ecdh_Yc value conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # point at infinity doesn't have a defined encoding, but some libraries # encode it as 0, 0, check if it is rejected subst = dict((i, 0x00) for i in range(-1, -65, -1)) node = node.add_child(fuzz_message(ClientKeyExchangeGenerator(), substitutions=subst)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["invalid point (0, 0)"] = conversation # invalid ecdh_Yc value conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(fuzz_message(ClientKeyExchangeGenerator(), substitutions=dict((i, 0x00) for i in range(-1, -33, -1)))) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["invalid point (self-inconsistent, y all zero)"] = conversation # invalid ecdh_Yc value conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(fuzz_message(ClientKeyExchangeGenerator(), xors={-1:0xff})) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node = node.add_child(ExpectClose()) conversations["invalid point (self-inconsistent)"] = conversation # truncated Client Key Exchange conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(truncate_handshake(ClientKeyExchangeGenerator(), 1)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error)) node = node.add_child(ExpectClose()) conversations["truncated ecdh_Yc value"] = conversation # padded Client Key Exchange conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = {ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension(). create([GroupName.secp256r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension(). create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = {ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None} node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(TCPBufferingEnable()) # uncompressed EC points need to be self consistent, by changing # one coordinate without changing the other we create an invalid point node = node.add_child(pad_handshake(ClientKeyExchangeGenerator(), 1)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error)) node = node.add_child(ExpectClose()) conversations["padded Client Key Exchange"] = conversation good = 0 bad = 0 failed = [] # 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], filter(lambda x: x[0] != 'sanity', conversations.items()), [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: 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 obsolete signature algorithm is rejected by server""" host = "localhost" port = 4433 num_limit = 10 run_exclude = set() expected_failures = {} last_exp_tmp = None private_key = None cert = None argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:x:X:n:k:c:", ["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 == '-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 == '--help': help_msg() sys.exit(0) elif opt == '-k': text_key = open(arg, 'rb').read() if sys.version_info[0] >= 3: text_key = str(text_key, 'utf-8') private_key = parsePEMKey(text_key, private=True) elif opt == '-c': text_cert = open(arg, 'rb').read() if sys.version_info[0] >= 3: text_cert = str(text_cert, 'utf-8') cert = X509() cert.parse(text_cert) else: raise ValueError("Unknown option: {0}".format(opt)) if not private_key: raise ValueError("Specify private key file using -k") if not cert: raise ValueError("Specify certificate file using -c") if args: run_only = set(args) else: run_only = None conversations = {} # sanity check for Client Certificates conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {ExtensionType.signature_algorithms : SignatureAlgorithmsExtension().create(ECDSA_SIG_ALL + RSA_SIG_ALL), ExtensionType.signature_algorithms_cert : SignatureAlgorithmsCertExtension().create(ECDSA_SIG_ALL + RSA_SIG_ALL), ExtensionType.supported_groups : SupportedGroupsExtension().create([ GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1]), ExtensionType.ec_point_formats : ECPointFormatsExtension().create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectCertificateRequest()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(CertificateGenerator(X509CertChain([cert]))) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(CertificateVerifyGenerator(private_key)) 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\n\n")) node = node.add_child(ExpectApplicationData()) node = node.add_child(AlertGenerator(AlertDescription.close_notify)) node = node.add_child(ExpectClose()) node.next_sibling = ExpectAlert() node.next_sibling.add_child(ExpectClose()) conversations["sanity"] = conversation # force MD5 signature on CertificateVerify conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {ExtensionType.signature_algorithms : SignatureAlgorithmsExtension().create(ECDSA_SIG_ALL + RSA_SIG_ALL), ExtensionType.signature_algorithms_cert : SignatureAlgorithmsCertExtension().create(ECDSA_SIG_ALL + RSA_SIG_ALL), ExtensionType.supported_groups : SupportedGroupsExtension().create([ GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1]), ExtensionType.ec_point_formats : ECPointFormatsExtension().create([ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectCertificateRequest()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(CertificateGenerator(X509CertChain([cert]))) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(TCPBufferingEnable()) sig_type = (HashAlgorithm.md5, SignatureAlgorithm.ecdsa) node = node.add_child(CertificateVerifyGenerator(private_key, msg_alg=sig_type )) # the other side can close connection right away, add options to handle it node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) # we expect closure or Alert and then closure of socket node = node.add_child(ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter)) node.add_child(ExpectClose()) conversations["md5+ecdsa forced"] = conversation for h_alg in ["sha512", "sha384", "sha256", "sha224", "sha1"]: for real_h_alg in ["sha512", "sha384", "sha256", "sha224", "sha1"]: conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] ext = {ExtensionType.signature_algorithms : SignatureAlgorithmsExtension().create(ECDSA_SIG_ALL + RSA_SIG_ALL), ExtensionType.signature_algorithms_cert : SignatureAlgorithmsCertExtension().create(ECDSA_SIG_ALL + RSA_SIG_ALL), ExtensionType.supported_groups : SupportedGroupsExtension().create([ GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1]), ExtensionType.ec_point_formats : ECPointFormatsExtension().create([ ECPointFormat.uncompressed])} node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) node = node.add_child(ExpectServerHello(version=(3, 3))) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectCertificateRequest()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(CertificateGenerator(X509CertChain([cert]))) node = node.add_child(ClientKeyExchangeGenerator()) alg = (getattr(HashAlgorithm, h_alg), SignatureAlgorithm.ecdsa) real_alg = (getattr(HashAlgorithm, real_h_alg), SignatureAlgorithm.ecdsa) if alg == real_alg: node = node.add_child(CertificateVerifyGenerator( private_key, msg_alg=alg, sig_alg=real_alg)) 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\n\n")) node = node.add_child(ExpectApplicationData()) node = node.add_child(AlertGenerator( AlertDescription.close_notify)) node = node.add_child(ExpectClose()) node.next_sibling = ExpectAlert() node.next_sibling.add_child(ExpectClose()) conversations["make {0}+ecdsa signature in CertificateVerify" .format(h_alg)] = conversation else: node = node.add_child(TCPBufferingEnable()) node = node.add_child(CertificateVerifyGenerator( private_key, msg_alg=alg, sig_alg=real_alg)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(TCPBufferingDisable()) node = node.add_child(TCPBufferingFlush()) node = node.add_child(ExpectAlert( AlertLevel.fatal, AlertDescription.decrypt_error)) node = node.add_child(ExpectClose()) conversations["make {0}+ecdsa signature, advertise it as " "{1}+ecdsa in CertificateVerify" .format(h_alg, real_h_alg)] = 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 throught 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 support for ECDSA signatures in CertificateVerify\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() expected_failures = {} last_exp_tmp = None argv = sys.argv[1:] opts, args = getopt.getopt(argv, "h:p:e:n:x:X:", ["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 == '-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 == '--help': help_msg() sys.exit(0) else: raise ValueError("Unknown option: {0}".format(opt)) if args: run_only = set(args) else: run_only = None """Test if server supports the ECDHE_RSA key exchange""" conversations = {} conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] ext = { ExtensionType.renegotiation_info: None, ExtensionType.supported_groups: SupportedGroupsExtension().create( [GroupName.secp256r1, GroupName.secp384r1]), ExtensionType.ec_point_formats: ECPointFormatsExtension().create([ECPointFormat.uncompressed]) } node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext)) ext = { ExtensionType.renegotiation_info: None, ExtensionType.ec_point_formats: None } node = node.add_child(ExpectServerHello(extensions=ext)) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) 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(bytearray(b"GET / HTTP/1.0\n\n"))) node = node.add_child(ExpectApplicationData()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() conversations["sanity"] = conversation conversation = Connect(host, port) node = conversation ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA] node = node.add_child( ClientHelloGenerator( ciphers, extensions={ExtensionType.renegotiation_info: None})) node = node.add_child( ExpectServerHello(extensions={ExtensionType.renegotiation_info: None})) node = node.add_child(ExpectCertificate()) node = node.add_child(ExpectServerKeyExchange()) node = node.add_child(ExpectServerHelloDone()) node = node.add_child(ClientKeyExchangeGenerator()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child(ExpectAlert()) node.next_sibling = ExpectClose() node.add_child(Close()) conversations["ECDHE w/o extension"] = 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: 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") else: bad += 1 failed.append(c_name) 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 or xpass: sys.exit(1)
def test(self): sock = MockSocket(server_hello_ciphertext) record_layer = RecordLayer(sock) ext = [SNIExtension().create(bytearray(b'server')), TLSExtension(extType=ExtensionType.renegotiation_info) .create(bytearray(b'\x00')), SupportedGroupsExtension().create([GroupName.x25519, GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1, GroupName.ffdhe2048, GroupName.ffdhe3072, GroupName.ffdhe4096, GroupName.ffdhe6144, GroupName.ffdhe8192]), ECPointFormatsExtension().create([ECPointFormat.uncompressed]), TLSExtension(extType=35), ClientKeyShareExtension().create([KeyShareEntry().create(GroupName.x25519, client_key_public, client_key_private)]), SupportedVersionsExtension().create([TLS_1_3_DRAFT, (3, 3), (3, 2)]), SignatureAlgorithmsExtension().create([(HashAlgorithm.sha256, SignatureAlgorithm.ecdsa), (HashAlgorithm.sha384, SignatureAlgorithm.ecdsa), (HashAlgorithm.sha512, SignatureAlgorithm.ecdsa), (HashAlgorithm.sha1, SignatureAlgorithm.ecdsa), SignatureScheme.rsa_pss_sha256, SignatureScheme.rsa_pss_sha384, SignatureScheme.rsa_pss_sha512, SignatureScheme.rsa_pkcs1_sha256, SignatureScheme.rsa_pkcs1_sha384, SignatureScheme.rsa_pkcs1_sha512, SignatureScheme.rsa_pkcs1_sha1, (HashAlgorithm.sha256, SignatureAlgorithm.dsa), (HashAlgorithm.sha384, SignatureAlgorithm.dsa), (HashAlgorithm.sha512, SignatureAlgorithm.dsa), (HashAlgorithm.sha1, SignatureAlgorithm.dsa)]), TLSExtension(extType=45).create(bytearray(b'\x01\x01')), TLSExtension(extType=ExtensionType.client_hello_padding) .create(bytearray(252)) ] client_hello = ClientHello() client_hello.create((3, 3), bytearray(b'\xaf!\x15k\x04\xdbc\x9ef\x15J\x1f\xe5' b'\xad\xfa\xea\xdf\x9eA4\x16\x00\rW\xb8' b'\xe1\x12mM\x11\x9a\x8b'), bytearray(b''), [CipherSuite.TLS_AES_128_GCM_SHA256, CipherSuite.TLS_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_AES_256_GCM_SHA384, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 0xCCA9, CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, 0x0032, CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 0x0038, CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 0x0013, CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256, CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA, CipherSuite.TLS_RSA_WITH_RC4_128_SHA, CipherSuite.TLS_RSA_WITH_RC4_128_MD5], extensions=ext) self.assertEqual(client_hello.write(), client_hello_ciphertext[5:]) for result in record_layer.recvRecord(): # check if non-blocking self.assertNotIn(result, (0, 1)) header, parser = result hs_type = parser.get(1) self.assertEqual(hs_type, HandshakeType.server_hello) server_hello = ServerHello().parse(parser) self.assertEqual(server_hello.server_version, TLS_1_3_DRAFT) self.assertEqual(server_hello.cipher_suite, CipherSuite.TLS_AES_128_GCM_SHA256) server_key_share = server_hello.getExtension(ExtensionType.key_share) server_key_share = server_key_share.server_share self.assertEqual(server_key_share.group, GroupName.x25519) # for TLS_AES_128_GCM_SHA256: prf_name = 'sha256' prf_size = 256 // 8 secret = bytearray(prf_size) psk = bytearray(prf_size) # early secret secret = secureHMAC(secret, psk, prf_name) self.assertEqual(secret, str_to_bytearray( "33ad0a1c607ec03b 09e6cd9893680ce2" "10adf300aa1f2660 e1b22e10f170f92a")) # derive secret for handshake secret = derive_secret(secret, b"derived", None, prf_name) self.assertEqual(secret, str_to_bytearray( "6f2615a108c702c5 678f54fc9dbab697" "16c076189c48250c ebeac3576c3611ba")) # extract secret "handshake" Z = x25519(client_key_private, server_key_share.key_exchange) self.assertEqual(Z, str_to_bytearray( "f677c3cdac26a755 455b130efa9b1a3f" "3cafb153544ca46a ddf670df199d996e")) secret = secureHMAC(secret, Z, prf_name) self.assertEqual(secret, str_to_bytearray( "0cefce00d5d29fd0 9f5de36c86fc8e72" "99b4ad11ba4211c6 7063c2cc539fc4f9")) handshake_hashes = HandshakeHashes() handshake_hashes.update(client_hello_plaintext) handshake_hashes.update(server_hello_payload) # derive "tls13 c hs traffic" c_hs_traffic = derive_secret(secret, bytearray(b'c hs traffic'), handshake_hashes, prf_name) self.assertEqual(c_hs_traffic, str_to_bytearray( "5a63db760b817b1b da96e72832333aec" "6a177deeadb5b407 501ac10c17dac0a4")) s_hs_traffic = derive_secret(secret, bytearray(b's hs traffic'), handshake_hashes, prf_name) self.assertEqual(s_hs_traffic, str_to_bytearray( "3aa72a3c77b791e8 f4de243f9ccce172" "941f8392aeb05429 320f4b572ccfe744")) # derive master secret secret = derive_secret(secret, b"derived", None, prf_name) self.assertEqual(secret, str_to_bytearray( "32cadf38f3089048 5c54bf4f1184eaa5" "569eeef15a43f3c7 6ab33965a47c9ff6")) # extract secret "master secret = secureHMAC(secret, bytearray(prf_size), prf_name) self.assertEqual(secret, str_to_bytearray( "6c6d4b3e7c925460 82d7b7a32f6ce219" "3804f1bb930fed74 5c6b93c71397f424"))
def conv_generator(conf, host, port, sni_hostname, cert=None, key=None): """Generate a conversation based on dict with configuration.""" root = Connect(host, port) hs = HandshakeSettings() # only RSA is supported if conf['Server_authentication'] != "RSA" and \ conf['Server_authentication'] != "anon": print("Substituting {0} to RSA for server auth".format( conf['Server_authentication']), file=sys.stderr) # get the cipher that matches the imposed restrictions cipher_trans = { "AES_128_CBC": "aes128", "AES_256_CBC": "aes256", "AES_128_GCM": "aes128gcm", "AES_256_GCM": "aes256gcm", "3DES_EDE_CBC": "3des", "RC4": "rc4", "Chacha20_Poly1305": "chacha20-poly1305" } hs.cipherNames = [cipher_trans.get(conf['Cipher'], None)] if hs.cipherNames == [None]: raise ValueError("Unknown cipher type: {0}".format(conf['Cipher'])) mac_trans = { "AEAD": "aead", "MD5_HMAC": "md5", "SHA1_HMAC": "sha", "SHA256_HMAC": "sha256", "SHA384_HMAC": "sha384" } hs.macNames = [mac_trans.get(conf['Integrity'], None)] if hs.macNames == [None]: raise ValueError("Unknown integrity type: {0}".format( conf['Integrity'])) if conf['Key_exchange'] == 'DHE' and \ conf['Server_authentication'] == "anon": suites = CipherSuite.getAnonSuites(hs) elif conf['Key_exchange'] == 'ECDHE' and \ conf['Server_authentication'] == "anon": suites = CipherSuite.getEcdhAnonSuites(hs) elif conf['Key_exchange'] == 'RSA': suites = CipherSuite.getCertSuites(hs) elif conf['Key_exchange'] == 'DHE': suites = CipherSuite.getDheCertSuites(hs) elif conf['Key_exchange'] == 'ECDHE': suites = CipherSuite.getEcdheCertSuites(hs) else: raise ValueError("Unknown key exchange type: {0}".format( conf['Key_exchange'])) if not suites: raise ValueError( "Couldn't find matching cipher for {0} {3} {1} {2}".format( conf['Key_exchange'], conf['Cipher'], conf['Integrity'], conf['Server_authentication'])) # session ID/resumption handling if conf['CH_SessionID'] == 'random': sess_ID = getRandomBytes(16) elif conf['CH_SessionID'] == 'empty': sess_ID = bytearray() else: raise ValueError("Unknown CH_SessionID value".format( conf['CH_SessionID'])) # compression if conf['CH_compression'] == 'null_only': compress = [0] elif conf['CH_compression'] == 'null_and_deflate': compress = [0, 1] else: raise ValueError("Unknown CH_compression value: {0}".format( conf['CH_compression'])) # Renegotiation Info if conf['CH_renegotiation_info_SCSV'] == "first": suites.insert(0, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) elif conf['CH_renegotiation_info_SCSV'] == "last": suites.append(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) elif conf['CH_renegotiation_info_SCSV'] == "absent": pass elif conf['CH_renegotiation_info_SCSV'] == "second": suites.append(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) suites.append(0xeaea) # GREASE else: raise ValueError( "Unexpected CH_renegotiation_info_SCSV value: {0}".format( conf['CH_renegotiation_info_SCSV'])) # whether to send extensions if conf['CH_extensions_present'] == "false": ext = None elif conf['CH_extensions_present'] != "true": raise ValueError("Unexpected CH_extensions_present value: {0}".format( conf['CH_extensions_present'])) else: ext = dict() # session ticket if conf['CH_session_ticket'] != "no_ext": print("Not generating session ticket extension", file=sys.stderr) # renegotiation info if conf['CH_renegotiation_info_ext'] == "true": ext[ExtensionType.renegotiation_info] = \ RenegotiationInfoExtension().create(bytearray()) elif conf['CH_renegotiation_info_ext'] == "false": pass else: raise ValueError( "Unknown option in CH_renegotiation_info_ext: {0}".format( conf['CH_renegotiation_info_ext'])) # signature algorithms if conf['CH_signature_algorithms_ext'] == "false": pass elif conf['CH_signature_algorithms_ext'] != "true": raise ValueError( "Unknown option CH_signature_algorithms_ext: {0}".format( conf["CH_signature_algorithms_ext"])) else: sig = conf['SKE_signature_scheme'] if sig == "none" or sig == "no_message": # enter some random ones: ext[ExtensionType.signature_algorithms] = \ SignatureAlgorithmsExtension()\ .create([SignatureScheme.rsa_pkcs1_sha256, SignatureScheme.rsa_pss_sha256]) else: if "dsa" in sig: print("Changing {0} to RSA scheme".format(sig)) sig = sig.replace("ecdsa", "rsa") sig = sig.replace("dsa", "rsa") sig = sig.replace("rsa_sha", "rsa_pkcs1_sha") sig = sig.replace("rsapss", "rsa_pss") if "sha224" in sig: scheme = (HashAlgorithm.sha224, SignatureAlgorithm.rsa) else: scheme = getattr(SignatureScheme, sig) ext[ExtensionType.signature_algorithms] = \ SignatureAlgorithmsExtension()\ .create([scheme]) # supported groups extension if conf['CH_supported_groups_ext'] == "false": groups = [ GroupName.ffdhe2048, GroupName.secp256r1, GroupName.x25519 ] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) pass elif conf['CH_supported_groups_ext'] != "true": raise ValueError( "Unknown option in CH_supported_groups_ext: {0}".format( conf['CH_supported_groups_ext'])) else: if conf['SKE_dh_group'] == "no_message": groups = [ GroupName.ffdhe2048, GroupName.secp256r1, GroupName.x25519 ] elif conf['SKE_dh_group'] == "ffdhe1024": groups = [GroupName.secp256r1, GroupName.x25519] else: groups = [getattr(GroupName, conf['SKE_dh_group'])] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ext[ExtensionType.ec_point_formats] = \ ECPointFormatsExtension()\ .create([ECPointFormat.uncompressed, ECPointFormat.ansiX962_compressed_char2, ECPointFormat.ansiX962_compressed_prime]) # encrypt then MAC if conf['CH_encrypt_then_mac_ext'] == "false": pass elif conf['CH_encrypt_then_mac_ext'] != "true": raise ValueError( "Unknown option in CH_encrypt_then_mac_ext: {0}".format( conf['CH_encrypt_then_mac_ext'])) else: ext[ExtensionType.encrypt_then_mac] = \ TLSExtension(extType=ExtensionType.encrypt_then_mac)\ .create(bytearray(0)) # server name if conf['CH_server_name'] == "no_ext": pass elif conf['CH_server_name'] == "correct": ext[ExtensionType.server_name] = \ SNIExtension().create(sni_hostname) elif conf['CH_server_name'] == "mismatch": ext[ExtensionType.server_name] = \ SNIExtension().create(sni_hostname + b'.www') else: raise ValueError("Unknown option in CH_server_name: {0}".format( conf['CH_server_name'])) # OCSP staple if conf['CH_status_request_ext'] == "false": pass elif conf['CH_status_request_ext'] != "true": raise ValueError( "Unknown option in CH_status_request_ext: {0}".format( conf['CH_status_request_ext'])) else: ext[ExtensionType.status_request] = \ StatusRequestExtension().create() # Extended Master Secret ext if conf['CH_extended_master_secret_ext'] == "false": pass elif conf['CH_extended_master_secret_ext'] != "true": raise ValueError( ("Unknown value in CH_extended_master_secret_ext" ": {0}").format(conf['CH_extended_master_secret_ext'])) else: ext[ExtensionType.extended_master_secret] = \ TLSExtension(extType=ExtensionType.extended_master_secret)\ .create(bytearray()) # # node = root.add_child( ClientHelloGenerator(suites, session_id=sess_ID, compression=compress, extensions=ext)) if conf['CH_server_name'] == "mismatch": node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.unrecognized_name)) al_node = node node = node.add_child(ExpectServerHello()) if conf['CH_server_name'] == "mismatch": # make the sending of warning alert node optional al_node.next_sibling = node node = node.add_child(ExpectCertificate()) # TODO if conf['Certificate_Status_msg'] if conf['SKE_dh_group'] != "no_message": node = node.add_child(ExpectServerKeyExchange()) if conf['CR_sent'] == "true": node = node.add_child(ExpectCertificateRequest()) elif conf['CR_sent'] != "false": raise ValueError("Unknown option in CR_sent: {0}".format( conf['CR_sent'])) node = node.add_child(ExpectServerHelloDone()) if conf['CR_sent'] == "true": if conf['CV_signature_scheme'] == "no_message": node = node.add_child(CertificateGenerator()) else: node = node.add_child(CertificateGenerator(X509CertChain([cert]))) node = node.add_child(ClientKeyExchangeGenerator()) if conf['CV_signature_scheme'] != "no_message": sig = conf['CV_signature_scheme'] if "dsa" in sig: print("Changing {0} to RSA scheme in CV".format(sig)) sig = sig.replace("ecdsa", "rsa") sig = sig.replace("dsa", "rsa") sig = sig.replace("rsa_sha", "rsa_pkcs1_sha") sig = sig.replace("rsapss", "rsa_pss") if "sha224" in sig: scheme = (HashAlgorithm.sha224, SignatureAlgorithm.rsa) else: scheme = getattr(SignatureScheme, sig) node = node.add_child(CertificateVerifyGenerator(key, msg_alg=scheme)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) if conf['Disconnect'] == "true": 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(node.next_sibling) node = node.add_child(Connect(host, port)) node = node.add_child(ResetRenegotiationInfo()) node = node.add_child(ResetHandshakeHashes()) hs = HandshakeSettings() hs.cipherNames = [cipher_trans.get(conf['H2Cipher'], None)] if hs.cipherNames == [None]: raise ValueError("Unknown cipher type: {0}".format(conf['H2Cipher'])) hs.macNames = [mac_trans.get(conf["H2Integrity"], None)] if hs.macNames == [None]: raise ValueError("Unknown integrity type: {0}".format( conf['H2Integrity'])) if conf['H2Key_exchange'] == 'DHE' and \ conf['H2Server_authentication'] == "anon": suites = CipherSuite.getAnonSuites(hs) elif conf['H2Key_exchange'] == "ECDHE" and \ conf['H2Server_authentication'] == "anon": suites = CipherSuite.getEcdhAnonSuites(hs) elif conf['H2Key_exchange'] == "RSA": suites = CipherSuite.getCertSuites(hs) elif conf['H2Key_exchange'] == "DHE": suites = CipherSuite.getDheCertSuites(hs) elif conf['H2Key_exchange'] == "ECDHE": suites = CipherSuite.getEcdheCertSuites(hs) else: raise ValueError("Unknown key exchange type: {0}".format( conf['H2Key_exchange'])) if not suites: raise ValueError( "Couldn't find matching cipher for {0} {3} {1} {2}".format( conf['H2Key_exchange'], conf['H2Cipher'], conf['H2Integrity'], conf['H2Server_authentication'])) if conf['H2CH_SessionID'] == 'random': sess_ID = getRandomBytes(16) elif conf['H2CH_SessionID'] == 'empty': sess_ID = bytearray() elif conf['H2CH_SessionID'] == "resume": sess_ID = None else: raise ValueError("Unknown session id value: {0}".format( conf['H2CH_SessionID'])) # compression if conf['H2CH_compression'] == 'null_only': compress = [0] elif conf['H2CH_compression'] == 'null_and_deflate': compress = [0, 1] else: raise ValueError("Unknown H2CH_compression value: {0}".format( conf['H2CH_compression'])) # Renegotiation Info if conf['H2CH_renegotiation_info_SCSV'] == "first": suites.insert(0, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) elif conf['H2CH_renegotiation_info_SCSV'] == "last": suites.append(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) elif conf['H2CH_renegotiation_info_SCSV'] == "absent": pass elif conf['H2CH_renegotiation_info_SCSV'] == "second": suites.append(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV) suites.append(0xeaea) # GREASE else: raise ValueError( "Unexpected H2CH_renegotiation_info_SCSV value: {0}".format( conf['H2CH_renegotiation_info_SCSV'])) # whether to send extensions if conf['H2CH_extensions_present'] == "false": ext = None elif conf['H2CH_extensions_present'] != "true": raise ValueError("Unexpected CH_extensions_present value: {0}".format( conf['H2CH_extensions_present'])) else: ext = dict() # session ticket if conf['H2CH_session_ticket'] != "no_ext": print("Not generating session ticket extension", file=sys.stderr) # renegotiation info if conf['H2CH_renegotiation_info_ext'] == "true": ext[ExtensionType.renegotiation_info] = None elif conf['H2CH_renegotiation_info_ext'] == "false": pass else: raise ValueError("Unknown option in H2CH_renegotiation_info_ext: " "{0}".format(conf['H2CH_renegotiation_info_ext'])) # signature algorithms if conf['H2CH_signature_algorithms_ext'] == "false": pass elif conf['H2CH_signature_algorithms_ext'] != "true": raise ValueError("Unknown option H2CH_signature_algorithms_ext: " "{0}".format( conf["H2CH_signature_algorithms_ext"])) else: sig = conf['H2SKE_signature_scheme'] if sig == "none" or sig == "no_message": # enter some random ones: ext[ExtensionType.signature_algorithms] = \ SignatureAlgorithmsExtension()\ .create([SignatureScheme.rsa_pkcs1_sha256, SignatureScheme.rsa_pss_sha256]) else: if "dsa" in sig: print("Changing {0} to RSA scheme".format(sig)) sig = sig.replace("ecdsa", "rsa") sig = sig.replace("dsa", "rsa") sig = sig.replace("rsa_sha", "rsa_pkcs1_sha") sig = sig.replace("rsapss", "rsa_pss") if "sha224" in sig: scheme = (HashAlgorithm.sha224, SignatureAlgorithm.rsa) else: scheme = getattr(SignatureScheme, sig) ext[ExtensionType.signature_algorithms] = \ SignatureAlgorithmsExtension()\ .create([scheme]) # supported groups extension if conf['H2CH_supported_groups_ext'] == "false": groups = [ GroupName.ffdhe2048, GroupName.secp256r1, GroupName.x25519 ] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) pass elif conf['H2CH_supported_groups_ext'] != "true": raise ValueError( "Unknown option in H2CH_supported_groups_ext: {0}".format( conf['H2CH_supported_groups_ext'])) else: if conf['H2SKE_dh_group'] == "no_message": groups = [ GroupName.ffdhe2048, GroupName.secp256r1, GroupName.x25519 ] elif conf['H2SKE_dh_group'] == "ffdhe1024": groups = [GroupName.secp256r1, GroupName.x25519] else: groups = [getattr(GroupName, conf['H2SKE_dh_group'])] ext[ExtensionType.supported_groups] = \ SupportedGroupsExtension().create(groups) ext[ExtensionType.ec_point_formats] = \ ECPointFormatsExtension()\ .create([ECPointFormat.uncompressed, ECPointFormat.ansiX962_compressed_char2, ECPointFormat.ansiX962_compressed_prime]) # encrypt then MAC if conf['H2CH_encrypt_then_mac_ext'] == "false": pass elif conf['H2CH_encrypt_then_mac_ext'] != "true": raise ValueError( "Unknown option in H2CH_encrypt_then_mac_ext: {0}".format( conf['H2CH_encrypt_then_mac_ext'])) else: ext[ExtensionType.encrypt_then_mac] = \ TLSExtension(extType=ExtensionType.encrypt_then_mac)\ .create(bytearray(0)) # server name if conf['H2CH_server_name'] == "no_ext": pass elif conf['H2CH_server_name'] == "correct": ext[ExtensionType.server_name] = \ SNIExtension().create(sni_hostname) elif conf['H2CH_server_name'] == "mismatch": ext[ExtensionType.server_name] = \ SNIExtension().create(sni_hostname + b'.www') else: raise ValueError("Unknown option in H2CH_server_name: {0}".format( conf['H2CH_server_name'])) # OCSP staple if conf['H2CH_status_request_ext'] == "false": pass elif conf['H2CH_status_request_ext'] != "true": raise ValueError( "Unknown option in H2CH_status_request_ext: {0}".format( conf['H2CH_status_request_ext'])) else: ext[ExtensionType.status_request] = \ StatusRequestExtension().create() # Extended Master Secret ext if conf['H2CH_extended_master_secret_ext'] == "false": pass elif conf['H2CH_extended_master_secret_ext'] != "true": raise ValueError( ("Unknown value in H2CH_extended_master_secret_ext" ": {0}").format(conf['H2CH_extended_master_secret_ext'])) else: ext[ExtensionType.extended_master_secret] = \ TLSExtension(extType=ExtensionType.extended_master_secret)\ .create(bytearray()) node = node.add_child( ClientHelloGenerator(suites, session_id=sess_ID, compression=compress, extensions=ext)) if conf['H2CH_server_name'] == "mismatch": node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.unrecognized_name)) al_node = node if conf['H2SH_SessionID'] == "resume": print("doing resumption") node = node.add_child(ExpectServerHello(resume=True)) if conf['H2CH_server_name'] == "mismatch": # make the sending of warning alert node optional al_node.next_sibling = node node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() else: node = node.add_child(ExpectServerHello()) if conf['H2CH_server_name'] == "mismatch": # make the sending of warning alert node optional al_node.next_sibling = node node = node.add_child(ExpectCertificate()) # TODO if conf['Certificate_Status_msg'] if conf['H2SKE_dh_group'] != "no_message": node = node.add_child(ExpectServerKeyExchange()) if conf['H2CR_sent'] == "true": node = node.add_child(ExpectCertificateRequest()) elif conf['H2CR_sent'] != "false": raise ValueError("Unknown option in H2CR_sent: {0}".format( conf['H2CR_sent'])) node = node.add_child(ExpectServerHelloDone()) if conf['H2CR_sent'] == "true": if conf['H2CV_signature_scheme'] == "no_message": node = node.add_child(CertificateGenerator()) else: node = node.add_child( CertificateGenerator(X509CertChain([cert]))) node = node.add_child(ClientKeyExchangeGenerator()) if conf['H2CV_signature_scheme'] != "no_message": sig = conf['H2CV_signature_scheme'] if "dsa" in sig: print("Changing {0} to RSA scheme in CV".format(sig)) sig = sig.replace("ecdsa", "rsa") sig = sig.replace("dsa", "rsa") sig = sig.replace("rsa_sha", "rsa_pkcs1_sha") sig = sig.replace("rsapss", "rsa_pss") if "sha224" in sig: scheme = (HashAlgorithm.sha224, SignatureAlgorithm.rsa) else: scheme = getattr(SignatureScheme, sig) node = node.add_child( CertificateVerifyGenerator(key, msg_alg=scheme)) node = node.add_child(ChangeCipherSpecGenerator()) node = node.add_child(FinishedGenerator()) node = node.add_child(ExpectChangeCipherSpec()) node = node.add_child(ExpectFinished()) node = node.add_child( AlertGenerator(AlertLevel.warning, AlertDescription.close_notify)) node = node.add_child( ExpectAlert(AlertLevel.warning, AlertDescription.close_notify)) node.next_sibling = ExpectClose() return root