def test_parse_with_invalid_data(self):
        parser = Parser(bytearray(b'\x00\x01\x00'))

        ext = SupportedGroupsExtension()

        with self.assertRaises(SyntaxError):
            ext.parse(parser)
    def test_write(self):
        ext = SupportedGroupsExtension()
        ext.create([19, 21])

        self.assertEqual(bytearray(
            b'\x00\x0A' +           # type of extension - 10
            b'\x00\x06' +           # overall length of extension
            b'\x00\x04' +           # length of extension list array
            b'\x00\x13' +           # secp192r1
            b'\x00\x15'             # secp224r1
            ), ext.write())
示例#3
0
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

    for prot_version in [(3, 0), (0, 0), (2, 0), (0, 2), (1, 0), (1, 3),
                         (1, 2), (0, 1)]:
        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, prot_version])
        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,
                                 version=prot_version))
        node = node.add_child(
            ExpectAlert(description=AlertDescription.protocol_version))
        node = node.add_child(ExpectClose())
        conversations['version {0}'.format(prot_version)] = 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:
        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("Legacy version in TLS 1.3")
    print("Check that invalid legacy versions are rejected")
    print("with protocol version alert by the TLS 1.3 server.\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)
示例#4
0
def main():
    host = "localhost"
    port = 4433
    fatal_alert = "decode_error"
    run_exclude = set()

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:", ["help", "alert="])
    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 == '--alert':
            fatal_alert = 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)
    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

    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_pkcs1_sha1, SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_pss_sha256
    ]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sig_algs)
    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["tolerance legacy RSA PKCS#1.5"] = conversation

    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 = [(10, SignatureAlgorithm.rsa),
                SignatureScheme.rsa_pss_rsae_sha256,
                SignatureScheme.rsa_pss_pss_sha256]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sig_algs)
    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[
        "tolerance unallocated 0x0A01 (10+RSA) method"] = conversation

    # 32717 is the maximum possible amount of methods that can fit into the
    # ClientHello packet -- in TLS 1.3, there are also other mandatory
    # extensions
    for n in [215, 2355, 8132, 23754, 32717]:
        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)
        n = n - 2  # these are the mandatory methods in the end
        sig_algs = list(
            chain(((i, j) for i in range(10, 224)
                   for j in range(10, (n // 214) + 10)),
                  ((i, 163) for i in range(10, (n % 214) + 10)), [
                      SignatureScheme.rsa_pss_rsae_sha256,
                      SignatureScheme.rsa_pss_pss_sha256
                  ]))
        ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
            .create(sig_algs)
        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()
        # OpenSSL sends the list of advertised and it doesn't fit a single
        # application data
        node = node.next_sibling.add_child(Close())
        conversations["tolerance {0} methods".format(n)] = conversation

    # Use empty supported algorithm extension
    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_AES_128_GCM_SHA256,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    ext = OrderedDict()
    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 = []
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sig_algs)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, getattr(AlertDescription, fatal_alert)))
    node = node.add_child(ExpectClose())
    conversations["empty list of signature methods"] = \
            conversation

    # Only undefined algorithms
    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)
    sigs = [
        (HashAlgorithm.sha256, 24),  # undefined signature algorithm
        (24, SignatureAlgorithm.rsa),  # undefined hash algorithm
        (10, 10),  # undefined pair
        (9, 24),  # undefined pair
        (0xff, 0xff)  # undefined pair
    ]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sigs)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.handshake_failure))
    node = node.next_sibling = ExpectClose()
    conversations["only undefined sigalgs"] = conversation

    # RSA-PSS is mandatory
    # More thoroughly tested in  scripts/test-tls13-pkcs-signature.py
    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)
    sigs = [SignatureScheme.rsa_pkcs1_sha1, SignatureScheme.rsa_pkcs1_sha512]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sigs)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.handshake_failure))
    node = node.next_sibling = ExpectClose()
    conversations["only legacy sigalgs"] = conversation

    # padded extension
    conversation = Connect(host, port)
    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)
    ext[ExtensionType.signature_algorithms] = \
        TLSExtension(extType=ExtensionType.signature_algorithms) \
            .create(bytearray(b'\x00\x04'  # length of array
                              b'\x08\x04'  # rsa_pss_rsae_sha256
                              b'\x08\x09'  # rsa_pss_pss_sha256
                              b'\x04\x03'))
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node = node.add_child(ExpectClose())
    conversations["padded sigalgs"] = conversation

    # send properly formatted one byte extension
    conversation = Connect(host, port)
    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)
    ext[ExtensionType.signature_algorithms] = \
        TLSExtension(extType=ExtensionType.signature_algorithms) \
            .create(bytearray(b'\x00\x01'  # length of array
                              b'\x02'))
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node = node.add_child(ExpectClose())
    conversations["one byte array"] = conversation

    # send properly formatted three byte extension
    conversation = Connect(host, port)
    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)
    ext[ExtensionType.signature_algorithms] = \
        TLSExtension(extType=ExtensionType.signature_algorithms) \
            .create(bytearray(b'\x00\x05'  # length of array
                              b'\x08\x04'  # rsa_pss_rsae_sha256
                              b'\x08\x09'  # rsa_pss_pss_sha256
                              b'\x02'))
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node = node.add_child(ExpectClose())
    conversations["three byte array"] = conversation

    # Fuzz the length of supported extensions
    for i in range(1, 0x100):
        conversation = Connect(host, port)
        node = conversation
        ciphers = [
            CipherSuite.TLS_AES_128_GCM_SHA256,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
        ext = OrderedDict()
        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)
        hello = ClientHelloGenerator(ciphers, extensions=ext)
        node = node.add_child(fuzz_message(hello, xors={-5: i}))
        node = node.add_child(
            ExpectAlert(AlertLevel.fatal, getattr(AlertDescription,
                                                  fatal_alert)))
        node = node.add_child(ExpectClose())
        conversations["fuzz length inside extension to {0}".format(4^i)] = \
                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")
        else:
            bad += 1
            failed.append(c_name)

    print("Signature Algorithms in TLS 1.3")
    print("Check if valid signature algorithm extensions are accepted and")
    print("invalid properly rejected by the TLS 1.3 server.\n")
    print("version: {0}\n".format(version))

    print("Test end")
    print("successful: {0}".format(good))
    print("failed: {0}".format(bad))
    failed_sorted = sorted(failed, key=natural_sort_keys)
    print("  {0}".format('\n  '.join(repr(i) for i in failed_sorted)))

    if bad > 0:
        sys.exit(1)
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 = {}

    conversation = Connect(host, port)
    node = conversation
    ext = {}
    sigalgs = [(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha256, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha384, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha512, SignatureAlgorithm.ecdsa)]
    ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(sigalgs)
    ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
    curves = [GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1]
    ext[ExtensionType.supported_groups] = \
            SupportedGroupsExtension().create(curves)
    ciphers = [
        CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
    node = node.add_child(ExpectServerHello())
    # ECDSA is not supported by tlslite-ng v0.7.0a3
    #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

    # all algorithms, but in order from strongest to weakest
    conversation = Connect(host, port)
    node = conversation
    ext = {}
    sigalgs = [(HashAlgorithm.sha512, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha384, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha256, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha1, SignatureAlgorithm.ecdsa)]
    ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(sigalgs)
    ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
    curves = [GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1]
    ext[ExtensionType.supported_groups] = \
            SupportedGroupsExtension().create(curves)
    ciphers = [
        CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
    node = node.add_child(ExpectServerHello())
    # ECDSA is not supported by tlslite-ng v0.7.0a3
    #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 - strongest to weakest"] = conversation

    # test all hashes one by one
    for h_alg in ["sha1", "sha256", "sha384", "sha512"]:
        conversation = Connect(host, port)
        node = conversation
        ext = {}
        sigalgs = [(getattr(HashAlgorithm, h_alg), SignatureAlgorithm.ecdsa)]
        ext[ExtensionType.signature_algorithms] = \
                SignatureAlgorithmsExtension().create(sigalgs)
        ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
        curves = [
            GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1
        ]
        ext[ExtensionType.supported_groups] = \
                SupportedGroupsExtension().create(curves)
        ciphers = [
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
        node = node.add_child(
            ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
        node = node.add_child(ExpectServerHello())
        # ECDSA is not supported by tlslite-ng v0.7.0a3
        #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["connect with {0}+ecdsa only".format(
            h_alg)] = 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("Test if the server doesn't have the TLSv1.3 limitation on ECDSA")
    print("signatures also in TLSv1.2 mode.\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():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    dhe = False
    # max number of extensions
    max_ext = 16382

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:n:e:x:X:d", ["help"])
    for opt, arg in opts:
        if opt == '-h':
            host = arg
        elif opt == '-p':
            port = int(arg)
        elif opt == '-d':
            dhe = True
            max_ext = 16374
        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 = {}

    sig_algs = [SignatureScheme.rsa_pkcs1_sha256,
               SignatureScheme.rsa_pss_rsae_sha256,
               SignatureScheme.rsa_pss_pss_sha256]

    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_algs)
        ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(sig_algs)
        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]
    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())
    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\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
    if dhe:
        ext = {}
        groups = [GroupName.secp256r1,
                  GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(sig_algs)
        ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(sig_algs)
        ext[ExtensionType.renegotiation_info] = None
        ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                   CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
    else:
        ext = {ExtensionType.renegotiation_info: None}
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(extensions=ext))
    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\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 - secure renego as ext"] = conversation

    for i in [1, 5, 30, 31, 32, 62, 63, 64, 1022, 1023, 1024,
              4094, 4095, 4096, 8190, 8191, 8192, max_ext]:
        conversation = Connect(host, port)
        node = conversation
        ext = OrderedDict((j+64, AutoEmptyExtension()) for j in range(i))
        if ExtensionType.supports_npn in ext:
            del ext[ExtensionType.supports_npn]
            ext[i+64+1] = AutoEmptyExtension()
        if dhe:
            groups = [GroupName.secp256r1,
                      GroupName.ffdhe2048]
            ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
                .create(groups)
            ext[ExtensionType.signature_algorithms] = \
                SignatureAlgorithmsExtension().create(sig_algs)
            ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(sig_algs)
            ciphers = [CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                       CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
        else:
            ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
        ext[ExtensionType.renegotiation_info] = None
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
        ext = {ExtensionType.renegotiation_info: None}
        node = node.add_child(ExpectServerHello(extensions=ext))
        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\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["{0} extensions".format(i+1)] = 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:
        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("Verify that renegotiation info extension is recognized even if it")
    print("is preceded by a very large number of extensions that are yet")
    print("undefined\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 or xpass:
        sys.exit(1)
示例#7
0
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:", ["help"])
    for opt, arg in opts:
        if opt == '-h':
            host = arg
        elif opt == '-p':
            port = int(arg)
        elif opt == '-e':
            run_exclude.add(arg)
        elif opt == '-n':
            num_limit = int(arg)
        elif opt == '--help':
            help_msg()
            sys.exit(0)
        else:
            raise ValueError("Unknown option: {0}".format(opt))

    if args:
        run_only = set(args)
    else:
        run_only = None

    conversations = {}

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_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

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_AES_128_GCM_SHA256,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    ext = {}
    groups = [GroupName.secp256r1]
    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(description=AlertDescription.missing_extension))
    node = node.add_child(ExpectClose())
    conversations["key_share extension omitted"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_AES_128_GCM_SHA256,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    ext = {}
    groups = [GroupName.secp256r1]
    ext[ExtensionType.key_share] = AutoEmptyExtension()
    ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\
        .create([TLS_1_3_DRAFT, (3, 3)])
    ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
        .create(groups)
    ext[ExtensionType.psk_key_exchange_modes] = PskKeyExchangeModesExtension()\
        .create([PskKeyExchangeMode.psk_ke, PskKeyExchangeMode.psk_dhe_ke])
    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(description=AlertDescription.decode_error))
    node = node.add_child(ExpectClose())
    conversations[
        "empty key_share extension with valid psk_key exhange modes"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_AES_128_GCM_SHA256,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    ext = {}
    groups = [GroupName.secp256r1]
    ext[ExtensionType.key_share] = AutoEmptyExtension()
    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(description=AlertDescription.decode_error))
    node = node.add_child(ExpectClose())
    conversations["empty key_share extension"] = 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
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except Exception:
            print("Error while processing")
            print(traceback.format_exc())
            res = False

        if res:
            good += 1
            print("OK\n")
        else:
            bad += 1
            failed.append(c_name)

    print("Test with omitted or empty key_share extension.")
    print("Check if communication is rejected with correct alert message")
    print("with the TLS 1.3 server.\n")
    print("version: {0}\n".format(version))

    print("Test end")
    print("successful: {0}".format(good))
    print("failed: {0}".format(bad))
    failed_sorted = sorted(failed, key=natural_sort_keys)
    print("  {0}".format('\n  '.join(repr(i) for i in failed_sorted)))

    if bad > 0:
        sys.exit(1)
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    cookie = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:", ["help", "cookie"])
    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 == '--cookie':
            cookie = True
        elif opt == '--help':
            help_msg()
            sys.exit(0)
        else:
            raise ValueError("Unknown option: {0}".format(opt))

    if args:
        run_only = set(args)
    else:
        run_only = None

    conversations = {}

    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
               CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
    ext = {}
    groups = [GroupName.secp256r1]
    key_shares = []
    for group in groups:
        key_shares.append(key_share_gen(group))
    ext[ExtensionType.key_share] = ClientKeyShareExtension().create(key_shares)
    ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\
        .create([TLS_1_3_DRAFT, (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

    unknown_groups = {
        'EC': list(range(34, 255)),  # Unassigned groups from EC range
        'FFDHE': list(range(261, 507)),  # Unassigned groups from FFDHE range
    }
    known_groups = [GroupName.secp256r1, GroupName.ffdhe2048]

    # Unknown key_shares, one known group and range of unknown groups in supported_groups
    for group_name, unknown_group in unknown_groups.items():
        for size in [64, 128, 256]:
            for known_group in known_groups:
                conversation = Connect(host, port)
                node = conversation
                ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
                        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
                ext = OrderedDict()

                groups = [known_group] + unknown_group
                key_shares = [KeyShareEntry().create(un_group, bytearray(b'\xab'*size)) for un_group in unknown_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))

                ext = OrderedDict()
                if cookie:
                    ext[ExtensionType.cookie] = None
                ext[ExtensionType.key_share] = None
                ext[ExtensionType.supported_versions] = None
                node = node.add_child(ExpectHelloRetryRequest(extensions=ext))
                node = node.add_child(ExpectChangeCipherSpec())

                ext = OrderedDict()
                groups = [known_group] + unknown_group
                key_shares = [key_share_gen(groups[0])]
                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)
                if cookie:
                    ext[ExtensionType.cookie] = ch_cookie_handler
                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(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["only unknown key_share from {0} range, key_share of size {1} + {2} in supported_groups".format(
                    group_name, size, GroupName.toRepr(known_group))] = conversation

                # One known group and list of unknown groups, unknown ones are listed first
                conversation = Connect(host, port)
                node = conversation
                ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
                        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
                ext = OrderedDict()

                groups = unknown_group + [known_group]
                key_shares = [KeyShareEntry().create(un_group, bytearray(b'\xab'*size)) for un_group in unknown_group]
                key_shares.append(key_share_gen(groups[-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(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["known group {0} and unknown groups from {1} range, key_share of size {2}".format(
                    GroupName.toRepr(known_group), group_name, size)] = conversation

            # Unknown supported_groups and key_shares
            conversation = Connect(host, port)
            node = conversation
            ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
                    CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
            ext = OrderedDict()

            groups = unknown_group
            key_shares = [KeyShareEntry().create(un_group, bytearray(b'\xab'*size)) for un_group in unknown_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(ExpectAlert(AlertLevel.fatal,
                                            AlertDescription.handshake_failure))
            node.add_child(ExpectClose())

            conversations["only unknown supported_groups from {0} range, key_share of size {1}".format(
                group_name, size)] = conversation

    # run the conversation
    good = 0
    bad = 0
    failed = []
    if not num_limit:
        num_limit = len(conversations)

    # make sure that sanity test is run first and last
    # to verify that server was running and kept running throught
    sanity_test = ('sanity', conversations['sanity'])
    ordered_tests = chain([sanity_test],
                          islice(filter(lambda x: x[0] != 'sanity',
                                        conversations.items()), num_limit),
                          [sanity_test])

    for c_name, c_test in ordered_tests:
        if run_only and c_name not in run_only or c_name in run_exclude:
            continue
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except Exception:
            print("Error while processing")
            print(traceback.format_exc())
            res = False

        if res:
            good += 1
            print("OK\n")
        else:
            bad += 1
            failed.append(c_name)

    print("Unrecognised groups in TLS 1.3")
    print("Check that server replies with HRR, aborts the connection")
    print("with handshake_failure or chooses a known group from client list.")
    print("Groups with IDs from FFDHE and ECDH range.\n")
    print("version: {0}\n".format(version))

    print("Test end")
    print("successful: {0}".format(good))
    print("failed: {0}".format(bad))
    failed_sorted = sorted(failed, key=natural_sort_keys)
    print("  {0}".format('\n  '.join(repr(i) for i in failed_sorted)))

    if bad > 0:
        sys.exit(1)
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    dhe = False
    tls13 = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:x:X:d", ["help", "tls-1.3"])
    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 == '-d':
            dhe = True
        elif opt == '--tls-1.3':
            tls13 = 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(RSA_SIG_ALL)
        ext[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,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(version=(3, 3), extensions=ext))
    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

    conversation = Connect(host, port)
    node = conversation
    if dhe:
        ext = {}
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ciphers = [
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 2), extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(version=(3, 2), extensions=ext))
    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 - TLSv1.1"] = conversation

    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(RSA_SIG_ALL)
        ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
        ciphers = [
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 4), extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(version=(3, 3), extensions=ext))
    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 - SSL3.4 version negotiation"] = conversation

    conversation = Connect(host, port, version=(3, 3))
    node = conversation
    if dhe:
        ext = {}
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(RSA_SIG_ALL)
        ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
        ciphers = [
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(version=(3, 3), extensions=ext))
    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["record TLSv1.2 hello TLSv1.2"] = conversation

    conversation = Connect(host, port, version=(3, 2))
    node = conversation
    if dhe:
        ext = {}
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        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,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 2), extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(version=(3, 2), extensions=ext))
    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["record TLSv1.1 hello TLSv1.1"] = conversation

    conversation = Connect(host, port, version=(3, 4))
    node = conversation
    if dhe:
        ext = {}
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(RSA_SIG_ALL)
        ext[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,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
            CipherSuite.TLS_AES_128_GCM_SHA256
        ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 4), extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(version=(3, 3), extensions=ext))
    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\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["record SSL3.4 hello SSL3.4"] = conversation

    # test with FALLBACK_SCSV
    if dhe:
        positions = (0, 1, 2, 3)
    else:
        positions = (0, 1, 2)
    for place in positions:
        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(RSA_SIG_ALL)
            ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        ciphers.insert(place, CipherSuite.TLS_FALLBACK_SCSV)
        node = node.add_child(
            ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
        if tls13:
            node = node.add_child(
                ExpectAlert(AlertLevel.fatal,
                            AlertDescription.inappropriate_fallback))
            node = node.add_child(ExpectClose())
        else:
            ext = {ExtensionType.renegotiation_info: None}
            node = node.add_child(
                ExpectServerHello(version=(3, 3), extensions=ext))
            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\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["FALLBACK - hello TLSv1.2 - pos {0}".format(
            place)] = conversation

        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(RSA_SIG_ALL)
            ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        ciphers.insert(place, CipherSuite.TLS_FALLBACK_SCSV)
        node = node.add_child(
            ClientHelloGenerator(ciphers, version=(3, 2), extensions=ext))
        node = node.add_child(
            ExpectAlert(AlertLevel.fatal,
                        AlertDescription.inappropriate_fallback))
        node = node.add_child(ExpectClose())
        conversations["FALLBACK - hello TLSv1.1 - pos {0}".format(
            place)] = conversation

        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(RSA_SIG_ALL)
            ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        ciphers.insert(place, CipherSuite.TLS_FALLBACK_SCSV)
        node = node.add_child(
            ClientHelloGenerator(ciphers, version=(3, 4), extensions=ext))
        if tls13:
            node = node.add_child(
                ExpectAlert(AlertLevel.fatal,
                            AlertDescription.inappropriate_fallback))
            node = node.add_child(ExpectClose())
        else:
            ext = {ExtensionType.renegotiation_info: None}
            node = node.add_child(
                ExpectServerHello(version=(3, 3), extensions=ext))
            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["FALLBACK - hello SSL3.4 - pos {0}".format(
            place)] = conversation

        conversation = Connect(host, port, version=(3, 3))
        node = conversation
        if dhe:
            ext = {}
            groups = [GroupName.secp256r1, GroupName.ffdhe2048]
            ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
                .create(groups)
            ext[ExtensionType.signature_algorithms] = \
                SignatureAlgorithmsExtension().create(RSA_SIG_ALL)
            ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        ciphers.insert(place, CipherSuite.TLS_FALLBACK_SCSV)
        node = node.add_child(
            ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
        if tls13:
            node = node.add_child(
                ExpectAlert(AlertLevel.fatal,
                            AlertDescription.inappropriate_fallback))
            node = node.add_child(ExpectClose())
        else:
            ext = {ExtensionType.renegotiation_info: None}
            node = node.add_child(
                ExpectServerHello(version=(3, 3), extensions=ext))
            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["FALLBACK - record TLSv1.2 hello TLSv1.2 - pos {0}".
                      format(place)] = conversation

        conversation = Connect(host, port, version=(3, 2))
        node = conversation
        if dhe:
            ext = {}
            groups = [GroupName.secp256r1, GroupName.ffdhe2048]
            ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
                .create(groups)
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        ciphers.insert(place, CipherSuite.TLS_FALLBACK_SCSV)
        node = node.add_child(
            ClientHelloGenerator(ciphers, version=(3, 2), extensions=ext))
        node = node.add_child(
            ExpectAlert(AlertLevel.fatal,
                        AlertDescription.inappropriate_fallback))
        node = node.add_child(ExpectClose())
        conversations["FALLBACK - record TLSv1.1 hello TLSv1.1 - pos {0}".
                      format(place)] = conversation

        conversation = Connect(host, port, version=(3, 4))
        node = conversation
        if dhe:
            ext = {}
            groups = [GroupName.secp256r1, GroupName.ffdhe2048]
            ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
                .create(groups)
            ext[ExtensionType.signature_algorithms] = \
                SignatureAlgorithmsExtension().create(RSA_SIG_ALL)
            ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(RSA_SIG_ALL)
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                CipherSuite.TLS_AES_128_GCM_SHA256
            ]
        ciphers.insert(place, CipherSuite.TLS_FALLBACK_SCSV)
        node = node.add_child(
            ClientHelloGenerator(ciphers, version=(3, 4), extensions=ext))
        if tls13:
            node = node.add_child(
                ExpectAlert(AlertLevel.fatal,
                            AlertDescription.inappropriate_fallback))
            node = node.add_child(ExpectClose())
        else:
            ext = {ExtensionType.renegotiation_info: None}
            node = node.add_child(
                ExpectServerHello(version=(3, 3), extensions=ext))
            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\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["FALLBACK - record SSL3.4 hello SSL3.4 - pos {0}".format(
            place)] = 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:
        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("Check if server correctly handles FALLBACK_SCSV\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 or xpass:
        sys.exit(1)
示例#10
0
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 or xpass:
        sys.exit(1)
示例#11
0
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:", ["help"])
    for opt, arg in opts:
        if opt == '-h':
            host = arg
        elif opt == '-p':
            port = int(arg)
        elif opt == '-e':
            run_exclude.add(arg)
        elif opt == '-n':
            num_limit = int(arg)
        elif opt == '--help':
            help_msg()
            sys.exit(0)
        else:
            raise ValueError("Unknown option: {0}".format(opt))

    if args:
        run_only = set(args)
    else:
        run_only = None

    conversations = {}

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_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

    for prot_version in [(3, 0), (0, 0), (2, 0), (0, 2), (1, 0), (1, 3),
                         (1, 2), (0, 1)]:
        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, prot_version])
        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,
                                 version=prot_version))
        node = node.add_child(
            ExpectAlert(description=AlertDescription.protocol_version))
        node = node.add_child(ExpectClose())
        conversations['version {0}'.format(prot_version)] = conversation

    # run the conversation
    good = 0
    bad = 0
    failed = []
    if not num_limit:
        num_limit = len(conversations)

    # make sure that sanity test is run first and last
    # to verify that server was running and kept running throught
    sanity_test = ('sanity', conversations['sanity'])
    ordered_tests = chain([sanity_test],
                          islice(
                              filter(lambda x: x[0] != 'sanity',
                                     conversations.items()), num_limit),
                          [sanity_test])

    for c_name, c_test in ordered_tests:
        if run_only and c_name not in run_only or c_name in run_exclude:
            continue
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except:
            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("Legacy version in TLS 1.3")
    print("Check that invalid legacy versions are rejected")
    print("with protocol version alert by the TLS 1.3 server.\n")
    print("version: {0}\n".format(version))

    print("Test end")
    print("successful: {0}".format(good))
    print("failed: {0}".format(bad))
    failed_sorted = sorted(failed, key=natural_sort_keys)
    print("  {0}".format('\n  '.join(repr(i) for i in failed_sorted)))

    if bad > 0:
        sys.exit(1)
示例#12
0
def main():
    """check if fuzzed ciphertext is rejected by server"""
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    dhe = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:x:X:n:d", ["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 == '-d':
            dhe = 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_GCM_SHA256,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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(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

    # 8 chars: explicit nonce
    # 18 chars: AES-CTR encrypt: GET / HTTP/1.0\r\n\r\n
    # 16 chars: GCM tag 128 bit
    # 1 char: because the offsets are 1-based, not 0-based
    fuzzes = [(-i, j) for i in range(1, 8 + 18 + 16 + 1)
              for j in [1 << x for x in range(8)]]
    for pos, val in fuzzes:
        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_GCM_SHA256,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
            ]
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
        node = node.add_child(ExpectServerHello())
        node = node.add_child(ExpectCertificate())
        if dhe:
            node = node.add_child(ExpectServerKeyExchange())
        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(
            fuzz_encrypted_message(
                ApplicationDataGenerator(b"GET / HTTP/1.0\r\n\r\n"),
                xors={pos: val}))
        node = node.add_child(
            ExpectAlert(AlertLevel.fatal, AlertDescription.bad_record_mac))
        node = node.add_child(ExpectClose())

        conversations["XOR position " + str(pos) + " with " + str(hex(val))] = \
                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:
        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 if AES-128-GCM tags are being checked by the")
    print(
        "server. Expects TLS 1.2 or earlier and RSA key exchange (or (EC)DHE")
    print("if -d option is used\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 or xpass:
        sys.exit(1)
def main():
    """Check what signature algorithms server advertises"""
    hostname = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    cert = None
    private_key = None
    ext_spec = {
        'CH': None,
        'SH': None,
        'EE': None,
        'CT': None,
        'CR': None,
        'NST': None,
        'HRR': None
    }

    sigalgs = [
        SignatureScheme.ecdsa_secp521r1_sha512,
        SignatureScheme.ecdsa_secp384r1_sha384,
        SignatureScheme.ecdsa_secp256r1_sha256,
        (HashAlgorithm.sha224, SignatureAlgorithm.ecdsa),
        (HashAlgorithm.sha1,
         SignatureAlgorithm.ecdsa), SignatureScheme.rsa_pss_rsae_sha512,
        SignatureScheme.rsa_pss_pss_sha512,
        SignatureScheme.rsa_pss_rsae_sha384,
        SignatureScheme.rsa_pss_pss_sha384,
        SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_pss_sha256, SignatureScheme.rsa_pkcs1_sha512,
        SignatureScheme.rsa_pkcs1_sha384, SignatureScheme.rsa_pkcs1_sha256,
        SignatureScheme.rsa_pkcs1_sha224, SignatureScheme.rsa_pkcs1_sha1
    ]

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:x:X:s:k:c:E:", ["help"])
    for opt, arg in opts:
        if opt == '-h':
            hostname = 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)
        elif opt == '-s':
            sigalgs = sig_algs_to_ids(arg)
        elif opt == '-E':
            ext_spec = expected_ext_parser(arg)
        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 args:
        run_only = set(args)
    else:
        run_only = None

    conversations = {}

    # sanity check for Client Certificates
    conversation = Connect(hostname, 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([(3, 4), (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)
    ext = dict_update_non_present(ext, ext_spec['CH'])
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = dict_update_non_present(None, ext_spec['SH'])
    node = node.add_child(ExpectServerHello(extensions=ext))
    node = node.add_child(ExpectChangeCipherSpec())
    ext = dict_update_non_present(None, ext_spec['EE'])
    node = node.add_child(ExpectEncryptedExtensions(extensions=ext))
    node = node.add_child(ExpectCertificateRequest())
    node = node.add_child(ExpectCertificate())
    node = node.add_child(ExpectCertificateVerify())
    node = node.add_child(ExpectFinished())
    node = node.add_child(CertificateGenerator())
    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

    if cert and private_key:
        # sanity check for Client Certificates
        conversation = Connect(hostname, 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([(3, 4), (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)
        ext = dict_update_non_present(ext, ext_spec['CH'])
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
        ext = dict_update_non_present(None, ext_spec['SH'])
        node = node.add_child(ExpectServerHello(extensions=ext))
        node = node.add_child(ExpectChangeCipherSpec())
        ext = dict_update_non_present(None, ext_spec['EE'])
        node = node.add_child(ExpectEncryptedExtensions(extensions=ext))
        node = node.add_child(ExpectCertificateRequest())
        node = node.add_child(ExpectCertificate())
        node = node.add_child(ExpectCertificateVerify())
        node = node.add_child(ExpectFinished())
        node = node.add_child(CertificateGenerator(X509CertChain([cert])))
        node = node.add_child(CertificateVerifyGenerator(private_key))
        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["with certificate"] = conversation

    # verify the advertised hashes
    conversation = Connect(hostname, 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([(3, 4), (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)
    ext = dict_update_non_present(ext, ext_spec['CH'])
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = dict_update_non_present(None, ext_spec['SH'])
    node = node.add_child(ExpectServerHello(extensions=ext))
    node = node.add_child(ExpectChangeCipherSpec())
    ext = dict_update_non_present(None, ext_spec['EE'])
    node = node.add_child(ExpectEncryptedExtensions(extensions=ext))
    node = node.add_child(ExpectCertificateRequest(sigalgs))
    # extensions are not yet supported in Certificate messages
    node = node.add_child(ExpectCertificate())
    node = node.add_child(ExpectCertificateVerify())
    node = node.add_child(ExpectFinished())
    node = node.add_child(CertificateGenerator())
    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["check sigalgs in cert request"] = conversation

    # verify the sent extensions
    conversation = Connect(hostname, 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([(3, 4), (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)
    ext = dict_update_non_present(ext, ext_spec['CH'])
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = dict_update_non_present(None, ext_spec['SH'])
    node = node.add_child(ExpectServerHello(extensions=ext))
    node = node.add_child(ExpectChangeCipherSpec())
    node = node.add_child(ExpectEncryptedExtensions())
    ext = {
        ExtensionType.signature_algorithms:
        SignatureAlgorithmsExtension().create(sigalgs)
    }
    ext = dict_update_non_present(ext, ext_spec['CR'])
    node = node.add_child(ExpectCertificateRequest(extensions=ext))
    node = node.add_child(ExpectCertificate())
    node = node.add_child(ExpectCertificateVerify())
    node = node.add_child(ExpectFinished())
    node = node.add_child(CertificateGenerator())
    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["verify extensions in CertificateRequest"] = 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:
        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 to verify if server accepts empty certificate messages and")
    print("advertises only expected signature algotithms and extensions in ")
    print("Certificate Request message\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():
    """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 or xpass:
        sys.exit(1)
示例#15
0
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:", ["help"])
    for opt, arg in opts:
        if opt == '-h':
            host = arg
        elif opt == '-p':
            port = int(arg)
        elif opt == '-e':
            run_exclude.add(arg)
        elif opt == '-n':
            num_limit = int(arg)
        elif opt == '--help':
            help_msg()
            sys.exit(0)
        else:
            raise ValueError("Unknown option: {0}".format(opt))

    if args:
        run_only = set(args)
    else:
        run_only = None

    conversations = {}

    # sanity conversation
    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
               CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
    ext = {}
    groups = [GroupName.secp256r1]
    ext[ExtensionType.key_share] = key_share_ext_gen(groups)
    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,
                SignatureScheme.rsa_pss_rsae_sha384,
                SignatureScheme.rsa_pss_pss_sha384]
    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

    # empty
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
               CipherSuite.TLS_AES_256_GCM_SHA384]
    for cipher in ciphers:
        conversation = Connect(host, port)
        node = conversation
        ciphers = [cipher,
                   CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
        ext = {}
        groups = [GroupName.secp256r1]
        ext[ExtensionType.key_share] = key_share_ext_gen(groups)
        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,
                    SignatureScheme.rsa_pss_rsae_sha384,
                    SignatureScheme.rsa_pss_pss_sha384]
        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(trunc_start=0,
                                                trunc_end=0))

        # This message may be sent right after server finished
        cycle = ExpectNewSessionTicket()
        node = node.add_child(cycle)
        node.add_child(cycle)

        # we do not expect any application data back
        # after malforming the Finished message
        node.next_sibling = ExpectAlert(AlertLevel.fatal,
                                        AlertDescription.decode_error)
        node = node.next_sibling.add_child(ExpectClose())
        conversations["empty - cipher %s" \
                         % (CipherSuite.ietfNames[cipher])] = conversation

    # single bit error
    scenarios = [(CipherSuite.TLS_AES_128_GCM_SHA256, 32),
                 (CipherSuite.TLS_AES_256_GCM_SHA384, 48)]
    for cipher, prf_bytes in scenarios:
        for mbit in range(8*prf_bytes):
            mbyte = mbit // 8 + 1
            conversation = Connect(host, port)
            node = conversation
            ciphers = [cipher,
                       CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
            ext = {}
            groups = [GroupName.secp256r1]
            ext[ExtensionType.key_share] = key_share_ext_gen(groups)
            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,
                        SignatureScheme.rsa_pss_rsae_sha384,
                        SignatureScheme.rsa_pss_pss_sha384]
            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(fuzz_message(FinishedGenerator(),
                                               xors={-mbyte: 0x01 << mbit%8}))
            # This message may be sent right after server finished
            cycle = ExpectNewSessionTicket()
            node = node.add_child(cycle)
            node.add_child(cycle)

            # we do not expect any application data back
            # after malforming the Finished message
            node.next_sibling = ExpectAlert(AlertLevel.fatal,
                                            AlertDescription.decrypt_error)
            node = node.next_sibling.add_child(ExpectClose())
            conversations["single bit error - cipher %s, bit %d" \
                          % (CipherSuite.ietfNames[cipher],
                             mbit)] = conversation

    # truncation
    # cipher, start, end
    scenarios = [
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0,  -1),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0,  -2),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0,  -4),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0,  -8),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0,  -16),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0,  -32),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0,  12), # TLS-1.2 size
        (CipherSuite.TLS_AES_128_GCM_SHA256, 1,  None),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 2,  None),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 4,  None),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 8,  None),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 16, None),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 32, None),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0,  -1),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0,  -2),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0,  -4),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0,  -8),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0,  -16), # SHA-256 size
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0,  -32),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0,  12), # TLS-1.2 size
        (CipherSuite.TLS_AES_256_GCM_SHA384, 1,  None),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 2,  None),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 4,  None),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 8,  None),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 16, None), # SHA-256 size
        (CipherSuite.TLS_AES_256_GCM_SHA384, 32, None)
        ]
    for cipher, start, end in scenarios:
        conversation = Connect(host, port)
        node = conversation
        ciphers = [cipher,
                   CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
        ext = {}
        groups = [GroupName.secp256r1]
        ext[ExtensionType.key_share] = key_share_ext_gen(groups)
        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,
                    SignatureScheme.rsa_pss_rsae_sha384,
                    SignatureScheme.rsa_pss_pss_sha384]
        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(trunc_start=start,
                                                trunc_end=end))

        # This message may be sent right after server finished
        cycle = ExpectNewSessionTicket()
        node = node.add_child(cycle)
        node.add_child(cycle)

        # we do not expect any application data back
        # after malforming the Finished message
        node.next_sibling = ExpectAlert(AlertLevel.fatal,
                                        AlertDescription.decode_error)
        node = node.next_sibling.add_child(ExpectClose())
        conversations["truncation - cipher %s, start %d, end %s" \
                      % (CipherSuite.ietfNames[cipher],
                         start, end)] = conversation

    # padding
    # cipher, padding byte, left padding, right padding
    scenarios = [
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 1),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 2),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 4),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 8),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 16), # SHA-384 size
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 32),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 48),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 2**14-4-32), # max record
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 0x20000), # intermediate
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 0x30000), # bigger than max ClientHello
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 0, 256**3-1-32), # max handshake
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 1, 0),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 2, 0),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 4, 0),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 8, 0),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 16, 0), # SHA-384 size
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 32, 0),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 48, 0),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 2**14-4-32, 0), # max record
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 12, 0),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 1, 1),
        (CipherSuite.TLS_AES_128_GCM_SHA256, 0, 8, 8), # SHA-384 size
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 1),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 2),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 4),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 8),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 16), # SHA-512 size
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 32),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 48),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 2**14-4-48), # max record
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 0x20000),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 0x30000), # bigger than max ClientHello
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 256**3-1-48), # max handshake
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 0, 12),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 1, 0),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 2, 0),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 4, 0),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 8, 0),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 16, 0), # SHA-512 size
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 32, 0),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 48, 0),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 2**14-4-48, 0), # max record
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 1, 1),
        (CipherSuite.TLS_AES_256_GCM_SHA384, 0, 8, 8) # SHA-512 size
        ]
    for cipher, pad_byte, pad_left, pad_right in scenarios:
        # longer timeout for longer messages
        # Because the client is sending encrypted data without waiting
        # on any server response, it can actually produce data at a faster
        # rate than the server is able to process it, meaning that a server
        # that aborts only after decrypting a full handshake message may have
        # quite a few records in the queue after we, as a client have finished
        # sending them. Since tlslite-ng has the ciphers implemented in
        # pure python, they are very slow, speeds of just 71.5KiB/s for
        # AES-256-GCM are not atypical. which translates to about 4 minutes
        # to transfer this data. Set the timeout to 5 for a small margin of
        # error.
        # Note: because we still are waiting for the server to send us an alert
        # (all graph terminal nodes go through ExpectAlert), server that fails
        # to do that will still cause the whole test conversation to fail in
        # case it just closes the connection on us
        timeout = 5 if max(pad_left, pad_right) < 2**14 * 4 else 300
        conversation = Connect(host, port, timeout=timeout)
        node = conversation
        ciphers = [cipher,
                   CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
        ext = {}
        groups = [GroupName.secp256r1]
        ext[ExtensionType.key_share] = key_share_ext_gen(groups)
        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,
                    SignatureScheme.rsa_pss_rsae_sha384,
                    SignatureScheme.rsa_pss_pss_sha384]
        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())

        # (the crazy handling of the messages below is because we are
        # sending one message (Finished) in multiple records, and server
        # can abort the connection after processing any number of records)

        # conditionally wait for NewSessionTicket messages
        # this will help in case the server does send early NST (without
        # waiting for client Finished) but will abort reading of the
        # Finished after one record
        no_message = node.add_child(ExpectNoMessage(0.001))
        nst = ExpectNewSessionTicket(note='first')
        no_message.next_sibling = nst
        nst.add_child(no_message)
        node = no_message

        # alert+close can happen during sending large Finished message,
        # therefore we are specifying it as its sibling
        close_node = ExpectAlert(AlertLevel.fatal,
                                 AlertDescription.decode_error)
        close_node.add_child(ExpectClose())
        node = node.add_child(FinishedGenerator(
                                  pad_byte=pad_byte,
                                  pad_left=pad_left,
                                  pad_right=pad_right))
        node.next_sibling = close_node

        # This message may be sent right after server finished
        cycle = ExpectNewSessionTicket(note='second')
        node = node.add_child(cycle)
        node.add_child(cycle)

        # we do not expect any application data back
        # after malforming the Finished message
        node.next_sibling = close_node

        conversations["padding - cipher %s, "
                      "pad_byte %d, "
                      "pad_left %d, "
                      "pad_right %d" \
                      % (CipherSuite.ietfNames[cipher],
                         pad_byte, pad_left, pad_right)] = 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
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except Exception:
            print("Error while processing")
            print(traceback.format_exc())
            res = False

        if res:
            good += 1
            print("OK\n")
        else:
            bad += 1
            failed.append(c_name)

    print("Fuzzing TLS 1.3 Finished messages")
    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)
示例#16
0
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    dhe = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:d", ["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 == '-d':
            dhe = 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())
    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

    # 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
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except Exception:
            print("Error while processing")
            print(traceback.format_exc())
            res = False

        if res:
            good += 1
            print("OK\n")
        else:
            bad += 1
            failed.append(c_name)

    print("Basic conversation script; check basic communication with typical")
    print("cipher, TLS 1.2 or earlier and RSA key exchange (or (EC)DHE if")
    print("-d option is used)\n")
    print("version: {0}\n".format(version))

    print("Test end")
    print("successful: {0}".format(good))
    print("failed: {0}".format(bad))
    failed_sorted = sorted(failed, key=natural_sort_keys)
    print("  {0}".format('\n  '.join(repr(i) for i in failed_sorted)))

    if bad > 0:
        sys.exit(1)
示例#17
0
def main():
    """Test if server does not allow resumption with different cipher."""
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    swap_ciphers = False
    dhe = False
    splitting = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:x:X:n:d",
                               ["help", "swap-ciphers", "n/n-1"])
    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 == "--swap-ciphers":
            swap_ciphers = True
        elif opt == '-d':
            dhe = True
        elif opt == "--n/n-1":
            splitting = 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())
    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())
    if 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["sanity"] = conversation

    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_256_CBC_SHA,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    if 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["sanity - aes-256 cipher"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ext = {ExtensionType.renegotiation_info: None}
    if dhe:
        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_256_CBC_SHA,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_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_DHE_RSA_WITH_AES_128_CBC_SHA
        ]
    else:
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    if dhe:
        if swap_ciphers:
            exp_ciph = [
                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
            ]
        else:
            exp_ciph = [
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA
            ]
    else:
        if swap_ciphers:
            exp_ciph = CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA
        else:
            exp_ciph = CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA
    node = node.add_child(
        ExpectServerHello(cipher=exp_ciph,
                          extensions={ExtensionType.renegotiation_info: None}))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    close = ExpectClose()
    node.next_sibling = close
    node = node.add_child(ExpectClose())
    node = node.add_child(Close())
    node = node.add_child(Connect(host, port))
    close.add_child(node)

    node = node.add_child(ResetHandshakeHashes())
    node = node.add_child(ResetRenegotiationInfo())
    node = node.add_child(
        ClientHelloGenerator(
            ciphers, extensions={ExtensionType.renegotiation_info: None}))
    node = node.add_child(
        ExpectServerHello(extensions={ExtensionType.renegotiation_info: None},
                          resume=True))
    node = node.add_child(ExpectChangeCipherSpec())
    node = node.add_child(ExpectFinished())
    node = node.add_child(ChangeCipherSpecGenerator())
    node = node.add_child(FinishedGenerator())
    node = node.add_child(
        ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\n\n")))
    node = node.add_child(ExpectApplicationData())
    if 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()
    node = node.add_child(ExpectClose())

    conversations["sanity - session ID resume"] = conversation

    # check if resumption with a different cipher fails
    conversation = Connect(host, port)
    node = conversation
    ext = {ExtensionType.renegotiation_info: None}
    if dhe:
        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_256_CBC_SHA,
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_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_DHE_RSA_WITH_AES_128_CBC_SHA
        ]
    else:
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    if dhe:
        if swap_ciphers:
            exp_ciph = [
                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
            ]
        else:
            exp_ciph = [
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA
            ]
    else:
        if swap_ciphers:
            exp_ciph = CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA
        else:
            exp_ciph = CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA
    node = node.add_child(
        ExpectServerHello(cipher=exp_ciph,
                          extensions={ExtensionType.renegotiation_info: None}))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    close = ExpectClose()
    node.next_sibling = close
    node = node.add_child(ExpectClose())
    node = node.add_child(Close())
    node = node.add_child(Connect(host, port))
    close.add_child(node)

    node = node.add_child(ResetHandshakeHashes())
    node = node.add_child(ResetRenegotiationInfo())
    if dhe:
        if swap_ciphers:
            ciphers = [
                CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
                CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA
            ]
        else:
            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
            ]
    else:
        if swap_ciphers:
            ciphers = [CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA]
        else:
            ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter))
    node.add_child(ExpectClose())

    conversations[
        "resumption with cipher from old CH but not selected by server"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ext = {ExtensionType.renegotiation_info: None}
    if dhe:
        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
        ]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectServerHello(extensions={ExtensionType.renegotiation_info: None}))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    close = ExpectClose()
    node.next_sibling = close
    node = node.add_child(ExpectClose())
    node = node.add_child(Close())
    node = node.add_child(Connect(host, port))
    close.add_child(node)

    node = node.add_child(ResetHandshakeHashes())
    node = node.add_child(ResetRenegotiationInfo())
    if dhe:
        ciphers = [
            CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA,
            CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA,
            CipherSuite.TLS_ECDH_ANON_WITH_NULL_SHA
        ]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_NULL_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.illegal_parameter))
    node.add_child(ExpectClose())

    conversations["resumption of safe session with NULL cipher"] = 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:
        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("Misbehaving client session resumption script")
    print("Check if server detects a misbehaving client in session"
          " resumption\n")
    print("Reproducer for CVE-2010-4180\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 or xpass:
        sys.exit(1)
示例#18
0
def main():
    """Check that server properly rejects malformed signatures in TLS 1.3"""
    hostname = "localhost"
    port = 4433
    num_limit = 120
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    cert = None
    private_key = None

    # algorithms to expect from server in Certificate Request
    cr_sigalgs = [
        SignatureScheme.ecdsa_secp521r1_sha512,
        SignatureScheme.ecdsa_secp384r1_sha384,
        SignatureScheme.ecdsa_secp256r1_sha256,
        (HashAlgorithm.sha224, SignatureAlgorithm.ecdsa),
        (HashAlgorithm.sha1,
         SignatureAlgorithm.ecdsa), SignatureScheme.rsa_pss_rsae_sha512,
        SignatureScheme.rsa_pss_pss_sha512,
        SignatureScheme.rsa_pss_rsae_sha384,
        SignatureScheme.rsa_pss_pss_sha384,
        SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_pss_sha256, SignatureScheme.rsa_pkcs1_sha512,
        SignatureScheme.rsa_pkcs1_sha384, SignatureScheme.rsa_pkcs1_sha256,
        SignatureScheme.rsa_pkcs1_sha224, SignatureScheme.rsa_pkcs1_sha1
    ]

    # algorithms to advertise in ClientHello
    sig_algs = [
        SignatureScheme.ecdsa_secp521r1_sha512,
        SignatureScheme.ecdsa_secp384r1_sha384,
        SignatureScheme.ecdsa_secp256r1_sha256,
        SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_pss_sha256,
        SignatureScheme.rsa_pss_rsae_sha384, SignatureScheme.rsa_pss_pss_sha384
    ]

    hashalgs = hashes_to_list("sha256 sha384 sha512")

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:x:X:n:s:k:c:",
                               ["help", "hash-order="])
    for opt, arg in opts:
        if opt == '-h':
            hostname = 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 == '-s':
            cr_sigalgs = sig_algs_to_ids(arg)
        elif opt == '--hash-order':
            hashalgs = hashes_to_list(arg)
        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 args:
        run_only = set(args)
    else:
        run_only = None

    if not cert or not private_key:
        raise Exception("A Client certificate and a private key are required")

    certType = cert.certAlg

    conversations = {}
    conversations_long = {}

    # sanity check for Client Certificates
    conversation = Connect(hostname, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_AES_128_GCM_SHA256,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    ext = {}
    groups = [GroupName.secp256r1]
    ext[ExtensionType.key_share] = key_share_ext_gen(groups)
    ext[ExtensionType.supported_versions] = \
        SupportedVersionsExtension().create([(3, 4), (3, 3)])
    ext[ExtensionType.supported_groups] = \
        SupportedGroupsExtension().create(groups)
    ext[ExtensionType.signature_algorithms] = \
        SignatureAlgorithmsExtension().create(sig_algs)
    ext[ExtensionType.signature_algorithms_cert] = \
        SignatureAlgorithmsCertExtension().create(ECDSA_SIG_ALL + 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(ExpectCertificateRequest())
    node = node.add_child(ExpectCertificate())
    node = node.add_child(ExpectCertificateVerify())
    node = node.add_child(ExpectFinished())
    node = node.add_child(CertificateGenerator(X509CertChain([cert])))
    node = node.add_child(CertificateVerifyGenerator(private_key))
    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

    # verify the advertised hashes
    conversation = Connect(hostname, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_AES_128_GCM_SHA256,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    ext = {}
    groups = [GroupName.secp256r1]
    ext[ExtensionType.key_share] = key_share_ext_gen(groups)
    ext[ExtensionType.supported_versions] = \
        SupportedVersionsExtension().create([(3, 4), (3, 3)])
    ext[ExtensionType.supported_groups] = \
        SupportedGroupsExtension().create(groups)
    ext[ExtensionType.signature_algorithms] = \
        SignatureAlgorithmsExtension().create(sig_algs)
    ext[ExtensionType.signature_algorithms_cert] = \
        SignatureAlgorithmsCertExtension().create(ECDSA_SIG_ALL + 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(ExpectCertificateRequest(cr_sigalgs))
    node = node.add_child(ExpectCertificate())
    node = node.add_child(ExpectCertificateVerify())
    node = node.add_child(ExpectFinished())
    node = node.add_child(CertificateGenerator())
    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["check sigalgs in cert request"] = conversation

    for sigalg in ECDSA_SIG_ALL:
        # set if test should succeed or fail based on cert type,
        # advertisement and forbidden algorithms
        expectPass = False
        if len(private_key) == 256 and \
                sigalg == SignatureScheme.ecdsa_secp256r1_sha256:
            expectPass = True
        elif len(private_key) == 384 and \
                sigalg == SignatureScheme.ecdsa_secp384r1_sha384:
            expectPass = True
        elif len(private_key) == 521 and \
                sigalg == SignatureScheme.ecdsa_secp521r1_sha512:
            expectPass = True
        # expect failure if an algorithm is not advertized
        if sigalg not in cr_sigalgs:
            expectPass = False

        conversation = Connect(hostname, port)
        node = conversation
        ciphers = [
            CipherSuite.TLS_AES_128_GCM_SHA256,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
        ext = {}
        # NOTE: groups do NOT influence the signature negotiation
        groups = [GroupName.secp256r1]
        ext[ExtensionType.key_share] = key_share_ext_gen(groups)
        ext[ExtensionType.supported_versions] = \
            SupportedVersionsExtension().create([(3, 4), (3, 3)])
        ext[ExtensionType.supported_groups] = \
            SupportedGroupsExtension().create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(sig_algs)
        ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(ECDSA_SIG_ALL +
                                                      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(ExpectCertificateRequest())
        node = node.add_child(ExpectCertificate())
        node = node.add_child(ExpectCertificateVerify())
        node = node.add_child(ExpectFinished())
        node = node.add_child(CertificateGenerator(X509CertChain([cert])))
        # force sigalg
        node = node.add_child(
            CertificateVerifyGenerator(private_key, msg_alg=sigalg))
        node = node.add_child(FinishedGenerator())

        result = "works"
        # only signatures of matching certificate type should work
        if expectPass:
            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()

        else:
            node = node.add_child(
                ExpectAlert(AlertLevel.fatal,
                            AlertDescription.illegal_parameter))
            node.add_child(ExpectClose())

            result = "is refused"

        name = SignatureScheme.toRepr(sigalg)
        if not name:
            name = "{0}+{1}".format(HashAlgorithm.toStr(sigalg[0]),
                                    SignatureAlgorithm.toStr(sigalg[1]))
        conversations["check {0} signature {1}".format(name,
                                                       result)] = conversation

    # verify that an ECDSA signature with mismatched message hash fails
    if len(private_key) == 256:
        sig_alg = SignatureScheme.ecdsa_secp384r1_sha384
        msg_alg = SignatureScheme.ecdsa_secp256r1_sha256
    elif len(private_key) == 384:
        sig_alg = SignatureScheme.ecdsa_secp256r1_sha256
        msg_alg = SignatureScheme.ecdsa_secp384r1_sha384
    else:
        assert len(private_key) == 521
        sig_alg = SignatureScheme.ecdsa_secp384r1_sha384
        msg_alg = SignatureScheme.ecdsa_secp521r1_sha512

    conversation = Connect(hostname, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_AES_128_GCM_SHA256,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    ext = {}
    groups = [GroupName.secp256r1]
    ext[ExtensionType.key_share] = key_share_ext_gen(groups)
    ext[ExtensionType.supported_versions] = \
        SupportedVersionsExtension().create([(3, 4), (3, 3)])
    ext[ExtensionType.supported_groups] = \
        SupportedGroupsExtension().create(groups)
    ext[ExtensionType.signature_algorithms] = \
        SignatureAlgorithmsExtension().create(sig_algs)
    ext[ExtensionType.signature_algorithms_cert] = \
        SignatureAlgorithmsCertExtension().create(ECDSA_SIG_ALL + 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(ExpectCertificateRequest())
    node = node.add_child(ExpectCertificate())
    node = node.add_child(ExpectCertificateVerify())
    node = node.add_child(ExpectFinished())
    node = node.add_child(CertificateGenerator(X509CertChain([cert])))
    node = node.add_child(
        CertificateVerifyGenerator(private_key,
                                   sig_alg=sig_alg,
                                   msg_alg=msg_alg))
    node = node.add_child(FinishedGenerator())
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decrypt_error))
    node.add_child(ExpectClose())

    conversations["check ecdsa signature with mismatched hash fails"] = \
        conversation

    # check that fuzzed signatures are rejected
    if len(private_key) == 256:
        # bacause of DER encoding of the signature, the mapping between key size
        # and signature size is non-linear
        siglen = 70
    elif len(private_key) == 384:
        siglen = 103
    else:
        assert len(private_key) == 521
        siglen = 137
    for pos in range(siglen):
        for xor in [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]:
            conversation = Connect(hostname, port)
            node = conversation
            ciphers = [
                CipherSuite.TLS_AES_128_GCM_SHA256,
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
            ]
            ext = {}
            groups = [GroupName.secp256r1]
            ext[ExtensionType.key_share] = key_share_ext_gen(groups)
            ext[ExtensionType.supported_versions] = \
                SupportedVersionsExtension().create([(3, 4), (3, 3)])
            ext[ExtensionType.supported_groups] = \
                SupportedGroupsExtension().create(groups)
            ext[ExtensionType.signature_algorithms] = \
                SignatureAlgorithmsExtension().create(sig_algs)
            ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(ECDSA_SIG_ALL + \
                                                          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(ExpectCertificateRequest())
            node = node.add_child(ExpectCertificate())
            node = node.add_child(ExpectCertificateVerify())
            node = node.add_child(ExpectFinished())
            node = node.add_child(CertificateGenerator(X509CertChain([cert])))
            node = node.add_child(
                CertificateVerifyGenerator(private_key,
                                           padding_xors={pos: xor}))
            node = node.add_child(FinishedGenerator())
            node = node.add_child(
                ExpectAlert(AlertLevel.fatal, AlertDescription.decrypt_error))
            node.add_child(ExpectClose())

            conversations_long["check that fuzzed signatures are rejected." +
                               " Malformed {0} - xor {1} at {2}".format(
                                   certType, hex(xor), pos)] = conversation

    # run the conversation
    good = 0
    bad = 0
    xfail = 0
    xpass = 0
    failed = []
    xpassed = []
    if not num_limit:
        num_limit = len(conversations_long)

    # 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)
        long_tests = [(k, v) for k, v in conversations_long.items()
                      if k in run_only]
        short_tests = [(k, v) for k, v in conversations.items()
                       if (k != 'sanity') and k in run_only]
    else:
        long_tests = [(k, v) for k, v in conversations_long.items()
                      if k not in run_exclude]
        short_tests = [(k, v) for k, v in conversations.items()
                       if (k != 'sanity') and k not in run_exclude]
    sampled_tests = sample(long_tests, min(num_limit, len(long_tests)))
    ordered_tests = chain(sanity_tests, short_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 to verify that server properly accepts or refuses")
    print("ECDSA signatures in TLS1.3; SHA224 and SHA1 signatures are always")
    print("refused, Other signatures are accepted or refused accordingly to")
    print("the key provided.\n")
    print("Test should be run three times, once each with P-256, P-384 and")
    print("P-521 client certificate.\n")

    print("Test end")
    print(20 * '=')
    print("version: {0}".format(version))
    print(20 * '=')
    print("TOTAL: {0}".format(
        len(sampled_tests) + len(short_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
    no_ins_renego = False
    private_key = None
    cert = None
    early_abort = False
    dhe = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:x:X:n:k:c:d",
                               ["help", "no-ins-renego", "early-abort"])
    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 == '-d':
            dhe = True
        elif opt == '-n':
            num_limit = int(arg)
        elif opt == '--no-ins-renego':
            no_ins_renego = True
        elif opt == '--help':
            help_msg()
            sys.exit(0)
        elif opt == '--early-abort':
            early_abort = True
        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 = {}

    conversation = Connect(host, port)
    node = conversation
    sig_algs = [
        SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_pss_sha256, SignatureScheme.rsa_pkcs1_sha256,
        SignatureScheme.ecdsa_secp256r1_sha256
    ]
    if dhe:
        ext = {}
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
                .create(groups)
        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 = {}
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sig_algs)
    ext[ExtensionType.signature_algorithms_cert] = \
        SignatureAlgorithmsCertExtension().create(sig_algs)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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 /?Renegotiation_Test=tlsfuzzer 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

    # renegotiation
    conversation = Connect(host, port)
    node = conversation

    sig_algs = [
        SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_pss_sha256, SignatureScheme.rsa_pkcs1_sha256,
        SignatureScheme.ecdsa_secp256r1_sha256
    ]
    if dhe:
        ext = {ExtensionType.renegotiation_info: None}
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
                .create(groups)
        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
        ]
    else:
        ext = {ExtensionType.renegotiation_info: None}
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sig_algs)
    ext[ExtensionType.signature_algorithms_cert] = \
        SignatureAlgorithmsCertExtension().create(sig_algs)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(extensions=ext))
    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())
    # send GET request
    node = node.add_child(
        ApplicationDataGenerator(
            bytearray(b"GET /secure/test HTTP/1.0\r\n\r\n")))
    # 2nd handshake
    node = node.add_child(ExpectHelloRequest())
    node = node.add_child(ResetHandshakeHashes())
    ext = {ExtensionType.renegotiation_info: None}
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sig_algs)
    ext[ExtensionType.signature_algorithms_cert] = \
        SignatureAlgorithmsCertExtension().create(sig_algs)
    node = node.add_child(
        ClientHelloGenerator(ciphers, session_id=bytearray(0), extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(extensions=ext))
    node = node.add_child(ExpectCertificate())
    if dhe:
        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(ExpectApplicationData())
    conversations["try secure renegotiation"] = conversation

    # insecure renegotiation
    conversation = Connect(host, port)
    node = conversation
    sig_algs = [
        SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_pss_sha256, SignatureScheme.rsa_pkcs1_sha256,
        SignatureScheme.ecdsa_secp256r1_sha256
    ]
    if dhe:
        ext = {ExtensionType.renegotiation_info: None}
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
                .create(groups)
        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
        ]
    else:
        ext = {ExtensionType.renegotiation_info: None}
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sig_algs)
    ext[ExtensionType.signature_algorithms_cert] = \
        SignatureAlgorithmsCertExtension().create(sig_algs)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    # send GET request
    node = node.add_child(
        ApplicationDataGenerator(
            bytearray(b"GET /secure/test HTTP/1.0\r\n\r\n")))
    if early_abort:
        node = node.add_child(
            ExpectAlert(AlertLevel.fatal, AlertDescription.handshake_failure))
        node = node.add_child(ExpectClose())
    else:
        node = node.add_child(ExpectHelloRequest())
        # 2nd handshake
        node = node.add_child(ResetHandshakeHashes())
        ext = {}
        ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
            .create(sig_algs)
        ext[ExtensionType.signature_algorithms_cert] = \
                    SignatureAlgorithmsCertExtension().create(sig_algs)
        node = node.add_child(
            ClientHelloGenerator(ciphers,
                                 session_id=bytearray(0),
                                 extensions=ext))
        if no_ins_renego:
            node = node.add_child(
                ExpectAlert(AlertLevel.fatal,
                            AlertDescription.handshake_failure))
            node = node.add_child(ExpectClose())
        else:
            node = node.add_child(ExpectServerHello())
            node = node.add_child(ExpectCertificate())
            if dhe:
                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(ExpectApplicationData())
    conversations["try insecure (legacy) renegotiation"] = 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:
        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("Verify that the server disabled renegotiation (both legacy")
    print("and secure). Use client certificates for the test.\n")
    print("Test expects the server to ask for renegotiation after the client")
    print("asks for \"/secure/test\" resource\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()

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n: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 == '-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

    for version_id in range(0, 4):
        conversation = Connect(host, port, version=(3, version_id))
        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["tls 1.3 negotiation with SSL 3.{0} in record layer".format(version_id)] = conversation


    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([(3, 9)])
    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.protocol_version))
    conversations["tls 1.8 only"] = conversation


    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
               CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
               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([(3, 9), (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))

    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)
    # verify that there is no supported versions in server hello
    node = node.add_child(ExpectServerHello(version = (3, 3),
                          extensions={ExtensionType.renegotiation_info:None}))
    node = node.add_child(ExpectCertificate())
    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["fallback from TLS 1.8 to 1.2"] = conversation


    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
               CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
               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([(3, 9), (3, 2)])
    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))

    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)
    # verify that there is no supported versions in server hello
    node = node.add_child(ExpectServerHello(version = (3, 2),
                          extensions={ExtensionType.renegotiation_info:None}))
    node = node.add_child(ExpectCertificate())
    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["fallback from TLS 1.8 to 1.1"] = conversation


    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
               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_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, version=(3, 4), extensions=ext))
    # negotiate TLS 1.2; it is valid for an implementation to abort handshake
    # but we don't cover it
    node = node.add_child(ExpectServerHello(version = (3, 3),
                          extensions={ExtensionType.renegotiation_info:None}))
    node = node.add_child(ExpectCertificate())
    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["TLS 1.3 in client hello legacy field"] = conversation


    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
                CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
               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_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, version=(3, 9), extensions=ext))
    # negotiate TLS 1.2; it is valid for an implementation to abort handshake
    # but we don't cover it
    node = node.add_child(ExpectServerHello(version = (3, 3),
                          extensions={ExtensionType.renegotiation_info:None}))
    node = node.add_child(ExpectCertificate())
    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["TLS 1.8 in client hello legacy field"] = conversation


    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
               CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
               CipherSuite.TLS_RSA_WITH_RC4_128_SHA,
               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([(3, 0)])
    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.protocol_version))
    conversations["SSL 3.0 in supported version"] = conversation


    # instruct RecordLayer to use SSLv2 record layer protocol (0, 2)
    conversation = Connect(host, port, version=(0, 2))
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256]
    node = node.add_child(ClientHelloGenerator(ciphers,
                                               version=(3, 4),
                                               ssl2=True))
    node = node.add_child(ExpectAlert())
    conversations["SSL 2.0 ClientHello with TLS 1.3 version and TLS 1.3 only ciphersuites"] = conversation

    # verify that the server does not support any of the draft implementations
    for l_ver in range(256):
        conversation = Connect(host, port)
        node = conversation
        ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
                   CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                   CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
        ext = {}
        groups = [GroupName.secp256r1]
        ext[ExtensionType.key_share] = key_share_ext_gen(groups)
        ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\
            .create([(127, l_ver), (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))

        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)
        # verify that there is no supported versions in server hello
        node = node.add_child(ExpectServerHello(version=(3, 3),
                              extensions={ExtensionType.renegotiation_info:None}))
        node = node.add_child(ExpectCertificate())
        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(AlertLevel.warning,
                                          AlertDescription.close_notify))
        node.next_sibling = ExpectClose()
        conversations["fallback from TLS 1.3-draft{0} to 1.2"
                      .format(l_ver)] = 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
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except Exception:
            print("Error while processing")
            print(traceback.format_exc())
            res = False

        if res:
            good += 1
            print("OK\n")
        else:
            bad += 1
            failed.append(c_name)

    print("Check version negotiation under TLS 1.3 with the supported")
    print("versions extension")
    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)
示例#21
0
def main():
    host = "localhost"
    port = 4433
    num_limit = 100
    fatal_alert = "decode_error"
    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", "alert="])
    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 == '--alert':
            fatal_alert = 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

    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_pkcs1_sha1, 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["tolerance legacy RSA PKCS#1.5"] = conversation

    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 = [(10, SignatureAlgorithm.rsa),
                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[
        "tolerance unallocated 0x0A01 (10+RSA) method"] = conversation

    # 32717 is the maximum possible amount of methods that can fit into the
    # ClientHello packet -- in TLS 1.3, there are also other mandatory
    # extensions
    for n in [215, 2355, 8132, 23754, 32717]:
        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)
        n = n - 2  # these are the mandatory methods in the end
        sig_algs = [(HashAlgorithm.sha1, SignatureAlgorithm.dsa)] * n
        sig_algs += [
            SignatureScheme.rsa_pss_rsae_sha256,
            SignatureScheme.rsa_pss_pss_sha256
        ]
        ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
            .create(sig_algs)
        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)

        # ApplicationData message may show up 1 to many times
        node.next_sibling = ExpectApplicationData()
        node = node.next_sibling.add_child(
            AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
        cycle_alert = ExpectAlert()
        node = node.add_child(cycle_alert)
        node.next_sibling = ExpectApplicationData()
        node.next_sibling.add_child(cycle_alert)
        node.next_sibling.next_sibling = ExpectClose()

        conversations["duplicated {0} non-rsa schemes".format(
            n)] = conversation

    for n in [215, 2355, 8132, 23754, 32717]:
        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)
        n = n - 2  # these are the mandatory methods in the end
        sig_algs = [SignatureScheme.rsa_pkcs1_sha1] * n
        sig_algs += [
            SignatureScheme.rsa_pss_rsae_sha256,
            SignatureScheme.rsa_pss_pss_sha256
        ]
        ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
            .create(sig_algs)
        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)

        # ApplicationData message may show up 1 to many times
        node.next_sibling = ExpectApplicationData()
        node = node.next_sibling.add_child(
            AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
        cycle_alert = ExpectAlert()
        node = node.add_child(cycle_alert)
        node.next_sibling = ExpectApplicationData()
        node.next_sibling.add_child(cycle_alert)
        node.next_sibling.next_sibling = ExpectClose()

        conversations["{0} invalid schemes".format(n)] = conversation

    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)
    # Add all supported sig_algs, put rsa at the end
    sig_algs = []
    for sig_alg in ['ecdsa', 'dsa', 'rsa']:
        sig_algs += [(getattr(HashAlgorithm, x), getattr(SignatureAlgorithm, sig_alg))\
                      for x in ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512']]
    # ed25519(0x0807), ed448(0x0808)
    sig_algs += [(8, 7), (8, 8)]
    sig_algs += [
        SignatureScheme.rsa_pss_pss_sha256, SignatureScheme.rsa_pss_pss_sha384,
        SignatureScheme.rsa_pss_pss_sha512,
        SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_rsae_sha384,
        SignatureScheme.rsa_pss_rsae_sha512
    ]
    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[
        "unique and well-known sig_algs, rsa algorithms last"] = conversation

    # 32717 is the maximum possible amount of methods that can fit into the
    # ClientHello packet -- in TLS 1.3, there are also other mandatory
    # extensions
    for n in [215, 2355, 8132, 23754, 32717]:
        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)
        n = n - 2  # these are the mandatory methods in the end
        sig_algs = list(
            chain(((i, j) for i in range(10, 224)
                   for j in range(10, (n // 214) + 10)),
                  ((i, 163) for i in range(10, (n % 214) + 10)), [
                      SignatureScheme.rsa_pss_rsae_sha256,
                      SignatureScheme.rsa_pss_pss_sha256
                  ]))
        ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
            .create(sig_algs)
        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()
        # OpenSSL sends the list of advertised and it doesn't fit a single
        # application data
        node = node.next_sibling.add_child(Close())
        conversations["tolerance {0} methods".format(n)] = conversation

    # 32715 is the maximum possible amount of methods that can fit into the
    # ClientHello packet -- in TLS 1.3, there are also other mandatory
    # extensions
    n = 32715
    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)
    n = n - 2  # these are the mandatory methods in the end
    n = n - len(RSA_SIG_ALL)  # number of methods in sig_alg_cert extension
    sig_algs = list(
        chain(((i, j) for i in range(10, 224)
               for j in range(10, (n // 214) + 10)),
              ((i, 163) for i in range(10, (n % 214) + 10)), [
                  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()
    # OpenSSL sends the list of advertised and it doesn't fit a single
    # application data
    node = node.next_sibling.add_child(Close())
    conversations["tolerance 32715 methods with sig_alg_cert"] = conversation

    # Use empty supported algorithm extension
    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_AES_128_GCM_SHA256,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    ext = OrderedDict()
    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 = []
    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, getattr(AlertDescription, fatal_alert)))
    node = node.add_child(ExpectClose())
    conversations["empty list of signature methods"] = \
            conversation

    # Only undefined algorithms
    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)
    sigs = [
        (HashAlgorithm.sha256, 24),  # undefined signature algorithm
        (24, SignatureAlgorithm.rsa),  # undefined hash algorithm
        (10, 10),  # undefined pair
        (9, 24),  # undefined pair
        (0xff, 0xff)  # undefined pair
    ]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sigs)
    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.handshake_failure))
    node = node.next_sibling = ExpectClose()
    conversations["only undefined sigalgs"] = conversation

    # RSA-PSS is mandatory
    # More thoroughly tested in  scripts/test-tls13-pkcs-signature.py
    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)
    sigs = [SignatureScheme.rsa_pkcs1_sha1, SignatureScheme.rsa_pkcs1_sha512]
    ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
        .create(sigs)
    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.handshake_failure))
    node = node.next_sibling = ExpectClose()
    conversations["only legacy sigalgs"] = conversation

    # padded extension
    conversation = Connect(host, port)
    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)
    ext[ExtensionType.signature_algorithms] = \
        TLSExtension(extType=ExtensionType.signature_algorithms) \
            .create(bytearray(b'\x00\x04'  # length of array
                              b'\x08\x04'  # rsa_pss_rsae_sha256
                              b'\x08\x09'  # rsa_pss_pss_sha256
                              b'\x04\x03'))
    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.decode_error))
    node = node.add_child(ExpectClose())
    conversations["padded sigalgs"] = conversation

    # send properly formatted one byte extension
    conversation = Connect(host, port)
    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)
    ext[ExtensionType.signature_algorithms] = \
        TLSExtension(extType=ExtensionType.signature_algorithms) \
            .create(bytearray(b'\x00\x01'  # length of array
                              b'\x02'))
    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.decode_error))
    node = node.add_child(ExpectClose())
    conversations["one byte array"] = conversation

    # send properly formatted three byte extension
    conversation = Connect(host, port)
    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)
    ext[ExtensionType.signature_algorithms] = \
        TLSExtension(extType=ExtensionType.signature_algorithms) \
            .create(bytearray(b'\x00\x05'  # length of array
                              b'\x08\x04'  # rsa_pss_rsae_sha256
                              b'\x08\x09'  # rsa_pss_pss_sha256
                              b'\x02'))
    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.decode_error))
    node = node.add_child(ExpectClose())
    conversations["three byte array"] = conversation

    # Fuzz the length of supported extensions
    for i in range(1, 0x100):
        conversation = Connect(host, port)
        node = conversation
        ciphers = [
            CipherSuite.TLS_AES_128_GCM_SHA256,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
        ext = OrderedDict()
        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_cert] = SignatureAlgorithmsCertExtension()\
            .create(RSA_SIG_ALL)
        ext[ExtensionType.signature_algorithms] = SignatureAlgorithmsExtension()\
            .create(sig_algs)
        hello = ClientHelloGenerator(ciphers, extensions=ext)
        node = node.add_child(fuzz_message(hello, xors={-5: i}))
        node = node.add_child(
            ExpectAlert(AlertLevel.fatal, getattr(AlertDescription,
                                                  fatal_alert)))
        node = node.add_child(ExpectClose())
        conversations["fuzz length inside extension to {0}".format(4^i)] = \
                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("Signature Algorithms in TLS 1.3")
    print("Check if valid signature algorithm extensions are accepted and")
    print("invalid properly rejected by the TLS 1.3 server.\n")
    print("Server must be configured to support only rsa_pss_rsae_sha512")
    print("signature algorithm.")

    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)
示例#22
0
def main():
    """Test if server supports unsupported curve fallback"""
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:", ["help"])
    for opt, arg in opts:
        if opt == '-h':
            host = arg
        elif opt == '-p':
            port = int(arg)
        elif opt == '-e':
            run_exclude.add(arg)
        elif opt == '-n':
            num_limit = int(arg)
        elif opt == '--help':
            help_msg()
            sys.exit(0)
        else:
            raise ValueError("Unknown option: {0}".format(opt))

    if args:
        run_only = set(args)
    else:
        run_only = None

    conversations = {}

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
        CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
    ]
    ext = {
        ExtensionType.renegotiation_info:
        None,
        ExtensionType.supported_groups:
        SupportedGroupsExtension().create([GroupName.secp160k1])
    }
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectServerHello(
            cipher=CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
            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(
        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["check for unsupported curve fallback"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
        CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    node = node.add_child(ClientHelloGenerator(ciphers))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    node = node.add_child(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

    # run the conversation
    good = 0
    bad = 0
    failed = []
    if not num_limit:
        num_limit = len(conversations)

    # make sure that sanity test is run first and last
    # to verify that server was running and kept running throught
    sanity_test = ('sanity', conversations['sanity'])
    ordered_tests = chain([sanity_test],
                          islice(
                              filter(lambda x: x[0] != 'sanity',
                                     conversations.items()), num_limit),
                          [sanity_test])

    for c_name, c_test in ordered_tests:
        if run_only and c_name not in run_only or c_name in run_exclude:
            continue
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except:
            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)
示例#23
0
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    dhe = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:d", ["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 == '-d':
            dhe = 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(RSA_SIG_ALL)
        ext[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]
    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())
    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

    # verify that server does not advertise support for heartbeat extension
    conversation = Connect(host, port)
    node = conversation
    ext = {}
    ext[ExtensionType.heartbeat] = HeartbeatExtension().create(
        HeartbeatMode.PEER_ALLOWED_TO_SEND)
    if dhe:
        groups = [GroupName.secp256r1,
                  GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(RSA_SIG_ALL)
        ext[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]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                   CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(extensions=ext))
    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["no extension in Server Hello"] = conversation

    # verify that server rejects heartbeat message
    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(TCPBufferingEnable())
    ext = {}
    ext[ExtensionType.heartbeat] = HeartbeatExtension().create(
        HeartbeatMode.PEER_ALLOWED_TO_SEND)
    if dhe:
        groups = [GroupName.secp256r1,
                  GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(RSA_SIG_ALL)
        ext[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]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                   CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    # this assumes the server supports/negotiatiates TLS 1.2
    node = node.add_child(SetRecordVersion((3, 3)))
    node = node.add_child(HeartbeatGenerator(bytearray(b'test heartbeat')))
    node = node.add_child(TCPBufferingDisable())
    node = node.add_child(TCPBufferingFlush())
    node = node.add_child(ExpectServerHello(extensions=ext))
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    node = node.add_child(ExpectServerHelloDone())
    node = node.add_child(ExpectAlert(AlertLevel.fatal,
                                      AlertDescription.unexpected_message))
    node.add_child(ExpectClose())
    conversations["heartbeat in handshake without support in server"] = \
        conversation

    # verify that server rejects heartbleed message
    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(TCPBufferingEnable())
    ext = {}
    ext[ExtensionType.heartbeat] = HeartbeatExtension().create(
        HeartbeatMode.PEER_ALLOWED_TO_SEND)
    if dhe:
        groups = [GroupName.secp256r1,
                  GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(RSA_SIG_ALL)
        ext[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]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                   CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    # this assumes the server supports/negotiatiates TLS 1.2
    node = node.add_child(SetRecordVersion((3, 3)))
    node = node.add_child(fuzz_message(
        HeartbeatGenerator(bytearray(b'test heartbeat')),
        substitutions={1: 0, 2: 64}))
    node = node.add_child(TCPBufferingDisable())
    node = node.add_child(TCPBufferingFlush())
    node = node.add_child(ExpectServerHello(extensions=ext))
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    node = node.add_child(ExpectServerHelloDone())
    node = node.add_child(ExpectAlert(AlertLevel.fatal,
                                      AlertDescription.unexpected_message))
    node.add_child(ExpectClose())
    conversations["heartbleed in handshake without support in server"] = \
        conversation

    # see if post-handshake heartbeat (encrypted) is rejected too
    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(RSA_SIG_ALL)
        ext[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]
    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())
    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(HeartbeatGenerator(bytearray(b'test heartbeat')))
    node = node.add_child(ExpectAlert(AlertLevel.fatal,
                                      AlertDescription.unexpected_message))
    node.add_child(ExpectClose())
    conversations["heartbeat after handshake"] = conversation

    # see if post-handshake heartbleed (encrypted) is rejected too
    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(RSA_SIG_ALL)
        ext[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]
    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())
    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(fuzz_message(
        HeartbeatGenerator(bytearray(b'test heartbeat')),
        substitutions={1: 0, 2: 64}))
    node = node.add_child(ExpectAlert(AlertLevel.fatal,
                                      AlertDescription.unexpected_message))
    node.add_child(ExpectClose())
    conversations["heartbleed after handshake"] = 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
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except Exception:
            print("Error while processing")
            print(traceback.format_exc())
            res = False

        if res:
            good += 1
            print("OK\n")
        else:
            bad += 1
            failed.append(c_name)

    print("Test to verify that server does not support heartbeat extension\n")
    print("Also verify that the server will not tolerate heartbeat messages\n")
    print("version: {0}\n".format(version))

    print("Test end")
    print("successful: {0}".format(good))
    print("failed: {0}".format(bad))
    failed_sorted = sorted(failed, key=natural_sort_keys)
    print("  {0}".format('\n  '.join(repr(i) for i in failed_sorted)))

    if bad > 0:
        sys.exit(1)
示例#24
0
def main():
    """Test if server supports the RFC 7919 key exchange"""
    host = "localhost"
    port = 4433
    num_limit = None
    fatal_alert = "insufficient_security"
    run_exclude = set()

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:", ["help", "alert="])
    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 == '--alert':
            fatal_alert = 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_DHE_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(
        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(AlertLevel.warning, AlertDescription.close_notify))
    node.next_sibling = ExpectClose()
    node.add_child(ExpectClose())

    conversations["sanity"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
        CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
    ]
    node = node.add_child(
        ClientHelloGenerator(
            ciphers, extensions={ExtensionType.renegotiation_info: None}))
    node = node.add_child(
        ExpectServerHello(cipher=CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                          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(
        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(AlertLevel.warning, AlertDescription.close_notify))
    node.next_sibling = ExpectClose()
    node.add_child(ExpectClose())

    conversations["Check if DHE preferred"] = conversation

    for group in GroupName.allFF:
        conversation = Connect(host, port)
        node = conversation
        ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
        ext = {ExtensionType.renegotiation_info: None}
        ext[ExtensionType.supported_groups] = \
                SupportedGroupsExtension().create([group])
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
        node = node.add_child(
            ExpectServerHello(
                extensions={ExtensionType.renegotiation_info: None}))
        node = node.add_child(ExpectCertificate())
        node = node.add_child(ExpectServerKeyExchange(valid_groups=[group]))
        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(AlertLevel.warning, AlertDescription.close_notify))
        node.next_sibling = ExpectClose()
        node.add_child(ExpectClose())

        conversations["{0} negotiation".format(GroupName.toStr(group))] = \
                conversation

        conversation = Connect(host, port)
        node = conversation
        ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
        ext = {ExtensionType.renegotiation_info: None}
        ext[ExtensionType.supported_groups] = \
                SupportedGroupsExtension().create([511, group])
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
        node = node.add_child(
            ExpectServerHello(
                extensions={ExtensionType.renegotiation_info: None}))
        node = node.add_child(ExpectCertificate())
        node = node.add_child(ExpectServerKeyExchange(valid_groups=[group]))
        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(AlertLevel.warning, AlertDescription.close_notify))
        node.next_sibling = ExpectClose()
        node.add_child(ExpectClose())

        conversations["unassigned tolerance, {0} negotiation".format(GroupName.toStr(group))] = \
                conversation

        conversation = Connect(host, port)
        node = conversation
        ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
        ext = {ExtensionType.renegotiation_info: None}
        ext[ExtensionType.supported_groups] = \
                SupportedGroupsExtension().create([GroupName.secp256r1, group])
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
        node = node.add_child(
            ExpectServerHello(
                extensions={ExtensionType.renegotiation_info: None}))
        node = node.add_child(ExpectCertificate())
        node = node.add_child(ExpectServerKeyExchange(valid_groups=[group]))
        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(AlertLevel.warning, AlertDescription.close_notify))
        node.next_sibling = ExpectClose()
        node.add_child(ExpectClose())

        conversations["tolerate ECC curve in groups without ECC cipher, "
                      "negotiate {0} ".format(GroupName.toStr(group))] = \
                conversation

        for group2 in GroupName.allFF:
            if group == group2:
                continue
            conversation = Connect(host, port)
            node = conversation
            ciphers = [CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
            ext = {ExtensionType.renegotiation_info: None}
            ext[ExtensionType.supported_groups] = \
                    SupportedGroupsExtension().create([511, group, group2])
            node = node.add_child(ClientHelloGenerator(ciphers,
                                                       extensions=ext))
            node = node.add_child(
                ExpectServerHello(
                    extensions={ExtensionType.renegotiation_info: None}))
            node = node.add_child(ExpectCertificate())
            node = node.add_child(
                ExpectServerKeyExchange(valid_groups=[group, group2]))
            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(AlertLevel.warning, AlertDescription.close_notify))
            node.next_sibling = ExpectClose()
            node.add_child(ExpectClose())

            conversations["{0} or {1} negotiation".format(
                GroupName.toStr(group),
                GroupName.toStr(group2))] = conversation

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
        CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
    ]
    ext = {ExtensionType.renegotiation_info: None}
    ext[ExtensionType.supported_groups] = \
            SupportedGroupsExtension().create([511])
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectServerHello(cipher=CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                          extensions={ExtensionType.renegotiation_info: None}))
    node = node.add_child(ExpectCertificate())
    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(AlertLevel.warning, AlertDescription.close_notify))
    node.next_sibling = ExpectClose()
    node.add_child(ExpectClose())

    conversations["fallback to non-ffdhe"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
        CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
    ]
    ext = {ExtensionType.renegotiation_info: None}
    ext[ExtensionType.supported_groups] = \
            SupportedGroupsExtension().create([GroupName.secp256r1, 511])
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectServerHello(cipher=CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                          extensions={ExtensionType.renegotiation_info: None}))
    node = node.add_child(ExpectCertificate())
    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(AlertLevel.warning, AlertDescription.close_notify))
    node.next_sibling = ExpectClose()
    node.add_child(ExpectClose())

    conversations[
        "fallback to non-ffdhe with secp256r1 advertised"] = conversation

    # first paragraph of section 4 in RFC 7919
    conversation = Connect(host, port)
    node = conversation
    ciphers = [
        CipherSuite.TLS_RSA_WITH_NULL_SHA,
        CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
    ]
    ext = {ExtensionType.renegotiation_info: None}
    ext[ExtensionType.supported_groups] = \
            SupportedGroupsExtension().create([511])
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, getattr(AlertDescription, fatal_alert)))
    node.add_child(ExpectClose())

    conversations["no overlap between groups"] = conversation

    good = 0
    bad = 0
    failed = []
    num_limit = num_limit or 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
        try:
            runner.run()
        except Exception:
            print("Error while processing")
            print(traceback.format_exc())
            res = False

        if res:
            good += 1
            print("OK\n")
        else:
            bad += 1
            failed.append(c_name)

    print("Test end")
    print("successful: {0}".format(good))
    print("failed: {0}".format(bad))
    failed_sorted = sorted(failed, key=natural_sort_keys)
    print("  {0}".format('\n  '.join(repr(i) for i in failed_sorted)))

    if bad > 0:
        sys.exit(1)
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    dhe = False
    splitting = None

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:x:X:n:d", ["help", "1/n-1", "0/n"])
    for opt, arg in opts:
        if opt == '-h':
            host = arg
        elif opt == '-p':
            port = int(arg)
        elif opt == '-e':
            run_exclude.add(arg)
        elif opt == '-x':
            expected_failures[arg] = None
            last_exp_tmp = str(arg)
        elif opt == '-X':
            if not last_exp_tmp:
                raise ValueError("-x has to be specified before -X")
            expected_failures[last_exp_tmp] = str(arg)
        elif opt == '-n':
            num_limit = int(arg)
        elif opt == '-d':
            dhe = True
        elif opt == '--1/n-1':
            splitting = 1
        elif opt == '--0/n':
            splitting = 0
        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())
    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")))
    if splitting is not None:
        node = node.add_child(ExpectApplicationData(size=splitting))
    node = node.add_child(ExpectApplicationData())
    node = node.add_child(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    node.next_sibling = ExpectClose()
    conversations["sanity"] = conversation

    # skip Client Hello
    conversation = Connect(host, port)
    node = conversation
    if dhe:
        node = node.add_child(
            ClientKeyExchangeGenerator(
                cipher=CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
                version=(3, 3),
                dh_Yc=2**2047 - 1))
    else:
        node = node.add_child(
            ClientKeyExchangeGenerator(
                cipher=CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
                version=(3, 3),
                encrypted_premaster=bytearray(b'\xff' * 256)))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.unexpected_message))
    node = node.add_child(ExpectClose())
    conversations["skip Client Hello"] = conversation

    # skip client key exchange
    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())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    node = node.add_child(ExpectServerHelloDone())
    node = node.add_child(ChangeCipherSpecGenerator())
    node = node.add_child(FinishedGenerator())
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.unexpected_message))
    node = node.add_child(ExpectClose())
    conversations["skip Client Key Exchange"] = conversation

    # skip Change Cipher Spec
    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())
    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(FinishedGenerator())
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.unexpected_message))
    node = node.add_child(ExpectClose())
    conversations["skip Change Cipher Spec"] = conversation

    # skip Finished
    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())
    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(
        ApplicationDataGenerator(bytearray(b"GET / HTTP/1.0\r\n\r\n")))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.unexpected_message))
    node = node.add_child(ExpectClose())
    conversations["skip Finished"] = 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:
        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("Script to verify if client skipping messages will cause connection")
    print("failure. This will effectively test for CVE-2014-0224.\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)
示例#26
0
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    ext_exclude = set()
    cookie = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:x:X:n:", ["help", "cookie", "exc="])
    for opt, arg in opts:
        if opt == '-h':
            host = arg
        elif opt == '-p':
            port = int(arg)
        elif opt == '-e':
            run_exclude.add(arg)
        elif opt == '-x':
            expected_failures[arg] = None
            last_exp_tmp = str(arg)
        elif opt == '-X':
            if not last_exp_tmp:
                raise ValueError("-x has to be specified before -X")
            expected_failures[last_exp_tmp] = str(arg)
        elif opt == '-n':
            num_limit = int(arg)
        elif opt == '--exc':
            ext_exclude.add(int(arg))
        elif opt == '--cookie':
            cookie = True
        elif opt == '--help':
            help_msg()
            sys.exit(0)
        else:
            raise ValueError("Unknown option: {0}".format(opt))

    if args:
        run_only = set(args)
    else:
        run_only = None

    conversations = {}

    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
               CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
    ext = {}
    groups = [GroupName.secp256r1]
    key_shares = []
    for group in groups:
        key_shares.append(key_share_gen(group))
    ext[ExtensionType.key_share] = ClientKeyShareExtension().create(key_shares)
    ext[ExtensionType.supported_versions] = SupportedVersionsExtension()\
        .create([TLS_1_3_DRAFT, (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

    conversation = Connect(host, port)
    node = conversation
    ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
               CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
    ext = OrderedDict()
    groups = [GroupName.secp256r1]
    key_shares = []
    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))

    hrr_ext = OrderedDict()
    if cookie:
        hrr_ext[ExtensionType.cookie] = None
    hrr_ext[ExtensionType.key_share] = None
    hrr_ext[ExtensionType.supported_versions] = None
    node = node.add_child(ExpectHelloRetryRequest(extensions=hrr_ext))
    node = node.add_child(ExpectChangeCipherSpec())

    # Reverse extensions
    rev_ext = OrderedDict()
    rev_ext.update(reversed(ext.items()))
    groups = [GroupName.secp256r1]
    key_shares = []
    for group in groups:
        key_shares.append(key_share_gen(group))
    rev_ext[ExtensionType.key_share] = ClientKeyShareExtension().create(key_shares)
    if cookie:
        rev_ext[ExtensionType.cookie] = ch_cookie_handler
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=rev_ext))
    node = node.add_child(ExpectAlert(AlertLevel.fatal,
                                      AlertDescription.illegal_parameter))
    node.add_child(ExpectClose())
    conversations["HRR reversed order of known extensions"] = conversation

    unassigned_ext_id = list(range(52, 65279))

    # Exclude extensions from a list of unassigned ones
    unassigned_ext_id = [ext for ext in unassigned_ext_id if ext not in ext_exclude]

    chunk_size = 4096
    for ext_chunk in (unassigned_ext_id[j:j + chunk_size]
                      for j in range(0, len(unassigned_ext_id), chunk_size)):
        conversation = Connect(host, port)
        node = conversation
        ciphers = [CipherSuite.TLS_AES_128_GCM_SHA256,
                   CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
        ext = OrderedDict()
        groups = [GroupName.secp256r1]
        key_shares = []
        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)
        for ext_id in ext_chunk:
            ext[ext_id] = AutoEmptyExtension()
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))

        hrr_ext = OrderedDict()
        if cookie:
            hrr_ext[ExtensionType.cookie] = None
        hrr_ext[ExtensionType.key_share] = None
        hrr_ext[ExtensionType.supported_versions] = None
        node = node.add_child(ExpectHelloRetryRequest(extensions=hrr_ext))
        node = node.add_child(ExpectChangeCipherSpec())

        # Reverse extensions
        rev_ext = OrderedDict()
        rev_ext.update(reversed(ext.items()))
        groups = [GroupName.secp256r1]
        key_shares = []
        for group in groups:
            key_shares.append(key_share_gen(group))
        rev_ext[ExtensionType.key_share] = ClientKeyShareExtension().create(key_shares)
        if cookie:
            rev_ext[ExtensionType.cookie] = ch_cookie_handler
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=rev_ext))
        node = node.add_child(ExpectAlert(AlertLevel.fatal,
                                          AlertDescription.illegal_parameter))
        node.add_child(ExpectClose())

        conversations["HRR reversed order of unassigned extensions, ext_ids in range from {0} to {1}".format(
            ext_chunk[0], ext_chunk[-1])] = 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("TLS 1.3 communication with shuffled extensions in CH messages.")
    print("Verify that server reject second CH message,")
    print("when the order of extensions in first and second CH is different.")
    print("Also unassigned extensions are used.\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 test_write_empty(self):
        ext = SupportedGroupsExtension()

        self.assertEqual(bytearray(b'\x00\x0A\x00\x00'), ext.write())
示例#28
0
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    dhe = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:d", ["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 == '-d':
            dhe = 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(
                [SignatureScheme.rsa_pkcs1_sha256,
                 SignatureScheme.rsa_pss_rsae_sha256])
        ext[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
        ]
    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())
    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

    conversation = Connect(host, port)
    node = conversation
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    else:
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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\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["only http/1.1"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ext = {ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.')])}
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    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(
        ExpectAlert(AlertLevel.fatal,
                    AlertDescription.no_application_protocol))
    node.add_child(ExpectClose())
    conversations["only http/1."] = conversation

    conversation = Connect(host, port)
    node = conversation
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.X')])
    }
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    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(
        ExpectAlert(AlertLevel.fatal,
                    AlertDescription.no_application_protocol))
    node.add_child(ExpectClose())
    conversations["only http/1.X"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ext = {
        ExtensionType.alpn:
        ALPNExtension().create([bytearray(b'http/1.'),
                                bytearray(b'http/1.1')])
    }
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    else:
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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\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["http/1. and http/1.1"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ext = {ExtensionType.alpn: ALPNExtension().create([bytearray(b'')])}
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    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(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node.add_child(ExpectClose())
    conversations["empty element"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ext = {ExtensionType.alpn: ALPNExtension().create([])}
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    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(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node.add_child(ExpectClose())
    conversations["empty list"] = conversation

    conversation = Connect(host, port)
    node = conversation
    ext = {
        ExtensionType.alpn:
        TLSExtension(extType=ExtensionType.alpn).create(bytearray())
    }
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    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(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node.add_child(ExpectClose())
    conversations["empty extension"] = conversation

    # underflow length of "protocol_name_list" test
    conversation = Connect(host, port)
    node = conversation
    # the ALPN extension needs to be the last one for fuzz_message to work
    # correctly
    ext = OrderedDict()
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    else:
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    ext[ExtensionType.alpn] = ALPNExtension().create(
        [bytearray(b'http/1.1'), bytearray(b'http/2')])
    msg = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    # -17 is position of second byte in 2 byte long length of "protocol_name_list"
    # setting it to value of 9 (bytes) will hide the second item in the "protocol_name_list"
    node = node.add_child(fuzz_message(msg, substitutions={-17: 9}))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node = node.add_child(ExpectClose())
    conversations["underflow length of protocol_name_list"] = conversation

    # overflow length of "protocol_name_list" test
    conversation = Connect(host, port)
    node = conversation
    # the ALPN extension needs to be the last one for fuzz_message to work
    # correctly
    ext = OrderedDict()
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    else:
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    ext[ExtensionType.alpn] = ALPNExtension().create(
        [bytearray(b'http/1.1'), bytearray(b'http/2')])
    msg = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    # -17 is position of second byte in 2 byte long length of "protocol_name_list"
    # setting it to value of 18 (bytes) will raise the length value for 2 more bytes
    node = node.add_child(fuzz_message(msg, substitutions={-17: 18}))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node = node.add_child(ExpectClose())
    conversations["overflow length of protocol_name_list"] = conversation

    # overflow length of last item in "protocol_name_list" test
    conversation = Connect(host, port)
    node = conversation
    # the ALPN extension needs to be the last one for fuzz_message to work
    # correctly
    ext = OrderedDict()
    if dhe:
        add_dhe_extensions(ext)
        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
        ]
    else:
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    ext[ExtensionType.alpn] = ALPNExtension().create(
        [bytearray(b'http/1.1'), bytearray(b'http/2')])
    msg = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    # -7 is position of a length (1 byte long) for the last item in "protocol_name_list"
    # setting it to value of 8 (bytes) will raise the length value for 2 more bytes
    node = node.add_child(fuzz_message(msg, substitutions={-7: 8}))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.decode_error))
    node = node.add_child(ExpectClose())
    conversations["overflow length of last item"] = conversation

    # renegotiation with protocol change
    conversation = Connect(host, port)
    node = conversation

    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
        ciphers = [
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        ]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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())
    # 2nd handshake
    node = node.add_child(ResetHandshakeHashes())
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/2')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
    node = node.add_child(
        ClientHelloGenerator(ciphers, session_id=bytearray(0), extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/2')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    node.next_sibling = ExpectClose()
    conversations["renegotiation with protocol change"] = conversation

    # renegotiation without protocol change
    conversation = Connect(host, port)
    node = conversation

    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
        ciphers = [
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        ]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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())
    # 2nd handshake
    node = node.add_child(ResetHandshakeHashes())
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
    node = node.add_child(
        ClientHelloGenerator(ciphers, session_id=bytearray(0), extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    node.next_sibling = ExpectClose()
    conversations["renegotiation without protocol change"] = conversation

    # renegotiation 2nd handshake alpn
    conversation = Connect(host, port)
    node = conversation
    ext = {ExtensionType.renegotiation_info: None}
    if dhe:
        add_dhe_extensions(ext)
        ciphers = [
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        ]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(extensions=ext))
    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())
    # 2nd handshake
    node = node.add_child(ResetHandshakeHashes())
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
    node = node.add_child(
        ClientHelloGenerator(ciphers, session_id=bytearray(0), extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    node.next_sibling = ExpectClose()
    conversations["renegotiation 2nd handshake alpn"] = conversation

    # resumption without alpn change
    conversation = Connect(host, port)
    node = conversation
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
        ciphers = [
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        ]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    close = ExpectClose()
    node.next_sibling = close
    node = node.add_child(ExpectClose())
    node = node.add_child(Close())
    node = node.add_child(Connect(host, port))
    close.add_child(node)

    node = node.add_child(ResetHandshakeHashes())
    node = node.add_child(ResetRenegotiationInfo())
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext, resume=True))
    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())
    node.next_sibling = ExpectClose()
    node = node.add_child(ExpectClose())

    conversations["resumption without alpn change"] = conversation

    # resumption with alpn change
    conversation = Connect(host, port)
    node = conversation
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
        ciphers = [
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        ]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    close = ExpectClose()
    node.next_sibling = close
    node = node.add_child(ExpectClose())
    node = node.add_child(Close())
    node = node.add_child(Connect(host, port))
    close.add_child(node)

    node = node.add_child(ResetHandshakeHashes())
    node = node.add_child(ResetRenegotiationInfo())
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'h2')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'h2')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext, resume=True))
    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())
    node.next_sibling = ExpectClose()
    node = node.add_child(ExpectClose())

    conversations["resumption with alpn change"] = conversation

    # resumption with alpn
    conversation = Connect(host, port)
    node = conversation
    ext = {ExtensionType.renegotiation_info: None}
    if dhe:
        add_dhe_extensions(ext)
        ciphers = [
            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA
        ]
    else:
        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {ExtensionType.renegotiation_info: None}
    node = node.add_child(ExpectServerHello(extensions=ext))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    close = ExpectClose()
    node.next_sibling = close
    node = node.add_child(ExpectClose())
    node = node.add_child(Close())
    node = node.add_child(Connect(host, port))
    close.add_child(node)

    node = node.add_child(ResetHandshakeHashes())
    node = node.add_child(ResetRenegotiationInfo())
    ext = {
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')]),
        ExtensionType.renegotiation_info: None
    }
    if dhe:
        add_dhe_extensions(ext)
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext, resume=True))
    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())
    node.next_sibling = ExpectClose()
    node = node.add_child(ExpectClose())

    conversations["resumption with alpn"] = conversation

    # 16269 byte long array and 255 byte long items test
    # Client Hello longer than 2^14 bytes
    conversation = Connect(host, port)
    node = conversation
    proto = bytearray(b"A" * 255)
    lista = []
    lista.append(proto)
    # 63 items 255 bytes long + 1 item 195 bytes long + 1 item 8 byte long (http/1.1)
    for p in range(1, 63):
        lista.append(proto)
    if dhe:
        # (in DHE we send more extensions and longer cipher suite list, so the
        # extension has to be shorter)
        # 145 + 1 byte to reproduce the issue
        lista.append(bytearray(b'B' * 146))
    else:
        # 195 + 1 byte to reproduce the issue
        lista.append(bytearray(b'B' * 196))
    lista.append(bytearray(b'http/1.1'))
    ext = {ExtensionType.alpn: ALPNExtension().create(lista)}
    if dhe:
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(
                [SignatureScheme.rsa_pkcs1_sha256,
                 SignatureScheme.rsa_pss_rsae_sha256])
        ext[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
        ]
    else:
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    node.next_sibling = ExpectClose()
    conversations["16269 byte long array"] = 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
        print("{0} ...".format(c_name))

        runner = Runner(c_test)

        res = True
        try:
            runner.run()
        except Exception:
            print("Error while processing")
            print(traceback.format_exc())
            res = False

        if res:
            good += 1
            print("OK\n")
        else:
            bad += 1
            failed.append(c_name)

    print("ALPN extension tests")
    print("Verify that the ALPN extenion is supported in the server and has")
    print("correct error handling.")
    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 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 throught
    sanity_test = ('sanity', conversations['sanity'])
    ordered_tests = chain([sanity_test],
                          islice(filter(lambda x: x[0] != 'sanity',
                                        conversations.items()), num_limit),
                          [sanity_test])

    for c_name, c_test in ordered_tests:
        if run_only and c_name not in run_only or c_name in run_exclude:
            continue
        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)
示例#30
0
def main():
    host = "localhost"
    port = 4433
    num_limit = 100
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    dhe = False

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:x:X:n:d", ["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 == '-d':
            dhe = 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
    ext = {}
    if dhe:
        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_CCM,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_RSA_WITH_AES_256_CCM,
            CipherSuite.TLS_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_RSA_WITH_AES_256_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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

    # reject ciphers in TLS1.1
    conversation = Connect(host, port)
    node = conversation
    ext = {}
    if dhe:
        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_CCM,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_RSA_WITH_AES_256_CCM,
            CipherSuite.TLS_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_RSA_WITH_AES_256_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, version=(3, 2)))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.handshake_failure))
    node.add_child(ExpectClose())
    conversations["AES-CCM in TLS1.1"] = conversation

    # empty application data message acceptance
    node = conversation
    ext = {}
    if dhe:
        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_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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()))
    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(AlertLevel.warning, AlertDescription.close_notify))
    node.next_sibling = ExpectClose()
    conversations["empty app data"] = conversation

    # empty application data message acceptance with _8 ciphers
    node = conversation
    ext = {}
    if dhe:
        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_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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()))
    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(AlertLevel.warning, AlertDescription.close_notify))
    node.next_sibling = ExpectClose()
    conversations["empty app data with _8 ciphers"] = conversation

    # 1/n-1 message splitting
    conversation = Connect(host, port)
    node = conversation
    ext = {}
    if dhe:
        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_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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"G")))
    node = node.add_child(
        ApplicationDataGenerator(bytearray(b"ET / HTTP/1.0\r\n\r\n")))
    node = node.add_child(ExpectApplicationData())
    node = node.add_child(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(
        ExpectAlert(AlertLevel.warning, AlertDescription.close_notify))
    node.next_sibling = ExpectClose()
    conversations["1/n-1 record splitting"] = conversation

    # plaintext just under the maximum permissible
    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(SetMaxRecordSize(2**16 - 1))
    ext = {}
    if dhe:
        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_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    data = bytearray(b"GET / HTTP/1.0\r\n" + b"X-test: " + b"A" *
                     (2**14 - 28) + b"\r\n\r\n")
    assert len(data) == 2**14
    node = node.add_child(ApplicationDataGenerator(data))
    node = node.add_child(ExpectApplicationData())
    node = node.add_child(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    # allow for multiple application data records in response
    node = node.add_child(ExpectApplicationData())
    loop = node
    node = node.add_child(
        ExpectAlert(AlertLevel.warning, AlertDescription.close_notify))
    loop.next_sibling = node
    node.next_sibling = ExpectClose()
    conversations["max size plaintext"] = conversation

    # plaintext over the maximum permissible
    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(SetMaxRecordSize(2**16 - 1))
    ext = {}
    if dhe:
        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_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    data = bytearray(b"GET / HTTP/1.0\r\n" + b"X-test: " + b"A" *
                     (2**14 - 28) + b"\r\n\r\n")
    assert len(data) == 2**14
    node = node.add_child(ApplicationDataGenerator(data))
    node = node.add_child(ExpectApplicationData())
    node = node.add_child(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    # allow for multiple application data records in response
    node = node.add_child(ExpectApplicationData())
    loop = node
    node = node.add_child(
        ExpectAlert(AlertLevel.warning, AlertDescription.close_notify))
    loop.next_sibling = node
    node.next_sibling = ExpectClose()
    conversations["max size plaintext with _8 ciphers"] = conversation

    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(SetMaxRecordSize(2**16 - 1))
    ext = {}
    if dhe:
        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_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    data = bytearray(b"GET / HTTP/1.0\r\n" + b"X-test: " + b"A" *
                     (2**14 - 28 + 1) + b"\r\n\r\n")
    assert len(data) == 2**14 + 1
    node = node.add_child(ApplicationDataGenerator(data))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, [
            AlertDescription.decompression_failure,
            AlertDescription.record_overflow
        ]))
    node.add_child(ExpectClose())
    conversations["too big plaintext"] = conversation

    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(SetMaxRecordSize(2**16 - 1))
    ext = {}
    if dhe:
        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_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    data = bytearray(b"GET / HTTP/1.0\r\n" + b"X-test: " + b"A" *
                     (2**14 - 28 + 1) + b"\r\n\r\n")
    assert len(data) == 2**14 + 1
    node = node.add_child(ApplicationDataGenerator(data))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, [
            AlertDescription.decompression_failure,
            AlertDescription.record_overflow
        ]))
    node.add_child(ExpectClose())
    conversations["too big plaintext with _8 ciphers"] = conversation

    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(SetMaxRecordSize(2**16 - 1))
    ext = {}
    if dhe:
        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_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    data = bytearray(b"GET / HTTP/1.0\r\n" + b"X-test: " + b"A" *
                     (2**14 + 1024 - 28) + b"\r\n\r\n")
    assert len(data) == 2**14 + 1024
    node = node.add_child(ApplicationDataGenerator(data))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, [
            AlertDescription.decompression_failure,
            AlertDescription.record_overflow
        ]))
    node.add_child(ExpectClose())
    conversations["too big plaintext - max compress"] = conversation

    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(SetMaxRecordSize(2**16 - 1))
    ext = {}
    if dhe:
        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_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    data = bytearray(b"GET / HTTP/1.0\r\n" + b"X-test: " + b"A" *
                     (2**14 + 1024 - 28) + b"\r\n\r\n")
    assert len(data) == 2**14 + 1024
    node = node.add_child(ApplicationDataGenerator(data))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, [
            AlertDescription.decompression_failure,
            AlertDescription.record_overflow
        ]))
    node.add_child(ExpectClose())
    conversations[
        "too big plaintext - max compress with _8 ciphers"] = conversation

    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(SetMaxRecordSize(2**16 - 1))
    ext = {}
    if dhe:
        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_CCM,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    data = bytearray(b"GET / HTTP/1.0\r\n" + b"X-test: " + b"A" *
                     (2**14 + 1024 - 28 + 1) + b"\r\n\r\n")
    assert len(data) == 2**14 + 1024 + 1
    node = node.add_child(ApplicationDataGenerator(data))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.record_overflow))
    node.add_child(ExpectClose())
    conversations["too big plaintext - above TLSCompressed max"] = conversation

    conversation = Connect(host, port)
    node = conversation
    node = node.add_child(SetMaxRecordSize(2**16 - 1))
    ext = {}
    if dhe:
        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_CCM_8,
            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    else:
        ext = None
        ciphers = [
            CipherSuite.TLS_RSA_WITH_AES_128_CCM_8,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
    node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
    node = node.add_child(ExpectServerHello())
    node = node.add_child(ExpectCertificate())
    if dhe:
        node = node.add_child(ExpectServerKeyExchange())
    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())
    data = bytearray(b"GET / HTTP/1.0\r\n" + b"X-test: " + b"A" *
                     (2**14 + 1024 - 28 + 1) + b"\r\n\r\n")
    assert len(data) == 2**14 + 1024 + 1
    node = node.add_child(ApplicationDataGenerator(data))
    node = node.add_child(
        ExpectAlert(AlertLevel.fatal, AlertDescription.record_overflow))
    node.add_child(ExpectClose())
    conversations[
        "too big plaintext - above TLSCompressed max with _8 ciphers"] = conversation

    # fuzz the tag (last 16 bytes or last 8 bytes in case of _8 ciphers)
    for n in [17, 9]:
        for val in [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]:
            for pos in range(-1, -n, -1):
                conversation = Connect(host, port)
                node = conversation
                ext = {}
                if dhe:
                    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)
                    if n == 17:
                        ciphers = [
                            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
                            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM
                        ]
                    else:
                        ciphers = [
                            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8,
                            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
                        ]
                else:
                    ext = None
                    if n == 17:
                        ciphers = [CipherSuite.TLS_RSA_WITH_AES_128_CCM]
                    else:
                        ciphers = [CipherSuite.TLS_RSA_WITH_AES_256_CCM_8]
                node = node.add_child(
                    ClientHelloGenerator(ciphers, extensions=ext))
                node = node.add_child(ExpectServerHello())
                node = node.add_child(ExpectCertificate())
                if dhe:
                    node = node.add_child(ExpectServerKeyExchange())
                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())
                msg = ApplicationDataGenerator(
                    bytearray(b"GET / HTTP/1.0\r\n\r\n"))
                node = node.add_child(
                    fuzz_encrypted_message(msg, xors={pos: val}))
                node = node.add_child(
                    ExpectAlert(AlertLevel.fatal,
                                AlertDescription.bad_record_mac))
                node.add_child(ExpectClose())
                conversations["fuzz tag with {0} on pos {1} - using cipher with {2} byte tag".format(val, pos, n-1)] \
                        = conversation

    # too small message handling
    for val in range(16):
        conversation = Connect(host, port)
        node = conversation
        ext = {}
        if dhe:
            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_CCM,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM,
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_RSA_WITH_AES_128_CCM,
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
            ]
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
        node = node.add_child(ExpectServerHello())
        node = node.add_child(ExpectCertificate())
        if dhe:
            node = node.add_child(ExpectServerKeyExchange())
        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())
        # any byte value will do, a1 chosen at random
        msg = PlaintextMessageGenerator(ContentType.application_data,
                                        bytearray([0xa1] * val))
        node = node.add_child(msg)
        node = node.add_child(
            ExpectAlert(AlertLevel.fatal, AlertDescription.bad_record_mac))
        node.add_child(ExpectClose())
        conversations["{0} bytes long ciphertext".format(val)] \
                = conversation

    # too small message handling against _8 ciphers
    for val in range(8):
        conversation = Connect(host, port)
        node = conversation
        ext = {}
        if dhe:
            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_CCM_8,
                CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8,
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
            ]
        else:
            ext = None
            ciphers = [
                CipherSuite.TLS_RSA_WITH_AES_128_CCM_8,
                CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
            ]
        node = node.add_child(ClientHelloGenerator(ciphers, extensions=ext))
        node = node.add_child(ExpectServerHello())
        node = node.add_child(ExpectCertificate())
        if dhe:
            node = node.add_child(ExpectServerKeyExchange())
        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())
        # any byte value will do, a1 chosen at random
        msg = PlaintextMessageGenerator(ContentType.application_data,
                                        bytearray([0xa1] * val))
        node = node.add_child(msg)
        node = node.add_child(
            ExpectAlert(AlertLevel.fatal, AlertDescription.bad_record_mac))
        node.add_child(ExpectClose())
        conversations["{0} bytes long ciphertext against _8 ciphers".format(val)] \
                = 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:
        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("This script runs fuzzing tests against TLS1.2 AES-CCM ciphers")

    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)
示例#31
0
def main():
    host = "localhost"
    port = 4433
    num_limit = None
    run_exclude = set()
    expected_failures = {}
    last_exp_tmp = None
    dhe = False
    sigalgs = [
        SignatureScheme.rsa_pkcs1_sha256, SignatureScheme.rsa_pkcs1_sha384,
        SignatureScheme.rsa_pkcs1_sha512, SignatureScheme.rsa_pss_rsae_sha256,
        SignatureScheme.rsa_pss_rsae_sha384,
        SignatureScheme.rsa_pss_rsae_sha512,
        SignatureScheme.rsa_pss_pss_sha256, SignatureScheme.rsa_pss_pss_sha384,
        SignatureScheme.rsa_pss_pss_sha512
    ]

    argv = sys.argv[1:]
    opts, args = getopt.getopt(argv, "h:p:e:n:x:X:d", ["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 == '-d':
            dhe = 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(sigalgs)
        ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(sigalgs)
        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
        ]
    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())
    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

    # client hello max size
    conversation = Connect(host, port)
    node = conversation
    proto = bytearray(b"A" * 255)
    lista = []
    lista.append(proto)
    for p in range(1, 255):
        lista.append(proto)
    # max size with
    if dhe:
        lista.append(bytearray(b'B' * 181))
    else:
        lista.append(bytearray(b'B' * 239))
    lista.append(bytearray(b'http/1.1'))
    # cipher suites array length 2^16-2, ciphers are two bytes
    # max number of ciphers can be 32767
    ciphers = []
    # adding ciphers from unassigned ranges
    # 0x00,0x5D-5F      Unassigned (93-95)
    for c in range(93, 96):
        ciphers.append(c)
    # 0x00,0x6E-83      Unassigned (110-131)
    for c in range(110, 132):
        ciphers.append(c)
    # 0x00,0xC6-FE      Unassigned (198-254)
    for c in range(198, 255):
        ciphers.append(c)
    # 0x01-55,*         Unassigned (255-22015)
    for c in range(255, 22016):
        ciphers.append(c)
    # 0x56,0x01-0xC0,0x00       Unassigned (22017-49152)
    # adding 10921 ciphers, from unassigned range above
    if dhe:
        # with DHE we send two valid ciphers, not one
        for c in range(22017, 32939 - 1):
            ciphers.append(c)
    else:
        for c in range(22017, 32939):
            ciphers.append(c)
    # adding ciphers we actually want to use
    if dhe:
        ciphers.append(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
        ciphers.append(CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA)
    else:
        ciphers.append(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA)
    ciphers.append(CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
    # cipher suites array filled with 32767 2bytes values
    ext = {ExtensionType.alpn: ALPNExtension().create(lista)}
    if dhe:
        groups = [GroupName.secp256r1, GroupName.ffdhe2048]
        ext[ExtensionType.supported_groups] = SupportedGroupsExtension()\
            .create(groups)
        ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(sigalgs)
        ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(sigalgs)
    # adding session_id, compression methonds
    node = node.add_child(
        ClientHelloGenerator(ciphers,
                             session_id=bytearray(32),
                             extensions=ext,
                             compression=range(0, 255)))
    ext = {
        ExtensionType.renegotiation_info: None,
        ExtensionType.alpn: ALPNExtension().create([bytearray(b'http/1.1')])
    }
    node = node.add_child(ExpectServerHello(extensions=ext))
    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(
        AlertGenerator(AlertLevel.warning, AlertDescription.close_notify))
    node = node.add_child(ExpectAlert())
    node.next_sibling = ExpectClose()
    conversations["max client hello"] = 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:
        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("Check if server will accept Client Hello message of maximum valid")
    print("size\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 or xpass:
        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: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
    ext = {}
    sigalgs = [(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha224, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha256, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha384, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha512, SignatureAlgorithm.ecdsa)]
    ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(sigalgs)
    ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(SIG_ALL)
    curves = [GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1]
    ext[ExtensionType.supported_groups] = \
            SupportedGroupsExtension().create(curves)
    ciphers = [
        CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
    node = node.add_child(ExpectServerHello())
    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

    # all algorithms, but in order from strongest to weakest
    conversation = Connect(host, port)
    node = conversation
    ext = {}
    sigalgs = [(HashAlgorithm.sha512, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha384, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha256, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha224, SignatureAlgorithm.ecdsa),
               (HashAlgorithm.sha1, SignatureAlgorithm.ecdsa)]
    ext[ExtensionType.signature_algorithms] = \
            SignatureAlgorithmsExtension().create(sigalgs)
    ext[ExtensionType.signature_algorithms_cert] = \
            SignatureAlgorithmsCertExtension().create(SIG_ALL)
    curves = [GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1]
    ext[ExtensionType.supported_groups] = \
            SupportedGroupsExtension().create(curves)
    ciphers = [
        CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    ]
    node = node.add_child(
        ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
    node = node.add_child(ExpectServerHello())
    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 - strongest to weakest"] = conversation

    # test all hashes one by one
    for h_alg in ["sha1", "sha224", "sha256", "sha384", "sha512"]:
        conversation = Connect(host, port)
        node = conversation
        ext = {}
        sigalgs = [(getattr(HashAlgorithm, h_alg), SignatureAlgorithm.ecdsa)]
        ext[ExtensionType.signature_algorithms] = \
                SignatureAlgorithmsExtension().create(sigalgs)
        ext[ExtensionType.signature_algorithms_cert] = \
                SignatureAlgorithmsCertExtension().create(SIG_ALL)
        curves = [
            GroupName.secp256r1, GroupName.secp384r1, GroupName.secp521r1
        ]
        ext[ExtensionType.supported_groups] = \
                SupportedGroupsExtension().create(curves)
        ciphers = [
            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
        node = node.add_child(
            ClientHelloGenerator(ciphers, version=(3, 3), extensions=ext))
        node = node.add_child(ExpectServerHello())
        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["connect with {0}+ecdsa only".format(
            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 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("Test if the server doesn't have the TLSv1.3 limitation on ECDSA")
    print("signatures also in TLSv1.2 mode.\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)
示例#33
0
def main():
    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 = []
    variables_check = \
        {'ServerHello.random':
         collected_randoms,
         'ServerHello.extensions.key_share.key_exchange':
         collected_key_shares}

    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 = []
    ext[ExtensionType.key_share] = key_share_ext_gen(groups)
    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(CopyVariables(variables_check))
    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

    for group in [
            GroupName.secp384r1, GroupName.secp521r1, GroupName.x25519,
            GroupName.x448, GroupName.ffdhe2048, GroupName.ffdhe3072
    ]:
        conversation = Connect(host, port)
        node = conversation
        ciphers = [
            CipherSuite.TLS_AES_128_GCM_SHA256,
            CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV
        ]
        ext = {}
        groups = [group]
        key_shares = []
        ext[ExtensionType.key_share] = key_share_ext_gen(groups)
        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(CopyVariables(variables_check))
        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["TLS 1.3 with {0}".format(GroupName.toStr(group))] \
            = conversation

    # run the conversation
    good = 0
    bad = 0
    failed = []
    if not num_limit:
        num_limit = len(conversations)

    # make sure that sanity test is run first and last
    # to verify that server was running and kept running throught
    sanity_test = ('sanity', conversations['sanity'])
    ordered_tests = chain([sanity_test],
                          islice(
                              filter(lambda x: x[0] != 'sanity',
                                     conversations.items()), num_limit),
                          [sanity_test])

    for c_name, c_test in ordered_tests:
        if run_only and c_name not in run_only or c_name in run_exclude:
            continue
        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 ServerHello random values are unique")
    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)