1*f034e78fStb# $OpenBSD: tlsfuzzer.py,v 1.56 2024/09/18 19:12:37 tb Exp $ 258007204Stb# 358007204Stb# Copyright (c) 2020 Theo Buehler <tb@openbsd.org> 458007204Stb# 558007204Stb# Permission to use, copy, modify, and distribute this software for any 658007204Stb# purpose with or without fee is hereby granted, provided that the above 758007204Stb# copyright notice and this permission notice appear in all copies. 858007204Stb# 958007204Stb# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1058007204Stb# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1158007204Stb# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1258007204Stb# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1358007204Stb# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1458007204Stb# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1558007204Stb# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1658007204Stb 1758007204Stbimport getopt 1858007204Stbimport os 1958007204Stbimport subprocess 2058007204Stbimport sys 2158007204Stbfrom timeit import default_timer as timer 2258007204Stb 2358007204Stbtlsfuzzer_scriptdir = "/usr/local/share/tlsfuzzer/scripts/" 2458007204Stb 2558007204Stbclass Test: 2658007204Stb """ 2758007204Stb Represents a tlsfuzzer test script. 2858007204Stb name: the script's name 2958007204Stb args: arguments to feed to the script 3058007204Stb tls12_args: override args for a TLSv1.2 server 3158007204Stb tls13_args: override args for a TLSv1.3 server 3258007204Stb 3358007204Stb XXX Add client cert support. 3458007204Stb """ 3558007204Stb def __init__(self, name="", args=[], tls12_args=[], tls13_args=[]): 3658007204Stb self.name = name 3758007204Stb self.tls12_args = args 3858007204Stb self.tls13_args = args 3958007204Stb if tls12_args: 4058007204Stb self.tls12_args = tls12_args 4158007204Stb if tls13_args: 4258007204Stb self.tls13_args = tls13_args 4358007204Stb 4458007204Stb def args(self, has_tls1_3: True): 4558007204Stb if has_tls1_3: 4658007204Stb return self.tls13_args 4758007204Stb else: 4858007204Stb return self.tls12_args 4958007204Stb 5058007204Stb def __repr__(self): 5158007204Stb return "<Test: %s tls12_args: %s tls13_args: %s>" % ( 52f84b1df5Stb self.name, self.tls12_args, self.tls13_args 5358007204Stb ) 5458007204Stb 5558007204Stbclass TestGroup: 5658007204Stb """ A group of Test objects to be run by TestRunner.""" 5758007204Stb def __init__(self, title="Tests", tests=[]): 5858007204Stb self.title = title 5958007204Stb self.tests = tests 6058007204Stb 6158007204Stb def __iter__(self): 6258007204Stb return iter(self.tests) 6358007204Stb 6458007204Stb# argument to pass to several tests 6558007204Stbtls13_unsupported_ciphers = [ 6658007204Stb "-e", "TLS 1.3 with ffdhe2048", 6758007204Stb "-e", "TLS 1.3 with ffdhe3072", 6858007204Stb "-e", "TLS 1.3 with x448", 6958007204Stb] 7058007204Stb 712b3fe024Stbdef substitute_alert(want, got): 722b3fe024Stb return f"Expected alert description \"{want}\" " \ 732b3fe024Stb + f"does not match received \"{got}\"" 742b3fe024Stb 75cdcbc686Stb# test-tls13-finished.py has 70 failing tests that expect a "decode_error" 76cdcbc686Stb# instead of the "decrypt_error" sent by tls13_server_finished_recv(). 77cdcbc686Stb# Both alerts appear to be reasonable in this context, so work around this 78cdcbc686Stb# in the test instead of the library. 79cdcbc686Stbdef generate_test_tls13_finished_args(): 802b3fe024Stb assertion = substitute_alert("decode_error", "decrypt_error"); 81cdcbc686Stb paddings = [ 82cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 1), 83cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 2), 84cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 4), 85cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 8), 86cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 16), 87cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 32), 88cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 48), 89cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 2**14-4-32), 90cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 0x20000), 91cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 0x30000), 92cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 1, 0), 93cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 2, 0), 94cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 4, 0), 95cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 8, 0), 96cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 16, 0), 97cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 32, 0), 98cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 48, 0), 99cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 2**14-4-32, 0), 100cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 12, 0), 101cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 1, 1), 102cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 8, 8), 103cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 1), 104cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 2), 105cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 4), 106cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 8), 107cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 16), 108cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 32), 109cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 48), 110cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 2**14-4-48), 111cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 0x20000), 112cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 0x30000), 113cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 12), 114cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 1, 0), 115cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 2, 0), 116cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 4, 0), 117cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 8, 0), 118cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 16, 0), 119cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 32, 0), 120cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 48, 0), 121cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 2**14-4-48, 0), 122cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 1, 1), 123cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 8, 8), 124cdcbc686Stb ] 125cdcbc686Stb truncations = [ 126cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, -1), 127cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, -2), 128cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, -4), 129cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, -8), 130cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, -16), 131cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, -32), 132cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 0, 12), 133cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 1, None), 134cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 2, None), 135cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 4, None), 136cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 8, None), 137cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 16, None), 138cdcbc686Stb ("TLS_AES_128_GCM_SHA256", 32, None), 139cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, -1), 140cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, -2), 141cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, -4), 142cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, -8), 143cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, -16), 144cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, -32), 145cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 0, 12), 146cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 1, None), 147cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 2, None), 148cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 4, None), 149cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 8, None), 150cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 16, None), 151cdcbc686Stb ("TLS_AES_256_GCM_SHA384", 32, None), 152cdcbc686Stb ] 153cdcbc686Stb 154cdcbc686Stb args = [ 155cdcbc686Stb "-x", "empty - cipher TLS_AES_128_GCM_SHA256", "-X", assertion, 156cdcbc686Stb "-x", "empty - cipher TLS_AES_256_GCM_SHA384", "-X", assertion, 157cdcbc686Stb ] 158cdcbc686Stb padding_fmt = "padding - cipher %s, pad_byte 0, pad_left %d, pad_right %d" 159cdcbc686Stb for padding in paddings: 160cdcbc686Stb args += ["-x", padding_fmt % padding, "-X", assertion] 161cdcbc686Stb truncation_fmt = "truncation - cipher %s, start %d, end %s" 162cdcbc686Stb for truncation in truncations: 163cdcbc686Stb args += ["-x", truncation_fmt % truncation, "-X", assertion] 164cdcbc686Stb return args 165cdcbc686Stb 166c05f8ee0Stbtls13_tests = TestGroup("TLSv1.3 tests", [ 167c05f8ee0Stb Test("test-tls13-ccs.py"), 168c05f8ee0Stb Test("test-tls13-conversation.py"), 169c05f8ee0Stb Test("test-tls13-count-tickets.py"), 170c05f8ee0Stb Test("test-tls13-empty-alert.py"), 171c05f8ee0Stb Test("test-tls13-finished.py", generate_test_tls13_finished_args()), 172c05f8ee0Stb Test("test-tls13-finished-plaintext.py"), 173c05f8ee0Stb Test("test-tls13-hrr.py"), 174c05f8ee0Stb Test("test-tls13-keyshare-omitted.py"), 175c05f8ee0Stb Test("test-tls13-legacy-version.py"), 176c05f8ee0Stb Test("test-tls13-nociphers.py"), 177c05f8ee0Stb Test("test-tls13-record-padding.py"), 1786338e29cStb # Exclude QUIC transport parameters 17978fec973Stb Test("test-tls13-shuffled-extentions.py", [ "--exc", "57" ]), 180c05f8ee0Stb Test("test-tls13-zero-content-type.py"), 181c05f8ee0Stb 182c05f8ee0Stb # The skipped tests fail due to a bug in BIO_gets() which masks the retry 183c05f8ee0Stb # signalled from an SSL_read() failure. Testing with httpd(8) shows we're 184c05f8ee0Stb # handling these corner cases correctly since tls13_record_layer.c -r1.47. 185c05f8ee0Stb Test("test-tls13-zero-length-data.py", [ 186c05f8ee0Stb "-e", "zero-length app data", 187c05f8ee0Stb "-e", "zero-length app data with large padding", 188c05f8ee0Stb "-e", "zero-length app data with padding", 189c05f8ee0Stb ]), 1903374c67dStb 1913374c67dStb # We don't currently handle NSTs 1923374c67dStb Test("test-tls13-connection-abort.py", ["-e", "After NewSessionTicket"]), 193c05f8ee0Stb]) 194c05f8ee0Stb 19558007204Stb# Tests that take a lot of time (> ~30s on an x280) 19658007204Stbtls13_slow_tests = TestGroup("slow TLSv1.3 tests", [ 19758007204Stb # XXX: Investigate the occasional message 19858007204Stb # "Got shared secret with 1 most significant bytes equal to zero." 19958007204Stb Test("test-tls13-dhe-shared-secret-padding.py", tls13_unsupported_ciphers), 20058007204Stb 20158007204Stb Test("test-tls13-invalid-ciphers.py"), 20258007204Stb Test("test-tls13-serverhello-random.py", tls13_unsupported_ciphers), 20392edee68Stb 20492edee68Stb # Mark two tests cases as xfail for now. The tests expect an arguably 20592edee68Stb # correct decode_error while we send a decrypt_error (like fizz/boring). 20692edee68Stb Test("test-tls13-record-layer-limits.py", [ 20792edee68Stb "-x", "max size payload (2**14) of Finished msg, with 16348 bytes of left padding, cipher TLS_AES_128_GCM_SHA256", 208563ec054Stb "-X", substitute_alert("decode_error", "decrypt_error"), 20992edee68Stb "-x", "max size payload (2**14) of Finished msg, with 16348 bytes of left padding, cipher TLS_CHACHA20_POLY1305_SHA256", 210563ec054Stb "-X", substitute_alert("decode_error", "decrypt_error"), 21192edee68Stb ]), 212a590e228Stb # We don't accept an empty ECPF extension since it must advertise the 213a590e228Stb # uncompressed point format. Exclude this extension type from the test. 214a590e228Stb Test( 215a590e228Stb "test-tls13-large-number-of-extensions.py", 216*f034e78fStb tls13_args = ["--exc", "11"], 217a590e228Stb ), 21858007204Stb]) 21958007204Stb 22058007204Stbtls13_extra_cert_tests = TestGroup("TLSv1.3 certificate tests", [ 22158007204Stb # need to set up client certs to run these 22258007204Stb Test("test-tls13-certificate-request.py"), 22358007204Stb Test("test-tls13-certificate-verify.py"), 22458007204Stb Test("test-tls13-ecdsa-in-certificate-verify.py"), 225c02cd125Stb Test("test-tls13-eddsa-in-certificate-verify.py"), 22658007204Stb 22758007204Stb # Test expects the server to have installed three certificates: 22858007204Stb # with P-256, P-384 and P-521 curve. Also SHA1+ECDSA is verified 22958007204Stb # to not work. 23058007204Stb Test("test-tls13-ecdsa-support.py"), 23158007204Stb]) 23258007204Stb 23358007204Stbtls13_failing_tests = TestGroup("failing TLSv1.3 tests", [ 23458007204Stb # Some tests fail because we fail later than the scripts expect us to. 23558007204Stb # With X25519, we accept weak peer public keys and fail when we actually 23658007204Stb # compute the keyshare. Other tests seem to indicate that we could be 23758007204Stb # stricter about what keyshares we accept. 2389bc11146Stb Test("test-tls13-crfg-curves.py", [ 2399bc11146Stb '-e', 'all zero x448 key share', 2409bc11146Stb '-e', 'empty x448 key share', 2419bc11146Stb '-e', 'sanity x448 with compression ansiX962_compressed_char2', 2429bc11146Stb '-e', 'sanity x448 with compression ansiX962_compressed_prime', 2439bc11146Stb '-e', 'sanity x448 with compression uncompressed', 2449bc11146Stb '-e', 'too big x448 key share', 2459bc11146Stb '-e', 'too small x448 key share', 2469bc11146Stb '-e', 'x448 key share of "1"', 2479bc11146Stb ]), 2489bc11146Stb Test("test-tls13-ecdhe-curves.py", [ 2499bc11146Stb '-e', 'sanity - x448', 2509bc11146Stb '-e', 'x448 - key share from other curve', 2519bc11146Stb '-e', 'x448 - point at infinity', 2529bc11146Stb '-e', 'x448 - right 0-padded key_share', 2539bc11146Stb '-e', 'x448 - right-truncated key_share', 2549bc11146Stb ]), 25558007204Stb 256bb0ca798Stb # The test sends records with protocol version 0x0300 instead of 0x0303 2577880f693Stb # and currently fails with OpenSSL and LibreSSL for this reason. 258bb0ca798Stb # We have the logic corresponding to NSS's fix for CVE-2020-25648 259bb0ca798Stb # https://hg.mozilla.org/projects/nss/rev/57bbefa793232586d27cee83e74411171e128361 260bb0ca798Stb # so should not be affected by this issue. 261bb0ca798Stb Test("test-tls13-multiple-ccs-messages.py"), 262bb0ca798Stb 26358007204Stb # https://github.com/openssl/openssl/issues/8369 26458007204Stb Test("test-tls13-obsolete-curves.py"), 26558007204Stb 26658007204Stb # 3 failing rsa_pss_pss tests 26758007204Stb Test("test-tls13-rsa-signatures.py"), 26858007204Stb 269e7667ed5Stb # The failing tests all expect an ri extension. What's up with that? 27058007204Stb Test("test-tls13-version-negotiation.py"), 27158007204Stb]) 27258007204Stb 27358007204Stbtls13_slow_failing_tests = TestGroup("slow, failing TLSv1.3 tests", [ 27458007204Stb # Other test failures bugs in keyshare/tlsext negotiation? 27558007204Stb Test("test-tls13-unrecognised-groups.py"), # unexpected closure 27658007204Stb 277563ec054Stb # 5 occasional failures: 278563ec054Stb # 'app data split, conversation with KeyUpdate msg' 279563ec054Stb # 'fragmented keyupdate msg' 280563ec054Stb # 'multiple KeyUpdate messages' 281563ec054Stb # 'post-handshake KeyUpdate msg with update_not_request' 282563ec054Stb # 'post-handshake KeyUpdate msg with update_request' 283563ec054Stb Test("test-tls13-keyupdate.py"), 284563ec054Stb 28558007204Stb Test("test-tls13-symetric-ciphers.py"), # unexpected message from peer 28658007204Stb 28758007204Stb # 6 tests fail: 'rsa_pkcs1_{md5,sha{1,224,256,384,512}} signature' 28858007204Stb # We send server hello, but the test expects handshake_failure 28958007204Stb Test("test-tls13-pkcs-signature.py"), 29058007204Stb # 8 tests fail: 'tls13 signature rsa_pss_{pss,rsae}_sha{256,384,512} 29158007204Stb Test("test-tls13-rsapss-signatures.py"), 29258007204Stb]) 29358007204Stb 29458007204Stbtls13_unsupported_tests = TestGroup("TLSv1.3 tests for unsupported features", [ 29558007204Stb # Tests for features we don't support 29658007204Stb Test("test-tls13-0rtt-garbage.py"), 29758007204Stb Test("test-tls13-ffdhe-groups.py"), 29858007204Stb Test("test-tls13-ffdhe-sanity.py"), 29958007204Stb Test("test-tls13-psk_dhe_ke.py"), 30058007204Stb Test("test-tls13-psk_ke.py"), 30158007204Stb 30258007204Stb # need server to react to HTTP GET for /keyupdate 30358007204Stb Test("test-tls13-keyupdate-from-server.py"), 30458007204Stb 3052218185dStb # needs an echo server 3062218185dStb Test("test-tls13-lengths.py"), 3072218185dStb 30858007204Stb # Weird test: tests servers that don't support 1.3 30958007204Stb Test("test-tls13-non-support.py"), 31058007204Stb 31158007204Stb # broken test script 31258007204Stb # UnboundLocalError: local variable 'cert' referenced before assignment 31358007204Stb Test("test-tls13-post-handshake-auth.py"), 31458007204Stb 315390e08e8Stb # ExpectNewSessionTicket 316390e08e8Stb Test("test-tls13-session-resumption.py"), 317390e08e8Stb 31858007204Stb # Server must be configured to support only rsa_pss_rsae_sha512 31958007204Stb Test("test-tls13-signature-algorithms.py"), 32058007204Stb]) 32158007204Stb 32258007204Stbtls12_exclude_legacy_protocols = [ 32358007204Stb # all these have BIO_read timeouts against TLSv1.3 32458007204Stb "-e", "Protocol (3, 0)", 325521ba2f2Sbeck "-e", "Protocol (3, 1)", 326521ba2f2Sbeck "-e", "Protocol (3, 2)", 32758007204Stb "-e", "Protocol (3, 0) in SSLv2 compatible ClientHello", 32858007204Stb # the following only fail with TLSv1.3 32958007204Stb "-e", "Protocol (3, 1) in SSLv2 compatible ClientHello", 33058007204Stb "-e", "Protocol (3, 2) in SSLv2 compatible ClientHello", 33158007204Stb "-e", "Protocol (3, 3) in SSLv2 compatible ClientHello", 33258007204Stb "-e", "Protocol (3, 1) with x448 group", 33358007204Stb "-e", "Protocol (3, 2) with x448 group", 33458007204Stb "-e", "Protocol (3, 3) with x448 group", 335521ba2f2Sbeck # These don't work without TLSv1.0 and TLSv1.1 336521ba2f2Sbeck "-e", "Protocol (3, 1) with secp256r1 group", 337521ba2f2Sbeck "-e", "Protocol (3, 1) with secp384r1 group", 338521ba2f2Sbeck "-e", "Protocol (3, 1) with secp521r1 group", 339521ba2f2Sbeck "-e", "Protocol (3, 1) with x25519 group", 340521ba2f2Sbeck "-e", "Protocol (3, 2) with secp256r1 group", 341521ba2f2Sbeck "-e", "Protocol (3, 2) with secp384r1 group", 342521ba2f2Sbeck "-e", "Protocol (3, 2) with secp521r1 group", 343521ba2f2Sbeck "-e", "Protocol (3, 2) with x25519 group", 34458007204Stb] 34558007204Stb 34658007204Stbtls12_tests = TestGroup("TLSv1.2 tests", [ 34758007204Stb # Tests that pass as they are. 34858007204Stb Test("test-aes-gcm-nonces.py"), 3493374c67dStb Test("test-connection-abort.py"), 35058007204Stb Test("test-conversation.py"), 35158007204Stb Test("test-cve-2016-2107.py"), 35231b5396fStb Test("test-cve-2016-6309.py"), 35358007204Stb Test("test-dhe-rsa-key-exchange.py"), 35458007204Stb Test("test-early-application-data.py"), 35558007204Stb Test("test-empty-extensions.py"), 3560eecc477Stb Test("test-extensions.py"), 35758007204Stb Test("test-fuzzed-MAC.py"), 35858007204Stb Test("test-fuzzed-ciphertext.py"), 35958007204Stb Test("test-fuzzed-finished.py"), 36058007204Stb Test("test-fuzzed-padding.py"), 3612e9afb88Stb Test("test-fuzzed-plaintext.py"), # fails once in a while 36258007204Stb Test("test-hello-request-by-client.py"), 36358007204Stb Test("test-invalid-cipher-suites.py"), 36458007204Stb Test("test-invalid-content-type.py"), 36558007204Stb Test("test-invalid-session-id.py"), 36658007204Stb Test("test-invalid-version.py"), 367*f034e78fStb Test("test-large-number-of-extensions.py"), 36844072c60Stb Test("test-lucky13.py"), 36958007204Stb Test("test-message-skipping.py"), 37058007204Stb Test("test-no-heartbeat.py"), 371a2cd7475Stb Test("test-record-layer-fragmentation.py"), 37258007204Stb Test("test-sslv2-connection.py"), 37358007204Stb Test("test-truncating-of-finished.py"), 37458007204Stb Test("test-truncating-of-kRSA-client-key-exchange.py"), 37558007204Stb Test("test-unsupported-curve-fallback.py"), 37658007204Stb Test("test-version-numbers.py"), 37758007204Stb Test("test-zero-length-data.py"), 37858007204Stb 37958007204Stb # Tests that need tweaking for unsupported features and ciphers. 38058007204Stb Test( 38158007204Stb "test-atypical-padding.py", [ 38258007204Stb "-e", "sanity - encrypt then MAC", 38358007204Stb "-e", "2^14 bytes of AppData with 256 bytes of padding (SHA1 + Encrypt then MAC)", 38458007204Stb ] 38558007204Stb ), 38658007204Stb Test( 387615b62e1Stb "test-ccs.py", [ 388615b62e1Stb "-x", "two bytes long CCS", 389f90ef06aStb "-X", substitute_alert("unexpected_message", "decode_error"), 390615b62e1Stb ] 391615b62e1Stb ), 392615b62e1Stb Test( 39358007204Stb "test-dhe-rsa-key-exchange-signatures.py", [ 39458007204Stb "-e", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA sha224 signature", 39558007204Stb "-e", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 sha224 signature", 39658007204Stb "-e", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA sha224 signature", 39758007204Stb "-e", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 sha224 signature", 39858007204Stb "-e", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA sha224 signature", 39958007204Stb ] 40058007204Stb ), 40176840887Stb Test("test-dhe-rsa-key-exchange-with-bad-messages.py", [ 40276840887Stb "-x", "invalid dh_Yc value - missing", 40376840887Stb "-X", substitute_alert("decode_error", "illegal_parameter"), 40476840887Stb ]), 40558007204Stb Test("test-dhe-key-share-random.py", tls12_exclude_legacy_protocols), 406521ba2f2Sbeck Test("test-export-ciphers-rejected.py", ["--min-ver", "TLSv1.2"]), 40758007204Stb Test( 40858007204Stb "test-downgrade-protection.py", 40958007204Stb tls12_args = ["--server-max-protocol", "TLSv1.2"], 410521ba2f2Sbeck tls13_args = [ 411521ba2f2Sbeck "--server-max-protocol", "TLSv1.3", 412521ba2f2Sbeck "-e", "TLS 1.3 downgrade check for Protocol (3, 1)", 413521ba2f2Sbeck "-e", "TLS 1.3 downgrade check for Protocol (3, 2)", 414521ba2f2Sbeck ] 41558007204Stb ), 416521ba2f2Sbeck Test( 417521ba2f2Sbeck "test-fallback-scsv.py", 418521ba2f2Sbeck tls13_args = [ 419521ba2f2Sbeck "--tls-1.3", 420521ba2f2Sbeck "-e", "FALLBACK - hello TLSv1.1 - pos 0", 421521ba2f2Sbeck "-e", "FALLBACK - hello TLSv1.1 - pos 1", 422521ba2f2Sbeck "-e", "FALLBACK - hello TLSv1.1 - pos 2", 423521ba2f2Sbeck "-e", "FALLBACK - record TLSv1.1 hello TLSv1.1 - pos 0", 424521ba2f2Sbeck "-e", "FALLBACK - record TLSv1.1 hello TLSv1.1 - pos 1", 425521ba2f2Sbeck "-e", "FALLBACK - record TLSv1.1 hello TLSv1.1 - pos 2", 426521ba2f2Sbeck "-e", "record TLSv1.1 hello TLSv1.1", 427521ba2f2Sbeck "-e", "sanity - TLSv1.1", 428521ba2f2Sbeck ] 429521ba2f2Sbeck ), 430dab3dacdStb 4313df9e801Stb Test("test-invalid-compression-methods.py", [ 4323df9e801Stb "-x", "invalid compression methods", 4332b3fe024Stb "-X", substitute_alert("illegal_parameter", "decode_error"), 4343df9e801Stb "-x", "only deflate compression method", 4352b3fe024Stb "-X", substitute_alert("illegal_parameter", "decode_error"), 4363df9e801Stb ]), 4373df9e801Stb 438a0f9d20cStb # Skip extended_master_secret test. Since we don't support this 439a0f9d20cStb # extension, we don't notice that it was dropped. 440a0f9d20cStb Test("test-renegotiation-changed-clienthello.py", [ 441a0f9d20cStb "-e", "drop extended_master_secret in renegotiation", 442a0f9d20cStb ]), 443a0f9d20cStb 444f90ef06aStb Test("test-sessionID-resumption.py", [ 445f90ef06aStb "-x", "Client Hello too long session ID", 446f90ef06aStb "-X", substitute_alert("decode_error", "illegal_parameter"), 447f90ef06aStb ]), 448f90ef06aStb 449dab3dacdStb # Without --sig-algs-drop-ok, two tests fail since we do not currently 450dab3dacdStb # implement the signature_algorithms_cert extension (although we MUST). 451dab3dacdStb Test("test-sig-algs-renegotiation-resumption.py", ["--sig-algs-drop-ok"]), 452dab3dacdStb 45358007204Stb Test("test-serverhello-random.py", args = tls12_exclude_legacy_protocols), 454521ba2f2Sbeck 455521ba2f2Sbeck Test("test-chacha20.py", [ "-e", "Chacha20 in TLS1.1" ]), 45658007204Stb]) 45758007204Stb 45858007204Stbtls12_slow_tests = TestGroup("slow TLSv1.2 tests", [ 45958007204Stb Test("test-cve-2016-7054.py"), 46058007204Stb Test("test-dhe-no-shared-secret-padding.py", tls12_exclude_legacy_protocols), 46158007204Stb Test("test-ecdhe-padded-shared-secret.py", tls12_exclude_legacy_protocols), 46258007204Stb Test("test-ecdhe-rsa-key-share-random.py", tls12_exclude_legacy_protocols), 4636338e29cStb # Start at extension number 58 to avoid QUIC transport parameters (57) 46478fec973Stb Test("test-large-hello.py", [ "-m", "58" ]), 46558007204Stb]) 46658007204Stb 46758007204Stbtls12_failing_tests = TestGroup("failing TLSv1.2 tests", [ 46858007204Stb # no shared cipher 46958007204Stb Test("test-aesccm.py"), 47058007204Stb # need server to set up alpn 47158007204Stb Test("test-alpn-negotiation.py"), 472ff0e7be1Stb # Failing on TLS_RSA_WITH_AES_128_CBC_SHA because server does not support it. 473ff0e7be1Stb Test("test-bleichenbacher-timing-pregenerate.py"), 47458007204Stb # many tests fail due to unexpected server_name extension 47558007204Stb Test("test-bleichenbacher-workaround.py"), 47658007204Stb 47758007204Stb # need client key and cert plus extra server setup 47858007204Stb Test("test-certificate-malformed.py"), 47958007204Stb Test("test-certificate-request.py"), 48058007204Stb Test("test-certificate-verify-malformed-sig.py"), 48158007204Stb Test("test-certificate-verify-malformed.py"), 48258007204Stb Test("test-certificate-verify.py"), 48358007204Stb Test("test-ecdsa-in-certificate-verify.py"), 484c02cd125Stb Test("test-eddsa-in-certificate-verify.py"), 48558007204Stb Test("test-renegotiation-disabled-client-cert.py"), 48658007204Stb Test("test-rsa-pss-sigs-on-certificate-verify.py"), 48758007204Stb Test("test-rsa-sigs-on-certificate-verify.py"), 48858007204Stb 48958007204Stb # test doesn't expect session ticket 49058007204Stb Test("test-client-compatibility.py"), 49158007204Stb # abrupt closure 49258007204Stb Test("test-client-hello-max-size.py"), 49358007204Stb # unknown signature algorithms 49458007204Stb Test("test-clienthello-md5.py"), 49558007204Stb 496208aabddStb # Tests expect an illegal_parameter or a decode_error alert. Should be 4979f325698Stb # added to ssl3_get_client_key_exchange on kex function failure. 49858007204Stb Test("test-ecdhe-rsa-key-exchange-with-bad-messages.py"), 49958007204Stb 5009f325698Stb # We send a handshake_failure due to no shared ciphers while the 5019f325698Stb # test expects to succeed. 50258007204Stb Test("test-ecdhe-rsa-key-exchange.py"), 50358007204Stb 50458007204Stb # no shared cipher 50558007204Stb Test("test-ecdsa-sig-flexibility.py"), 50658007204Stb 50758007204Stb # Tests expect SH but we send unexpected_message or handshake_failure 50858007204Stb # 'Application data inside Client Hello' 50958007204Stb # 'Application data inside Client Key Exchange' 51058007204Stb # 'Application data inside Finished' 51158007204Stb Test("test-interleaved-application-data-and-fragmented-handshakes-in-renegotiation.py"), 51258007204Stb # Tests expect SH but we send handshake_failure 51358007204Stb # 'Application data before Change Cipher Spec' 51458007204Stb # 'Application data before Client Key Exchange' 51558007204Stb # 'Application data before Finished' 51658007204Stb Test("test-interleaved-application-data-in-renegotiation.py"), 51758007204Stb 51858007204Stb # broken test script 51958007204Stb # TypeError: '<' not supported between instances of 'int' and 'NoneType' 52058007204Stb Test("test-invalid-client-hello-w-record-overflow.py"), 52158007204Stb 52258007204Stb # Lots of failures. abrupt closure 52358007204Stb Test("test-invalid-client-hello.py"), 52458007204Stb 52558007204Stb # abrupt closure 52658007204Stb # 'encrypted premaster set to all zero (n)' n in 256 384 512 52758007204Stb Test("test-invalid-rsa-key-exchange-messages.py"), 52858007204Stb 52958007204Stb # test expects illegal_parameter, we send unrecognized_name (which seems 53058007204Stb # correct according to rfc 6066?) 53158007204Stb Test("test-invalid-server-name-extension-resumption.py"), 53258007204Stb # let through some server names without sending an alert 53358007204Stb # again illegal_parameter vs unrecognized_name 53458007204Stb Test("test-invalid-server-name-extension.py"), 53558007204Stb 53658007204Stb # 4 failures: 53758007204Stb # 'insecure (legacy) renegotiation with GET after 2nd handshake' 53858007204Stb # 'insecure (legacy) renegotiation with incomplete GET' 53958007204Stb # 'secure renegotiation with GET after 2nd handshake' 54058007204Stb # 'secure renegotiation with incomplete GET' 54158007204Stb Test("test-legacy-renegotiation.py"), 54258007204Stb 54358007204Stb # 1 failure (timeout): we don't send the unexpected_message alert 54458007204Stb # 'duplicate change cipher spec after Finished' 54558007204Stb Test("test-message-duplication.py"), 54658007204Stb 54758007204Stb # server should send status_request 54858007204Stb Test("test-ocsp-stapling.py"), 54958007204Stb 55058007204Stb # unexpected closure 55158007204Stb Test("test-openssl-3712.py"), 55258007204Stb 55358007204Stb # failed: 3 (expect an alert, we send AD) 55458007204Stb # 'try insecure (legacy) renegotiation with incomplete GET' 55558007204Stb # 'try secure renegotiation with GET after 2nd CH' 55658007204Stb # 'try secure renegotiation with incomplete GET' 55758007204Stb Test("test-renegotiation-disabled.py"), 55858007204Stb 55958007204Stb # 'resumption of safe session with NULL cipher' 56058007204Stb # 'resumption with cipher from old CH but not selected by server' 56158007204Stb Test("test-resumption-with-wrong-ciphers.py"), 56258007204Stb 563f90ef06aStb # 'session resumption with empty session_id' 564f90ef06aStb # 'session resumption with random session_id' 565f90ef06aStb # 'session resumption with renegotiation' 566f90ef06aStb # AssertionError: Server did not send extension(s): session_ticket 567f90ef06aStb Test("test-session-ticket-resumption.py"), 568f90ef06aStb 56958007204Stb # 5 failures: 57058007204Stb # 'empty sigalgs' 57158007204Stb # 'only undefined sigalgs' 57258007204Stb # 'rsa_pss_pss_sha256 only' 57358007204Stb # 'rsa_pss_pss_sha384 only' 57458007204Stb # 'rsa_pss_pss_sha512 only' 57558007204Stb Test("test-sig-algs.py"), 57658007204Stb 57758007204Stb # 13 failures: 57858007204Stb # 'duplicated n non-rsa schemes' for n in 202 2342 8119 23741 32744 57958007204Stb # 'empty list of signature methods' 58058007204Stb # 'tolerance n RSA or ECDSA methods' for n in 215 2355 8132 23754 58158007204Stb # 'tolerance 32758 methods with sig_alg_cert' 58258007204Stb # 'tolerance max 32744 number of methods with sig_alg_cert' 58358007204Stb # 'tolerance max (32760) number of methods' 58458007204Stb Test("test-signature-algorithms.py"), 58558007204Stb 58658007204Stb # times out 58758007204Stb Test("test-ssl-death-alert.py"), 58858007204Stb 58958007204Stb # 17 pass, 13 fail. padding and truncation 59058007204Stb Test("test-truncating-of-client-hello.py"), 59158007204Stb 59258007204Stb # x448 tests need disabling plus x25519 corner cases need sorting out 59358007204Stb Test("test-x25519.py"), 594521ba2f2Sbeck 595521ba2f2Sbeck # Needs TLS 1.0 or 1.1 596521ba2f2Sbeck Test("test-TLSv1_2-rejected-without-TLSv1_2.py"), 59758007204Stb]) 59858007204Stb 59958007204Stbtls12_unsupported_tests = TestGroup("TLSv1.2 for unsupported features", [ 60058007204Stb # protocol_version 60158007204Stb Test("test-SSLv3-padding.py"), 602676445ddStb # we don't do RSA key exchanges 603676445ddStb Test("test-bleichenbacher-timing.py"), 6049f325698Stb # no encrypt-then-mac 6059f325698Stb Test("test-encrypt-then-mac-renegotiation.py"), 6069f325698Stb Test("test-encrypt-then-mac.py"), 6079f325698Stb # no EME support 6089f325698Stb Test("test-extended-master-secret-extension-with-client-cert.py"), 6099f325698Stb Test("test-extended-master-secret-extension.py"), 6109f325698Stb # no ffdhe 6119f325698Stb Test("test-ffdhe-expected-params.py"), 6129f325698Stb Test("test-ffdhe-negotiation.py"), 6134d9e4bf9Stb # record_size_limit/max_fragment_length extension (RFC 8449) 6144d9e4bf9Stb Test("test-record-size-limit.py"), 6159f325698Stb # expects the server to send the heartbeat extension 6169f325698Stb Test("test-heartbeat.py"), 6172218185dStb # needs an echo server 6182218185dStb Test("test-lengths.py"), 61958007204Stb]) 62058007204Stb 62158007204Stb# These tests take a ton of time to fail against an 1.3 server, 62258007204Stb# so don't run them against 1.3 pending further investigation. 62358007204Stblegacy_tests = TestGroup("Legacy protocol tests", [ 62458007204Stb Test("test-sslv2-force-cipher-3des.py"), 62558007204Stb Test("test-sslv2-force-cipher-non3des.py"), 62658007204Stb Test("test-sslv2-force-cipher.py"), 62758007204Stb Test("test-sslv2-force-export-cipher.py"), 62858007204Stb Test("test-sslv2hello-protocol.py"), 62958007204Stb]) 63058007204Stb 63158007204Stball_groups = [ 63258007204Stb tls13_tests, 63358007204Stb tls13_slow_tests, 63458007204Stb tls13_extra_cert_tests, 63558007204Stb tls13_failing_tests, 63658007204Stb tls13_slow_failing_tests, 63758007204Stb tls13_unsupported_tests, 63858007204Stb tls12_tests, 63958007204Stb tls12_slow_tests, 64058007204Stb tls12_failing_tests, 64158007204Stb tls12_unsupported_tests, 64258007204Stb legacy_tests, 64358007204Stb] 64458007204Stb 64558007204Stbfailing_groups = [ 64658007204Stb tls13_failing_tests, 64758007204Stb tls13_slow_failing_tests, 64858007204Stb tls12_failing_tests, 64958007204Stb] 65058007204Stb 65158007204Stbclass TestRunner: 652a84d9ac5Stb """ Runs the given tests against a server and displays stats. """ 65358007204Stb 65458007204Stb def __init__( 6556380fa64Stb self, timing=False, verbose=False, host="localhost", port=4433, 6566380fa64Stb use_tls1_3=True, dry_run=False, tests=[], scriptdir=tlsfuzzer_scriptdir, 65758007204Stb ): 65858007204Stb self.tests = [] 65958007204Stb 66058007204Stb self.dryrun = dry_run 66158007204Stb self.use_tls1_3 = use_tls1_3 6626380fa64Stb self.host = host 66358007204Stb self.port = str(port) 66458007204Stb self.scriptdir = scriptdir 66558007204Stb 66658007204Stb self.stats = [] 66758007204Stb self.failed = [] 66809e96d4eStb self.missing = [] 66958007204Stb 67058007204Stb self.timing = timing 67158007204Stb self.verbose = verbose 67258007204Stb 67358007204Stb def add(self, title="tests", tests=[]): 67458007204Stb # tests.sort(key=lambda test: test.name) 67558007204Stb self.tests.append(TestGroup(title, tests)) 67658007204Stb 67758007204Stb def add_group(self, group): 67858007204Stb self.tests.append(group) 67958007204Stb 68058007204Stb def run_script(self, test): 68158007204Stb script = test.name 6826380fa64Stb args = ["-h"] + [self.host] + ["-p"] + [self.port] + test.args(self.use_tls1_3) 68358007204Stb 68458007204Stb if self.dryrun: 68558007204Stb if not self.verbose: 68658007204Stb args = [] 68758007204Stb print(script , end=' ' if args else '') 68858007204Stb print(' '.join([f"\"{arg}\"" for arg in args])) 68958007204Stb return 69058007204Stb 69158007204Stb if self.verbose: 69258007204Stb print(script) 69358007204Stb else: 69458007204Stb print(f"{script[:68]:<72}", end=" ", flush=True) 69558007204Stb start = timer() 69609e96d4eStb scriptpath = os.path.join(self.scriptdir, script) 69709e96d4eStb if not os.path.exists(scriptpath): 69809e96d4eStb self.missing.append(script) 6995bec7355Stb print("MISSING") 7005bec7355Stb return 70158007204Stb test = subprocess.run( 70209e96d4eStb ["python3", scriptpath] + args, 70358007204Stb capture_output=not self.verbose, 70458007204Stb text=True, 70558007204Stb ) 70658007204Stb end = timer() 70758007204Stb self.stats.append((script, end - start)) 70858007204Stb if test.returncode == 0: 70958007204Stb print("OK") 71058007204Stb return 71158007204Stb print("FAILED") 71258007204Stb self.failed.append(script) 71358007204Stb 71458007204Stb if self.verbose: 71558007204Stb return 71658007204Stb 71758007204Stb print('\n'.join(test.stdout.split("Test end\n", 1)[1:]), end="") 71858007204Stb 71958007204Stb def run(self): 72058007204Stb for group in self: 72158007204Stb print(f"Running {group.title} ...") 72258007204Stb for test in group: 72358007204Stb self.run_script(test) 72458007204Stb return not self.failed 72558007204Stb 72658007204Stb def __iter__(self): 72758007204Stb return iter(self.tests) 72858007204Stb 72958007204Stb def __del__(self): 73058007204Stb if self.timing and self.stats: 73158007204Stb total = 0.0 73258007204Stb for (script, time) in self.stats: 73358007204Stb print(f"{round(time, 2):6.2f} {script}") 73458007204Stb total += time 73558007204Stb print(f"{round(total, 2):6.2f} total") 73658007204Stb 73758007204Stb if self.failed: 73858007204Stb print("Failed tests:") 73958007204Stb print('\n'.join(self.failed)) 74058007204Stb 74109e96d4eStb if self.missing: 74209e96d4eStb print("Missing tests (outdated package?):") 74309e96d4eStb print('\n'.join(self.missing)) 74409e96d4eStb 74558007204Stbclass TlsServer: 74658007204Stb """ Spawns an s_server listening on localhost:port if necessary. """ 74758007204Stb 7486380fa64Stb def __init__(self, host="localhost", port=4433): 74958007204Stb self.spawn = True 75058007204Stb # Check whether a server is already listening on localhost:port 75158007204Stb self.spawn = subprocess.run( 7526380fa64Stb ["nc", "-c", "-z", "-T", "noverify", host, str(port)], 75358007204Stb stderr=subprocess.DEVNULL, 75458007204Stb ).returncode != 0 75558007204Stb 75658007204Stb if self.spawn: 75758007204Stb self.server = subprocess.Popen( 75858007204Stb [ 75958007204Stb "openssl", 76058007204Stb "s_server", 76158007204Stb "-accept", 76258007204Stb str(port), 76366cd5d76Stb "-groups", 76466cd5d76Stb "X25519:P-256:P-521:P-384", 76558007204Stb "-key", 76658007204Stb "localhost.key", 76758007204Stb "-cert", 76858007204Stb "localhost.crt", 76958007204Stb "-www", 77058007204Stb ], 77158007204Stb stdout=subprocess.DEVNULL, 77258007204Stb stderr=subprocess.PIPE, 77358007204Stb text=True, 77458007204Stb ) 77558007204Stb 77658007204Stb # Check whether the server talks TLSv1.3 777f501c991Stb self.has_tls1_3 = True or subprocess.run( 77858007204Stb [ 77958007204Stb "nc", 78058007204Stb "-c", 78158007204Stb "-z", 78258007204Stb "-T", 78358007204Stb "noverify", 78458007204Stb "-T", 78558007204Stb "protocols=TLSv1.3", 78658007204Stb "localhost", 78758007204Stb str(port), 78858007204Stb ], 78958007204Stb stderr=subprocess.DEVNULL, 79058007204Stb ).returncode == 0 79158007204Stb 79258007204Stb self.check() 79358007204Stb 79458007204Stb def check(self): 79558007204Stb if self.spawn and self.server.poll() is not None: 79658007204Stb print(self.server.stderr.read()) 79758007204Stb raise RuntimeError( 79858007204Stb f"openssl s_server died. Return code: {self.server.returncode}." 79958007204Stb ) 80058007204Stb if self.spawn: 80158007204Stb self.server.stderr.detach() 80258007204Stb 80358007204Stb def __del__(self): 80458007204Stb if self.spawn: 80558007204Stb self.server.terminate() 80658007204Stb 80758007204Stb# Extract the arguments we pass to script 80858007204Stbdef defaultargs(script, has_tls1_3): 80958007204Stb return next( 81058007204Stb (test for group in all_groups for test in group if test.name == script), 81158007204Stb Test() 81258007204Stb ).args(has_tls1_3) 81358007204Stb 81458007204Stbdef list_or_missing(missing=True): 81558007204Stb tests = [test.name for group in all_groups for test in group] 81658007204Stb 81758007204Stb if missing: 81858007204Stb scripts = { 81958007204Stb f for f in os.listdir(tlsfuzzer_scriptdir) if f != "__pycache__" 82058007204Stb } 82158007204Stb missing = scripts - set(tests) 82258007204Stb if missing: 82358007204Stb print('\n'.join(sorted(missing))) 82458007204Stb exit(0) 82558007204Stb 82658007204Stb tests.sort() 82758007204Stb print('\n'.join(tests)) 82858007204Stb exit(0) 82958007204Stb 83058007204Stbdef usage(): 831ffcef067Stb print("Usage: python3 tlsfuzzer.py [-flmnstv] [-p port] [script [test...]]") 83258007204Stb print(" --help help") 83358007204Stb print(" -f run failing tests") 83458007204Stb print(" -l list tests") 83558007204Stb print(" -m list new tests after package update") 83658007204Stb print(" -n do not run tests, but list the ones that would be run") 83758007204Stb print(" -p port connect to this port - defaults to 4433") 83858007204Stb print(" -s run slow tests") 83958007204Stb print(" -t show timing stats at end") 84058007204Stb print(" -v verbose output") 84158007204Stb exit(0) 84258007204Stb 84358007204Stbdef main(): 84458007204Stb failing = False 84558007204Stb list = False 84658007204Stb missing = False 84758007204Stb dryrun = False 8486380fa64Stb host = "localhost" 84958007204Stb port = 4433 85058007204Stb slow = False 85158007204Stb timing = False 85258007204Stb verbose = False 85358007204Stb 85458007204Stb argv = sys.argv[1:] 8556380fa64Stb opts, args = getopt.getopt(argv, "fh:lmnp:stv", ["help"]) 85658007204Stb for opt, arg in opts: 85758007204Stb if opt == '--help': 85858007204Stb usage() 85958007204Stb elif opt == '-f': 86058007204Stb failing = True 8616380fa64Stb elif opt == '-h': 8626380fa64Stb host = arg 86358007204Stb elif opt == '-l': 86458007204Stb list = True 86558007204Stb elif opt == '-m': 86658007204Stb missing = True 86758007204Stb elif opt == '-n': 86858007204Stb dryrun = True 86958007204Stb elif opt == '-p': 87058007204Stb port = int(arg) 87158007204Stb elif opt == '-s': 87258007204Stb slow = True 87358007204Stb elif opt == '-t': 87458007204Stb timing = True 87558007204Stb elif opt == '-v': 87658007204Stb verbose = True 87758007204Stb else: 87858007204Stb raise ValueError(f"Unknown option: {opt}") 87958007204Stb 88058007204Stb if not os.path.exists(tlsfuzzer_scriptdir): 88158007204Stb print("package py3-tlsfuzzer is required for this regress") 88258007204Stb exit(1) 88358007204Stb 88458007204Stb if list and failing: 88558007204Stb failing = [test.name for group in failing_groups for test in group] 88658007204Stb failing.sort() 88758007204Stb print('\n'.join(failing)) 88858007204Stb exit(0) 88958007204Stb 89058007204Stb if list or missing: 89158007204Stb list_or_missing(missing) 89258007204Stb 8936380fa64Stb tls_server = TlsServer(host, port) 89458007204Stb 8956380fa64Stb tests = TestRunner(timing, verbose, host, port, tls_server.has_tls1_3, dryrun) 89658007204Stb 89758007204Stb if args: 89858007204Stb (dir, script) = os.path.split(args[0]) 89958007204Stb if dir and not dir == '.': 90058007204Stb tests.scriptdir = dir 90158007204Stb 90258007204Stb testargs = defaultargs(script, tls_server.has_tls1_3) 90358007204Stb 90458007204Stb tests.verbose = True 90558007204Stb tests.add("test from command line", [Test(script, testargs + args[1:])]) 90658007204Stb 90758007204Stb exit(not tests.run()) 90858007204Stb 90958007204Stb if failing: 91058007204Stb if tls_server.has_tls1_3: 91158007204Stb tests.add_group(tls13_failing_tests) 91258007204Stb if slow: 91358007204Stb tests.add_group(tls13_slow_failing_tests) 91458007204Stb tests.add_group(tls12_failing_tests) 91558007204Stb 91658007204Stb if tls_server.has_tls1_3: 91758007204Stb tests.add_group(tls13_tests) 91858007204Stb if slow: 91958007204Stb tests.add_group(tls13_slow_tests) 92058007204Stb else: 92158007204Stb tests.add_group(legacy_tests) 92258007204Stb 92358007204Stb tests.add_group(tls12_tests) 92458007204Stb if slow: 92558007204Stb tests.add_group(tls12_slow_tests) 92658007204Stb 92758007204Stb success = tests.run() 92858007204Stb del tests 92958007204Stb 93058007204Stb if not success: 93158007204Stb print("FAILED") 93258007204Stb exit(1) 93358007204Stb 93458007204Stbif __name__ == "__main__": 93558007204Stb main() 936