diff options
| author | cvs2svn <admin@example.com> | 2022-10-20 07:33:15 +0000 |
|---|---|---|
| committer | cvs2svn <admin@example.com> | 2022-10-20 07:33:15 +0000 |
| commit | 963a7b06e7d578322df5c53439ac3f52eae54095 (patch) | |
| tree | 47b3068b3442e2e9768ae23e8bcf303231adf015 /src/regress/lib/libssl/tlsfuzzer | |
| parent | 6ef02c2707dc554983552781e5b767ae8103de15 (diff) | |
| download | openbsd-tb_20221020.tar.gz openbsd-tb_20221020.tar.bz2 openbsd-tb_20221020.zip | |
This commit was manufactured by cvs2git to create tag 'tb_20221020'.tb_20221020
Diffstat (limited to 'src/regress/lib/libssl/tlsfuzzer')
| -rw-r--r-- | src/regress/lib/libssl/tlsfuzzer/Makefile | 47 | ||||
| -rw-r--r-- | src/regress/lib/libssl/tlsfuzzer/tlsfuzzer.py | 884 |
2 files changed, 0 insertions, 931 deletions
diff --git a/src/regress/lib/libssl/tlsfuzzer/Makefile b/src/regress/lib/libssl/tlsfuzzer/Makefile deleted file mode 100644 index b57b44daa7..0000000000 --- a/src/regress/lib/libssl/tlsfuzzer/Makefile +++ /dev/null | |||
| @@ -1,47 +0,0 @@ | |||
| 1 | # $OpenBSD: Makefile,v 1.6 2022/07/18 09:17:44 tb Exp $ | ||
| 2 | |||
| 3 | .if !exists(/usr/local/share/tlsfuzzer) | ||
| 4 | regress: | ||
| 5 | @echo package py3-tlsfuzzer is required for this regress | ||
| 6 | @echo SKIPPED | ||
| 7 | .else | ||
| 8 | |||
| 9 | REGRESS_TARGETS=regress-tlsfuzzer | ||
| 10 | |||
| 11 | localhost.key localhost.crt: | ||
| 12 | openssl req -x509 -newkey rsa -keyout localhost.key -out localhost.crt \ | ||
| 13 | -subj /CN=localhost -nodes -batch | ||
| 14 | |||
| 15 | certs: localhost.key localhost.crt | ||
| 16 | |||
| 17 | CLEANFILES += localhost.key localhost.crt | ||
| 18 | |||
| 19 | PORT ?= 4433 | ||
| 20 | SLOW = -s | ||
| 21 | TIMING = # -t | ||
| 22 | VERBOSE = # -v | ||
| 23 | |||
| 24 | regress-tlsfuzzer: certs | ||
| 25 | python3 ${.CURDIR}/tlsfuzzer.py ${SLOW} ${TIMING} ${VERBOSE} | ||
| 26 | |||
| 27 | failing: certs | ||
| 28 | python3 ${.CURDIR}/tlsfuzzer.py -f ${SLOW} ${TIMING} ${VERBOSE} | ||
| 29 | |||
| 30 | |||
| 31 | port: certs | ||
| 32 | python3 ${.CURDIR}/tlsfuzzer.py ${SLOW} ${TIMING} ${VERBOSE} -p ${PORT} | ||
| 33 | |||
| 34 | list: | ||
| 35 | @python3 ${.CURDIR}/tlsfuzzer.py -l | ||
| 36 | |||
| 37 | list-failing: | ||
| 38 | @python3 ${.CURDIR}/tlsfuzzer.py -l -f | ||
| 39 | |||
| 40 | missing: | ||
| 41 | @python3 ${.CURDIR}/tlsfuzzer.py -m | ||
| 42 | |||
| 43 | .PHONY: all certs failing list list-failing missing port | ||
| 44 | |||
| 45 | .endif | ||
| 46 | |||
| 47 | .include <bsd.regress.mk> | ||
diff --git a/src/regress/lib/libssl/tlsfuzzer/tlsfuzzer.py b/src/regress/lib/libssl/tlsfuzzer/tlsfuzzer.py deleted file mode 100644 index 0cbd90c2e2..0000000000 --- a/src/regress/lib/libssl/tlsfuzzer/tlsfuzzer.py +++ /dev/null | |||
| @@ -1,884 +0,0 @@ | |||
| 1 | # $OpenBSD: tlsfuzzer.py,v 1.47 2022/07/18 09:15:08 tb Exp $ | ||
| 2 | # | ||
| 3 | # Copyright (c) 2020 Theo Buehler <tb@openbsd.org> | ||
| 4 | # | ||
| 5 | # Permission to use, copy, modify, and distribute this software for any | ||
| 6 | # purpose with or without fee is hereby granted, provided that the above | ||
| 7 | # copyright notice and this permission notice appear in all copies. | ||
| 8 | # | ||
| 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
| 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
| 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
| 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
| 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
| 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
| 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 16 | |||
| 17 | import getopt | ||
| 18 | import os | ||
| 19 | import subprocess | ||
| 20 | import sys | ||
| 21 | from timeit import default_timer as timer | ||
| 22 | |||
| 23 | tlsfuzzer_scriptdir = "/usr/local/share/tlsfuzzer/scripts/" | ||
| 24 | |||
| 25 | class Test: | ||
| 26 | """ | ||
| 27 | Represents a tlsfuzzer test script. | ||
| 28 | name: the script's name | ||
| 29 | args: arguments to feed to the script | ||
| 30 | tls12_args: override args for a TLSv1.2 server | ||
| 31 | tls13_args: override args for a TLSv1.3 server | ||
| 32 | |||
| 33 | XXX Add client cert support. | ||
| 34 | """ | ||
| 35 | def __init__(self, name="", args=[], tls12_args=[], tls13_args=[]): | ||
| 36 | self.name = name | ||
| 37 | self.tls12_args = args | ||
| 38 | self.tls13_args = args | ||
| 39 | if tls12_args: | ||
| 40 | self.tls12_args = tls12_args | ||
| 41 | if tls13_args: | ||
| 42 | self.tls13_args = tls13_args | ||
| 43 | |||
| 44 | def args(self, has_tls1_3: True): | ||
| 45 | if has_tls1_3: | ||
| 46 | return self.tls13_args | ||
| 47 | else: | ||
| 48 | return self.tls12_args | ||
| 49 | |||
| 50 | def __repr__(self): | ||
| 51 | return "<Test: %s tls12_args: %s tls13_args: %s>" % ( | ||
| 52 | self.name, self.tls12_args, self.tls13_args | ||
| 53 | ) | ||
| 54 | |||
| 55 | class TestGroup: | ||
| 56 | """ A group of Test objects to be run by TestRunner.""" | ||
| 57 | def __init__(self, title="Tests", tests=[]): | ||
| 58 | self.title = title | ||
| 59 | self.tests = tests | ||
| 60 | |||
| 61 | def __iter__(self): | ||
| 62 | return iter(self.tests) | ||
| 63 | |||
| 64 | # argument to pass to several tests | ||
| 65 | tls13_unsupported_ciphers = [ | ||
| 66 | "-e", "TLS 1.3 with ffdhe2048", | ||
| 67 | "-e", "TLS 1.3 with ffdhe3072", | ||
| 68 | "-e", "TLS 1.3 with x448", | ||
| 69 | ] | ||
| 70 | |||
| 71 | def substitute_alert(want, got): | ||
| 72 | return f"Expected alert description \"{want}\" " \ | ||
| 73 | + f"does not match received \"{got}\"" | ||
| 74 | |||
| 75 | # test-tls13-finished.py has 70 failing tests that expect a "decode_error" | ||
| 76 | # instead of the "decrypt_error" sent by tls13_server_finished_recv(). | ||
| 77 | # Both alerts appear to be reasonable in this context, so work around this | ||
| 78 | # in the test instead of the library. | ||
| 79 | def generate_test_tls13_finished_args(): | ||
| 80 | assertion = substitute_alert("decode_error", "decrypt_error"); | ||
| 81 | paddings = [ | ||
| 82 | ("TLS_AES_128_GCM_SHA256", 0, 1), | ||
| 83 | ("TLS_AES_128_GCM_SHA256", 0, 2), | ||
| 84 | ("TLS_AES_128_GCM_SHA256", 0, 4), | ||
| 85 | ("TLS_AES_128_GCM_SHA256", 0, 8), | ||
| 86 | ("TLS_AES_128_GCM_SHA256", 0, 16), | ||
| 87 | ("TLS_AES_128_GCM_SHA256", 0, 32), | ||
| 88 | ("TLS_AES_128_GCM_SHA256", 0, 48), | ||
| 89 | ("TLS_AES_128_GCM_SHA256", 0, 2**14-4-32), | ||
| 90 | ("TLS_AES_128_GCM_SHA256", 0, 0x20000), | ||
| 91 | ("TLS_AES_128_GCM_SHA256", 0, 0x30000), | ||
| 92 | ("TLS_AES_128_GCM_SHA256", 1, 0), | ||
| 93 | ("TLS_AES_128_GCM_SHA256", 2, 0), | ||
| 94 | ("TLS_AES_128_GCM_SHA256", 4, 0), | ||
| 95 | ("TLS_AES_128_GCM_SHA256", 8, 0), | ||
| 96 | ("TLS_AES_128_GCM_SHA256", 16, 0), | ||
| 97 | ("TLS_AES_128_GCM_SHA256", 32, 0), | ||
| 98 | ("TLS_AES_128_GCM_SHA256", 48, 0), | ||
| 99 | ("TLS_AES_128_GCM_SHA256", 2**14-4-32, 0), | ||
| 100 | ("TLS_AES_128_GCM_SHA256", 12, 0), | ||
| 101 | ("TLS_AES_128_GCM_SHA256", 1, 1), | ||
| 102 | ("TLS_AES_128_GCM_SHA256", 8, 8), | ||
| 103 | ("TLS_AES_256_GCM_SHA384", 0, 1), | ||
| 104 | ("TLS_AES_256_GCM_SHA384", 0, 2), | ||
| 105 | ("TLS_AES_256_GCM_SHA384", 0, 4), | ||
| 106 | ("TLS_AES_256_GCM_SHA384", 0, 8), | ||
| 107 | ("TLS_AES_256_GCM_SHA384", 0, 16), | ||
| 108 | ("TLS_AES_256_GCM_SHA384", 0, 32), | ||
| 109 | ("TLS_AES_256_GCM_SHA384", 0, 48), | ||
| 110 | ("TLS_AES_256_GCM_SHA384", 0, 2**14-4-48), | ||
| 111 | ("TLS_AES_256_GCM_SHA384", 0, 0x20000), | ||
| 112 | ("TLS_AES_256_GCM_SHA384", 0, 0x30000), | ||
| 113 | ("TLS_AES_256_GCM_SHA384", 0, 12), | ||
| 114 | ("TLS_AES_256_GCM_SHA384", 1, 0), | ||
| 115 | ("TLS_AES_256_GCM_SHA384", 2, 0), | ||
| 116 | ("TLS_AES_256_GCM_SHA384", 4, 0), | ||
| 117 | ("TLS_AES_256_GCM_SHA384", 8, 0), | ||
| 118 | ("TLS_AES_256_GCM_SHA384", 16, 0), | ||
| 119 | ("TLS_AES_256_GCM_SHA384", 32, 0), | ||
| 120 | ("TLS_AES_256_GCM_SHA384", 48, 0), | ||
| 121 | ("TLS_AES_256_GCM_SHA384", 2**14-4-48, 0), | ||
| 122 | ("TLS_AES_256_GCM_SHA384", 1, 1), | ||
| 123 | ("TLS_AES_256_GCM_SHA384", 8, 8), | ||
| 124 | ] | ||
| 125 | truncations = [ | ||
| 126 | ("TLS_AES_128_GCM_SHA256", 0, -1), | ||
| 127 | ("TLS_AES_128_GCM_SHA256", 0, -2), | ||
| 128 | ("TLS_AES_128_GCM_SHA256", 0, -4), | ||
| 129 | ("TLS_AES_128_GCM_SHA256", 0, -8), | ||
| 130 | ("TLS_AES_128_GCM_SHA256", 0, -16), | ||
| 131 | ("TLS_AES_128_GCM_SHA256", 0, -32), | ||
| 132 | ("TLS_AES_128_GCM_SHA256", 0, 12), | ||
| 133 | ("TLS_AES_128_GCM_SHA256", 1, None), | ||
| 134 | ("TLS_AES_128_GCM_SHA256", 2, None), | ||
| 135 | ("TLS_AES_128_GCM_SHA256", 4, None), | ||
| 136 | ("TLS_AES_128_GCM_SHA256", 8, None), | ||
| 137 | ("TLS_AES_128_GCM_SHA256", 16, None), | ||
| 138 | ("TLS_AES_128_GCM_SHA256", 32, None), | ||
| 139 | ("TLS_AES_256_GCM_SHA384", 0, -1), | ||
| 140 | ("TLS_AES_256_GCM_SHA384", 0, -2), | ||
| 141 | ("TLS_AES_256_GCM_SHA384", 0, -4), | ||
| 142 | ("TLS_AES_256_GCM_SHA384", 0, -8), | ||
| 143 | ("TLS_AES_256_GCM_SHA384", 0, -16), | ||
| 144 | ("TLS_AES_256_GCM_SHA384", 0, -32), | ||
| 145 | ("TLS_AES_256_GCM_SHA384", 0, 12), | ||
| 146 | ("TLS_AES_256_GCM_SHA384", 1, None), | ||
| 147 | ("TLS_AES_256_GCM_SHA384", 2, None), | ||
| 148 | ("TLS_AES_256_GCM_SHA384", 4, None), | ||
| 149 | ("TLS_AES_256_GCM_SHA384", 8, None), | ||
| 150 | ("TLS_AES_256_GCM_SHA384", 16, None), | ||
| 151 | ("TLS_AES_256_GCM_SHA384", 32, None), | ||
| 152 | ] | ||
| 153 | |||
| 154 | args = [ | ||
| 155 | "-x", "empty - cipher TLS_AES_128_GCM_SHA256", "-X", assertion, | ||
| 156 | "-x", "empty - cipher TLS_AES_256_GCM_SHA384", "-X", assertion, | ||
| 157 | ] | ||
| 158 | padding_fmt = "padding - cipher %s, pad_byte 0, pad_left %d, pad_right %d" | ||
| 159 | for padding in paddings: | ||
| 160 | args += ["-x", padding_fmt % padding, "-X", assertion] | ||
| 161 | truncation_fmt = "truncation - cipher %s, start %d, end %s" | ||
| 162 | for truncation in truncations: | ||
| 163 | args += ["-x", truncation_fmt % truncation, "-X", assertion] | ||
| 164 | return args | ||
| 165 | |||
| 166 | tls13_tests = TestGroup("TLSv1.3 tests", [ | ||
| 167 | Test("test-tls13-ccs.py"), | ||
| 168 | Test("test-tls13-conversation.py"), | ||
| 169 | Test("test-tls13-count-tickets.py"), | ||
| 170 | Test("test-tls13-empty-alert.py"), | ||
| 171 | Test("test-tls13-finished.py", generate_test_tls13_finished_args()), | ||
| 172 | Test("test-tls13-finished-plaintext.py"), | ||
| 173 | Test("test-tls13-hrr.py"), | ||
| 174 | Test("test-tls13-keyshare-omitted.py"), | ||
| 175 | Test("test-tls13-legacy-version.py"), | ||
| 176 | Test("test-tls13-nociphers.py"), | ||
| 177 | Test("test-tls13-record-padding.py"), | ||
| 178 | # Exclude QUIC transport parameters | ||
| 179 | Test("test-tls13-shuffled-extentions.py", [ "--exc", "57" ]), | ||
| 180 | Test("test-tls13-zero-content-type.py"), | ||
| 181 | |||
| 182 | # The skipped tests fail due to a bug in BIO_gets() which masks the retry | ||
| 183 | # signalled from an SSL_read() failure. Testing with httpd(8) shows we're | ||
| 184 | # handling these corner cases correctly since tls13_record_layer.c -r1.47. | ||
| 185 | Test("test-tls13-zero-length-data.py", [ | ||
| 186 | "-e", "zero-length app data", | ||
| 187 | "-e", "zero-length app data with large padding", | ||
| 188 | "-e", "zero-length app data with padding", | ||
| 189 | ]), | ||
| 190 | ]) | ||
| 191 | |||
| 192 | # Tests that take a lot of time (> ~30s on an x280) | ||
| 193 | tls13_slow_tests = TestGroup("slow TLSv1.3 tests", [ | ||
| 194 | # XXX: Investigate the occasional message | ||
| 195 | # "Got shared secret with 1 most significant bytes equal to zero." | ||
| 196 | Test("test-tls13-dhe-shared-secret-padding.py", tls13_unsupported_ciphers), | ||
| 197 | |||
| 198 | Test("test-tls13-invalid-ciphers.py"), | ||
| 199 | Test("test-tls13-serverhello-random.py", tls13_unsupported_ciphers), | ||
| 200 | |||
| 201 | # Mark two tests cases as xfail for now. The tests expect an arguably | ||
| 202 | # correct decode_error while we send a decrypt_error (like fizz/boring). | ||
| 203 | Test("test-tls13-record-layer-limits.py", [ | ||
| 204 | "-x", "max size payload (2**14) of Finished msg, with 16348 bytes of left padding, cipher TLS_AES_128_GCM_SHA256", | ||
| 205 | "-X", substitute_alert("decode_error", "decrypt_error"), | ||
| 206 | "-x", "max size payload (2**14) of Finished msg, with 16348 bytes of left padding, cipher TLS_CHACHA20_POLY1305_SHA256", | ||
| 207 | "-X", substitute_alert("decode_error", "decrypt_error"), | ||
| 208 | ]), | ||
| 209 | # We don't accept an empty ECPF extension since it must advertise the | ||
| 210 | # uncompressed point format. Exclude this extension type from the test. | ||
| 211 | # Also exclude QUIC transport parameters. | ||
| 212 | Test( | ||
| 213 | "test-tls13-large-number-of-extensions.py", | ||
| 214 | tls13_args = ["--exc", "11", "--exc", "57"], | ||
| 215 | ), | ||
| 216 | ]) | ||
| 217 | |||
| 218 | tls13_extra_cert_tests = TestGroup("TLSv1.3 certificate tests", [ | ||
| 219 | # need to set up client certs to run these | ||
| 220 | Test("test-tls13-certificate-request.py"), | ||
| 221 | Test("test-tls13-certificate-verify.py"), | ||
| 222 | Test("test-tls13-ecdsa-in-certificate-verify.py"), | ||
| 223 | Test("test-tls13-eddsa-in-certificate-verify.py"), | ||
| 224 | |||
| 225 | # Test expects the server to have installed three certificates: | ||
| 226 | # with P-256, P-384 and P-521 curve. Also SHA1+ECDSA is verified | ||
| 227 | # to not work. | ||
| 228 | Test("test-tls13-ecdsa-support.py"), | ||
| 229 | ]) | ||
| 230 | |||
| 231 | tls13_failing_tests = TestGroup("failing TLSv1.3 tests", [ | ||
| 232 | # Some tests fail because we fail later than the scripts expect us to. | ||
| 233 | # With X25519, we accept weak peer public keys and fail when we actually | ||
| 234 | # compute the keyshare. Other tests seem to indicate that we could be | ||
| 235 | # stricter about what keyshares we accept. | ||
| 236 | Test("test-tls13-crfg-curves.py", [ | ||
| 237 | '-e', 'all zero x448 key share', | ||
| 238 | '-e', 'empty x448 key share', | ||
| 239 | '-e', 'sanity x448 with compression ansiX962_compressed_char2', | ||
| 240 | '-e', 'sanity x448 with compression ansiX962_compressed_prime', | ||
| 241 | '-e', 'sanity x448 with compression uncompressed', | ||
| 242 | '-e', 'too big x448 key share', | ||
| 243 | '-e', 'too small x448 key share', | ||
| 244 | '-e', 'x448 key share of "1"', | ||
| 245 | ]), | ||
| 246 | Test("test-tls13-ecdhe-curves.py", [ | ||
| 247 | '-e', 'sanity - x448', | ||
| 248 | '-e', 'x448 - key share from other curve', | ||
| 249 | '-e', 'x448 - point at infinity', | ||
| 250 | '-e', 'x448 - right 0-padded key_share', | ||
| 251 | '-e', 'x448 - right-truncated key_share', | ||
| 252 | ]), | ||
| 253 | |||
| 254 | # The test sends records with protocol version 0x0300 instead of 0x0303 | ||
| 255 | # and currently fails with OpenSSL and LibreSSL for this reason. | ||
| 256 | # We have the logic corresponding to NSS's fix for CVE-2020-25648 | ||
| 257 | # https://hg.mozilla.org/projects/nss/rev/57bbefa793232586d27cee83e74411171e128361 | ||
| 258 | # so should not be affected by this issue. | ||
| 259 | Test("test-tls13-multiple-ccs-messages.py"), | ||
| 260 | |||
| 261 | # https://github.com/openssl/openssl/issues/8369 | ||
| 262 | Test("test-tls13-obsolete-curves.py"), | ||
| 263 | |||
| 264 | # 3 failing rsa_pss_pss tests | ||
| 265 | Test("test-tls13-rsa-signatures.py"), | ||
| 266 | |||
| 267 | # The failing tests all expect an ri extension. What's up with that? | ||
| 268 | Test("test-tls13-version-negotiation.py"), | ||
| 269 | ]) | ||
| 270 | |||
| 271 | tls13_slow_failing_tests = TestGroup("slow, failing TLSv1.3 tests", [ | ||
| 272 | # Other test failures bugs in keyshare/tlsext negotiation? | ||
| 273 | Test("test-tls13-unrecognised-groups.py"), # unexpected closure | ||
| 274 | |||
| 275 | # 5 occasional failures: | ||
| 276 | # 'app data split, conversation with KeyUpdate msg' | ||
| 277 | # 'fragmented keyupdate msg' | ||
| 278 | # 'multiple KeyUpdate messages' | ||
| 279 | # 'post-handshake KeyUpdate msg with update_not_request' | ||
| 280 | # 'post-handshake KeyUpdate msg with update_request' | ||
| 281 | Test("test-tls13-keyupdate.py"), | ||
| 282 | |||
| 283 | Test("test-tls13-symetric-ciphers.py"), # unexpected message from peer | ||
| 284 | |||
| 285 | # 6 tests fail: 'rsa_pkcs1_{md5,sha{1,224,256,384,512}} signature' | ||
| 286 | # We send server hello, but the test expects handshake_failure | ||
| 287 | Test("test-tls13-pkcs-signature.py"), | ||
| 288 | # 8 tests fail: 'tls13 signature rsa_pss_{pss,rsae}_sha{256,384,512} | ||
| 289 | Test("test-tls13-rsapss-signatures.py"), | ||
| 290 | ]) | ||
| 291 | |||
| 292 | tls13_unsupported_tests = TestGroup("TLSv1.3 tests for unsupported features", [ | ||
| 293 | # Tests for features we don't support | ||
| 294 | Test("test-tls13-0rtt-garbage.py"), | ||
| 295 | Test("test-tls13-ffdhe-groups.py"), | ||
| 296 | Test("test-tls13-ffdhe-sanity.py"), | ||
| 297 | Test("test-tls13-psk_dhe_ke.py"), | ||
| 298 | Test("test-tls13-psk_ke.py"), | ||
| 299 | |||
| 300 | # need server to react to HTTP GET for /keyupdate | ||
| 301 | Test("test-tls13-keyupdate-from-server.py"), | ||
| 302 | |||
| 303 | # needs an echo server | ||
| 304 | Test("test-tls13-lengths.py"), | ||
| 305 | |||
| 306 | # Weird test: tests servers that don't support 1.3 | ||
| 307 | Test("test-tls13-non-support.py"), | ||
| 308 | |||
| 309 | # broken test script | ||
| 310 | # UnboundLocalError: local variable 'cert' referenced before assignment | ||
| 311 | Test("test-tls13-post-handshake-auth.py"), | ||
| 312 | |||
| 313 | # ExpectNewSessionTicket | ||
| 314 | Test("test-tls13-session-resumption.py"), | ||
| 315 | |||
| 316 | # Server must be configured to support only rsa_pss_rsae_sha512 | ||
| 317 | Test("test-tls13-signature-algorithms.py"), | ||
| 318 | ]) | ||
| 319 | |||
| 320 | tls12_exclude_legacy_protocols = [ | ||
| 321 | # all these have BIO_read timeouts against TLSv1.3 | ||
| 322 | "-e", "Protocol (3, 0)", | ||
| 323 | "-e", "Protocol (3, 0) in SSLv2 compatible ClientHello", | ||
| 324 | # the following only fail with TLSv1.3 | ||
| 325 | "-e", "Protocol (3, 1) in SSLv2 compatible ClientHello", | ||
| 326 | "-e", "Protocol (3, 2) in SSLv2 compatible ClientHello", | ||
| 327 | "-e", "Protocol (3, 3) in SSLv2 compatible ClientHello", | ||
| 328 | "-e", "Protocol (3, 1) with x448 group", | ||
| 329 | "-e", "Protocol (3, 2) with x448 group", | ||
| 330 | "-e", "Protocol (3, 3) with x448 group", | ||
| 331 | ] | ||
| 332 | |||
| 333 | tls12_tests = TestGroup("TLSv1.2 tests", [ | ||
| 334 | # Tests that pass as they are. | ||
| 335 | Test("test-TLSv1_2-rejected-without-TLSv1_2.py"), | ||
| 336 | Test("test-aes-gcm-nonces.py"), | ||
| 337 | Test("test-chacha20.py"), | ||
| 338 | Test("test-conversation.py"), | ||
| 339 | Test("test-cve-2016-2107.py"), | ||
| 340 | Test("test-cve-2016-6309.py"), | ||
| 341 | Test("test-dhe-rsa-key-exchange.py"), | ||
| 342 | Test("test-dhe-rsa-key-exchange-with-bad-messages.py"), | ||
| 343 | Test("test-early-application-data.py"), | ||
| 344 | Test("test-empty-extensions.py"), | ||
| 345 | Test("test-extensions.py"), | ||
| 346 | Test("test-fuzzed-MAC.py"), | ||
| 347 | Test("test-fuzzed-ciphertext.py"), | ||
| 348 | Test("test-fuzzed-finished.py"), | ||
| 349 | Test("test-fuzzed-padding.py"), | ||
| 350 | Test("test-fuzzed-plaintext.py"), # fails once in a while | ||
| 351 | Test("test-hello-request-by-client.py"), | ||
| 352 | Test("test-invalid-cipher-suites.py"), | ||
| 353 | Test("test-invalid-content-type.py"), | ||
| 354 | Test("test-invalid-session-id.py"), | ||
| 355 | Test("test-invalid-version.py"), | ||
| 356 | Test("test-lucky13.py"), | ||
| 357 | Test("test-message-skipping.py"), | ||
| 358 | Test("test-no-heartbeat.py"), | ||
| 359 | Test("test-record-layer-fragmentation.py"), | ||
| 360 | Test("test-sessionID-resumption.py"), | ||
| 361 | Test("test-sslv2-connection.py"), | ||
| 362 | Test("test-truncating-of-finished.py"), | ||
| 363 | Test("test-truncating-of-kRSA-client-key-exchange.py"), | ||
| 364 | Test("test-unsupported-curve-fallback.py"), | ||
| 365 | Test("test-version-numbers.py"), | ||
| 366 | Test("test-zero-length-data.py"), | ||
| 367 | |||
| 368 | # Tests that need tweaking for unsupported features and ciphers. | ||
| 369 | Test( | ||
| 370 | "test-atypical-padding.py", [ | ||
| 371 | "-e", "sanity - encrypt then MAC", | ||
| 372 | "-e", "2^14 bytes of AppData with 256 bytes of padding (SHA1 + Encrypt then MAC)", | ||
| 373 | ] | ||
| 374 | ), | ||
| 375 | Test( | ||
| 376 | "test-dhe-rsa-key-exchange-signatures.py", [ | ||
| 377 | "-e", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA sha224 signature", | ||
| 378 | "-e", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 sha224 signature", | ||
| 379 | "-e", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA sha224 signature", | ||
| 380 | "-e", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 sha224 signature", | ||
| 381 | "-e", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA sha224 signature", | ||
| 382 | ] | ||
| 383 | ), | ||
| 384 | Test("test-dhe-key-share-random.py", tls12_exclude_legacy_protocols), | ||
| 385 | Test("test-export-ciphers-rejected.py", ["--min-ver", "TLSv1.0"]), | ||
| 386 | Test( | ||
| 387 | "test-downgrade-protection.py", | ||
| 388 | tls12_args = ["--server-max-protocol", "TLSv1.2"], | ||
| 389 | tls13_args = ["--server-max-protocol", "TLSv1.3"], | ||
| 390 | ), | ||
| 391 | Test("test-fallback-scsv.py", tls13_args = ["--tls-1.3"] ), | ||
| 392 | |||
| 393 | Test("test-invalid-compression-methods.py", [ | ||
| 394 | "-x", "invalid compression methods", | ||
| 395 | "-X", substitute_alert("illegal_parameter", "decode_error"), | ||
| 396 | "-x", "only deflate compression method", | ||
| 397 | "-X", substitute_alert("illegal_parameter", "decode_error"), | ||
| 398 | ]), | ||
| 399 | |||
| 400 | # Skip extended_master_secret test. Since we don't support this | ||
| 401 | # extension, we don't notice that it was dropped. | ||
| 402 | Test("test-renegotiation-changed-clienthello.py", [ | ||
| 403 | "-e", "drop extended_master_secret in renegotiation", | ||
| 404 | ]), | ||
| 405 | |||
| 406 | # Without --sig-algs-drop-ok, two tests fail since we do not currently | ||
| 407 | # implement the signature_algorithms_cert extension (although we MUST). | ||
| 408 | Test("test-sig-algs-renegotiation-resumption.py", ["--sig-algs-drop-ok"]), | ||
| 409 | |||
| 410 | Test("test-serverhello-random.py", args = tls12_exclude_legacy_protocols), | ||
| 411 | ]) | ||
| 412 | |||
| 413 | tls12_slow_tests = TestGroup("slow TLSv1.2 tests", [ | ||
| 414 | Test("test-cve-2016-7054.py"), | ||
| 415 | Test("test-dhe-no-shared-secret-padding.py", tls12_exclude_legacy_protocols), | ||
| 416 | Test("test-ecdhe-padded-shared-secret.py", tls12_exclude_legacy_protocols), | ||
| 417 | Test("test-ecdhe-rsa-key-share-random.py", tls12_exclude_legacy_protocols), | ||
| 418 | # Start at extension number 58 to avoid QUIC transport parameters (57) | ||
| 419 | Test("test-large-hello.py", [ "-m", "58" ]), | ||
| 420 | ]) | ||
| 421 | |||
| 422 | tls12_failing_tests = TestGroup("failing TLSv1.2 tests", [ | ||
| 423 | # no shared cipher | ||
| 424 | Test("test-aesccm.py"), | ||
| 425 | # need server to set up alpn | ||
| 426 | Test("test-alpn-negotiation.py"), | ||
| 427 | # many tests fail due to unexpected server_name extension | ||
| 428 | Test("test-bleichenbacher-workaround.py"), | ||
| 429 | |||
| 430 | # need client key and cert plus extra server setup | ||
| 431 | Test("test-certificate-malformed.py"), | ||
| 432 | Test("test-certificate-request.py"), | ||
| 433 | Test("test-certificate-verify-malformed-sig.py"), | ||
| 434 | Test("test-certificate-verify-malformed.py"), | ||
| 435 | Test("test-certificate-verify.py"), | ||
| 436 | Test("test-ecdsa-in-certificate-verify.py"), | ||
| 437 | Test("test-eddsa-in-certificate-verify.py"), | ||
| 438 | Test("test-renegotiation-disabled-client-cert.py"), | ||
| 439 | Test("test-rsa-pss-sigs-on-certificate-verify.py"), | ||
| 440 | Test("test-rsa-sigs-on-certificate-verify.py"), | ||
| 441 | |||
| 442 | # test doesn't expect session ticket | ||
| 443 | Test("test-client-compatibility.py"), | ||
| 444 | # abrupt closure | ||
| 445 | Test("test-client-hello-max-size.py"), | ||
| 446 | # unknown signature algorithms | ||
| 447 | Test("test-clienthello-md5.py"), | ||
| 448 | |||
| 449 | # Tests expect an illegal_parameter or a decode_error alert. Should be | ||
| 450 | # added to ssl3_get_client_key_exchange on kex function failure. | ||
| 451 | Test("test-ecdhe-rsa-key-exchange-with-bad-messages.py"), | ||
| 452 | |||
| 453 | # We send a handshake_failure due to no shared ciphers while the | ||
| 454 | # test expects to succeed. | ||
| 455 | Test("test-ecdhe-rsa-key-exchange.py"), | ||
| 456 | |||
| 457 | # no shared cipher | ||
| 458 | Test("test-ecdsa-sig-flexibility.py"), | ||
| 459 | |||
| 460 | # Tests expect SH but we send unexpected_message or handshake_failure | ||
| 461 | # 'Application data inside Client Hello' | ||
| 462 | # 'Application data inside Client Key Exchange' | ||
| 463 | # 'Application data inside Finished' | ||
| 464 | Test("test-interleaved-application-data-and-fragmented-handshakes-in-renegotiation.py"), | ||
| 465 | # Tests expect SH but we send handshake_failure | ||
| 466 | # 'Application data before Change Cipher Spec' | ||
| 467 | # 'Application data before Client Key Exchange' | ||
| 468 | # 'Application data before Finished' | ||
| 469 | Test("test-interleaved-application-data-in-renegotiation.py"), | ||
| 470 | |||
| 471 | # broken test script | ||
| 472 | # TypeError: '<' not supported between instances of 'int' and 'NoneType' | ||
| 473 | Test("test-invalid-client-hello-w-record-overflow.py"), | ||
| 474 | |||
| 475 | # Lots of failures. abrupt closure | ||
| 476 | Test("test-invalid-client-hello.py"), | ||
| 477 | |||
| 478 | # abrupt closure | ||
| 479 | # 'encrypted premaster set to all zero (n)' n in 256 384 512 | ||
| 480 | Test("test-invalid-rsa-key-exchange-messages.py"), | ||
| 481 | |||
| 482 | # test expects illegal_parameter, we send unrecognized_name (which seems | ||
| 483 | # correct according to rfc 6066?) | ||
| 484 | Test("test-invalid-server-name-extension-resumption.py"), | ||
| 485 | # let through some server names without sending an alert | ||
| 486 | # again illegal_parameter vs unrecognized_name | ||
| 487 | Test("test-invalid-server-name-extension.py"), | ||
| 488 | |||
| 489 | # 14 pass | ||
| 490 | # 7 fail | ||
| 491 | # 'n extensions', n in 4095, 4096, 4097, 8191, 8192, 8193, 16383, | ||
| 492 | Test("test-large-number-of-extensions.py"), | ||
| 493 | |||
| 494 | # 4 failures: | ||
| 495 | # 'insecure (legacy) renegotiation with GET after 2nd handshake' | ||
| 496 | # 'insecure (legacy) renegotiation with incomplete GET' | ||
| 497 | # 'secure renegotiation with GET after 2nd handshake' | ||
| 498 | # 'secure renegotiation with incomplete GET' | ||
| 499 | Test("test-legacy-renegotiation.py"), | ||
| 500 | |||
| 501 | # 1 failure (timeout): we don't send the unexpected_message alert | ||
| 502 | # 'duplicate change cipher spec after Finished' | ||
| 503 | Test("test-message-duplication.py"), | ||
| 504 | |||
| 505 | # server should send status_request | ||
| 506 | Test("test-ocsp-stapling.py"), | ||
| 507 | |||
| 508 | # unexpected closure | ||
| 509 | Test("test-openssl-3712.py"), | ||
| 510 | |||
| 511 | # failed: 3 (expect an alert, we send AD) | ||
| 512 | # 'try insecure (legacy) renegotiation with incomplete GET' | ||
| 513 | # 'try secure renegotiation with GET after 2nd CH' | ||
| 514 | # 'try secure renegotiation with incomplete GET' | ||
| 515 | Test("test-renegotiation-disabled.py"), | ||
| 516 | |||
| 517 | # 'resumption of safe session with NULL cipher' | ||
| 518 | # 'resumption with cipher from old CH but not selected by server' | ||
| 519 | Test("test-resumption-with-wrong-ciphers.py"), | ||
| 520 | |||
| 521 | # 5 failures: | ||
| 522 | # 'empty sigalgs' | ||
| 523 | # 'only undefined sigalgs' | ||
| 524 | # 'rsa_pss_pss_sha256 only' | ||
| 525 | # 'rsa_pss_pss_sha384 only' | ||
| 526 | # 'rsa_pss_pss_sha512 only' | ||
| 527 | Test("test-sig-algs.py"), | ||
| 528 | |||
| 529 | # 13 failures: | ||
| 530 | # 'duplicated n non-rsa schemes' for n in 202 2342 8119 23741 32744 | ||
| 531 | # 'empty list of signature methods' | ||
| 532 | # 'tolerance n RSA or ECDSA methods' for n in 215 2355 8132 23754 | ||
| 533 | # 'tolerance 32758 methods with sig_alg_cert' | ||
| 534 | # 'tolerance max 32744 number of methods with sig_alg_cert' | ||
| 535 | # 'tolerance max (32760) number of methods' | ||
| 536 | Test("test-signature-algorithms.py"), | ||
| 537 | |||
| 538 | # times out | ||
| 539 | Test("test-ssl-death-alert.py"), | ||
| 540 | |||
| 541 | # 17 pass, 13 fail. padding and truncation | ||
| 542 | Test("test-truncating-of-client-hello.py"), | ||
| 543 | |||
| 544 | # x448 tests need disabling plus x25519 corner cases need sorting out | ||
| 545 | Test("test-x25519.py"), | ||
| 546 | ]) | ||
| 547 | |||
| 548 | tls12_unsupported_tests = TestGroup("TLSv1.2 for unsupported features", [ | ||
| 549 | # protocol_version | ||
| 550 | Test("test-SSLv3-padding.py"), | ||
| 551 | # we don't do RSA key exchanges | ||
| 552 | Test("test-bleichenbacher-timing.py"), | ||
| 553 | # no encrypt-then-mac | ||
| 554 | Test("test-encrypt-then-mac-renegotiation.py"), | ||
| 555 | Test("test-encrypt-then-mac.py"), | ||
| 556 | # no EME support | ||
| 557 | Test("test-extended-master-secret-extension-with-client-cert.py"), | ||
| 558 | Test("test-extended-master-secret-extension.py"), | ||
| 559 | # no ffdhe | ||
| 560 | Test("test-ffdhe-expected-params.py"), | ||
| 561 | Test("test-ffdhe-negotiation.py"), | ||
| 562 | # record_size_limit/max_fragment_length extension (RFC 8449) | ||
| 563 | Test("test-record-size-limit.py"), | ||
| 564 | # expects the server to send the heartbeat extension | ||
| 565 | Test("test-heartbeat.py"), | ||
| 566 | # needs an echo server | ||
| 567 | Test("test-lengths.py"), | ||
| 568 | ]) | ||
| 569 | |||
| 570 | # These tests take a ton of time to fail against an 1.3 server, | ||
| 571 | # so don't run them against 1.3 pending further investigation. | ||
| 572 | legacy_tests = TestGroup("Legacy protocol tests", [ | ||
| 573 | Test("test-sslv2-force-cipher-3des.py"), | ||
| 574 | Test("test-sslv2-force-cipher-non3des.py"), | ||
| 575 | Test("test-sslv2-force-cipher.py"), | ||
| 576 | Test("test-sslv2-force-export-cipher.py"), | ||
| 577 | Test("test-sslv2hello-protocol.py"), | ||
| 578 | ]) | ||
| 579 | |||
| 580 | all_groups = [ | ||
| 581 | tls13_tests, | ||
| 582 | tls13_slow_tests, | ||
| 583 | tls13_extra_cert_tests, | ||
| 584 | tls13_failing_tests, | ||
| 585 | tls13_slow_failing_tests, | ||
| 586 | tls13_unsupported_tests, | ||
| 587 | tls12_tests, | ||
| 588 | tls12_slow_tests, | ||
| 589 | tls12_failing_tests, | ||
| 590 | tls12_unsupported_tests, | ||
| 591 | legacy_tests, | ||
| 592 | ] | ||
| 593 | |||
| 594 | failing_groups = [ | ||
| 595 | tls13_failing_tests, | ||
| 596 | tls13_slow_failing_tests, | ||
| 597 | tls12_failing_tests, | ||
| 598 | ] | ||
| 599 | |||
| 600 | class TestRunner: | ||
| 601 | """ Runs the given tests troups against a server and displays stats. """ | ||
| 602 | |||
| 603 | def __init__( | ||
| 604 | self, timing=False, verbose=False, host="localhost", port=4433, | ||
| 605 | use_tls1_3=True, dry_run=False, tests=[], scriptdir=tlsfuzzer_scriptdir, | ||
| 606 | ): | ||
| 607 | self.tests = [] | ||
| 608 | |||
| 609 | self.dryrun = dry_run | ||
| 610 | self.use_tls1_3 = use_tls1_3 | ||
| 611 | self.host = host | ||
| 612 | self.port = str(port) | ||
| 613 | self.scriptdir = scriptdir | ||
| 614 | |||
| 615 | self.stats = [] | ||
| 616 | self.failed = [] | ||
| 617 | self.missing = [] | ||
| 618 | |||
| 619 | self.timing = timing | ||
| 620 | self.verbose = verbose | ||
| 621 | |||
| 622 | def add(self, title="tests", tests=[]): | ||
| 623 | # tests.sort(key=lambda test: test.name) | ||
| 624 | self.tests.append(TestGroup(title, tests)) | ||
| 625 | |||
| 626 | def add_group(self, group): | ||
| 627 | self.tests.append(group) | ||
| 628 | |||
| 629 | def run_script(self, test): | ||
| 630 | script = test.name | ||
| 631 | args = ["-h"] + [self.host] + ["-p"] + [self.port] + test.args(self.use_tls1_3) | ||
| 632 | |||
| 633 | if self.dryrun: | ||
| 634 | if not self.verbose: | ||
| 635 | args = [] | ||
| 636 | print(script , end=' ' if args else '') | ||
| 637 | print(' '.join([f"\"{arg}\"" for arg in args])) | ||
| 638 | return | ||
| 639 | |||
| 640 | if self.verbose: | ||
| 641 | print(script) | ||
| 642 | else: | ||
| 643 | print(f"{script[:68]:<72}", end=" ", flush=True) | ||
| 644 | start = timer() | ||
| 645 | scriptpath = os.path.join(self.scriptdir, script) | ||
| 646 | if not os.path.exists(scriptpath): | ||
| 647 | self.missing.append(script) | ||
| 648 | print("MISSING") | ||
| 649 | return | ||
| 650 | test = subprocess.run( | ||
| 651 | ["python3", scriptpath] + args, | ||
| 652 | capture_output=not self.verbose, | ||
| 653 | text=True, | ||
| 654 | ) | ||
| 655 | end = timer() | ||
| 656 | self.stats.append((script, end - start)) | ||
| 657 | if test.returncode == 0: | ||
| 658 | print("OK") | ||
| 659 | return | ||
| 660 | print("FAILED") | ||
| 661 | self.failed.append(script) | ||
| 662 | |||
| 663 | if self.verbose: | ||
| 664 | return | ||
| 665 | |||
| 666 | print('\n'.join(test.stdout.split("Test end\n", 1)[1:]), end="") | ||
| 667 | |||
| 668 | def run(self): | ||
| 669 | for group in self: | ||
| 670 | print(f"Running {group.title} ...") | ||
| 671 | for test in group: | ||
| 672 | self.run_script(test) | ||
| 673 | return not self.failed | ||
| 674 | |||
| 675 | def __iter__(self): | ||
| 676 | return iter(self.tests) | ||
| 677 | |||
| 678 | def __del__(self): | ||
| 679 | if self.timing and self.stats: | ||
| 680 | total = 0.0 | ||
| 681 | for (script, time) in self.stats: | ||
| 682 | print(f"{round(time, 2):6.2f} {script}") | ||
| 683 | total += time | ||
| 684 | print(f"{round(total, 2):6.2f} total") | ||
| 685 | |||
| 686 | if self.failed: | ||
| 687 | print("Failed tests:") | ||
| 688 | print('\n'.join(self.failed)) | ||
| 689 | |||
| 690 | if self.missing: | ||
| 691 | print("Missing tests (outdated package?):") | ||
| 692 | print('\n'.join(self.missing)) | ||
| 693 | |||
| 694 | class TlsServer: | ||
| 695 | """ Spawns an s_server listening on localhost:port if necessary. """ | ||
| 696 | |||
| 697 | def __init__(self, host="localhost", port=4433): | ||
| 698 | self.spawn = True | ||
| 699 | # Check whether a server is already listening on localhost:port | ||
| 700 | self.spawn = subprocess.run( | ||
| 701 | ["nc", "-c", "-z", "-T", "noverify", host, str(port)], | ||
| 702 | stderr=subprocess.DEVNULL, | ||
| 703 | ).returncode != 0 | ||
| 704 | |||
| 705 | if self.spawn: | ||
| 706 | self.server = subprocess.Popen( | ||
| 707 | [ | ||
| 708 | "openssl", | ||
| 709 | "s_server", | ||
| 710 | "-accept", | ||
| 711 | str(port), | ||
| 712 | "-groups", | ||
| 713 | "X25519:P-256:P-521:P-384", | ||
| 714 | "-key", | ||
| 715 | "localhost.key", | ||
| 716 | "-cert", | ||
| 717 | "localhost.crt", | ||
| 718 | "-www", | ||
| 719 | ], | ||
| 720 | stdout=subprocess.DEVNULL, | ||
| 721 | stderr=subprocess.PIPE, | ||
| 722 | text=True, | ||
| 723 | ) | ||
| 724 | |||
| 725 | # Check whether the server talks TLSv1.3 | ||
| 726 | self.has_tls1_3 = True or subprocess.run( | ||
| 727 | [ | ||
| 728 | "nc", | ||
| 729 | "-c", | ||
| 730 | "-z", | ||
| 731 | "-T", | ||
| 732 | "noverify", | ||
| 733 | "-T", | ||
| 734 | "protocols=TLSv1.3", | ||
| 735 | "localhost", | ||
| 736 | str(port), | ||
| 737 | ], | ||
| 738 | stderr=subprocess.DEVNULL, | ||
| 739 | ).returncode == 0 | ||
| 740 | |||
| 741 | self.check() | ||
| 742 | |||
| 743 | def check(self): | ||
| 744 | if self.spawn and self.server.poll() is not None: | ||
| 745 | print(self.server.stderr.read()) | ||
| 746 | raise RuntimeError( | ||
| 747 | f"openssl s_server died. Return code: {self.server.returncode}." | ||
| 748 | ) | ||
| 749 | if self.spawn: | ||
| 750 | self.server.stderr.detach() | ||
| 751 | |||
| 752 | def __del__(self): | ||
| 753 | if self.spawn: | ||
| 754 | self.server.terminate() | ||
| 755 | |||
| 756 | # Extract the arguments we pass to script | ||
| 757 | def defaultargs(script, has_tls1_3): | ||
| 758 | return next( | ||
| 759 | (test for group in all_groups for test in group if test.name == script), | ||
| 760 | Test() | ||
| 761 | ).args(has_tls1_3) | ||
| 762 | |||
| 763 | def list_or_missing(missing=True): | ||
| 764 | tests = [test.name for group in all_groups for test in group] | ||
| 765 | |||
| 766 | if missing: | ||
| 767 | scripts = { | ||
| 768 | f for f in os.listdir(tlsfuzzer_scriptdir) if f != "__pycache__" | ||
| 769 | } | ||
| 770 | missing = scripts - set(tests) | ||
| 771 | if missing: | ||
| 772 | print('\n'.join(sorted(missing))) | ||
| 773 | exit(0) | ||
| 774 | |||
| 775 | tests.sort() | ||
| 776 | print('\n'.join(tests)) | ||
| 777 | exit(0) | ||
| 778 | |||
| 779 | def usage(): | ||
| 780 | print("Usage: python3 tlsfuzzer.py [-flmnstv] [-p port] [script [test...]]") | ||
| 781 | print(" --help help") | ||
| 782 | print(" -f run failing tests") | ||
| 783 | print(" -l list tests") | ||
| 784 | print(" -m list new tests after package update") | ||
| 785 | print(" -n do not run tests, but list the ones that would be run") | ||
| 786 | print(" -p port connect to this port - defaults to 4433") | ||
| 787 | print(" -s run slow tests") | ||
| 788 | print(" -t show timing stats at end") | ||
| 789 | print(" -v verbose output") | ||
| 790 | exit(0) | ||
| 791 | |||
| 792 | def main(): | ||
| 793 | failing = False | ||
| 794 | list = False | ||
| 795 | missing = False | ||
| 796 | dryrun = False | ||
| 797 | host = "localhost" | ||
| 798 | port = 4433 | ||
| 799 | slow = False | ||
| 800 | timing = False | ||
| 801 | verbose = False | ||
| 802 | |||
| 803 | argv = sys.argv[1:] | ||
| 804 | opts, args = getopt.getopt(argv, "fh:lmnp:stv", ["help"]) | ||
| 805 | for opt, arg in opts: | ||
| 806 | if opt == '--help': | ||
| 807 | usage() | ||
| 808 | elif opt == '-f': | ||
| 809 | failing = True | ||
| 810 | elif opt == '-h': | ||
| 811 | host = arg | ||
| 812 | elif opt == '-l': | ||
| 813 | list = True | ||
| 814 | elif opt == '-m': | ||
| 815 | missing = True | ||
| 816 | elif opt == '-n': | ||
| 817 | dryrun = True | ||
| 818 | elif opt == '-p': | ||
| 819 | port = int(arg) | ||
| 820 | elif opt == '-s': | ||
| 821 | slow = True | ||
| 822 | elif opt == '-t': | ||
| 823 | timing = True | ||
| 824 | elif opt == '-v': | ||
| 825 | verbose = True | ||
| 826 | else: | ||
| 827 | raise ValueError(f"Unknown option: {opt}") | ||
| 828 | |||
| 829 | if not os.path.exists(tlsfuzzer_scriptdir): | ||
| 830 | print("package py3-tlsfuzzer is required for this regress") | ||
| 831 | exit(1) | ||
| 832 | |||
| 833 | if list and failing: | ||
| 834 | failing = [test.name for group in failing_groups for test in group] | ||
| 835 | failing.sort() | ||
| 836 | print('\n'.join(failing)) | ||
| 837 | exit(0) | ||
| 838 | |||
| 839 | if list or missing: | ||
| 840 | list_or_missing(missing) | ||
| 841 | |||
| 842 | tls_server = TlsServer(host, port) | ||
| 843 | |||
| 844 | tests = TestRunner(timing, verbose, host, port, tls_server.has_tls1_3, dryrun) | ||
| 845 | |||
| 846 | if args: | ||
| 847 | (dir, script) = os.path.split(args[0]) | ||
| 848 | if dir and not dir == '.': | ||
| 849 | tests.scriptdir = dir | ||
| 850 | |||
| 851 | testargs = defaultargs(script, tls_server.has_tls1_3) | ||
| 852 | |||
| 853 | tests.verbose = True | ||
| 854 | tests.add("test from command line", [Test(script, testargs + args[1:])]) | ||
| 855 | |||
| 856 | exit(not tests.run()) | ||
| 857 | |||
| 858 | if failing: | ||
| 859 | if tls_server.has_tls1_3: | ||
| 860 | tests.add_group(tls13_failing_tests) | ||
| 861 | if slow: | ||
| 862 | tests.add_group(tls13_slow_failing_tests) | ||
| 863 | tests.add_group(tls12_failing_tests) | ||
| 864 | |||
| 865 | if tls_server.has_tls1_3: | ||
| 866 | tests.add_group(tls13_tests) | ||
| 867 | if slow: | ||
| 868 | tests.add_group(tls13_slow_tests) | ||
| 869 | else: | ||
| 870 | tests.add_group(legacy_tests) | ||
| 871 | |||
| 872 | tests.add_group(tls12_tests) | ||
| 873 | if slow: | ||
| 874 | tests.add_group(tls12_slow_tests) | ||
| 875 | |||
| 876 | success = tests.run() | ||
| 877 | del tests | ||
| 878 | |||
| 879 | if not success: | ||
| 880 | print("FAILED") | ||
| 881 | exit(1) | ||
| 882 | |||
| 883 | if __name__ == "__main__": | ||
| 884 | main() | ||
