diff options
| author | Andrew Dinh <[email protected]> | 2026-09-12 07:06:45 +0200 |
|---|---|---|
| committer | Alexandr Nedvedicky <[email protected]> | 2026-10-19 16:12:02 +0200 |
| commit | cc7357b2ad82c157d48525e2813bd600222fe25b (patch) | |
| tree | 20ad45facdef17d4e119aa7e461f4c5fbb3172f4 /test | |
| parent | apps/ocsp.c: fail on invalid response times (diff) | |
| download | openssl-cc7357b2ad82c157d48525e2813bd600222fe25b.tar.gz openssl-cc7357b2ad82c157d48525e2813bd600222fe25b.zip | |
Move scripts script_70 - script_108 from QUIC multistream test
to QUIC radix tests. Also remove now unused test/quic_multistream_test.c
Assisted-by: Claude:claude-sonnet-5
Reviewed-by: Neil Horman <[email protected]>
Reviewed-by: Saša Nedvědický <[email protected]>
MergeDate: Mon Oct 19 14:13:33 2026
(Merged from https://github.com/openssl/openssl/pull/33103)
Diffstat (limited to 'test')
| -rw-r--r-- | test/build.info | 6 | ||||
| -rw-r--r-- | test/quic_multistream_test.c | 4308 | ||||
| -rw-r--r-- | test/radix/quic_ops.c | 295 | ||||
| -rw-r--r-- | test/radix/quic_tests.c | 1501 | ||||
| -rw-r--r-- | test/recipes/70-test_quic_multistream.t | 50 | ||||
| -rw-r--r-- | test/recipes/70-test_quic_radix.t | 28 | ||||
| -rwxr-xr-x | test/recipes/70-test_quic_radix_data/verify-qlog.py (renamed from test/recipes/70-test_quic_multistream_data/verify-qlog.py) | 4 |
7 files changed, 1769 insertions, 4423 deletions
diff --git a/test/build.info b/test/build.info index 655f8c25de0..1b5ffd46fe0 100644 --- a/test/build.info +++ b/test/build.info @@ -496,10 +496,6 @@ IF[{- !$disabled{tests} -}] $QUICTESTHELPERS=helpers/quictestlib.c helpers/noisydgrambio.c helpers/pktsplitbio.c - SOURCE[quic_multistream_test]=quic_multistream_test.c helpers/ssltestlib.c $QUICTESTHELPERS - INCLUDE[quic_multistream_test]=../include ../apps/include - DEPEND[quic_multistream_test]=../libcrypto.a ../libssl.a libtestutil.a - SOURCE[quic_radix_test]=radix/quic_radix.c SOURCE[quic_radix_test]=helpers/ssltestlib.c $QUICTESTHELPERS INCLUDE[quic_radix_test]=../include ../apps/include @@ -1510,7 +1506,7 @@ ENDIF PROGRAMS{noinst}=quic_fc_test quic_stream_test quic_cfq_test quic_txpim_test PROGRAMS{noinst}=quic_srtm_test quic_lcidm_test quic_rcidm_test PROGRAMS{noinst}=quic_fifd_test quic_txp_test quic_tserver_test - PROGRAMS{noinst}=quic_client_test quic_cc_test quic_multistream_test + PROGRAMS{noinst}=quic_client_test quic_cc_test PROGRAMS{noinst}=quic_radix_test SOURCE[quic_ackm_test]=quic_ackm_test.c cc_dummy.c diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c deleted file mode 100644 index 87d6defda16..00000000000 --- a/test/quic_multistream_test.c +++ /dev/null @@ -1,4308 +0,0 @@ -/* - * Copyright 2023-2026 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the Apache License 2.0 (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ -#include <openssl/ssl.h> -#include <openssl/quic.h> -#include <openssl/bio.h> -#include <openssl/lhash.h> -#include <openssl/rand.h> -#include "internal/quic_tserver.h" -#include "internal/quic_ssl.h" -#include "internal/quic_error.h" -#include "internal/quic_stream_map.h" -#include "internal/quic_engine.h" -#include "testutil.h" -#include "helpers/quictestlib.h" -#if defined(OPENSSL_THREADS) -#include "internal/thread_arch.h" -#endif -#include "internal/numbers.h" /* UINT64_C */ - -static const char *certfile, *keyfile; - -#if defined(_AIX) -/* - * Some versions of AIX define macros for events and revents for use when - * accessing pollfd structures (see Github issue #24236). That interferes - * with our use of these names here. We simply undef them. - */ -#undef revents -#undef events -#endif - -#if defined(OPENSSL_THREADS) -struct child_thread_args { - struct helper *h; - const struct script_op *script; - const char *script_name; - int thread_idx; - - CRYPTO_THREAD *t; - CRYPTO_MUTEX *m; - int testresult; - int done; - int s_checked_out; -}; -#endif - -typedef struct stream_info { - const char *name; - SSL *c_stream; - uint64_t s_stream_id; -} STREAM_INFO; - -DEFINE_LHASH_OF_EX(STREAM_INFO); - -struct helper { - int s_fd; - BIO *s_net_bio, *s_net_bio_own, *s_qtf_wbio, *s_qtf_wbio_own; - /* The BIO_ADDR used for BIO_bind() */ - BIO_ADDR *s_net_bio_orig_addr; - /* The resulting address, which is the one to connect to */ - BIO_ADDR *s_net_bio_addr; - - /* - * When doing a blocking mode test run, s_priv always points to the TSERVER - * and s is NULL when the main thread should not be touching s_priv. - */ - QUIC_TSERVER *s, *s_priv; - LHASH_OF(STREAM_INFO) *s_streams; - - int c_fd; - BIO *c_net_bio, *c_net_bio_own; - SSL_CTX *c_ctx; - SSL *c_conn; - LHASH_OF(STREAM_INFO) *c_streams; - -#if defined(OPENSSL_THREADS) - struct child_thread_args *threads; - size_t num_threads; - CRYPTO_MUTEX *misc_m; - CRYPTO_CONDVAR *misc_cv; -#endif - - OSSL_TIME start_time; - - /* - * This is a duration recording the amount of time we have skipped forwards - * for testing purposes relative to the real ossl_time_now() clock. We add - * a quantity of time to this every time we skip some time. - */ - CRYPTO_RWLOCK *time_lock; - OSSL_TIME time_slip; /* protected by time_lock */ - - QTEST_FAULT *qtf; - - int init, blocking, check_spin_again; - int free_order, need_injector; - - int (*qtf_packet_plain_cb)(struct helper *h, QUIC_PKT_HDR *hdr, - unsigned char *buf, size_t buf_len); - int (*qtf_handshake_cb)(struct helper *h, - unsigned char *buf, size_t buf_len); - int (*qtf_datagram_cb)(struct helper *h, - BIO_MSG *m, size_t stride); - uint64_t inject_word0, inject_word1; - uint64_t scratch0, scratch1, fail_count; -#if defined(OPENSSL_THREADS) - struct { - CRYPTO_THREAD *t; - CRYPTO_MUTEX *m; - CRYPTO_CONDVAR *c; - int ready, stop; - } server_thread; - int s_checked_out; -#endif -}; - -struct helper_local { - struct helper *h; - LHASH_OF(STREAM_INFO) *c_streams; - int thread_idx; - const struct script_op *check_op; - int explicit_event_handling; -}; - -struct script_op { - uint32_t op; - const void *arg0; - size_t arg1; - int (*check_func)(struct helper *h, struct helper_local *hl); - const char *stream_name; - uint64_t arg2; - int (*qtf_packet_plain_cb)(struct helper *h, QUIC_PKT_HDR *hdr, - unsigned char *buf, size_t buf_len); - int (*qtf_handshake_cb)(struct helper *h, - unsigned char *buf, size_t buf_len); - int (*qtf_datagram_cb)(struct helper *h, - BIO_MSG *m, size_t stride); -}; - -#define OPK_END 0 -#define OPK_CHECK 1 -#define OPK_C_SET_ALPN 2 -#define OPK_C_CONNECT_WAIT 3 -#define OPK_C_WRITE 4 -#define OPK_S_WRITE 5 -#define OPK_C_READ_EXPECT 6 -#define OPK_S_READ_EXPECT 7 -#define OPK_C_EXPECT_FIN 8 -#define OPK_S_EXPECT_FIN 9 -#define OPK_C_CONCLUDE 10 -#define OPK_S_CONCLUDE 11 -#define OPK_C_NEW_STREAM 14 -#define OPK_S_NEW_STREAM 15 -#define OPK_C_ACCEPT_STREAM_WAIT 16 -#define OPK_C_ACCEPT_STREAM_NONE 17 -#define OPK_C_FREE_STREAM 18 -#define OPK_C_SET_DEFAULT_STREAM_MODE 19 -#define OPK_C_SET_INCOMING_STREAM_POLICY 20 -#define OPK_C_SHUTDOWN_WAIT 21 -#define OPK_C_EXPECT_CONN_CLOSE_INFO 22 -#define OPK_S_EXPECT_CONN_CLOSE_INFO 23 -#define OPK_S_BIND_STREAM_ID 24 -#define OPK_C_WAIT_FOR_DATA 25 -#define OPK_C_WRITE_FAIL 26 -#define OPK_S_WRITE_FAIL 27 -#define OPK_C_READ_FAIL 28 -#define OPK_C_STREAM_RESET 29 -#define OPK_S_ACCEPT_STREAM_WAIT 30 -#define OPK_NEW_THREAD 31 -#define OPK_BEGIN_REPEAT 32 -#define OPK_END_REPEAT 33 -#define OPK_S_UNBIND_STREAM_ID 34 -#define OPK_C_READ_FAIL_WAIT 35 -#define OPK_C_CLOSE_SOCKET 36 -#define OPK_C_EXPECT_SSL_ERR 37 -#define OPK_EXPECT_ERR_REASON 38 -#define OPK_EXPECT_ERR_LIB 39 -#define OPK_SLEEP 40 -#define OPK_S_READ_FAIL 41 -#define OPK_S_SET_INJECT_PLAIN 42 -#define OPK_SET_INJECT_WORD 43 -#define OPK_C_INHIBIT_TICK 44 -#define OPK_C_SET_WRITE_BUF_SIZE 45 -#define OPK_S_SET_INJECT_HANDSHAKE 46 -#define OPK_S_NEW_TICKET 47 -#define OPK_C_SKIP_IF_UNBOUND 48 -#define OPK_S_SET_INJECT_DATAGRAM 49 -#define OPK_S_SHUTDOWN 50 -#define OPK_POP_ERR 51 -#define OPK_C_WRITE_EX2 52 -#define OPK_SKIP_IF_BLOCKING 53 -#define OPK_C_STREAM_RESET_FAIL 54 -#define OPK_C_SHUTDOWN 55 - -#define EXPECT_CONN_CLOSE_APP (1U << 0) -#define EXPECT_CONN_CLOSE_REMOTE (1U << 1) - -/* OPK_C_NEW_STREAM */ -#define ALLOW_FAIL (1U << 16) - -#define C_BIDI_ID(ordinal) \ - (((ordinal) << 2) | QUIC_STREAM_INITIATOR_CLIENT | QUIC_STREAM_DIR_BIDI) -#define S_BIDI_ID(ordinal) \ - (((ordinal) << 2) | QUIC_STREAM_INITIATOR_SERVER | QUIC_STREAM_DIR_BIDI) -#define C_UNI_ID(ordinal) \ - (((ordinal) << 2) | QUIC_STREAM_INITIATOR_CLIENT | QUIC_STREAM_DIR_UNI) -#define S_UNI_ID(ordinal) \ - (((ordinal) << 2) | QUIC_STREAM_INITIATOR_SERVER | QUIC_STREAM_DIR_UNI) - -#define ANY_ID UINT64_MAX - -#define OP_END \ - { OPK_END } -#define OP_CHECK(func, arg2) \ - { OPK_CHECK, NULL, 0, (func), NULL, (arg2) } -#define OP_C_SET_ALPN(alpn) \ - { OPK_C_SET_ALPN, (alpn), 0, NULL, NULL } -#define OP_C_CONNECT_WAIT() \ - { OPK_C_CONNECT_WAIT, NULL, 0, NULL, NULL } -#define OP_C_CONNECT_WAIT_OR_FAIL() \ - { OPK_C_CONNECT_WAIT, NULL, 1, NULL, NULL } -#define OP_C_WRITE(stream_name, buf, buf_len) \ - { OPK_C_WRITE, (buf), (buf_len), NULL, #stream_name } -#define OP_S_WRITE(stream_name, buf, buf_len) \ - { OPK_S_WRITE, (buf), (buf_len), NULL, #stream_name } -#define OP_C_READ_EXPECT(stream_name, buf, buf_len) \ - { OPK_C_READ_EXPECT, (buf), (buf_len), NULL, #stream_name } -#define OP_S_READ_EXPECT(stream_name, buf, buf_len) \ - { OPK_S_READ_EXPECT, (buf), (buf_len), NULL, #stream_name } -#define OP_C_EXPECT_FIN(stream_name) \ - { OPK_C_EXPECT_FIN, NULL, 0, NULL, #stream_name } -#define OP_S_EXPECT_FIN(stream_name) \ - { OPK_S_EXPECT_FIN, NULL, 0, NULL, #stream_name } -#define OP_C_CONCLUDE(stream_name) \ - { OPK_C_CONCLUDE, NULL, 0, NULL, #stream_name } -#define OP_S_CONCLUDE(stream_name) \ - { OPK_S_CONCLUDE, NULL, 0, NULL, #stream_name } -#define OP_C_NEW_STREAM_BIDI(stream_name, expect_id) \ - { OPK_C_NEW_STREAM, NULL, 0, NULL, #stream_name, (expect_id) } -#define OP_C_NEW_STREAM_BIDI_EX(stream_name, expect_id, flags) \ - { OPK_C_NEW_STREAM, NULL, (flags), NULL, #stream_name, (expect_id) } -#define OP_C_NEW_STREAM_UNI(stream_name, expect_id) \ - { OPK_C_NEW_STREAM, NULL, SSL_STREAM_FLAG_UNI, \ - NULL, #stream_name, (expect_id) } -#define OP_C_NEW_STREAM_UNI_EX(stream_name, expect_id, flags) \ - { OPK_C_NEW_STREAM, NULL, (flags) | SSL_STREAM_FLAG_UNI, \ - NULL, #stream_name, (expect_id) } -#define OP_S_NEW_STREAM_BIDI(stream_name, expect_id) \ - { OPK_S_NEW_STREAM, NULL, 0, NULL, #stream_name, (expect_id) } -#define OP_S_NEW_STREAM_UNI(stream_name, expect_id) \ - { OPK_S_NEW_STREAM, NULL, 1, NULL, #stream_name, (expect_id) } -#define OP_C_ACCEPT_STREAM_WAIT(stream_name) \ - { OPK_C_ACCEPT_STREAM_WAIT, NULL, 0, NULL, #stream_name } -#define OP_C_ACCEPT_STREAM_NONE() \ - { OPK_C_ACCEPT_STREAM_NONE, NULL, 0, NULL, NULL } -#define OP_C_FREE_STREAM(stream_name) \ - { OPK_C_FREE_STREAM, NULL, 0, NULL, #stream_name } -#define OP_C_SET_DEFAULT_STREAM_MODE(mode) \ - { OPK_C_SET_DEFAULT_STREAM_MODE, NULL, (mode), NULL, NULL } -#define OP_C_SET_INCOMING_STREAM_POLICY(policy) \ - { OPK_C_SET_INCOMING_STREAM_POLICY, NULL, (policy), NULL, NULL } -#define OP_C_SHUTDOWN(reason, flags) \ - { OPK_C_SHUTDOWN, (reason), (flags), NULL, NULL } -#define OP_C_SHUTDOWN_WAIT(reason, flags) \ - { OPK_C_SHUTDOWN_WAIT, (reason), (flags), NULL, NULL } -#define OP_C_EXPECT_CONN_CLOSE_INFO(ec, app, remote) \ - { OPK_C_EXPECT_CONN_CLOSE_INFO, NULL, \ - ((app) ? EXPECT_CONN_CLOSE_APP : 0) | ((remote) ? EXPECT_CONN_CLOSE_REMOTE : 0), \ - NULL, NULL, (ec) } -#define OP_S_EXPECT_CONN_CLOSE_INFO(ec, app, remote) \ - { OPK_S_EXPECT_CONN_CLOSE_INFO, NULL, \ - ((app) ? EXPECT_CONN_CLOSE_APP : 0) | ((remote) ? EXPECT_CONN_CLOSE_REMOTE : 0), \ - NULL, NULL, (ec) } -#define OP_S_BIND_STREAM_ID(stream_name, stream_id) \ - { OPK_S_BIND_STREAM_ID, NULL, 0, NULL, #stream_name, (stream_id) } -#define OP_C_WAIT_FOR_DATA(stream_name) \ - { OPK_C_WAIT_FOR_DATA, NULL, 0, NULL, #stream_name } -#define OP_C_WRITE_FAIL(stream_name) \ - { OPK_C_WRITE_FAIL, NULL, 0, NULL, #stream_name } -#define OP_S_WRITE_FAIL(stream_name) \ - { OPK_S_WRITE_FAIL, NULL, 0, NULL, #stream_name } -#define OP_C_READ_FAIL(stream_name) \ - { OPK_C_READ_FAIL, NULL, 0, NULL, #stream_name } -#define OP_S_READ_FAIL(stream_name, allow_zero_len) \ - { OPK_S_READ_FAIL, NULL, (allow_zero_len), NULL, #stream_name } -#define OP_C_STREAM_RESET(stream_name, aec) \ - { OPK_C_STREAM_RESET, NULL, 0, NULL, #stream_name, (aec) } -#define OP_C_STREAM_RESET_FAIL(stream_name, aec) \ - { OPK_C_STREAM_RESET_FAIL, NULL, 0, NULL, #stream_name, (aec) } -#define OP_S_ACCEPT_STREAM_WAIT(stream_name) \ - { OPK_S_ACCEPT_STREAM_WAIT, NULL, 0, NULL, #stream_name } -#define OP_NEW_THREAD(num_threads, script) \ - { OPK_NEW_THREAD, (script), (num_threads), NULL, NULL, 0 } -#define OP_BEGIN_REPEAT(n) \ - { OPK_BEGIN_REPEAT, NULL, (n) } -#define OP_END_REPEAT() \ - { OPK_END_REPEAT } -#define OP_S_UNBIND_STREAM_ID(stream_name) \ - { OPK_S_UNBIND_STREAM_ID, NULL, 0, NULL, #stream_name } -#define OP_C_READ_FAIL_WAIT(stream_name) \ - { OPK_C_READ_FAIL_WAIT, NULL, 0, NULL, #stream_name } -#define OP_C_CLOSE_SOCKET() \ - { OPK_C_CLOSE_SOCKET } -#define OP_C_EXPECT_SSL_ERR(stream_name, err) \ - { OPK_C_EXPECT_SSL_ERR, NULL, (err), NULL, #stream_name } -#define OP_EXPECT_ERR_REASON(err) \ - { OPK_EXPECT_ERR_REASON, NULL, (err) } -#define OP_EXPECT_ERR_LIB(lib) \ - { OPK_EXPECT_ERR_LIB, NULL, (lib) } -#define OP_SLEEP(ms) \ - { OPK_SLEEP, NULL, 0, NULL, NULL, (ms) } -#define OP_S_SET_INJECT_PLAIN(f) \ - { OPK_S_SET_INJECT_PLAIN, NULL, 0, NULL, NULL, 0, (f) } -#define OP_SET_INJECT_WORD(w0, w1) \ - { OPK_SET_INJECT_WORD, NULL, (w0), NULL, NULL, (w1), NULL } -#define OP_C_INHIBIT_TICK(inhibit) \ - { OPK_C_INHIBIT_TICK, NULL, (inhibit), NULL, NULL, 0, NULL } -#define OP_C_SET_WRITE_BUF_SIZE(stream_name, size) \ - { OPK_C_SET_WRITE_BUF_SIZE, NULL, (size), NULL, #stream_name } -#define OP_S_SET_INJECT_HANDSHAKE(f) \ - { OPK_S_SET_INJECT_HANDSHAKE, NULL, 0, NULL, NULL, 0, NULL, (f) } -#define OP_S_NEW_TICKET() \ - { OPK_S_NEW_TICKET } -#define OP_C_SKIP_IF_UNBOUND(stream_name, n) \ - { OPK_C_SKIP_IF_UNBOUND, NULL, (n), NULL, #stream_name } -#define OP_S_SET_INJECT_DATAGRAM(f) \ - { OPK_S_SET_INJECT_DATAGRAM, NULL, 0, NULL, NULL, 0, NULL, NULL, (f) } -#define OP_S_SHUTDOWN(error_code) \ - { OPK_S_SHUTDOWN, NULL, (error_code) } -#define OP_POP_ERR() \ - { OPK_POP_ERR } -#define OP_C_WRITE_EX2(stream_name, buf, buf_len, flags) \ - { OPK_C_WRITE_EX2, (buf), (buf_len), NULL, #stream_name, (flags) } -#define OP_CHECK2(func, arg1, arg2) \ - { OPK_CHECK, NULL, (arg1), (func), NULL, (arg2) } -#define OP_SKIP_IF_BLOCKING(n) \ - { OPK_SKIP_IF_BLOCKING, NULL, (n), NULL, 0 } - -static OSSL_TIME get_time(void *arg) -{ - struct helper *h = arg; - OSSL_TIME t; - - if (!TEST_true(CRYPTO_THREAD_read_lock(h->time_lock))) - return ossl_time_zero(); - - t = ossl_time_add(ossl_time_now(), h->time_slip); - - CRYPTO_THREAD_unlock(h->time_lock); - return t; -} - -static QUIC_TSERVER *s_lock(struct helper *h, struct helper_local *hl); -static void s_unlock(struct helper *h, struct helper_local *hl); - -#define ACQUIRE_S() s_lock(h, hl) -#define ACQUIRE_S_NOHL() s_lock(h, NULL) - -static unsigned long stream_info_hash(const STREAM_INFO *info) -{ - return OPENSSL_LH_strhash(info->name); -} - -static int stream_info_cmp(const STREAM_INFO *a, const STREAM_INFO *b) -{ - return strcmp(a->name, b->name); -} - -static void cleanup_stream(STREAM_INFO *info) -{ - SSL_free(info->c_stream); - OPENSSL_free(info); -} - -static void helper_cleanup_streams(LHASH_OF(STREAM_INFO) **lh) -{ - if (*lh == NULL) - return; - - lh_STREAM_INFO_doall(*lh, cleanup_stream); - lh_STREAM_INFO_free(*lh); - *lh = NULL; -} - -#if defined(OPENSSL_THREADS) -static CRYPTO_THREAD_RETVAL run_script_child_thread(void *arg); - -static int join_threads(struct child_thread_args *threads, size_t num_threads) -{ - int ok = 1; - size_t i; - CRYPTO_THREAD_RETVAL rv; - - for (i = 0; i < num_threads; ++i) { - if (threads[i].t != NULL) { - ossl_crypto_thread_native_join(threads[i].t, &rv); - - if (!threads[i].testresult) - /* Do not log failure here, worker will do it. */ - ok = 0; - - ossl_crypto_thread_native_clean(threads[i].t); - threads[i].t = NULL; - } - - ossl_crypto_mutex_free(&threads[i].m); - } - - return ok; -} - -static int join_server_thread(struct helper *h) -{ - CRYPTO_THREAD_RETVAL rv; - - if (h->server_thread.t == NULL) - return 1; - - ossl_crypto_mutex_lock(h->server_thread.m); - h->server_thread.stop = 1; - ossl_crypto_condvar_signal(h->server_thread.c); - ossl_crypto_mutex_unlock(h->server_thread.m); - - ossl_crypto_thread_native_join(h->server_thread.t, &rv); - ossl_crypto_thread_native_clean(h->server_thread.t); - h->server_thread.t = NULL; - return 1; -} - -/* Ensure the server-state lock is currently held. Idempotent. */ -static int *s_checked_out_p(struct helper *h, int thread_idx) -{ - return (thread_idx < 0) ? &h->s_checked_out - : &h->threads[thread_idx].s_checked_out; -} - -static QUIC_TSERVER *s_lock(struct helper *h, struct helper_local *hl) -{ - int *p_checked_out = s_checked_out_p(h, hl == NULL ? -1 : hl->thread_idx); - - if (h->server_thread.m == NULL || *p_checked_out) - return h->s; - - ossl_crypto_mutex_lock(h->server_thread.m); - h->s = h->s_priv; - *p_checked_out = 1; - return h->s; -} - -/* Ensure the server-state lock is currently not held. Idempotent. */ -static void s_unlock(struct helper *h, struct helper_local *hl) -{ - int *p_checked_out = s_checked_out_p(h, hl->thread_idx); - - if (h->server_thread.m == NULL || !*p_checked_out) - return; - - *p_checked_out = 0; - h->s = NULL; - ossl_crypto_mutex_unlock(h->server_thread.m); -} - -static unsigned int server_helper_thread(void *arg) -{ - struct helper *h = arg; - - ossl_crypto_mutex_lock(h->server_thread.m); - - for (;;) { - int ready, stop; - - ready = h->server_thread.ready; - stop = h->server_thread.stop; - - if (stop) - break; - - if (!ready) { - ossl_crypto_condvar_wait(h->server_thread.c, h->server_thread.m); - continue; - } - - ossl_quic_tserver_tick(h->s_priv); - ossl_crypto_mutex_unlock(h->server_thread.m); - /* - * Give the main thread an opportunity to get the mutex, which is - * sometimes necessary in some script operations. - */ - OSSL_sleep(1); - ossl_crypto_mutex_lock(h->server_thread.m); - } - - ossl_crypto_mutex_unlock(h->server_thread.m); - return 1; -} - -#else - -static QUIC_TSERVER *s_lock(struct helper *h, struct helper_local *hl) -{ - return h->s; -} - -static void s_unlock(struct helper *h, struct helper_local *hl) -{ -} - -#endif - -static void helper_cleanup(struct helper *h) -{ -#if defined(OPENSSL_THREADS) - join_threads(h->threads, h->num_threads); - join_server_thread(h); - OPENSSL_free(h->threads); - h->threads = NULL; - h->num_threads = 0; -#endif - - if (h->free_order == 0) { - /* order 0: streams, then conn */ - helper_cleanup_streams(&h->c_streams); - - SSL_free(h->c_conn); - h->c_conn = NULL; - } else { - /* order 1: conn, then streams */ - SSL_free(h->c_conn); - h->c_conn = NULL; - - helper_cleanup_streams(&h->c_streams); - } - - helper_cleanup_streams(&h->s_streams); - ossl_quic_tserver_free(h->s_priv); - h->s_priv = h->s = NULL; - - BIO_free(h->s_net_bio_own); - h->s_net_bio_own = NULL; - - BIO_free(h->c_net_bio_own); - h->c_net_bio_own = NULL; - - BIO_free(h->s_qtf_wbio_own); - h->s_qtf_wbio_own = NULL; - - qtest_fault_free(h->qtf); - h->qtf = NULL; - - if (h->s_fd >= 0) { - BIO_closesocket(h->s_fd); - h->s_fd = -1; - } - - if (h->c_fd >= 0) { - BIO_closesocket(h->c_fd); - h->c_fd = -1; - } - - BIO_ADDR_free(h->s_net_bio_addr); - h->s_net_bio_addr = NULL; - BIO_ADDR_free(h->s_net_bio_orig_addr); - h->s_net_bio_orig_addr = NULL; - - SSL_CTX_free(h->c_ctx); - h->c_ctx = NULL; - - CRYPTO_THREAD_lock_free(h->time_lock); - h->time_lock = NULL; - -#if defined(OPENSSL_THREADS) - ossl_crypto_mutex_free(&h->misc_m); - ossl_crypto_condvar_free(&h->misc_cv); - ossl_crypto_mutex_free(&h->server_thread.m); - ossl_crypto_condvar_free(&h->server_thread.c); -#endif -} - -static int helper_init(struct helper *h, const char *script_name, - int free_order, int blocking, - int need_injector) -{ - struct in_addr ina = { 0 }; - QUIC_TSERVER_ARGS s_args = { 0 }; - union BIO_sock_info_u info; - char title[128]; - QTEST_DATA *bdata = NULL; - - memset(h, 0, sizeof(*h)); - h->c_fd = -1; - h->s_fd = -1; - h->free_order = free_order; - h->blocking = blocking; - h->need_injector = need_injector; - h->time_slip = ossl_time_zero(); - - bdata = OPENSSL_zalloc(sizeof(QTEST_DATA)); - if (bdata == NULL) - goto err; - - if (!TEST_ptr(h->time_lock = CRYPTO_THREAD_lock_new())) - goto err; - - if (!TEST_ptr(h->s_streams = lh_STREAM_INFO_new(stream_info_hash, - stream_info_cmp))) - goto err; - - if (!TEST_ptr(h->c_streams = lh_STREAM_INFO_new(stream_info_hash, - stream_info_cmp))) - goto err; - - ina.s_addr = htonl(0x7f000001UL); - - h->s_fd = BIO_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0); - if (!TEST_int_ge(h->s_fd, 0)) - goto err; - - if (!TEST_true(BIO_socket_nbio(h->s_fd, 1))) - goto err; - - if (!TEST_ptr(h->s_net_bio_orig_addr = BIO_ADDR_new()) - || !TEST_ptr(h->s_net_bio_addr = BIO_ADDR_new())) - goto err; - - if (!TEST_true(BIO_ADDR_rawmake(h->s_net_bio_orig_addr, AF_INET, - &ina, sizeof(ina), 0))) - goto err; - - if (!TEST_true(BIO_bind(h->s_fd, h->s_net_bio_orig_addr, 0))) - goto err; - - info.addr = h->s_net_bio_addr; - if (!TEST_true(BIO_sock_info(h->s_fd, BIO_SOCK_INFO_ADDRESS, &info))) - goto err; - - if (!TEST_int_gt(BIO_ADDR_rawport(h->s_net_bio_addr), 0)) - goto err; - - if (!TEST_ptr(h->s_net_bio = h->s_net_bio_own = BIO_new_dgram(h->s_fd, 0))) - goto err; - - if (!BIO_up_ref(h->s_net_bio)) - goto err; - - if (need_injector) { - h->s_qtf_wbio = h->s_qtf_wbio_own = BIO_new(qtest_get_bio_method()); - if (!TEST_ptr(h->s_qtf_wbio)) - goto err; - - if (!TEST_ptr(BIO_push(h->s_qtf_wbio, h->s_net_bio))) - goto err; - - s_args.net_wbio = h->s_qtf_wbio; - } else { - s_args.net_wbio = h->s_net_bio; - } - - s_args.net_rbio = h->s_net_bio; - s_args.alpn = NULL; - s_args.now_cb = get_time; - s_args.now_cb_arg = h; - s_args.ctx = NULL; - - if (!TEST_ptr(h->s_priv = ossl_quic_tserver_new(&s_args, certfile, keyfile))) - goto err; - - if (!blocking) - h->s = h->s_priv; - - if (need_injector) { - h->qtf = qtest_create_injector(h->s_priv); - if (!TEST_ptr(h->qtf)) - goto err; - bdata->fault = h->qtf; - BIO_set_data(h->s_qtf_wbio, bdata); - bdata = NULL; - } - - h->s_net_bio_own = NULL; - h->s_qtf_wbio_own = NULL; - - h->c_fd = BIO_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0); - if (!TEST_int_ge(h->c_fd, 0)) - goto err; - - if (!TEST_true(BIO_socket_nbio(h->c_fd, 1))) - goto err; - - if (!TEST_ptr(h->c_net_bio = h->c_net_bio_own = BIO_new_dgram(h->c_fd, 0))) - goto err; - - if (!TEST_true(BIO_dgram_set_peer(h->c_net_bio, h->s_net_bio_addr))) - goto err; - - if (!TEST_ptr(h->c_ctx = SSL_CTX_new(OSSL_QUIC_client_method()))) - goto err; - - /* Set title for qlog purposes. */ - snprintf(title, sizeof(title), "quic_multistream_test: %s", script_name); - if (!TEST_true(ossl_quic_set_diag_title(h->c_ctx, title))) - goto err; - - if (!TEST_ptr(h->c_conn = SSL_new(h->c_ctx))) - goto err; - - /* Use custom time function for virtual time skip. */ - if (!TEST_true(ossl_quic_set_override_now_cb(h->c_conn, get_time, h))) - goto err; - - /* Takes ownership of our reference to the BIO. */ - SSL_set0_rbio(h->c_conn, h->c_net_bio); - h->c_net_bio_own = NULL; - - if (!TEST_true(BIO_up_ref(h->c_net_bio))) - goto err; - - SSL_set0_wbio(h->c_conn, h->c_net_bio); - - if (!TEST_true(SSL_set_blocking_mode(h->c_conn, h->blocking))) - goto err; - -#if defined(OPENSSL_THREADS) - if (!TEST_ptr(h->misc_m = ossl_crypto_mutex_new())) - goto err; - if (!TEST_ptr(h->misc_cv = ossl_crypto_condvar_new())) - goto err; -#endif - - if (h->blocking) { -#if defined(OPENSSL_THREADS) - if (!TEST_ptr(h->server_thread.m = ossl_crypto_mutex_new())) - goto err; - - if (!TEST_ptr(h->server_thread.c = ossl_crypto_condvar_new())) - goto err; - - h->server_thread.t - = ossl_crypto_thread_native_start(server_helper_thread, h, 1); - if (!TEST_ptr(h->server_thread.t)) - goto err; -#else - TEST_error("cannot support blocking mode without threads"); - goto err; -#endif - } - - h->start_time = ossl_time_now(); - h->init = 1; - return 1; - -err: - OPENSSL_free(bdata); - helper_cleanup(h); - return 0; -} - -static int helper_local_init(struct helper_local *hl, struct helper *h, - int thread_idx) -{ - hl->h = h; - hl->c_streams = NULL; - hl->thread_idx = thread_idx; - hl->explicit_event_handling = 0; - - if (!TEST_ptr(h)) - return 0; - - if (thread_idx < 0) { - hl->c_streams = h->c_streams; - } else { - if (!TEST_ptr(hl->c_streams = lh_STREAM_INFO_new(stream_info_hash, - stream_info_cmp))) - return 0; - } - - return 1; -} - -static void helper_local_cleanup(struct helper_local *hl) -{ - if (hl->h == NULL) - return; - - if (hl->thread_idx >= 0) - helper_cleanup_streams(&hl->c_streams); - - hl->h = NULL; -} - -static STREAM_INFO *get_stream_info(LHASH_OF(STREAM_INFO) *lh, - const char *stream_name) -{ - STREAM_INFO key, *info; - - if (!TEST_ptr(stream_name)) - return NULL; - - if (!strcmp(stream_name, "DEFAULT")) - return NULL; - - key.name = stream_name; - info = lh_STREAM_INFO_retrieve(lh, &key); - if (info == NULL) { - info = OPENSSL_zalloc(sizeof(*info)); - if (info == NULL) - return NULL; - - info->name = stream_name; - info->s_stream_id = UINT64_MAX; - lh_STREAM_INFO_insert(lh, info); - } - - return info; -} - -static int helper_local_set_c_stream(struct helper_local *hl, - const char *stream_name, - SSL *c_stream) -{ - STREAM_INFO *info = get_stream_info(hl->c_streams, stream_name); - - if (info == NULL) - return 0; - - info->c_stream = c_stream; - info->s_stream_id = UINT64_MAX; - return 1; -} - -static SSL *helper_local_get_c_stream(struct helper_local *hl, - const char *stream_name) -{ - STREAM_INFO *info; - - if (!strcmp(stream_name, "DEFAULT")) - return hl->h->c_conn; - - info = get_stream_info(hl->c_streams, stream_name); - if (info == NULL) - return NULL; - - return info->c_stream; -} - -static int -helper_set_s_stream(struct helper *h, const char *stream_name, - uint64_t s_stream_id) -{ - STREAM_INFO *info; - - if (!strcmp(stream_name, "DEFAULT")) - return 0; - - info = get_stream_info(h->s_streams, stream_name); - if (info == NULL) - return 0; - - info->c_stream = NULL; - info->s_stream_id = s_stream_id; - return 1; -} - -static uint64_t helper_get_s_stream(struct helper *h, const char *stream_name) -{ - STREAM_INFO *info; - - if (!strcmp(stream_name, "DEFAULT")) - return UINT64_MAX; - - info = get_stream_info(h->s_streams, stream_name); - if (info == NULL) - return UINT64_MAX; - - return info->s_stream_id; -} - -static int helper_packet_plain_listener(QTEST_FAULT *qtf, QUIC_PKT_HDR *hdr, - unsigned char *buf, size_t buf_len, - void *arg) -{ - struct helper *h = arg; - - return h->qtf_packet_plain_cb(h, hdr, buf, buf_len); -} - -static int helper_handshake_listener(QTEST_FAULT *fault, - unsigned char *buf, size_t buf_len, - void *arg) -{ - struct helper *h = arg; - - return h->qtf_handshake_cb(h, buf, buf_len); -} - -static int helper_datagram_listener(QTEST_FAULT *fault, - BIO_MSG *msg, size_t stride, - void *arg) -{ - struct helper *h = arg; - - return h->qtf_datagram_cb(h, msg, stride); -} - -static int is_want(SSL *s, int ret) -{ - int ec = SSL_get_error(s, ret); - - return ec == SSL_ERROR_WANT_READ || ec == SSL_ERROR_WANT_WRITE; -} - -static int check_consistent_want(SSL *s, int ret) -{ - int ec = SSL_get_error(s, ret); - int w = SSL_want(s); - - int ok = TEST_true( - (ec == SSL_ERROR_NONE && w == SSL_NOTHING) - || (ec == SSL_ERROR_ZERO_RETURN && w == SSL_NOTHING) - || (ec == SSL_ERROR_SSL && w == SSL_NOTHING) - || (ec == SSL_ERROR_SYSCALL && w == SSL_NOTHING) - || (ec == SSL_ERROR_WANT_READ && w == SSL_READING) - || (ec == SSL_ERROR_WANT_WRITE && w == SSL_WRITING) - || (ec == SSL_ERROR_WANT_CLIENT_HELLO_CB && w == SSL_CLIENT_HELLO_CB) - || (ec == SSL_ERROR_WANT_X509_LOOKUP && w == SSL_X509_LOOKUP) - || (ec == SSL_ERROR_WANT_RETRY_VERIFY && w == SSL_RETRY_VERIFY)); - - if (!ok) - TEST_error("got error=%d, want=%d", ec, w); - - return ok; -} - -static int run_script_worker(struct helper *h, const struct script_op *script, - const char *script_name, - int thread_idx) -{ - int testresult = 0; - unsigned char *tmp_buf = NULL; - int connect_started = 0; - size_t offset = 0; - size_t op_idx = 0; - const struct script_op *op = NULL; - int no_advance = 0, first = 1; -#if defined(OPENSSL_THREADS) - int end_wait_warning = 0; -#endif - OSSL_TIME op_start_time = ossl_time_zero(), op_deadline = ossl_time_zero(); - struct helper_local hl_, *hl = &hl_; -#define REPEAT_SLOTS 8 - size_t repeat_stack_idx[REPEAT_SLOTS], repeat_stack_done[REPEAT_SLOTS]; - size_t repeat_stack_limit[REPEAT_SLOTS]; - size_t repeat_stack_len = 0; - - if (!TEST_true(helper_local_init(hl, h, thread_idx))) - goto out; - -#define COMMON_SPIN_AGAIN() \ - { \ - no_advance = 1; \ - continue; \ - } -#define S_SPIN_AGAIN() \ - { \ - s_lock(h, hl); \ - ossl_quic_tserver_tick(h->s); \ - COMMON_SPIN_AGAIN(); \ - } -#define C_SPIN_AGAIN() \ - { \ - if (h->blocking) { \ - TEST_error("spin again in blocking mode"); \ - goto out; \ - } \ - COMMON_SPIN_AGAIN(); \ - } - - for (;;) { - SSL *c_tgt = h->c_conn; - uint64_t s_stream_id = UINT64_MAX; - - s_unlock(h, hl); - - if (no_advance) { - no_advance = 0; - } else { - if (!first) - ++op_idx; - - first = 0; - offset = 0; - op_start_time = ossl_time_now(); - op_deadline = ossl_time_add(op_start_time, ossl_ms2time(180000)); - } - - if (!TEST_int_le(ossl_time_compare(ossl_time_now(), op_deadline), 0)) { - TEST_error("op %zu timed out on thread %d", op_idx + 1, thread_idx); - goto out; - } - - op = &script[op_idx]; - - if (op->stream_name != NULL) { - c_tgt = helper_local_get_c_stream(hl, op->stream_name); - if (thread_idx < 0) - s_stream_id = helper_get_s_stream(h, op->stream_name); - else - s_stream_id = UINT64_MAX; - } - - if (thread_idx < 0) { - if (!h->blocking) { - ossl_quic_tserver_tick(h->s); - } -#if defined(OPENSSL_THREADS) - else if (h->blocking && !h->server_thread.ready) { - ossl_crypto_mutex_lock(h->server_thread.m); - h->server_thread.ready = 1; - ossl_crypto_condvar_signal(h->server_thread.c); - ossl_crypto_mutex_unlock(h->server_thread.m); - } - if (h->blocking) - assert(h->s == NULL); -#endif - } - - if (!hl->explicit_event_handling - && (thread_idx >= 0 || connect_started)) - SSL_handle_events(h->c_conn); - - if (thread_idx >= 0) { - /* Only allow certain opcodes on child threads. */ - switch (op->op) { - case OPK_END: - case OPK_CHECK: - case OPK_C_ACCEPT_STREAM_WAIT: - case OPK_C_NEW_STREAM: - case OPK_C_READ_EXPECT: - case OPK_C_EXPECT_FIN: - case OPK_C_WRITE: - case OPK_C_WRITE_EX2: - case OPK_C_CONCLUDE: - case OPK_C_FREE_STREAM: - case OPK_BEGIN_REPEAT: - case OPK_END_REPEAT: - case OPK_C_READ_FAIL_WAIT: - case OPK_C_EXPECT_SSL_ERR: - case OPK_EXPECT_ERR_REASON: - case OPK_EXPECT_ERR_LIB: - case OPK_POP_ERR: - case OPK_SLEEP: - break; - - default: - TEST_error("opcode %lu not allowed on child thread", - (unsigned long)op->op); - goto out; - } - } - - switch (op->op) { - case OPK_END: - if (!TEST_size_t_eq(repeat_stack_len, 0)) - goto out; - -#if defined(OPENSSL_THREADS) - if (thread_idx < 0) { - int done; - size_t i; - - for (i = 0; i < h->num_threads; ++i) { - if (h->threads[i].m == NULL) - continue; - - ossl_crypto_mutex_lock(h->threads[i].m); - done = h->threads[i].done; - ossl_crypto_mutex_unlock(h->threads[i].m); - - if (!done) { - if (!end_wait_warning) { - TEST_info("still waiting for other threads to finish (%zu)", i); - end_wait_warning = 1; - } - - S_SPIN_AGAIN(); - } - } - } -#endif - - TEST_info("script \"%s\" finished on thread %d", script_name, thread_idx); - testresult = 1; - goto out; - - case OPK_BEGIN_REPEAT: - if (!TEST_size_t_lt(repeat_stack_len, OSSL_NELEM(repeat_stack_idx))) - goto out; - - if (!TEST_size_t_gt(op->arg1, 0)) - goto out; - - repeat_stack_idx[repeat_stack_len] = op_idx + 1; - repeat_stack_done[repeat_stack_len] = 0; - repeat_stack_limit[repeat_stack_len] = op->arg1; - ++repeat_stack_len; - break; - - case OPK_C_SKIP_IF_UNBOUND: - if (c_tgt != NULL) - break; - - op_idx += op->arg1; - break; - - case OPK_SKIP_IF_BLOCKING: - if (!h->blocking) - break; - - op_idx += op->arg1; - break; - - case OPK_END_REPEAT: - if (!TEST_size_t_gt(repeat_stack_len, 0)) - goto out; - - if (++repeat_stack_done[repeat_stack_len - 1] - == repeat_stack_limit[repeat_stack_len - 1]) { - --repeat_stack_len; - } else { - op_idx = repeat_stack_idx[repeat_stack_len - 1]; - no_advance = 1; - continue; - } - - break; - - case OPK_CHECK: { - int ok; - - hl->check_op = op; - ok = op->check_func(h, hl); - hl->check_op = NULL; - - if (thread_idx < 0 && h->check_spin_again) { - h->check_spin_again = 0; - S_SPIN_AGAIN(); - } - - if (!TEST_true(ok)) - goto out; - } break; - - case OPK_C_SET_ALPN: { - const char *alpn = op->arg0; - size_t alpn_len = strlen(alpn); - - if (!TEST_size_t_le(alpn_len, UINT8_MAX) - || !TEST_ptr(tmp_buf = (unsigned char *)OPENSSL_malloc(alpn_len + 1))) - goto out; - - memcpy(tmp_buf + 1, alpn, alpn_len); - tmp_buf[0] = (unsigned char)alpn_len; - - /* 0 is the success case for SSL_set_alpn_protos(). */ - if (!TEST_false(SSL_set_alpn_protos(h->c_conn, tmp_buf, - (unsigned int)(alpn_len + 1)))) - goto out; - - OPENSSL_free(tmp_buf); - tmp_buf = NULL; - } break; - - case OPK_C_CONNECT_WAIT: { - int ret; - - connect_started = 1; - - ret = SSL_connect(h->c_conn); - if (!check_consistent_want(c_tgt, ret)) - goto out; - if (ret != 1) { - if (!h->blocking && is_want(h->c_conn, ret)) - C_SPIN_AGAIN(); - - if (op->arg1 == 0 && !TEST_int_eq(ret, 1)) - goto out; - } - } break; - - case OPK_C_WRITE: { - size_t bytes_written = 0; - int r; - - if (!TEST_ptr(c_tgt)) - goto out; - - r = SSL_write_ex(c_tgt, op->arg0, op->arg1, &bytes_written); - if (!TEST_true(r) - || !check_consistent_want(c_tgt, r) - || !TEST_size_t_eq(bytes_written, op->arg1)) - goto out; - } break; - - case OPK_C_WRITE_EX2: { - size_t bytes_written = 0; - int r; - - if (!TEST_ptr(c_tgt)) - goto out; - - r = SSL_write_ex2(c_tgt, op->arg0, op->arg1, op->arg2, - &bytes_written); - if (!TEST_true(r) - || !check_consistent_want(c_tgt, r) - || !TEST_size_t_eq(bytes_written, op->arg1)) - goto out; - } break; - - case OPK_S_WRITE: { - size_t bytes_written = 0; - - if (!TEST_uint64_t_ne(s_stream_id, UINT64_MAX)) - goto out; - - if (!TEST_true(ossl_quic_tserver_write(ACQUIRE_S(), s_stream_id, - op->arg0, op->arg1, - &bytes_written)) - || !TEST_size_t_eq(bytes_written, op->arg1)) - goto out; - } break; - - case OPK_C_CONCLUDE: { - if (!TEST_true(SSL_stream_conclude(c_tgt, 0))) - goto out; - } break; - - case OPK_S_CONCLUDE: { - if (!TEST_uint64_t_ne(s_stream_id, UINT64_MAX)) - goto out; - - ossl_quic_tserver_conclude(ACQUIRE_S(), s_stream_id); - } break; - - case OPK_C_WAIT_FOR_DATA: { - char buf[1]; - size_t bytes_read = 0; - - if (!TEST_ptr(c_tgt)) - goto out; - - if (!SSL_peek_ex(c_tgt, buf, sizeof(buf), &bytes_read) - || bytes_read == 0) - C_SPIN_AGAIN(); - } break; - - case OPK_C_READ_EXPECT: { - size_t bytes_read = 0; - int r; - - if (op->arg1 > 0 && tmp_buf == NULL - && !TEST_ptr(tmp_buf = OPENSSL_malloc(op->arg1))) - goto out; - - r = SSL_read_ex(c_tgt, tmp_buf + offset, op->arg1 - offset, - &bytes_read); - if (!check_consistent_want(c_tgt, r)) - goto out; - - if (!r) - C_SPIN_AGAIN(); - - if (bytes_read + offset != op->arg1) { - offset += bytes_read; - C_SPIN_AGAIN(); - } - - if (op->arg1 > 0 - && !TEST_mem_eq(tmp_buf, op->arg1, op->arg0, op->arg1)) - goto out; - - OPENSSL_free(tmp_buf); - tmp_buf = NULL; - } break; - - case OPK_S_READ_EXPECT: { - size_t bytes_read = 0; - - if (!TEST_uint64_t_ne(s_stream_id, UINT64_MAX)) - goto out; - - if (op->arg1 > 0 && tmp_buf == NULL - && !TEST_ptr(tmp_buf = OPENSSL_malloc(op->arg1))) - goto out; - - if (!TEST_true(ossl_quic_tserver_read(ACQUIRE_S(), s_stream_id, - tmp_buf + offset, - op->arg1 - offset, - &bytes_read))) - goto out; - - if (bytes_read + offset != op->arg1) { - offset += bytes_read; - S_SPIN_AGAIN(); - } - - if (op->arg1 > 0 - && !TEST_mem_eq(tmp_buf, op->arg1, op->arg0, op->arg1)) - goto out; - - OPENSSL_free(tmp_buf); - tmp_buf = NULL; - } break; - - case OPK_C_EXPECT_FIN: { - char buf[1]; - size_t bytes_read = 0; - int r; - - r = SSL_read_ex(c_tgt, buf, sizeof(buf), &bytes_read); - if (!check_consistent_want(c_tgt, r) - || !TEST_false(r) - || !TEST_size_t_eq(bytes_read, 0)) - goto out; - - if (is_want(c_tgt, 0)) - C_SPIN_AGAIN(); - - if (!TEST_int_eq(SSL_get_error(c_tgt, 0), - SSL_ERROR_ZERO_RETURN)) - goto out; - - if (!TEST_int_eq(SSL_want(c_tgt), SSL_NOTHING)) - goto out; - } break; - - case OPK_S_EXPECT_FIN: { - if (!TEST_uint64_t_ne(s_stream_id, UINT64_MAX)) - goto out; - - if (!ossl_quic_tserver_has_read_ended(ACQUIRE_S(), s_stream_id)) - S_SPIN_AGAIN(); - } break; - - case OPK_C_NEW_STREAM: { - SSL *c_stream; - uint64_t flags = op->arg1; - int allow_fail = ((flags & ALLOW_FAIL) != 0); - - flags &= ~(uint64_t)ALLOW_FAIL; - - if (!TEST_ptr_null(c_tgt)) - goto out; /* don't overwrite existing stream with same name */ - - if (!TEST_ptr(op->stream_name)) - goto out; - - c_stream = SSL_new_stream(h->c_conn, flags); - if (!allow_fail && !TEST_ptr(c_stream)) - goto out; - - if (allow_fail && c_stream == NULL) { - if (!TEST_size_t_eq(ERR_GET_REASON(ERR_peek_last_error()), - SSL_R_STREAM_COUNT_LIMITED)) - goto out; - - ++h->fail_count; - break; - } - - if (op->arg2 != UINT64_MAX - && !TEST_uint64_t_eq(SSL_get_stream_id(c_stream), - op->arg2)) - goto out; - - if (!TEST_true(helper_local_set_c_stream(hl, op->stream_name, c_stream))) - goto out; - } break; - - case OPK_S_NEW_STREAM: { - uint64_t stream_id = UINT64_MAX; - - if (!TEST_uint64_t_eq(s_stream_id, UINT64_MAX)) - goto out; /* don't overwrite existing stream with same name */ - - if (!TEST_ptr(op->stream_name)) - goto out; - - if (!TEST_true(ossl_quic_tserver_stream_new(ACQUIRE_S(), - op->arg1 > 0, - &stream_id))) - goto out; - - if (op->arg2 != UINT64_MAX - && !TEST_uint64_t_eq(stream_id, op->arg2)) - goto out; - - if (!TEST_true(helper_set_s_stream(h, op->stream_name, - stream_id))) - goto out; - } break; - - case OPK_C_ACCEPT_STREAM_WAIT: { - SSL *c_stream; - - if (!TEST_ptr_null(c_tgt)) - goto out; /* don't overwrite existing stream with same name */ - - if (!TEST_ptr(op->stream_name)) - goto out; - - if ((c_stream = SSL_accept_stream(h->c_conn, 0)) == NULL) - C_SPIN_AGAIN(); - - if (!TEST_true(helper_local_set_c_stream(hl, op->stream_name, - c_stream))) - goto out; - } break; - - case OPK_S_ACCEPT_STREAM_WAIT: { - uint64_t new_stream_id; - - if (!TEST_uint64_t_eq(s_stream_id, UINT64_MAX)) - goto out; - - if (!TEST_ptr(op->stream_name)) - goto out; - - new_stream_id = ossl_quic_tserver_pop_incoming_stream(ACQUIRE_S()); - if (new_stream_id == UINT64_MAX) - S_SPIN_AGAIN(); - - if (!TEST_true(helper_set_s_stream(h, op->stream_name, new_stream_id))) - goto out; - } break; - - case OPK_C_ACCEPT_STREAM_NONE: { - SSL *c_stream; - - if (!TEST_ptr_null(c_stream = SSL_accept_stream(h->c_conn, - SSL_ACCEPT_STREAM_NO_BLOCK))) { - SSL_free(c_stream); - goto out; - } - } break; - - case OPK_C_FREE_STREAM: { - if (!TEST_ptr(c_tgt) - || !TEST_true(!SSL_is_connection(c_tgt))) - goto out; - - if (!TEST_ptr(op->stream_name)) - goto out; - - if (!TEST_true(helper_local_set_c_stream(hl, op->stream_name, NULL))) - goto out; - - SSL_free(c_tgt); - c_tgt = NULL; - } break; - - case OPK_C_SET_DEFAULT_STREAM_MODE: { - if (!TEST_ptr(c_tgt)) - goto out; - - if (!TEST_true(SSL_set_default_stream_mode(c_tgt, (uint32_t)op->arg1))) - goto out; - } break; - - case OPK_C_SET_INCOMING_STREAM_POLICY: { - if (!TEST_ptr(c_tgt)) - goto out; - - if (!TEST_true(SSL_set_incoming_stream_policy(c_tgt, - (int)op->arg1, 0))) - goto out; - } break; - - case OPK_C_SHUTDOWN: { - int ret; - QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); - SSL_SHUTDOWN_EX_ARGS args = { 0 }; - - ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch), 0); - - if (!TEST_ptr(c_tgt)) - goto out; - - args.quic_reason = (const char *)op->arg0; - - ret = SSL_shutdown_ex(c_tgt, op->arg1, &args, sizeof(args)); - if (!TEST_int_ge(ret, 0)) - goto out; - } break; - - case OPK_C_SHUTDOWN_WAIT: { - int ret; - QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); - SSL_SHUTDOWN_EX_ARGS args = { 0 }; - - ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch), 0); - - if (!TEST_ptr(c_tgt)) - goto out; - - args.quic_reason = (const char *)op->arg0; - - ret = SSL_shutdown_ex(c_tgt, op->arg1, &args, sizeof(args)); - if (!TEST_int_ge(ret, 0)) - goto out; - - if (ret == 0) - C_SPIN_AGAIN(); - } break; - - case OPK_S_SHUTDOWN: { - ossl_quic_tserver_shutdown(ACQUIRE_S(), op->arg1); - } break; - - case OPK_C_EXPECT_CONN_CLOSE_INFO: { - SSL_CONN_CLOSE_INFO cc_info = { 0 }; - int expect_app = (op->arg1 & EXPECT_CONN_CLOSE_APP) != 0; - int expect_remote = (op->arg1 & EXPECT_CONN_CLOSE_REMOTE) != 0; - uint64_t error_code = op->arg2; - - if (!TEST_ptr(c_tgt)) - goto out; - - if (h->blocking - && !TEST_true(SSL_shutdown_ex(c_tgt, - SSL_SHUTDOWN_FLAG_WAIT_PEER, - NULL, 0))) - goto out; - - if (!SSL_get_conn_close_info(c_tgt, &cc_info, sizeof(cc_info))) - C_SPIN_AGAIN(); - - if (!TEST_int_eq(expect_app, - (cc_info.flags - & SSL_CONN_CLOSE_FLAG_TRANSPORT) - == 0) - || !TEST_int_eq(expect_remote, - (cc_info.flags - & SSL_CONN_CLOSE_FLAG_LOCAL) - == 0) - || !TEST_uint64_t_eq(error_code, cc_info.error_code)) { - TEST_info("Connection close reason: %s", cc_info.reason); - goto out; - } - } break; - - case OPK_S_EXPECT_CONN_CLOSE_INFO: { - const QUIC_TERMINATE_CAUSE *tc; - int expect_app = (op->arg1 & EXPECT_CONN_CLOSE_APP) != 0; - int expect_remote = (op->arg1 & EXPECT_CONN_CLOSE_REMOTE) != 0; - uint64_t error_code = op->arg2; - - if (!ossl_quic_tserver_is_term_any(ACQUIRE_S())) { - ossl_quic_tserver_ping(ACQUIRE_S()); - S_SPIN_AGAIN(); - } - - if (!TEST_ptr(tc = ossl_quic_tserver_get_terminate_cause(ACQUIRE_S()))) - goto out; - - if (!TEST_uint64_t_eq(error_code, tc->error_code) - || !TEST_int_eq(expect_app, tc->app) - || !TEST_int_eq(expect_remote, tc->remote)) - goto out; - } break; - - case OPK_S_BIND_STREAM_ID: { - if (!TEST_uint64_t_eq(s_stream_id, UINT64_MAX)) - goto out; - - if (!TEST_ptr(op->stream_name)) - goto out; - - if (!TEST_true(helper_set_s_stream(h, op->stream_name, op->arg2))) - goto out; - } break; - - case OPK_S_UNBIND_STREAM_ID: { - if (!TEST_uint64_t_ne(s_stream_id, UINT64_MAX)) - goto out; - - if (!TEST_ptr(op->stream_name)) - goto out; - - if (!TEST_true(helper_set_s_stream(h, op->stream_name, UINT64_MAX))) - goto out; - } break; - - case OPK_C_WRITE_FAIL: { - size_t bytes_written = 0; - int r; - - if (!TEST_ptr(c_tgt)) - goto out; - - r = SSL_write_ex(c_tgt, "apple", 5, &bytes_written); - if (!TEST_false(r) - || !check_consistent_want(c_tgt, r)) - goto out; - } break; - - case OPK_S_WRITE_FAIL: { - size_t bytes_written = 0; - - if (!TEST_uint64_t_ne(s_stream_id, UINT64_MAX)) - goto out; - - if (!TEST_false(ossl_quic_tserver_write(ACQUIRE_S(), s_stream_id, - (const unsigned char *)"apple", 5, - &bytes_written))) - goto out; - } break; - - case OPK_C_READ_FAIL: { - size_t bytes_read = 0; - char buf[1]; - int r; - - if (!TEST_ptr(c_tgt)) - goto out; - - r = SSL_read_ex(c_tgt, buf, sizeof(buf), &bytes_read); - if (!TEST_false(r)) - goto out; - if (!check_consistent_want(c_tgt, r)) - goto out; - } break; - - case OPK_C_READ_FAIL_WAIT: { - size_t bytes_read = 0; - char buf[1]; - int r; - - if (!TEST_ptr(c_tgt)) - goto out; - - r = SSL_read_ex(c_tgt, buf, sizeof(buf), &bytes_read); - if (!TEST_false(r)) - goto out; - if (!check_consistent_want(c_tgt, r)) - goto out; - - if (is_want(c_tgt, 0)) - C_SPIN_AGAIN(); - } break; - - case OPK_S_READ_FAIL: { - int ret; - size_t bytes_read = 0; - unsigned char buf[1]; - - if (!TEST_uint64_t_ne(s_stream_id, UINT64_MAX)) - goto out; - - ret = ossl_quic_tserver_read(ACQUIRE_S(), s_stream_id, - buf, sizeof(buf), - &bytes_read); - if (!TEST_true(ret == 0 || (op->arg1 && bytes_read == 0))) - goto out; - } break; - - case OPK_C_STREAM_RESET: - case OPK_C_STREAM_RESET_FAIL: { - SSL_STREAM_RESET_ARGS args = { 0 }; - - if (!TEST_ptr(c_tgt)) - goto out; - - args.quic_error_code = op->arg2; - if (op->op == OPK_C_STREAM_RESET) { - if (!TEST_true(SSL_stream_reset(c_tgt, &args, sizeof(args)))) - goto out; - } else { - if (!TEST_false(SSL_stream_reset(c_tgt, &args, sizeof(args)))) - goto out; - } - } break; - - case OPK_NEW_THREAD: { -#if !defined(OPENSSL_THREADS) - /* - * If this test script requires threading and we do not have - * support for it, skip the rest of it. - */ - TEST_skip("threading not supported, skipping"); - testresult = 1; - goto out; -#else - size_t i; - - if (!TEST_ptr_null(h->threads)) { - TEST_error("max one NEW_THREAD operation per script"); - goto out; - } - - h->threads = OPENSSL_calloc(op->arg1, sizeof(struct child_thread_args)); - if (!TEST_ptr(h->threads)) - goto out; - - h->num_threads = op->arg1; - - for (i = 0; i < op->arg1; ++i) { - h->threads[i].h = h; - h->threads[i].script = op->arg0; - h->threads[i].script_name = script_name; - h->threads[i].thread_idx = (int)i; - - h->threads[i].m = ossl_crypto_mutex_new(); - if (!TEST_ptr(h->threads[i].m)) - goto out; - - h->threads[i].t - = ossl_crypto_thread_native_start(run_script_child_thread, - &h->threads[i], 1); - if (!TEST_ptr(h->threads[i].t)) - goto out; - } -#endif - } break; - - case OPK_C_CLOSE_SOCKET: { - BIO_closesocket(h->c_fd); - h->c_fd = -1; - } break; - - case OPK_C_EXPECT_SSL_ERR: { - if (!TEST_size_t_eq((size_t)SSL_get_error(c_tgt, 0), op->arg1)) - goto out; - if (!TEST_int_eq(SSL_want(c_tgt), SSL_NOTHING)) - goto out; - } break; - - case OPK_EXPECT_ERR_REASON: { - if (!TEST_size_t_eq((size_t)ERR_GET_REASON(ERR_peek_last_error()), op->arg1)) - goto out; - } break; - - case OPK_EXPECT_ERR_LIB: { - if (!TEST_size_t_eq((size_t)ERR_GET_LIB(ERR_peek_last_error()), op->arg1)) - goto out; - } break; - - case OPK_POP_ERR: - ERR_pop(); - break; - - case OPK_SLEEP: { - OSSL_sleep(op->arg2); - } break; - - case OPK_S_SET_INJECT_PLAIN: - h->qtf_packet_plain_cb = op->qtf_packet_plain_cb; - - if (!TEST_true(qtest_fault_set_packet_plain_listener(h->qtf, - h->qtf_packet_plain_cb != NULL ? helper_packet_plain_listener : NULL, - h))) - goto out; - - break; - - case OPK_S_SET_INJECT_HANDSHAKE: - h->qtf_handshake_cb = op->qtf_handshake_cb; - - if (!TEST_true(qtest_fault_set_handshake_listener(h->qtf, - h->qtf_handshake_cb != NULL ? helper_handshake_listener : NULL, - h))) - goto out; - - break; - - case OPK_S_SET_INJECT_DATAGRAM: - h->qtf_datagram_cb = op->qtf_datagram_cb; - - if (!TEST_true(qtest_fault_set_datagram_listener(h->qtf, - h->qtf_datagram_cb != NULL ? helper_datagram_listener : NULL, - h))) - goto out; - - break; - - case OPK_SET_INJECT_WORD: - /* - * Must hold server tick lock - callbacks can be called from other - * thread when running test in blocking mode (tsan). - */ - ACQUIRE_S(); - h->inject_word0 = op->arg1; - h->inject_word1 = op->arg2; - break; - - case OPK_C_INHIBIT_TICK: { - QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); - - ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch), - (int)op->arg1); - } break; - - case OPK_C_SET_WRITE_BUF_SIZE: - if (!TEST_ptr(c_tgt)) - goto out; - - if (!TEST_true(ossl_quic_set_write_buffer_size(c_tgt, op->arg1))) - goto out; - - break; - - case OPK_S_NEW_TICKET: - if (!TEST_true(ossl_quic_tserver_new_ticket(ACQUIRE_S()))) - goto out; - break; - - default: - TEST_error("unknown op"); - goto out; - } - } - -out: - s_unlock(h, hl); /* idempotent */ - if (!testresult) { - size_t i; - const QUIC_TERMINATE_CAUSE *tcause; - const char *e_str, *f_str; - - TEST_error("failed in script \"%s\" at op %zu, thread %d\n", - script_name, op_idx + 1, thread_idx); - - for (i = 0; i < repeat_stack_len; ++i) - TEST_info("while repeating, iteration %zu of %zu, starting at script op %zu", - repeat_stack_done[i], - repeat_stack_limit[i], - repeat_stack_idx[i]); - - ERR_print_errors_fp(stderr); - - if (h->c_conn != NULL) { - SSL_CONN_CLOSE_INFO cc_info = { 0 }; - - if (SSL_get_conn_close_info(h->c_conn, &cc_info, sizeof(cc_info))) { - e_str = ossl_quic_err_to_string(cc_info.error_code); - f_str = ossl_quic_frame_type_to_string(cc_info.frame_type); - - if (e_str == NULL) - e_str = "?"; - if (f_str == NULL) - f_str = "?"; - - TEST_info("client side is closed: %llu(%s)/%llu(%s), " - "%s, %s, reason: \"%s\"", - (unsigned long long)cc_info.error_code, - e_str, - (unsigned long long)cc_info.frame_type, - f_str, - (cc_info.flags & SSL_CONN_CLOSE_FLAG_LOCAL) != 0 - ? "local" - : "remote", - (cc_info.flags & SSL_CONN_CLOSE_FLAG_TRANSPORT) != 0 - ? "transport" - : "app", - cc_info.reason != NULL ? cc_info.reason : "-"); - } - } - - tcause = (h->s != NULL - ? ossl_quic_tserver_get_terminate_cause(h->s) - : NULL); - if (tcause != NULL) { - e_str = ossl_quic_err_to_string(tcause->error_code); - f_str = ossl_quic_frame_type_to_string(tcause->frame_type); - - if (e_str == NULL) - e_str = "?"; - if (f_str == NULL) - f_str = "?"; - - TEST_info("server side is closed: %llu(%s)/%llu(%s), " - "%s, %s, reason: \"%s\"", - (unsigned long long)tcause->error_code, - e_str, - (unsigned long long)tcause->frame_type, - f_str, - tcause->remote ? "remote" : "local", - tcause->app ? "app" : "transport", - tcause->reason != NULL ? tcause->reason : "-"); - } - } - - OPENSSL_free(tmp_buf); - helper_local_cleanup(hl); - return testresult; -} - -static int run_script(const struct script_op *script, - const char *script_name, - int free_order, - int blocking) -{ - int testresult = 0; - struct helper h; - - if (!TEST_true(helper_init(&h, script_name, - free_order, blocking, 1))) - goto out; - - if (!TEST_true(run_script_worker(&h, script, script_name, -1))) - goto out; - -#if defined(OPENSSL_THREADS) - if (!TEST_true(join_threads(h.threads, h.num_threads))) - goto out; -#endif - - testresult = 1; -out: - helper_cleanup(&h); - return testresult; -} - -#if defined(OPENSSL_THREADS) -static CRYPTO_THREAD_RETVAL run_script_child_thread(void *arg) -{ - int testresult; - struct child_thread_args *args = arg; - - testresult = run_script_worker(args->h, args->script, - args->script_name, - args->thread_idx); - - ossl_crypto_mutex_lock(args->m); - args->testresult = testresult; - args->done = 1; - ossl_crypto_mutex_unlock(args->m); - return 1; -} -#endif - -/* 1. Simple single-stream test */ -static const struct script_op script_1[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 2. Multi-stream test */ -static const struct script_op script_2[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 3. Default stream detach/reattach test */ -static const struct script_op script_3[] = { - /* - * SSL_attach_stream()/SSL_detach_stream() no longer exists, - * there is no reason to keep their private implementation - * with test - */ - - OP_END -}; - -/* 4. Default stream mode test */ -static const struct script_op script_4[] = { - /* - * SSL_attach_stream()/SSL_detach_stream() no longer exists, - * there is no reason to keep their private implementation - * with test - */ - - OP_END -}; - -/* 5. Test stream reset functionality */ -static const struct script_op script_5[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 6. Test STOP_SENDING functionality */ -static const struct script_op script_6[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 7. Unidirectional default stream mode test (client sends first) */ -static const struct script_op script_7[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 8. Unidirectional default stream mode test (server sends first) */ -static const struct script_op script_8[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 9. Unidirectional default stream mode test (server sends first on bidi) */ -static const struct script_op script_9[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 10. Shutdown */ -static const struct script_op script_10[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 11. Many threads accepted on the same client connection */ -static const struct script_op script_11[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 12. Many threads initiated on the same client connection */ -static const struct script_op script_12[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 13. Many threads accepted on the same client connection (stress test) */ -static const struct script_op script_13[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 14. Many threads initiating on the same client connection (stress test) */ -static const struct script_op script_14[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 15. Client sending large number of streams, MAX_STREAMS test */ -static const struct script_op script_15[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 16. Server sending large number of streams, MAX_STREAMS test */ -static const struct script_op script_16[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 17. Key update test - unlimited */ -static const struct script_op script_17[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 18. Key update test - RTT-bounded */ -static const struct script_op script_18[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 19. Key update test - artificially triggered */ -static const struct script_op script_19[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 20. Multiple threads accept stream with socket forcibly closed (error test) */ -static const struct script_op script_20[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 21. Fault injection - unknown frame in 1-RTT packet */ -static int script_21_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, - unsigned char *buf, size_t len) -{ - int ok = 0; - WPACKET wpkt; - unsigned char frame_buf[21]; - size_t written; - - if (h->inject_word0 == 0 || hdr->type != h->inject_word0) - return 1; - - if (!TEST_true(WPACKET_init_static_len(&wpkt, frame_buf, - sizeof(frame_buf), 0))) - return 0; - - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, h->inject_word1))) - goto err; - - switch (h->inject_word1) { - case OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE: - case OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE: - case OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID: - /* - * These cases to be formatted properly need a single uint64_t - */ - if (!TEST_true(WPACKET_put_bytes_u64(&wpkt, (uint64_t)0))) - goto err; - break; - case OSSL_QUIC_FRAME_TYPE_MAX_DATA: - case OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI: - case OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI: - case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI: - case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI: - case OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED: - /* - * These cases require a single vlint - */ - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)0))) - goto err; - break; - case OSSL_QUIC_FRAME_TYPE_STOP_SENDING: - case OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA: - case OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED: - /* - * These cases require 2 variable integers - */ - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)0))) - goto err; - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)0))) - goto err; - break; - case OSSL_QUIC_FRAME_TYPE_STREAM: - case OSSL_QUIC_FRAME_TYPE_RESET_STREAM: - case OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP: - /* - * These cases require 3 variable integers - */ - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)0))) - goto err; - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)0))) - goto err; - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)0))) - goto err; - break; - case OSSL_QUIC_FRAME_TYPE_NEW_TOKEN: - /* - * Special case for new token - */ - - /* New token length, cannot be zero */ - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)1))) - goto err; - - /* 1 bytes of token data, to match the above length */ - if (!TEST_true(WPACKET_put_bytes_u8(&wpkt, (uint8_t)0))) - goto err; - break; - case OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID: - /* - * Special case for New Connection ids, has a combination - * of vlints and fixed width values - */ - - /* seq number */ - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)0))) - goto err; - - /* retire prior to */ - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, (uint64_t)0))) - goto err; - - /* Connection id length, arbitrary at 1 bytes */ - if (!TEST_true(WPACKET_put_bytes_u8(&wpkt, (uint8_t)1))) - goto err; - - /* The connection id, to match the above length */ - if (!TEST_true(WPACKET_put_bytes_u8(&wpkt, (uint8_t)0))) - goto err; - - /* 16 bytes total for the SRT */ - if (!TEST_true(WPACKET_memset(&wpkt, 0, 16))) - goto err; - - break; - } - - if (!TEST_true(WPACKET_get_total_written(&wpkt, &written))) - goto err; - - if (!qtest_fault_prepend_frame(h->qtf, frame_buf, written)) - goto err; - - ok = 1; -err: - if (ok) - WPACKET_finish(&wpkt); - else - WPACKET_cleanup(&wpkt); - return ok; -} - -static const struct script_op script_21[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 22. Fault injection - non-zero packet header reserved bits */ -static const struct script_op script_22[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 23. Fault injection - empty NEW_TOKEN */ -static const struct script_op script_23[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 24. Fault injection - excess value of MAX_STREAMS_BIDI */ -static const struct script_op script_24[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 25. Fault injection - excess value of MAX_STREAMS_UNI */ -static const struct script_op script_25[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 26. Fault injection - excess value of STREAMS_BLOCKED_BIDI */ -static const struct script_op script_26[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 27. Fault injection - excess value of STREAMS_BLOCKED_UNI */ -static const struct script_op script_27[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 28. Fault injection - received RESET_STREAM for send-only stream */ -static int script_28_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, - unsigned char *buf, size_t len) -{ - int ok = 0; - WPACKET wpkt; - unsigned char frame_buf[32]; - size_t written; - - if (h->inject_word0 == 0 || hdr->type != QUIC_PKT_TYPE_1RTT) - return 1; - - if (!TEST_true(WPACKET_init_static_len(&wpkt, frame_buf, - sizeof(frame_buf), 0))) - return 0; - - if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, h->inject_word1)) - || !TEST_true(WPACKET_quic_write_vlint(&wpkt, /* stream ID */ - h->inject_word0 - 1)) - || !TEST_true(WPACKET_quic_write_vlint(&wpkt, 123)) - || (h->inject_word1 == OSSL_QUIC_FRAME_TYPE_RESET_STREAM - && !TEST_true(WPACKET_quic_write_vlint(&wpkt, 5)))) /* final size */ - goto err; - - if (!TEST_true(WPACKET_get_total_written(&wpkt, &written))) - goto err; - - if (!qtest_fault_prepend_frame(h->qtf, frame_buf, written)) - goto err; - - ok = 1; -err: - if (ok) - WPACKET_finish(&wpkt); - else - WPACKET_cleanup(&wpkt); - return ok; -} - -static const struct script_op script_28[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 29. Fault injection - received RESET_STREAM for nonexistent send-only stream */ -static const struct script_op script_29[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 30. Fault injection - received STOP_SENDING for receive-only stream */ -static const struct script_op script_30[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 31. Fault injection - received STOP_SENDING for nonexistent receive-only stream */ -static const struct script_op script_31[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 32. Fault injection - STREAM frame for nonexistent stream */ -static const struct script_op script_32[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 33. Fault injection - STREAM frame with illegal offset */ -static const struct script_op script_33[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 34. Fault injection - STREAM frame which exceeds FC */ -static const struct script_op script_34[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 35. Fault injection - MAX_STREAM_DATA for receive-only stream */ -static const struct script_op script_35[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 36. Fault injection - MAX_STREAM_DATA for nonexistent stream */ -static const struct script_op script_36[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 37. Fault injection - STREAM_DATA_BLOCKED for send-only stream */ -static const struct script_op script_37[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 38. Fault injection - STREAM_DATA_BLOCKED for non-existent stream */ -static const struct script_op script_38[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 39. Fault injection - NEW_CONN_ID with zero-len CID */ -static const struct script_op script_39[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 40. Shutdown flush test */ -static const struct script_op script_40[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 41. Fault injection - PATH_CHALLENGE yields PATH_RESPONSE */ -static const struct script_op script_41[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 42. Fault injection - CRYPTO frame with illegal offset */ -static const struct script_op script_42[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 43. Fault injection - CRYPTO frame exceeding FC */ -static const struct script_op script_43[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 44. Fault injection - PADDING */ -static const struct script_op script_44[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 45. PING must generate ACK */ -static const struct script_op script_45[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 46. Fault injection - ACK - malformed initial range */ -static const struct script_op script_46[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 47. Fault injection - ACK - malformed subsequent range */ -static const struct script_op script_47[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 48. Fault injection - ACK - malformed subsequent range */ -static const struct script_op script_48[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 49. Fault injection - ACK - fictional PN */ -static const struct script_op script_49[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 50. Fault injection - ACK - duplicate PN */ -static const struct script_op script_50[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 51. Fault injection - PATH_RESPONSE is ignored */ -static const struct script_op script_51[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 52. Fault injection - ignore BLOCKED frames with bogus values */ -static const struct script_op script_52[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 53. Fault injection - excess CRYPTO buffer size */ -static const struct script_op script_53[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 54. Fault injection - corrupted crypto stream data */ -static const struct script_op script_54[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 55. Fault injection - NEW_CONN_ID with >20 byte CID */ -static const struct script_op script_55[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 56. Fault injection - NEW_CONN_ID with seq no < retire prior to */ -static const struct script_op script_56[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 57. Fault injection - NEW_CONN_ID with lower seq so ignored */ -static const struct script_op script_57[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 58. Fault injection - repeated HANDSHAKE_DONE */ -static const struct script_op script_58[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 59. Fault injection - multi-byte frame encoding */ -static const struct script_op script_59[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 60. Connection close reason truncation */ -static const struct script_op script_60[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 61. Fault injection - RESET_STREAM exceeding stream count FC */ -static const struct script_op script_61[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 62. Fault injection - STOP_SENDING with high ID */ -static const struct script_op script_62[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 63. Fault injection - STREAM frame exceeding stream limit */ -static const struct script_op script_63[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 64. Fault injection - STREAM - zero-length no-FIN is accepted */ -static const struct script_op script_64[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 65. Fault injection - CRYPTO - zero-length is accepted */ -static const struct script_op script_65[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 66. Fault injection - large MAX_STREAM_DATA */ -static const struct script_op script_66[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 67. Fault injection - large MAX_DATA */ -static const struct script_op script_67[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 68. Fault injection - Unexpected TLS messages */ -/* Send a CertificateRequest message post-handshake */ -static const struct script_op script_68[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -/* 69. Send a TLS KeyUpdate message post-handshake */ -static const struct script_op script_69[] = { - /* test moved to test/radix/quic_tests.c */ - OP_END -}; - -static int set_max_early_data(struct helper *h, struct helper_local *hl) -{ - - if (!TEST_true(ossl_quic_tserver_set_max_early_data(ACQUIRE_S(), - (uint32_t)hl->check_op->arg2))) - return 0; - - return 1; -} - -/* 70. Send a TLS NewSessionTicket message with invalid max_early_data */ -static const struct script_op script_70[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_C_WRITE(a, "apple", 5), - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - - OP_CHECK(set_max_early_data, 0xfffffffe), - OP_S_NEW_TICKET(), - OP_S_WRITE(a, "orange", 6), - - OP_C_EXPECT_CONN_CLOSE_INFO(OSSL_QUIC_ERR_PROTOCOL_VIOLATION, 0, 0), - - OP_END -}; - -/* 71. Send a TLS NewSessionTicket message with valid max_early_data */ -static const struct script_op script_71[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_C_WRITE(a, "apple", 5), - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - - OP_CHECK(set_max_early_data, 0xffffffff), - OP_S_NEW_TICKET(), - OP_S_WRITE(a, "orange", 6), - OP_C_READ_EXPECT(a, "orange", 6), - - OP_END -}; - -/* 72. Test that APL stops handing out streams after limit reached (bidi) */ -static int script_72_check(struct helper *h, struct helper_local *hl) -{ - if (!TEST_uint64_t_ge(h->fail_count, 50)) - return 0; - - return 1; -} - -static const struct script_op script_72[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - /* - * Request more streams than a server will initially hand out and test that - * they fail properly. - */ - OP_BEGIN_REPEAT(200), - - OP_C_NEW_STREAM_BIDI_EX(a, ANY_ID, ALLOW_FAIL | SSL_STREAM_FLAG_NO_BLOCK), - OP_C_SKIP_IF_UNBOUND(a, 2), - OP_C_WRITE(a, "apple", 5), - OP_C_FREE_STREAM(a), - - OP_END_REPEAT(), - - OP_CHECK(script_72_check, 0), - - OP_END -}; - -/* 73. Test that APL stops handing out streams after limit reached (uni) */ -static const struct script_op script_73[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - /* - * Request more streams than a server will initially hand out and test that - * they fail properly. - */ - OP_BEGIN_REPEAT(200), - - OP_C_NEW_STREAM_UNI_EX(a, ANY_ID, ALLOW_FAIL | SSL_STREAM_FLAG_NO_BLOCK), - OP_C_SKIP_IF_UNBOUND(a, 2), - OP_C_WRITE(a, "apple", 5), - OP_C_FREE_STREAM(a), - - OP_END_REPEAT(), - - OP_CHECK(script_72_check, 0), - - OP_END -}; - -/* 74. Version negotiation: QUIC_VERSION_1 ignored */ -static int generate_version_neg(WPACKET *wpkt, uint32_t version) -{ - QUIC_PKT_HDR hdr = { 0 }; - - hdr.type = QUIC_PKT_TYPE_VERSION_NEG; - hdr.version = 0; - hdr.fixed = 1; - hdr.dst_conn_id.id_len = 0; - hdr.src_conn_id.id_len = 8; - memset(hdr.src_conn_id.id, 0x55, 8); - - if (!TEST_true(ossl_quic_wire_encode_pkt_hdr(wpkt, 0, &hdr, NULL))) - return 0; - - if (!TEST_true(WPACKET_put_bytes_u32(wpkt, version))) - return 0; - - return 1; -} - -static int server_gen_version_neg(struct helper *h, BIO_MSG *msg, size_t stride) -{ - int rc = 0, have_wpkt = 0; - size_t l; - WPACKET wpkt; - BUF_MEM *buf = NULL; - uint32_t version; - - switch (h->inject_word0) { - case 0: - return 1; - case 1: - version = QUIC_VERSION_1; - break; - default: - version = 0x5432abcd; - break; - } - - if (!TEST_ptr(buf = BUF_MEM_new())) - goto err; - - if (!TEST_true(WPACKET_init(&wpkt, buf))) - goto err; - - have_wpkt = 1; - - generate_version_neg(&wpkt, version); - - if (!TEST_true(WPACKET_get_total_written(&wpkt, &l))) - goto err; - - if (!TEST_true(qtest_fault_resize_datagram(h->qtf, l))) - goto err; - - memcpy(msg->data, buf->data, l); - h->inject_word0 = 0; - - rc = 1; -err: - if (have_wpkt && !WPACKET_finish(&wpkt)) - WPACKET_cleanup(&wpkt); - - BUF_MEM_free(buf); - return rc; -} - -static int do_mutation = 0; -static QUIC_PKT_HDR *hdr_to_free = NULL; - -/* - * Check packets to transmit, if we have an initial packet - * Modify the version number to something incorrect - * so that we trigger a version negotiation - * Note, this is a use once function, it will only modify the - * first INITIAL packet it sees, after which it needs to be - * armed again - */ -static int script_74_alter_version(const QUIC_PKT_HDR *hdrin, - const OSSL_QTX_IOVEC *iovecin, size_t numin, - QUIC_PKT_HDR **hdrout, - const OSSL_QTX_IOVEC **iovecout, - size_t *numout, - void *arg) -{ - *hdrout = OPENSSL_memdup(hdrin, sizeof(QUIC_PKT_HDR)); - *iovecout = iovecin; - *numout = numin; - hdr_to_free = *hdrout; - - if (do_mutation == 0) - return 1; - do_mutation = 0; - - if (hdrin->type == QUIC_PKT_TYPE_INITIAL) - (*hdrout)->version = 0xdeadbeef; - return 1; -} - -static void script_74_finish_mutation(void *arg) -{ - OPENSSL_free(hdr_to_free); -} - -/* - * Enable the packet mutator for the client channel - * So that when we send a Initial packet - * We modify the version to be something invalid - * to force a version negotiation - */ -static int script_74_arm_packet_mutator(struct helper *h, - struct helper_local *hl) -{ - QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); - - do_mutation = 1; - if (!ossl_quic_channel_set_mutator(ch, script_74_alter_version, - script_74_finish_mutation, - NULL)) - return 0; - return 1; -} - -static const struct script_op script_74[] = { - OP_CHECK(script_74_arm_packet_mutator, 0), - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_C_WRITE(a, "apple", 5), - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - - OP_END -}; - -/* 75. Version negotiation: Unknown version causes connection abort */ -static const struct script_op script_75[] = { - OP_S_SET_INJECT_DATAGRAM(server_gen_version_neg), - OP_SET_INJECT_WORD(2, 0), - - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT_OR_FAIL(), - - OP_C_EXPECT_CONN_CLOSE_INFO(OSSL_QUIC_ERR_CONNECTION_REFUSED, 0, 0), - - OP_END -}; - -/* 76. Test peer-initiated shutdown wait */ -static int script_76_check(struct helper *h, struct helper_local *hl) -{ - if (!TEST_false(SSL_shutdown_ex(h->c_conn, - SSL_SHUTDOWN_FLAG_WAIT_PEER - | SSL_SHUTDOWN_FLAG_NO_BLOCK, - NULL, 0))) - return 0; - - return 1; -} - -static const struct script_op script_76[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_C_WRITE(a, "apple", 5), - - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - - /* Check a WAIT_PEER call doesn't succeed yet. */ - OP_CHECK(script_76_check, 0), - OP_S_SHUTDOWN(42), - - OP_C_SHUTDOWN_WAIT(NULL, SSL_SHUTDOWN_FLAG_WAIT_PEER), - OP_C_EXPECT_CONN_CLOSE_INFO(42, 1, 1), - - OP_END -}; - -/* 77. Ensure default stream popping operates correctly */ -static const struct script_op script_77[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_INCOMING_STREAM_POLICY(SSL_INCOMING_STREAM_POLICY_ACCEPT), - - OP_S_NEW_STREAM_BIDI(a, S_BIDI_ID(0)), - OP_S_WRITE(a, "Strawberry", 10), - - OP_C_READ_EXPECT(DEFAULT, "Strawberry", 10), - - OP_S_NEW_STREAM_BIDI(b, S_BIDI_ID(1)), - OP_S_WRITE(b, "xyz", 3), - - OP_C_ACCEPT_STREAM_WAIT(b), - OP_C_READ_EXPECT(b, "xyz", 3), - - OP_END -}; - -/* 78. Post-connection session ticket handling */ -static size_t new_session_count; - -static int on_new_session(SSL *s, SSL_SESSION *sess) -{ - ++new_session_count; - return 0; /* do not ref session, we aren't keeping it */ -} - -static int setup_session(struct helper *h, struct helper_local *hl) -{ - SSL_CTX_set_session_cache_mode(h->c_ctx, SSL_SESS_CACHE_BOTH); - SSL_CTX_sess_set_new_cb(h->c_ctx, on_new_session); - return 1; -} - -static int trigger_late_session_ticket(struct helper *h, struct helper_local *hl) -{ - new_session_count = 0; - - if (!TEST_true(ossl_quic_tserver_new_ticket(ACQUIRE_S()))) - return 0; - - return 1; -} - -static int check_got_session_ticket(struct helper *h, struct helper_local *hl) -{ - if (!TEST_size_t_gt(new_session_count, 0)) - return 0; - - return 1; -} - -static int check_idle_timeout(struct helper *h, struct helper_local *hl); - -static const struct script_op script_78[] = { - OP_C_SET_ALPN("ossltest"), - OP_CHECK(setup_session, 0), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_C_WRITE(a, "apple", 5), - - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - - OP_S_WRITE(a, "orange", 6), - OP_C_READ_EXPECT(a, "orange", 6), - - OP_CHECK(trigger_late_session_ticket, 0), - - OP_S_WRITE(a, "Strawberry", 10), - OP_C_READ_EXPECT(a, "Strawberry", 10), - - OP_CHECK(check_got_session_ticket, 0), OP_CHECK2(check_idle_timeout, SSL_VALUE_CLASS_FEATURE_NEGOTIATED, 30000), - - OP_END -}; - -/* 79. Optimised FIN test */ -static const struct script_op script_79[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_WRITE_EX2(DEFAULT, "apple", 5, SSL_WRITE_FLAG_CONCLUDE), - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - OP_S_EXPECT_FIN(a), - OP_S_WRITE(a, "orange", 6), - OP_S_CONCLUDE(a), - OP_C_READ_EXPECT(DEFAULT, "orange", 6), - OP_C_EXPECT_FIN(DEFAULT), - OP_END -}; - -/* 80. Stateless reset detection test */ -static QUIC_STATELESS_RESET_TOKEN test_reset_token = { - { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef } -}; - -/* - * Generate a packet in the following format: - * https://www.rfc-editor.org/rfc/rfc9000.html#name-stateless-reset - * Stateless Reset { - * Fixed Bits (2): 1 - * Unpredictable bits (38..) - * Stateless reset token (128) - * } - */ -static int script_80_send_stateless_reset(struct helper *h, QUIC_PKT_HDR *hdr, - unsigned char *buf, size_t len) -{ - unsigned char databuf[64]; - - if (h->inject_word1 == 0) - return 1; - - h->inject_word1 = 0; - - fprintf(stderr, "Sending stateless reset\n"); - - RAND_bytes(databuf, 64); - databuf[0] = 0x40; - memcpy(&databuf[48], test_reset_token.token, - sizeof(test_reset_token.token)); - - if (!TEST_int_eq(SSL_inject_net_dgram(h->c_conn, databuf, sizeof(databuf), - NULL, h->s_net_bio_addr), - 1)) - return 0; - - return 1; -} - -static int script_80_gen_new_conn_id(struct helper *h, QUIC_PKT_HDR *hdr, - unsigned char *buf, size_t len) -{ - int rc = 0; - size_t l; - unsigned char frame_buf[64]; - WPACKET wpkt; - QUIC_CONN_ID new_cid = { 0 }; - OSSL_QUIC_FRAME_NEW_CONN_ID ncid = { 0 }; - QUIC_CHANNEL *ch = ossl_quic_tserver_get_channel(ACQUIRE_S_NOHL()); - - if (h->inject_word0 == 0) - return 1; - - h->inject_word0 = 0; - - fprintf(stderr, "sending new conn id\n"); - if (!TEST_true(WPACKET_init_static_len(&wpkt, frame_buf, - sizeof(frame_buf), 0))) - return 0; - - ossl_quic_channel_get_diag_local_cid(ch, &new_cid); - - ncid.seq_num = 2; - ncid.retire_prior_to = 2; - ncid.conn_id = new_cid; - memcpy(ncid.stateless_reset.token, test_reset_token.token, - sizeof(test_reset_token.token)); - - if (!TEST_true(ossl_quic_wire_encode_frame_new_conn_id(&wpkt, &ncid))) - goto err; - - if (!TEST_true(WPACKET_get_total_written(&wpkt, &l))) - goto err; - - if (!qtest_fault_prepend_frame(h->qtf, frame_buf, l)) - goto err; - - rc = 1; -err: - if (rc) - WPACKET_finish(&wpkt); - else - WPACKET_cleanup(&wpkt); - - return rc; -} - -static int script_80_inject_pkt(struct helper *h, QUIC_PKT_HDR *hdr, - unsigned char *buf, size_t len) -{ - if (h->inject_word1 == 1) - return script_80_send_stateless_reset(h, hdr, buf, len); - else if (h->inject_word0 == 1) - return script_80_gen_new_conn_id(h, hdr, buf, len); - - return 1; -} - -static const struct script_op script_80[] = { - OP_S_SET_INJECT_PLAIN(script_80_inject_pkt), - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_WRITE(DEFAULT, "apple", 5), - OP_C_CONCLUDE(DEFAULT), - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - OP_SET_INJECT_WORD(1, 0), - OP_S_WRITE(a, "apple", 5), - OP_C_READ_EXPECT(DEFAULT, "apple", 5), - OP_SET_INJECT_WORD(0, 1), - OP_S_WRITE(a, "apple", 5), - OP_C_EXPECT_CONN_CLOSE_INFO(0, 0, 1), - OP_END -}; - -static int modify_static_tp(struct helper *h, struct helper_local *hl, int ssl_value) -{ - uint64_t v = 0; - - /* Test bad value is rejected. */ - if (!TEST_false(SSL_set_feature_request_uint(h->c_conn, - ssl_value, - OSSL_QUIC_VLINT_MAX + 1))) - return 0; - - /* Set value. */ - if (!TEST_true(SSL_set_feature_request_uint(h->c_conn, - ssl_value, - hl->check_op->arg2))) - return 0; - - if (!TEST_true(SSL_get_feature_request_uint(h->c_conn, - ssl_value, - &v))) - return 0; - - if (!TEST_uint64_t_eq(v, hl->check_op->arg2)) - return 0; - - return 1; -} - -static int check_static_tp(struct helper *h, struct helper_local *hl, int ssl_value) -{ - uint64_t v = 0; - - if (!TEST_true(SSL_get_value_uint(h->c_conn, (uint32_t)hl->check_op->arg1, - ssl_value, - &v))) - return 0; - - if (!TEST_uint64_t_eq(v, hl->check_op->arg2)) - return 0; - - return 1; -} - -static int cannot_change_static_tp(struct helper *h, struct helper_local *hl, int ssl_value) -{ - uint64_t v = 0; - - if (!TEST_true(SSL_get_feature_request_uint(h->c_conn, - ssl_value, - &v))) - return 0; - - if (!TEST_uint64_t_eq(v, hl->check_op->arg1)) - return 0; - - if (!TEST_false(SSL_set_feature_request_uint(h->c_conn, - ssl_value, - hl->check_op->arg2))) - return 0; - - return 1; -} - -static int modify_idle_timeout(struct helper *h, struct helper_local *hl) -{ - return modify_static_tp(h, hl, SSL_VALUE_QUIC_IDLE_TIMEOUT); -} - -static int check_idle_timeout(struct helper *h, struct helper_local *hl) -{ - return check_static_tp(h, hl, SSL_VALUE_QUIC_IDLE_TIMEOUT); -} - -static int cannot_change_idle_timeout(struct helper *h, struct helper_local *hl) -{ - return cannot_change_static_tp(h, hl, SSL_VALUE_QUIC_IDLE_TIMEOUT); -} - -/* 81. Idle timeout configuration */ -static const struct script_op script_81[] = { - OP_C_SET_ALPN("ossltest"), - OP_CHECK(modify_idle_timeout, 25000), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_idle_timeout, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 30000), - OP_CHECK2(check_idle_timeout, SSL_VALUE_CLASS_FEATURE_NEGOTIATED, 25000), - - OP_END -}; - -/* 82. Negotiated default idle timeout if not configured */ -static const struct script_op script_82[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_idle_timeout, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 30000), - OP_CHECK2(check_idle_timeout, SSL_VALUE_CLASS_FEATURE_NEGOTIATED, 30000), - - OP_END -}; - -/* 83. No late changes to idle timeout */ -static const struct script_op script_83[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(cannot_change_idle_timeout, 30000, 5000), - OP_CHECK2(check_idle_timeout, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 30000), - OP_CHECK2(check_idle_timeout, SSL_VALUE_CLASS_FEATURE_NEGOTIATED, 30000), - - OP_END -}; - -/* 84. Test query of available streams */ -static int check_avail_streams(struct helper *h, struct helper_local *hl) -{ - uint64_t v = 0; - - switch (hl->check_op->arg1) { - case 0: - if (!TEST_true(SSL_get_quic_stream_bidi_local_avail(h->c_conn, &v))) - return 0; - break; - case 1: - if (!TEST_true(SSL_get_quic_stream_bidi_remote_avail(h->c_conn, &v))) - return 0; - break; - case 2: - if (!TEST_true(SSL_get_quic_stream_uni_local_avail(h->c_conn, &v))) - return 0; - break; - case 3: - if (!TEST_true(SSL_get_quic_stream_uni_remote_avail(h->c_conn, &v))) - return 0; - break; - default: - return 0; - } - - if (!TEST_uint64_t_eq(v, hl->check_op->arg2)) - return 0; - - return 1; -} - -static int set_event_handling_mode_conn(struct helper *h, struct helper_local *hl); -static int reenable_test_event_handling(struct helper *h, struct helper_local *hl); - -static int check_write_buf_stat(struct helper *h, struct helper_local *hl) -{ - SSL *c_a; - uint64_t size, used, avail; - - if (!TEST_ptr(c_a = helper_local_get_c_stream(hl, "a"))) - return 0; - - if (!TEST_true(SSL_get_stream_write_buf_size(c_a, &size)) - || !TEST_true(SSL_get_stream_write_buf_used(c_a, &used)) - || !TEST_true(SSL_get_stream_write_buf_avail(c_a, &avail)) - || !TEST_uint64_t_ge(size, avail) - || !TEST_uint64_t_ge(size, used) - || !TEST_uint64_t_eq(avail + used, size)) - return 0; - - if (!TEST_uint64_t_eq(used, hl->check_op->arg1)) - return 0; - - return 1; -} - -static const struct script_op script_84[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_avail_streams, 0, 100), - OP_CHECK2(check_avail_streams, 1, 100), - OP_CHECK2(check_avail_streams, 2, 100), - OP_CHECK2(check_avail_streams, 3, 100), - - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - - OP_CHECK2(check_avail_streams, 0, 99), - OP_CHECK2(check_avail_streams, 1, 100), - OP_CHECK2(check_avail_streams, 2, 100), - OP_CHECK2(check_avail_streams, 3, 100), - - OP_C_NEW_STREAM_UNI(b, C_UNI_ID(0)), - - OP_CHECK2(check_avail_streams, 0, 99), - OP_CHECK2(check_avail_streams, 1, 100), - OP_CHECK2(check_avail_streams, 2, 99), - OP_CHECK2(check_avail_streams, 3, 100), - - OP_S_NEW_STREAM_BIDI(c, S_BIDI_ID(0)), - OP_S_WRITE(c, "x", 1), - - OP_C_ACCEPT_STREAM_WAIT(c), - OP_C_READ_EXPECT(c, "x", 1), - - OP_CHECK2(check_avail_streams, 0, 99), - OP_CHECK2(check_avail_streams, 1, 99), - OP_CHECK2(check_avail_streams, 2, 99), - OP_CHECK2(check_avail_streams, 3, 100), - - OP_S_NEW_STREAM_UNI(d, S_UNI_ID(0)), - OP_S_WRITE(d, "x", 1), - - OP_C_ACCEPT_STREAM_WAIT(d), - OP_C_READ_EXPECT(d, "x", 1), - - OP_CHECK2(check_avail_streams, 0, 99), - OP_CHECK2(check_avail_streams, 1, 99), - OP_CHECK2(check_avail_streams, 2, 99), - OP_CHECK2(check_avail_streams, 3, 99), - - OP_CHECK2(check_write_buf_stat, 0, 0), - OP_CHECK(set_event_handling_mode_conn, SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT), - OP_C_WRITE(a, "apple", 5), - OP_CHECK2(check_write_buf_stat, 5, 0), - - OP_CHECK(reenable_test_event_handling, 0), - - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - OP_S_WRITE(a, "orange", 6), - OP_C_READ_EXPECT(a, "orange", 6), - - OP_END -}; - -/* 85. Test SSL_poll (lite, non-blocking) */ -ossl_unused static int script_85_poll(struct helper *h, struct helper_local *hl) -{ - int ok = 1, ret, expected_ret = 1; - static const struct timeval timeout = { 0 }; - size_t result_count, expected_result_count = 0; - SSL_POLL_ITEM items[5] = { 0 }, *item = items; - SSL *c_a, *c_b, *c_c, *c_d; - size_t i; - uint64_t mode, expected_revents[5] = { 0 }; - - if (!TEST_ptr(c_a = helper_local_get_c_stream(hl, "a")) - || !TEST_ptr(c_b = helper_local_get_c_stream(hl, "b")) - || !TEST_ptr(c_c = helper_local_get_c_stream(hl, "c")) - || !TEST_ptr(c_d = helper_local_get_c_stream(hl, "d"))) - return 0; - - item->desc = SSL_as_poll_descriptor(c_a); - item->events = UINT64_MAX; - item->revents = UINT64_MAX; - ++item; - - item->desc = SSL_as_poll_descriptor(c_b); - item->events = UINT64_MAX; - item->revents = UINT64_MAX; - ++item; - - item->desc = SSL_as_poll_descriptor(c_c); - item->events = UINT64_MAX; - item->revents = UINT64_MAX; - ++item; - - item->desc = SSL_as_poll_descriptor(c_d); - item->events = UINT64_MAX; - item->revents = UINT64_MAX; - ++item; - - item->desc = SSL_as_poll_descriptor(h->c_conn); - item->events = UINT64_MAX; - item->revents = UINT64_MAX; - ++item; - - result_count = SIZE_MAX; - ret = SSL_poll(items, OSSL_NELEM(items), sizeof(SSL_POLL_ITEM), - &timeout, 0, - &result_count); - - mode = hl->check_op->arg2; - switch (mode) { - case 0: - /* No incoming data yet */ - expected_revents[0] = SSL_POLL_EVENT_W; - expected_revents[1] = SSL_POLL_EVENT_W; - expected_revents[2] = SSL_POLL_EVENT_W; - expected_revents[3] = SSL_POLL_EVENT_W; - expected_revents[4] = SSL_POLL_EVENT_OS; - expected_result_count = 5; - break; - case 1: - /* Expect more events */ - expected_revents[0] = SSL_POLL_EVENT_W | SSL_POLL_EVENT_R; - expected_revents[1] = SSL_POLL_EVENT_W | SSL_POLL_EVENT_ER; - expected_revents[2] = SSL_POLL_EVENT_EW; - expected_revents[3] = SSL_POLL_EVENT_W; - expected_revents[4] = SSL_POLL_EVENT_OS | SSL_POLL_EVENT_ISB; - expected_result_count = 5; - break; - default: - return 0; - } - - if (!TEST_int_eq(ret, expected_ret) - || !TEST_size_t_eq(result_count, expected_result_count)) - ok = 0; - - for (i = 0; i < OSSL_NELEM(items); ++i) - if (!TEST_uint64_t_eq(items[i].revents, expected_revents[i])) { - TEST_error("mismatch at index %zu in poll results, mode %d", - i, (int)mode); - ok = 0; - } - - return ok; -} - -static const struct script_op script_85[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_C_WRITE(a, "flamingo", 8), - - OP_C_NEW_STREAM_BIDI(b, C_BIDI_ID(1)), - OP_C_WRITE(b, "orange", 6), - - OP_C_NEW_STREAM_BIDI(c, C_BIDI_ID(2)), - OP_C_WRITE(c, "Strawberry", 10), - - OP_C_NEW_STREAM_BIDI(d, C_BIDI_ID(3)), - OP_C_WRITE(d, "sync", 4), - - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_BIND_STREAM_ID(b, C_BIDI_ID(1)), - OP_S_BIND_STREAM_ID(c, C_BIDI_ID(2)), - OP_S_BIND_STREAM_ID(d, C_BIDI_ID(3)), - - /* Check nothing readable yet. */ - OP_CHECK(script_85_poll, 0), - - /* Send something that will make client sockets readable. */ - OP_S_READ_EXPECT(a, "flamingo", 8), - OP_S_WRITE(a, "herringbone", 11), - - /* Send something that will make 'b' reset. */ - OP_S_SET_INJECT_PLAIN(script_28_inject_plain), - OP_SET_INJECT_WORD(C_BIDI_ID(1) + 1, OSSL_QUIC_FRAME_TYPE_RESET_STREAM), - - /* Ensure sync. */ - OP_S_READ_EXPECT(d, "sync", 4), - OP_S_WRITE(d, "x", 1), - OP_C_READ_EXPECT(d, "x", 1), - - /* Send something that will make 'c' reset. */ - OP_S_SET_INJECT_PLAIN(script_28_inject_plain), - OP_SET_INJECT_WORD(C_BIDI_ID(2) + 1, OSSL_QUIC_FRAME_TYPE_STOP_SENDING), - - OP_S_NEW_STREAM_BIDI(z, S_BIDI_ID(0)), - OP_S_WRITE(z, "z", 1), - - /* Ensure sync. */ - OP_S_WRITE(d, "x", 1), - OP_C_READ_EXPECT(d, "x", 1), - - /* Check a is now readable. */ - OP_CHECK(script_85_poll, 1), - - OP_END -}; - -#define POLL_FMT "%s%s%s%s%s%s%s%s%s%s%s%s%s" -#define POLL_PRINTA(_revents_) \ - (_revents_) & SSL_POLL_EVENT_F ? "SSL_POLL_EVENT_F " : "", \ - (_revents_) & SSL_POLL_EVENT_EL ? "SSL_POLL_EVENT_EL " : "", \ - (_revents_) & SSL_POLL_EVENT_EC ? "SSL_POLL_EVENT_EC " : "", \ - (_revents_) & SSL_POLL_EVENT_ECD ? "SSL_POLL_EVENT_ECD " : "", \ - (_revents_) & SSL_POLL_EVENT_ER ? "SSL_POLL_EVENT_ER " : "", \ - (_revents_) & SSL_POLL_EVENT_EW ? "SSL_POLL_EVENT_EW " : "", \ - (_revents_) & SSL_POLL_EVENT_R ? "SSL_POLL_EVENT_R " : "", \ - (_revents_) & SSL_POLL_EVENT_W ? "SSL_POLL_EVENT_W " : "", \ - (_revents_) & SSL_POLL_EVENT_IC ? "SSL_POLL_EVENT_IC " : "", \ - (_revents_) & SSL_POLL_EVENT_ISB ? "SSL_POLL_EVENT_ISB " : "", \ - (_revents_) & SSL_POLL_EVENT_ISU ? "SSL_POLL_EVENT_ISU " : "", \ - (_revents_) & SSL_POLL_EVENT_OSB ? "SSL_POLL_EVENT_OSB " : "", \ - (_revents_) & SSL_POLL_EVENT_OSU ? "SSL_POLL_EVENT_OSU " : "" - -/* 88. Test SSL_poll (lite, non-blocking) */ -ossl_unused static int script_88_poll(struct helper *h, struct helper_local *hl) -{ - int ok = 1, ret, expected_ret = 1; - static const struct timeval timeout = { 0 }; - size_t result_count, processed; - SSL_POLL_ITEM items[2] = { 0 }, *item = items; - SSL *c_a; - size_t i; - uint64_t mode, expected_revents[2] = { 0 }; - - if (!TEST_ptr(c_a = helper_local_get_c_stream(hl, "a"))) - return 0; - - item->desc = SSL_as_poll_descriptor(c_a); - item->events = UINT64_MAX; - item->revents = UINT64_MAX; - ++item; - - item->desc = SSL_as_poll_descriptor(h->c_conn); - item->events = UINT64_MAX; - item->revents = UINT64_MAX; - ++item; - - result_count = SIZE_MAX; - ret = SSL_poll(items, OSSL_NELEM(items), sizeof(SSL_POLL_ITEM), - &timeout, 0, - &result_count); - - mode = hl->check_op->arg2; - switch (mode) { - case 0: - /* No incoming data yet */ - expected_revents[0] = SSL_POLL_EVENT_W; - expected_revents[1] = SSL_POLL_EVENT_OS; - break; - case 1: - /* Expect more events */ - expected_revents[0] = SSL_POLL_EVENT_R; - expected_revents[1] = SSL_POLL_EVENT_OS; - break; - default: - return 0; - } - - if (!TEST_int_eq(ret, expected_ret)) - ok = 0; - - /* - * Unlike script 85 which always expects all objects - * get signaled in single call to SSL_poll() we must - * assume here we can get notification for only one. - */ - processed = 0; - for (i = 0; i < OSSL_NELEM(items); ++i) { - if (items[i].revents == 0) - continue; - - processed++; - if (!TEST_uint64_t_eq(items[i].revents, expected_revents[i])) { - TEST_info("wanted: " POLL_FMT " got: " POLL_FMT, - POLL_PRINTA(expected_revents[i]), - POLL_PRINTA(items[i].revents)); - TEST_error("mismatch at index %zu in poll results, mode %d", - i, (int)mode); - ok = 0; - } - } - - if (!TEST_size_t_eq(processed, result_count)) - ok = 0; - - return ok; -} - -ossl_unused static int script_88_poll_conly(struct helper *h, struct helper_local *hl) -{ - int ok = 1; - static const struct timeval timeout = { 0 }; - size_t result_count; - SSL_POLL_ITEM items[1] = { 0 }; - int done = 0; - OSSL_TIME t_limit; - - result_count = SIZE_MAX; - - items[0].desc = SSL_as_poll_descriptor(h->c_conn); - items[0].events = UINT64_MAX; - items[0].revents = UINT64_MAX; - - t_limit = ossl_time_add(ossl_time_now(), - ossl_ticks2time(5 * OSSL_TIME_SECOND)); - while (done == 0 && ok == 1) { - ok = SSL_poll(items, OSSL_NELEM(items), sizeof(SSL_POLL_ITEM), - &timeout, 0, - &result_count); - - if (!TEST_int_eq(ok, 1)) - continue; - - if (result_count == 0) - OSSL_sleep(10); - - TEST_info("received event " POLL_FMT, POLL_PRINTA(items[0].revents)); - - if ((items[0].revents & SSL_POLL_EVENT_EC) == SSL_POLL_EVENT_EC) - SSL_shutdown(h->c_conn); - done = ((items[0].revents & SSL_POLL_EVENT_ECD) == SSL_POLL_EVENT_ECD); - - if (ossl_time_compare(ossl_time_now(), t_limit) == 1) { - TEST_error("shutdown time exceeded 5sec"); - ok = 0; - } - } - - return ok; -} - -/* - * verify SSL_poll() signals SSL_POLL_EVENT_EC event - * to notify client it's time to call SSL_shutdown(). - */ -static const struct script_op script_88[] = { - OP_SKIP_IF_BLOCKING(16), - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - - /* Check nothing readable yet. */ - OP_CHECK(script_88_poll, 0 /* ->arg2 */), - - OP_C_WRITE(a, "flamingo", 8), - OP_C_CONCLUDE(a), - - /* Send something that will make client sockets readable. */ - OP_S_READ_EXPECT(a, "flamingo", 8), - OP_S_WRITE(a, "flamingo", 8), - OP_S_CONCLUDE(a), - - OP_CHECK(script_88_poll, 1 /* ->arg2 */), - - OP_C_READ_EXPECT(a, "flamingo", 8), - - /* - * client calls non-blocking SSL_shutdown() and gives - * server chance to run by calling sleep. - */ - OP_C_SHUTDOWN(NULL, 0), - OP_SLEEP(100), - - /* - * Here we call SSL_poll() and handle SSL_POLL_EVENT_EC - * and SSL_POLL_EVENT_ECD on connection object. Whenever - * _EC event comes we call SSL_shutdown() to keep connection - * draining. We keep calling SSL_poll()/SSL_shutdown() until - * SSL_poll() signals SSL_POLL_EVENT_ECD to let us know connection - * has dried out and con be closed. - */ - OP_CHECK(script_88_poll_conly, 0), - - OP_END -}; -/* 86. Event Handling Mode Configuration */ -static int set_event_handling_mode_conn(struct helper *h, struct helper_local *hl) -{ - hl->explicit_event_handling = 1; - return SSL_set_event_handling_mode(h->c_conn, hl->check_op->arg2); -} - -static int reenable_test_event_handling(struct helper *h, struct helper_local *hl) -{ - hl->explicit_event_handling = 0; - return 1; -} - -static ossl_unused int set_event_handling_mode_stream(struct helper *h, struct helper_local *hl) -{ - SSL *ssl = helper_local_get_c_stream(hl, "a"); - - if (!TEST_ptr(ssl)) - return 0; - - return SSL_set_event_handling_mode(ssl, hl->check_op->arg2); -} - -static const struct script_op script_86[] = { - OP_SKIP_IF_BLOCKING(23), - - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - /* Turn on explicit handling mode. */ - OP_CHECK(set_event_handling_mode_conn, SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT), - - /* - * Create a new stream and write data. This won't get sent - * to the network net because we are in explicit mode - * and we haven't called SSL_handle_events(). - */ - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_C_WRITE(a, "apple", 5), - - /* Put connection back into implicit handling mode. */ - OP_CHECK(set_event_handling_mode_conn, SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT), - - /* Override at stream level. */ - OP_CHECK(set_event_handling_mode_stream, SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT), - OP_C_WRITE(a, "orange", 6), - OP_C_CONCLUDE(a), - - /* - * Confirm the data isn't going to arrive. OP_SLEEP is always undesirable - * but we have no reasonable way to synchronise on something not arriving - * given all network traffic is essentially stopped and there are no other - * signals arriving from the peer which could be used for synchronisation. - * Slow OSes will pass this anyway (fail-open). - */ - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - - OP_BEGIN_REPEAT(20), - OP_S_READ_FAIL(a, 1), - OP_SLEEP(10), - OP_END_REPEAT(), - - /* Now let the data arrive and confirm it arrives. */ - OP_CHECK(reenable_test_event_handling, 0), - OP_S_READ_EXPECT(a, "appleorange", 11), - OP_S_EXPECT_FIN(a), - - /* Back into explicit mode. */ - OP_CHECK(set_event_handling_mode_conn, - SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT), - OP_S_WRITE(a, "ok", 2), - OP_C_READ_FAIL(a), - - /* Works once event handling is done. */ - OP_CHECK(reenable_test_event_handling, 0), - OP_C_READ_EXPECT(a, "ok", 2), - - OP_END -}; - -/* 87. Test stream reset functionality */ -static const struct script_op script_87[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - OP_C_NEW_STREAM_BIDI(a, C_BIDI_ID(0)), - OP_C_WRITE(a, "apple", 5), - OP_C_CONCLUDE(a), - OP_S_BIND_STREAM_ID(a, C_BIDI_ID(0)), - OP_S_READ_EXPECT(a, "apple", 5), - OP_S_EXPECT_FIN(a), - OP_S_WRITE(a, "orange", 6), - OP_C_READ_EXPECT(a, "orange", 6), - OP_S_CONCLUDE(a), - OP_C_EXPECT_FIN(a), - OP_SLEEP(1000), - OP_C_STREAM_RESET_FAIL(a, 42), - OP_END -}; - -static int modify_udp_payload_size_max(struct helper *h, struct helper_local *hl) -{ - if (!TEST_false(SSL_set_feature_request_uint(h->c_conn, - SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, - QUIC_MIN_INITIAL_DGRAM_LEN - 1))) - return 0; - - if (!TEST_false(SSL_set_feature_request_uint(h->c_conn, - SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, - QUIC_DEFAULT_MAX_UDP_PAYLOAD_SIZE + 1))) - return 0; - - return modify_static_tp(h, hl, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX); -} - -static int check_udp_payload_size_max(struct helper *h, struct helper_local *hl) -{ - return check_static_tp(h, hl, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX); -} - -static int cannot_change_udp_payload_size_max(struct helper *h, struct helper_local *hl) -{ - return cannot_change_static_tp(h, hl, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX); -} - -/* 89. Max udp payload size configuration */ -static const struct script_op script_89[] = { - OP_C_SET_ALPN("ossltest"), - OP_CHECK(modify_udp_payload_size_max, QUIC_DEFAULT_MAX_UDP_PAYLOAD_SIZE), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_udp_payload_size_max, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_MIN_INITIAL_DGRAM_LEN), - OP_CHECK2(check_udp_payload_size_max, - SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_MAX_UDP_PAYLOAD_SIZE), - - OP_END -}; - -/* 90. Negotiated default max udp payload size if not configured */ -static const struct script_op script_90[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_udp_payload_size_max, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_MIN_INITIAL_DGRAM_LEN), - OP_CHECK2(check_udp_payload_size_max, - SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_MIN_INITIAL_DGRAM_LEN), - - OP_END -}; - -/* 91. No late changes to max udp payload size */ -static const struct script_op script_91[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(cannot_change_udp_payload_size_max, QUIC_MIN_INITIAL_DGRAM_LEN, - QUIC_DEFAULT_MAX_UDP_PAYLOAD_SIZE), - OP_CHECK2(check_udp_payload_size_max, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_MIN_INITIAL_DGRAM_LEN), - - OP_END -}; - -static int modify_window_con(struct helper *h, struct helper_local *hl) -{ - return modify_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWCON); -} - -static int check_window_con(struct helper *h, struct helper_local *hl) -{ - return check_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWCON); -} - -static int cannot_change_window_con(struct helper *h, struct helper_local *hl) -{ - return cannot_change_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWCON); -} - -/* 92. Connection window configuration */ -static const struct script_op script_92[] = { - OP_C_SET_ALPN("ossltest"), - OP_CHECK(modify_window_con, 800000), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_window_con, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 768 * 1024), - OP_CHECK2(check_window_con, SSL_VALUE_CLASS_FEATURE_REQUEST, 800000), - - OP_END -}; - -/* 93. Negotiated default connection window if not configured */ -static const struct script_op script_93[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_window_con, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 768 * 1024), - OP_CHECK2(check_window_con, SSL_VALUE_CLASS_FEATURE_REQUEST, 768 * 1024), - - OP_END -}; - -/* 94. No late changes to connection window */ -static const struct script_op script_94[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(cannot_change_window_con, 768 * 1024, 800000), - OP_CHECK2(check_window_con, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 768 * 1024), - - OP_END -}; - -static int modify_window_bidi_stream(struct helper *h, struct helper_local *hl) -{ - return modify_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWBSTR); -} - -static int check_window_bidi_stream(struct helper *h, struct helper_local *hl) -{ - return check_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWBSTR); -} - -static int cannot_change_window_bidi_stream(struct helper *h, struct helper_local *hl) -{ - return cannot_change_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWBSTR); -} - -/* 95. Bidi stream window configuration */ -static const struct script_op script_95[] = { - OP_C_SET_ALPN("ossltest"), - OP_CHECK(modify_window_bidi_stream, 600000), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_window_bidi_stream, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024), - OP_CHECK2(check_window_bidi_stream, SSL_VALUE_CLASS_FEATURE_REQUEST, 600000), - - OP_END -}; - -/* 96. Negotiated default bidi stream window if not configured */ -static const struct script_op script_96[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_window_bidi_stream, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024), - OP_CHECK2(check_window_bidi_stream, SSL_VALUE_CLASS_FEATURE_REQUEST, 512 * 1024), - - OP_END -}; - -/* 97. No late changes to bidi stream window */ -static const struct script_op script_97[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(cannot_change_window_bidi_stream, 512 * 1024, 600000), - OP_CHECK2(check_window_bidi_stream, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024), - - OP_END -}; - -static int modify_window_uni_stream(struct helper *h, struct helper_local *hl) -{ - return modify_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWUSTR); -} - -static int check_window_uni_stream(struct helper *h, struct helper_local *hl) -{ - return check_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWUSTR); -} - -static int cannot_change_window_uni_stream(struct helper *h, struct helper_local *hl) -{ - return cannot_change_static_tp(h, hl, SSL_VALUE_QUIC_WINDOWUSTR); -} - -/* 98. Uni stream window configuration */ -static const struct script_op script_98[] = { - OP_C_SET_ALPN("ossltest"), - OP_CHECK(modify_window_uni_stream, 600000), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_window_uni_stream, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024), - OP_CHECK2(check_window_uni_stream, SSL_VALUE_CLASS_FEATURE_REQUEST, 600000), - - OP_END -}; - -/* 99. Negotiated default uni stream window if not configured */ -static const struct script_op script_99[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_window_uni_stream, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024), - OP_CHECK2(check_window_uni_stream, SSL_VALUE_CLASS_FEATURE_REQUEST, 512 * 1024), - - OP_END -}; - -/* 100. No late changes to uni stream window */ -static const struct script_op script_100[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(cannot_change_window_uni_stream, 512 * 1024, 600000), - OP_CHECK2(check_window_uni_stream, SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024), - - OP_END -}; - -static int -modify_ack_delay_exponent(struct helper *h, struct helper_local *hl) -{ - if (!TEST_false(SSL_set_feature_request_uint(h->c_conn, - SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, - QUIC_MAX_ACK_DELAY_EXP + 1))) - return 0; - - return modify_static_tp(h, hl, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT); -} - -static int check_ack_delay_exponent(struct helper *h, struct helper_local *hl) -{ - return check_static_tp(h, hl, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT); -} - -static int cannot_change_ack_delay_exponent(struct helper *h, struct helper_local *hl) -{ - return cannot_change_static_tp(h, hl, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT); -} - -/* 101. Ack delay exponent configuration */ -static const struct script_op script_101[] = { - OP_C_SET_ALPN("ossltest"), - OP_CHECK(modify_ack_delay_exponent, QUIC_DEFAULT_ACK_DELAY_EXP + 1), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_ack_delay_exponent, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP), - OP_CHECK2(check_ack_delay_exponent, - SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP + 1), - - OP_END -}; - -/* 102. Negotiated default ack delay exponent if not configured */ -static const struct script_op script_102[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_ack_delay_exponent, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP), - OP_CHECK2(check_ack_delay_exponent, - SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP), - - OP_END -}; - -/* 103. No late changes to ack delay exponent */ -static const struct script_op script_103[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(cannot_change_ack_delay_exponent, QUIC_DEFAULT_ACK_DELAY_EXP, - QUIC_DEFAULT_ACK_DELAY_EXP + 1), - OP_CHECK2(check_ack_delay_exponent, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP), - - OP_END -}; - -static int modify_ack_delay_max(struct helper *h, struct helper_local *hl) -{ - if (!TEST_false(SSL_set_feature_request_uint(h->c_conn, - SSL_VALUE_QUIC_ACK_DELAY_MAX, - QUIC_MAX_MAX_ACK_DELAY + 1))) - return 0; - - return modify_static_tp(h, hl, SSL_VALUE_QUIC_ACK_DELAY_MAX); -} - -static int check_ack_delay_max(struct helper *h, struct helper_local *hl) -{ - return check_static_tp(h, hl, SSL_VALUE_QUIC_ACK_DELAY_MAX); -} - -static int cannot_change_ack_delay_max(struct helper *h, struct helper_local *hl) -{ - return cannot_change_static_tp(h, hl, SSL_VALUE_QUIC_ACK_DELAY_MAX); -} - -/* 104. Max ack delay configuration */ -static const struct script_op script_104[] = { - OP_C_SET_ALPN("ossltest"), - OP_CHECK(modify_ack_delay_max, QUIC_DEFAULT_MAX_ACK_DELAY / 2), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_ack_delay_max, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY), - OP_CHECK2(check_ack_delay_max, - SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY / 2), - - OP_END -}; - -/* 105. Negotiated default max ack delay if not configured */ -static const struct script_op script_105[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(check_ack_delay_max, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY), - OP_CHECK2(check_ack_delay_max, - SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY), - - OP_END -}; - -/* 106. No late changes to max ack delay */ -static const struct script_op script_106[] = { - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT(), - - OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE), - - OP_CHECK2(cannot_change_ack_delay_max, QUIC_DEFAULT_MAX_ACK_DELAY, - QUIC_DEFAULT_MAX_ACK_DELAY / 2), - OP_CHECK2(check_ack_delay_max, - SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY), - - OP_END -}; - -static const struct script_op *const scripts[] = { - script_1, - script_2, - script_3, - script_4, - script_5, - script_6, - script_7, - script_8, - script_9, - script_10, - script_11, - script_12, - script_13, - script_14, - script_15, - script_16, - script_17, - script_18, - script_19, - script_20, - script_21, - script_22, - script_23, - script_24, - script_25, - script_26, - script_27, - script_28, - script_29, - script_30, - script_31, - script_32, - script_33, - script_34, - script_35, - script_36, - script_37, - script_38, - script_39, - script_40, - script_41, - script_42, - script_43, - script_44, - script_45, - script_46, - script_47, - script_48, - script_49, - script_50, - script_51, - script_52, - script_53, - script_54, - script_55, - script_56, - script_57, - script_58, - script_59, - script_60, - script_61, - script_62, - script_63, - script_64, - script_65, - script_66, - script_67, - script_68, - script_69, - script_70, - script_71, - script_72, - script_73, - script_74, - script_75, - script_76, - script_77, - script_78, - script_79, - script_80, - script_81, - script_82, - script_83, - script_84, - script_85, - script_86, - script_87, - script_88, - script_89, - script_90, - script_91, - script_92, - script_93, - script_94, - script_95, - script_96, - script_97, - script_98, - script_99, - script_100, - script_101, - script_102, - script_103, - script_104, - script_105, - script_106, -}; - -static int test_script(int idx) -{ - int script_idx, free_order, blocking; - char script_name[64]; - - free_order = idx % 2; - idx /= 2; - - blocking = idx % 2; - idx /= 2; - - script_idx = idx; - - if (blocking && free_order) - return 1; /* don't need to test free_order twice */ - -#if !defined(OPENSSL_THREADS) - if (blocking) { - TEST_skip("cannot test in blocking mode without threads"); - return 1; - } -#endif - - snprintf(script_name, sizeof(script_name), "script %d", script_idx + 1); - - TEST_info("Running script %d (order=%d, blocking=%d)", script_idx + 1, - free_order, blocking); - - return run_script(scripts[script_idx], script_name, free_order, blocking); -} - -/* Dynamically generated tests. */ -static struct script_op dyn_frame_types_script[] = { - OP_S_SET_INJECT_PLAIN(script_21_inject_plain), - OP_SET_INJECT_WORD(0, 0), /* dynamic */ - - OP_C_SET_ALPN("ossltest"), - OP_C_CONNECT_WAIT_OR_FAIL(), - - OP_C_EXPECT_CONN_CLOSE_INFO(OSSL_QUIC_ERR_FRAME_ENCODING_ERROR, 0, 0), - - OP_END -}; - -struct forbidden_frame_type { - uint64_t pkt_type, frame_type, expected_err; -}; - -static const struct forbidden_frame_type forbidden_frame_types[] = { - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_VLINT_MAX, OSSL_QUIC_ERR_FRAME_ENCODING_ERROR }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_VLINT_MAX, OSSL_QUIC_ERR_FRAME_ENCODING_ERROR }, - { QUIC_PKT_TYPE_1RTT, OSSL_QUIC_VLINT_MAX, OSSL_QUIC_ERR_FRAME_ENCODING_ERROR }, - - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAM, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_RESET_STREAM, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STOP_SENDING, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_DATA, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAM, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_RESET_STREAM, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STOP_SENDING, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_DATA, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, - - /* Client uses a zero-length CID so this is not allowed. */ - { QUIC_PKT_TYPE_1RTT, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, -}; - -static ossl_unused int test_dyn_frame_types(int idx) -{ - size_t i; - char script_name[64]; - struct script_op *s = dyn_frame_types_script; - - for (i = 0; i < OSSL_NELEM(dyn_frame_types_script); ++i) - if (s[i].op == OPK_SET_INJECT_WORD) { - s[i].arg1 = (size_t)forbidden_frame_types[idx].pkt_type; - s[i].arg2 = forbidden_frame_types[idx].frame_type; - } else if (s[i].op == OPK_C_EXPECT_CONN_CLOSE_INFO) { - s[i].arg2 = forbidden_frame_types[idx].expected_err; - } - - snprintf(script_name, sizeof(script_name), - "dyn script %d", idx); - - return run_script(dyn_frame_types_script, script_name, 0, 0); -} - -OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n") - -int setup_tests(void) -{ -#if defined(_PUT_MODEL_) - return TEST_skip("QUIC is not supported by this build"); -#endif - - if (!test_skip_common_options()) { - TEST_error("Error parsing test options\n"); - return 0; - } - - if (!TEST_ptr(certfile = test_get_argument(0)) - || !TEST_ptr(keyfile = test_get_argument(1))) - return 0; - - ADD_ALL_TESTS(test_dyn_frame_types, OSSL_NELEM(forbidden_frame_types)); - ADD_ALL_TESTS(test_script, OSSL_NELEM(scripts) * 2 * 2); - return 1; -} diff --git a/test/radix/quic_ops.c b/test/radix/quic_ops.c index f1e61478426..c16509ea89c 100644 --- a/test/radix/quic_ops.c +++ b/test/radix/quic_ops.c @@ -382,6 +382,11 @@ DEF_FUNC(hf_accept_conn) if (conn == NULL) F_SPIN_AGAIN(); + if (!TEST_true(SSL_set_blocking_mode(conn, 0))) { + SSL_free(conn); + goto err; + } + if (!TEST_true(RADIX_PROCESS_set_ssl(RP(), conn_name, conn))) { SSL_free(conn); goto err; @@ -441,7 +446,7 @@ DEF_FUNC(hf_pop_err) return 1; } -DEF_FUNC(hf_stream_reset) +static int hf_stream_reset_impl(FUNC_CTX *fctx, int expect_success) { int ok = 0; const char *name; @@ -451,14 +456,29 @@ DEF_FUNC(hf_stream_reset) F_POP2(name, args.quic_error_code); REQUIRE_SSL(ssl); - if (!TEST_true(SSL_stream_reset(ssl, &args, sizeof(args)))) - goto err; + if (expect_success) { + if (!TEST_true(SSL_stream_reset(ssl, &args, sizeof(args)))) + goto err; + } else { + if (!TEST_false(SSL_stream_reset(ssl, &args, sizeof(args)))) + goto err; + } ok = 1; err: return ok; } +DEF_FUNC(hf_stream_reset) +{ + return hf_stream_reset_impl(fctx, 1); +} + +DEF_FUNC(hf_stream_reset_fail) +{ + return hf_stream_reset_impl(fctx, 0); +} + DEF_FUNC(hf_set_default_stream_mode) { int ok = 0; @@ -476,6 +496,23 @@ err: return ok; } +DEF_FUNC(hf_set_event_handling_mode) +{ + int ok = 0; + uint64_t mode; + SSL *ssl; + + F_POP(mode); + REQUIRE_SSL(ssl); + + if (!TEST_true(SSL_set_event_handling_mode(ssl, mode))) + goto err; + + ok = 1; +err: + return ok; +} + DEF_FUNC(hf_set_incoming_stream_policy) { int ok = 0; @@ -494,7 +531,7 @@ err: return ok; } -DEF_FUNC(hf_shutdown_wait) +static int hf_shutdown_impl(FUNC_CTX *fctx, int retry) { int ok = 0, ret; uint64_t flags; @@ -514,7 +551,7 @@ DEF_FUNC(hf_shutdown_wait) if (!TEST_int_ge(ret, 0)) goto err; - if (ret == 0) + if (retry && ret == 0) F_SPIN_AGAIN(); ok = 1; @@ -522,6 +559,25 @@ err: return ok; } +DEF_FUNC(hf_shutdown_wait) +{ + return hf_shutdown_impl(fctx, 1); +} + +/* + * Like hf_shutdown_wait, but only calls SSL_shutdown_ex() once rather than + * retrying until it reports the shutdown fully complete. Use only when the + * script itself is testing an app-managed, poll-driven shutdown sequence + * (e.g. a single non-blocking SSL_shutdown_ex() call followed by the script + * manually polling and re-driving shutdown) — hf_shutdown_wait's retry loop + * would otherwise drive the shutdown to completion here and there, silently + * bypassing the very sequence under test. + */ +DEF_FUNC(hf_shutdown_once) +{ + return hf_shutdown_impl(fctx, 0); +} + DEF_FUNC(hf_conclude) { int ok = 0; @@ -1715,6 +1771,173 @@ err: return ok; } +DEF_FUNC(hf_set_max_early_data) +{ + int ok = 0; + uint64_t value; + SSL *ssl; + QUIC_CHANNEL *ch; + + F_POP(value); + REQUIRE_SSL(ssl); + + ch = ossl_quic_conn_get_channel(ssl); + if (!TEST_true(SSL_set_max_early_data(ossl_quic_channel_get0_tls(ch), + (uint32_t)value))) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_FUNC(hf_stream_limit_probe) +{ + int ok = 0; + SSL *conn, *stream; + uint64_t flags, count, min_fail, fail_count = 0, i; + size_t written; + + F_POP2(count, min_fail); + F_POP(flags); + REQUIRE_SSL(conn); + + for (i = 0; i < count; ++i) { + stream = SSL_new_stream(conn, flags); + if (stream == NULL) { + if (!TEST_size_t_eq((size_t)ERR_GET_REASON(ERR_peek_last_error()), + (size_t)SSL_R_STREAM_COUNT_LIMITED)) + goto err; + + ++fail_count; + continue; + } + + if (!TEST_true(SSL_write_ex(stream, "apple", 5, &written))) { + SSL_free(stream); + goto err; + } + + SSL_free(stream); + } + + if (!TEST_uint64_t_ge(fail_count, min_fail)) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_FUNC(hf_check_idle_timeout) +{ + int ok = 0; + SSL *ssl; + uint64_t value_class, expected, v = 0; + + F_POP(expected); + F_POP(value_class); + REQUIRE_SSL(ssl); + + if (!TEST_true(SSL_get_value_uint(ssl, (uint32_t)value_class, + SSL_VALUE_QUIC_IDLE_TIMEOUT, &v)) + || !TEST_uint64_t_eq(v, expected)) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_FUNC(hf_modify_value_uint) +{ + int ok = 0; + SSL *ssl; + uint64_t ssl_value, requested, v = 0; + + F_POP(requested); + F_POP(ssl_value); + REQUIRE_SSL(ssl); + + /* Test bad value is rejected. */ + if (!TEST_false(SSL_set_feature_request_uint(ssl, (uint32_t)ssl_value, + OSSL_QUIC_VLINT_MAX + 1))) + goto err; + + /* Set value. */ + if (!TEST_true(SSL_set_feature_request_uint(ssl, (uint32_t)ssl_value, + requested)) + || !TEST_true(SSL_get_feature_request_uint(ssl, (uint32_t)ssl_value, &v)) + || !TEST_uint64_t_eq(v, requested)) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_FUNC(hf_reject_value_uint) +{ + int ok = 0; + SSL *ssl; + uint64_t ssl_value, bad; + + F_POP(bad); + F_POP(ssl_value); + REQUIRE_SSL(ssl); + + if (!TEST_false(SSL_set_feature_request_uint(ssl, (uint32_t)ssl_value, + bad))) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_FUNC(hf_check_value_uint) +{ + int ok = 0; + SSL *ssl; + uint64_t ssl_value, value_class, expected, v = 0; + + F_POP(expected); + F_POP(value_class); + F_POP(ssl_value); + REQUIRE_SSL(ssl); + + if (!TEST_true(SSL_get_value_uint(ssl, (uint32_t)value_class, + (uint32_t)ssl_value, &v)) + || !TEST_uint64_t_eq(v, expected)) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_FUNC(hf_cannot_change_value_uint) +{ + int ok = 0; + SSL *ssl; + uint64_t ssl_value, current, requested, v = 0; + + F_POP(requested); + F_POP(current); + F_POP(ssl_value); + REQUIRE_SSL(ssl); + + if (!TEST_true(SSL_get_feature_request_uint(ssl, (uint32_t)ssl_value, &v)) + || !TEST_uint64_t_eq(v, current) + || !TEST_false(SSL_set_feature_request_uint(ssl, (uint32_t)ssl_value, + requested))) + goto err; + + ok = 1; +err: + return ok; +} + #define OP_UNBIND(name) \ (OP_PUSH_PZ(#name), \ OP_FUNC(hf_unbind)) @@ -1892,6 +2115,11 @@ err: OP_PUSH_U64(mode), \ OP_FUNC(hf_set_default_stream_mode)) +#define OP_SET_EVENT_HANDLING_MODE(name, mode) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_U64(mode), \ + OP_FUNC(hf_set_event_handling_mode)) + #define OP_SET_INCOMING_STREAM_POLICY(name, policy, error_code) \ (OP_SELECT_SSL(0, name), \ OP_PUSH_U64(policy), \ @@ -1904,6 +2132,12 @@ err: OP_PUSH_U64(error_code), \ OP_FUNC(hf_stream_reset)) +#define OP_STREAM_RESET_FAIL(name, error_code) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_PZ(#name), \ + OP_PUSH_U64(error_code), \ + OP_FUNC(hf_stream_reset_fail)) + #define OP_SHUTDOWN_WAIT(name, flags, error_code, reason) \ (OP_SELECT_SSL(0, name), \ OP_PUSH_U64(flags), \ @@ -1911,6 +2145,13 @@ err: OP_PUSH_PZ(reason), \ OP_FUNC(hf_shutdown_wait)) +#define OP_SHUTDOWN_ONCE(name, flags, error_code, reason) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_U64(flags), \ + OP_PUSH_U64(error_code), \ + OP_PUSH_PZ(reason), \ + OP_FUNC(hf_shutdown_once)) + #define OP_EXPECT_FIN(name) \ (OP_SELECT_SSL(0, name), \ OP_FUNC(hf_expect_fin)) @@ -2067,3 +2308,47 @@ err: (OP_SELECT_SSL(0, name), \ OP_PUSH_SIZE(size), \ OP_FUNC(hf_set_write_buf_size)) + +#define OP_SET_MAX_EARLY_DATA(name, value) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_U64(value), \ + OP_FUNC(hf_set_max_early_data)) + +#define OP_STREAM_LIMIT_PROBE(conn_name, flags, count, min_fail) \ + (OP_SELECT_SSL(0, conn_name), \ + OP_PUSH_U64(flags), \ + OP_PUSH_U64(count), \ + OP_PUSH_U64(min_fail), \ + OP_FUNC(hf_stream_limit_probe)) + +#define OP_CHECK_IDLE_TIMEOUT(name, value_class, expected_ms) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_U64(value_class), \ + OP_PUSH_U64(expected_ms), \ + OP_FUNC(hf_check_idle_timeout)) + +#define OP_MODIFY_VALUE_UINT(name, ssl_value, requested) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_U64(ssl_value), \ + OP_PUSH_U64(requested), \ + OP_FUNC(hf_modify_value_uint)) + +#define OP_REJECT_VALUE_UINT(name, ssl_value, bad) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_U64(ssl_value), \ + OP_PUSH_U64(bad), \ + OP_FUNC(hf_reject_value_uint)) + +#define OP_CHECK_VALUE_UINT(name, ssl_value, value_class, expected) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_U64(ssl_value), \ + OP_PUSH_U64(value_class), \ + OP_PUSH_U64(expected), \ + OP_FUNC(hf_check_value_uint)) + +#define OP_CANNOT_CHANGE_VALUE_UINT(name, ssl_value, current, requested) \ + (OP_SELECT_SSL(0, name), \ + OP_PUSH_U64(ssl_value), \ + OP_PUSH_U64(current), \ + OP_PUSH_U64(requested), \ + OP_FUNC(hf_cannot_change_value_uint)) diff --git a/test/radix/quic_tests.c b/test/radix/quic_tests.c index c23f299764e..5b6a84db38e 100644 --- a/test/radix/quic_tests.c +++ b/test/radix/quic_tests.c @@ -1039,20 +1039,6 @@ err: return ok; } -/* - * script_5 - script_106 are place holders for tests we - * currently keep in test/quic_multistream_test.c. - * We need to move those here so we can get rid off - * QUIC T-server mock-up. - * - * there should be one PR for each script being moved here, - * to make reviewer's life easier. Once all scripts will be - * moved we can find better names for script_5, ..., script_106. - * - * The scaffolding here hopes to avoid conflicts in 'scripts' - * array below when more PRs will be in flight. - */ - /* 5. Test stream reset functionality */ DEF_SCRIPT(script_5, "Test stream reset functionality") { @@ -1918,6 +1904,108 @@ DEF_SCRIPT(script_21, "Fault injection - unknown frame in 1-RTT packet") OP_EXPECT_CONN_CLOSE_INFO(C, OSSL_QUIC_ERR_FRAME_ENCODING_ERROR, 0, 0); } +struct forbidden_frame_type { + uint64_t pkt_type, frame_type, expected_err; +}; + +static const struct forbidden_frame_type forbidden_frame_types[] = { + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_VLINT_MAX, OSSL_QUIC_ERR_FRAME_ENCODING_ERROR }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_VLINT_MAX, OSSL_QUIC_ERR_FRAME_ENCODING_ERROR }, + { QUIC_PKT_TYPE_1RTT, OSSL_QUIC_VLINT_MAX, OSSL_QUIC_ERR_FRAME_ENCODING_ERROR }, + + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAM, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_RESET_STREAM, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STOP_SENDING, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_DATA, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAM, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_RESET_STREAM, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STOP_SENDING, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_DATA, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, + + /* Client uses a zero-length CID so this is not allowed. */ + { QUIC_PKT_TYPE_1RTT, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID, OSSL_QUIC_ERR_PROTOCOL_VIOLATION }, +}; + +static int forbidden_frame_client_hello_cb(SSL *s, int *al, void *arg) +{ + radix_fault.ch = ossl_quic_conn_get_channel(s); + return ossl_quic_channel_set_mutator(radix_fault.ch, radix_fault_mutate, + radix_fault_finish, &radix_fault); +} + +DEF_FUNC(arm_forbidden_frame) +{ + int ok = 0; + SSL *listener; + + REQUIRE_SSL(listener); + + OPENSSL_free((unsigned char *)radix_fault.io.buf); + memset(&radix_fault, 0, sizeof(radix_fault)); + radix_fault.cb = script_21_inject_plain; + F_POP2(radix_fault.word0, radix_fault.word1); + + SSL_CTX_set_client_hello_cb(SSL_get_SSL_CTX(listener), + forbidden_frame_client_hello_cb, NULL); + + TEST_info("Packet type %llu, frame type %llu", + (unsigned long long)radix_fault.word0, + (unsigned long long)radix_fault.word1); + ok = 1; +err: + return ok; +} + +DEF_SCRIPT(forbidden_frame_types, "Fault injection - forbidden frame types") +{ + size_t i; + + for (i = 0; i < OSSL_NELEM(forbidden_frame_types); ++i) { + OP_CLEAR(); + OP_NEW_SSL_L_LISTEN(L); + + OP_SELECT_SSL(0, L); + OP_PUSH_U64(forbidden_frame_types[i].pkt_type); + OP_PUSH_U64(forbidden_frame_types[i].frame_type); + OP_FUNC(arm_forbidden_frame); + + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + OP_CONNECT_WAIT_OR_FAIL(C); + + OP_EXPECT_CONN_CLOSE_INFO(C, forbidden_frame_types[i].expected_err, 0, 0); + } +} + /* 22. Fault injection - non-zero packet header reserved bits */ static int script_22_inject_plain(RADIX_FAULT *fault, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) @@ -3939,152 +4027,1462 @@ DEF_SCRIPT(script_69, "Send a TLS KeyUpdate message post-handshake") OP_EXPECT_CONN_CLOSE_INFO(C, OSSL_QUIC_ERR_CRYPTO_ERR_BEGIN + SSL_AD_UNEXPECTED_MESSAGE, 0, 0); } -DEF_SCRIPT(script_70, "place holder for multistrem script_70") +DEF_SCRIPT(script_70, "Send a TLS NewSessionTicket message with invalid max_early_data") +{ + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + OP_NEW_STREAM(C, Ca, 0); + OP_WRITE(Ca, "apple", 5); + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); + + OP_SET_MAX_EARLY_DATA(S, 0xfffffffe); + OP_ENGINE_TICK_DISABLE(S); + OP_NEW_TICKET(S); + OP_WRITE(Sa, "orange", 6); + OP_ENGINE_TICK_ENABLE(S); + + OP_EXPECT_CONN_CLOSE_INFO(C, OSSL_QUIC_ERR_PROTOCOL_VIOLATION, 0, 0); +} + +DEF_SCRIPT(script_71, "Send a TLS NewSessionTicket message with valid max_early_data") +{ + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + OP_NEW_STREAM(C, Ca, 0); + OP_WRITE(Ca, "apple", 5); + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); + + OP_SET_MAX_EARLY_DATA(S, 0xffffffff); + OP_NEW_TICKET(S); + OP_WRITE(Sa, "orange", 6); + OP_READ_EXPECT(Ca, "orange", 6); +} + +DEF_SCRIPT(script_72, "Test that APL stops handing out streams after limit reached (bidi)") +{ + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + /* + * Request more streams than a server will initially hand out and test that + * they fail properly. + */ + OP_STREAM_LIMIT_PROBE(C, SSL_STREAM_FLAG_NO_BLOCK, 200, 50); +} + +DEF_SCRIPT(script_73, "Test that APL stops handing out streams after limit reached (uni)") +{ + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + /* + * Request more streams than a server will initially hand out and test that + * they fail properly. + */ + OP_STREAM_LIMIT_PROBE(C, SSL_STREAM_FLAG_UNI | SSL_STREAM_FLAG_NO_BLOCK, 200, 50); +} + +/* + * Check packets to transmit, if we have an initial packet + * Modify the version number to something incorrect + * so that we trigger a version negotiation + * Note, this is a use once function, it will only modify the + * first INITIAL packet it sees, after which it needs to be + * armed again + */ +static int do_mutation_74 = 0; +static QUIC_PKT_HDR *hdr_to_free_74 = NULL; + +static int script_74_alter_version(const QUIC_PKT_HDR *hdrin, + const OSSL_QTX_IOVEC *iovecin, size_t numin, + QUIC_PKT_HDR **hdrout, + const OSSL_QTX_IOVEC **iovecout, + size_t *numout, + void *arg) +{ + *hdrout = OPENSSL_memdup(hdrin, sizeof(QUIC_PKT_HDR)); + *iovecout = iovecin; + *numout = numin; + hdr_to_free_74 = *hdrout; + + if (do_mutation_74 == 0) + return 1; + do_mutation_74 = 0; + + if (hdrin->type == QUIC_PKT_TYPE_INITIAL) + (*hdrout)->version = 0xdeadbeef; + return 1; +} + +static void script_74_finish_mutation(void *arg) +{ + OPENSSL_free(hdr_to_free_74); +} + +/* + * Enable the packet mutator for the client channel + * So that when we send a Initial packet + * We modify the version to be something invalid + * to force a version negotiation + */ +DEF_FUNC(script_74_arm_packet_mutator) +{ + int ok = 0; + SSL *ssl; + QUIC_CHANNEL *ch; + + REQUIRE_SSL(ssl); + ch = ossl_quic_conn_get_channel(ssl); + + do_mutation_74 = 1; + if (!TEST_true(ossl_quic_channel_set_mutator(ch, script_74_alter_version, + script_74_finish_mutation, NULL))) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_SCRIPT(script_74, "Version negotiation: QUIC_VERSION_1 ignored") +{ + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_SELECT_SSL(0, C); + OP_FUNC(script_74_arm_packet_mutator); + + OP_CONNECT_WAIT(C); + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + OP_NEW_STREAM(C, Ca, 0); + OP_WRITE(Ca, "apple", 5); + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); +} + +/* + * No channel exists yet for an unaccepted connection, so the usual + * RADIX_FAULT channel mutator can't intercept this datagram; filter the + * listener's wbio directly instead. + */ +#define BIO_TYPE_SCRIPT_75_FILTER (0x80 | BIO_TYPE_FILTER) +static BIO_METHOD *script_75_filter_meth; +static uint32_t script_75_word0; + +static int script_75_sendmmsg(BIO *b, BIO_MSG *msg, size_t stride, + size_t num_msg, uint64_t flags, size_t *msgs_processed) +{ + BIO *next = BIO_next(b); + QUIC_PKT_HDR hdr; + WPACKET wpkt; + size_t written; + + if (next == NULL) + return 0; + + if (script_75_word0 != 0 && num_msg > 0) { + memset(&hdr, 0, sizeof(hdr)); + hdr.type = QUIC_PKT_TYPE_VERSION_NEG; + hdr.version = 0; + hdr.fixed = 1; + hdr.dst_conn_id.id_len = 0; + hdr.src_conn_id.id_len = 8; + memset(hdr.src_conn_id.id, 0x55, 8); + + if (!TEST_true(WPACKET_init_static_len(&wpkt, msg[0].data, + msg[0].data_len, 0))) + return 0; + + if (!TEST_true(ossl_quic_wire_encode_pkt_hdr(&wpkt, 0, &hdr, NULL)) + || !TEST_true(WPACKET_put_bytes_u32(&wpkt, + script_75_word0 == 1 ? QUIC_VERSION_1 : 0x5432abcd)) + || !TEST_true(WPACKET_get_total_written(&wpkt, &written))) { + WPACKET_cleanup(&wpkt); + return 0; + } + WPACKET_finish(&wpkt); + + msg[0].data_len = written; + script_75_word0 = 0; + } + + return BIO_sendmmsg(next, msg, stride, num_msg, flags, msgs_processed); +} + +static long script_75_ctrl(BIO *b, int cmd, long larg, void *parg) +{ + BIO *next = BIO_next(b); + + if (next == NULL) + return -1; + + return BIO_ctrl(next, cmd, larg, parg); +} + +DEF_FUNC(script_75_arm_version_neg) +{ + int ok = 0; + SSL *listener; + BIO *filter, *real_wbio; + + REQUIRE_SSL(listener); + + script_75_word0 = 2; /* unknown version */ + + if (script_75_filter_meth == NULL) { + if (!TEST_ptr(script_75_filter_meth = BIO_meth_new( + BIO_TYPE_SCRIPT_75_FILTER, "Version Negotiation Filter"))) + goto err; + if (!TEST_true(BIO_meth_set_sendmmsg(script_75_filter_meth, + script_75_sendmmsg)) + || !TEST_true(BIO_meth_set_ctrl(script_75_filter_meth, + script_75_ctrl))) + goto err; + } + + if (!TEST_ptr(real_wbio = SSL_get_wbio(listener))) + goto err; + if (!TEST_true(BIO_up_ref(real_wbio))) + goto err; + + if (!TEST_ptr(filter = BIO_new(script_75_filter_meth))) { + BIO_free(real_wbio); + goto err; + } + + if (!TEST_ptr(BIO_push(filter, real_wbio))) { + BIO_free(real_wbio); + BIO_free(filter); + goto err; + } + + SSL_set0_wbio(listener, filter); + + ok = 1; +err: + return ok; +} + +DEF_SCRIPT(script_75, "Version negotiation: Unknown version causes connection abort") +{ + OP_NEW_SSL_L_LISTEN(L); + + OP_SELECT_SSL(0, L); + OP_FUNC(script_75_arm_version_neg); + + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + OP_CONNECT_WAIT_OR_FAIL(C); + + OP_EXPECT_CONN_CLOSE_INFO(C, OSSL_QUIC_ERR_CONNECTION_REFUSED, 0, 0); +} + +DEF_FUNC(check_peer_shutdown_wait_76) +{ + int ok = 0; + SSL *ssl; + + REQUIRE_SSL(ssl); + + if (!TEST_false(SSL_shutdown_ex(ssl, + SSL_SHUTDOWN_FLAG_WAIT_PEER | SSL_SHUTDOWN_FLAG_NO_BLOCK, + NULL, 0))) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_SCRIPT(script_76, "Test peer-initiated shutdown wait") +{ + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + OP_NEW_STREAM(C, Ca, 0); + OP_WRITE(Ca, "apple", 5); + + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); + + /* Check a WAIT_PEER call doesn't succeed yet. */ + OP_SELECT_SSL(0, C); + OP_FUNC(check_peer_shutdown_wait_76); + + OP_SHUTDOWN_WAIT(S, 0, 42, NULL); + + OP_SHUTDOWN_WAIT(C, SSL_SHUTDOWN_FLAG_WAIT_PEER, 0, NULL); + OP_EXPECT_CONN_CLOSE_INFO(C, 42, 1, 1); +} + +DEF_SCRIPT(script_77, "Ensure default stream popping operates correctly") +{ + OP_SIMPLE_PAIR_CONN(); + OP_ACCEPT_CONN_WAIT(L, S, 0); + + OP_SET_INCOMING_STREAM_POLICY(C, SSL_INCOMING_STREAM_POLICY_ACCEPT, 0); + + OP_NEW_STREAM(S, Sa, 0); + OP_WRITE(Sa, "Strawberry", 10); + + OP_READ_EXPECT(C, "Strawberry", 10); + + OP_NEW_STREAM(S, Sb, 0); + OP_WRITE(Sb, "xyz", 3); + + OP_ACCEPT_STREAM_WAIT(C, Cb, 0); + OP_READ_EXPECT(Cb, "xyz", 3); +} + +static size_t new_session_count_78; + +static int on_new_session_78(SSL *s, SSL_SESSION *sess) +{ + ++new_session_count_78; + return 0; /* do not ref session, we aren't keeping it */ +} + +DEF_FUNC(setup_session_78) { + int ok = 0; + SSL *ssl; + SSL_CTX *ctx; + + REQUIRE_SSL(ssl); + ctx = SSL_get_SSL_CTX(ssl); + + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH); + SSL_CTX_sess_set_new_cb(ctx, on_new_session_78); + + ok = 1; +err: + return ok; } -DEF_SCRIPT(script_71, "place holder for multistrem script_71") +DEF_FUNC(reset_new_session_count_78) { + new_session_count_78 = 0; + return 1; } -DEF_SCRIPT(script_72, "place holder for multistrem script_72") +DEF_FUNC(check_got_session_ticket_78) { + return TEST_size_t_gt(new_session_count_78, 0); } -DEF_SCRIPT(script_73, "place holder for multistrem script_73") +DEF_SCRIPT(script_78, "Post-connection session ticket handling") { + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_SELECT_SSL(0, C); + OP_FUNC(setup_session_78); + + OP_CONNECT_WAIT(C); + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + OP_NEW_STREAM(C, Ca, 0); + OP_WRITE(Ca, "apple", 5); + + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); + + OP_WRITE(Sa, "orange", 6); + OP_READ_EXPECT(Ca, "orange", 6); + + OP_FUNC(reset_new_session_count_78); + OP_NEW_TICKET(S); + + OP_WRITE(Sa, "Strawberry", 10); + OP_READ_EXPECT(Ca, "Strawberry", 10); + + OP_FUNC(check_got_session_ticket_78); + OP_CHECK_IDLE_TIMEOUT(C, SSL_VALUE_CLASS_FEATURE_NEGOTIATED, 30000); +} + +DEF_SCRIPT(script_79, "Optimised FIN test") +{ + OP_SIMPLE_PAIR_CONN(); + OP_ACCEPT_CONN_WAIT(L, S, 0); + + OP_WRITE_EX2(C, "apple", 5, SSL_WRITE_FLAG_CONCLUDE); + + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); + OP_EXPECT_FIN(Sa); + OP_WRITE(Sa, "orange", 6); + OP_CONCLUDE(Sa); + + OP_READ_EXPECT(C, "orange", 6); + OP_EXPECT_FIN(C); +} + +/* 80. Stateless reset detection test */ +static QUIC_STATELESS_RESET_TOKEN script_80_reset_token = { + { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef } +}; + +static SSL *script_80_c_ssl; +static BIO_ADDR *script_80_s_addr; + +DEF_FUNC(setup_stateless_reset_80) +{ + int ok = 0; + SSL *c_ssl, *s_ssl; + BIO *s_bio; + int s_fd = -1; + union BIO_sock_info_u s_info; + + REQUIRE_SSL_2(c_ssl, s_ssl); + + script_80_c_ssl = c_ssl; + BIO_ADDR_free(script_80_s_addr); + + if (!TEST_ptr(s_bio = SSL_get_rbio(s_ssl)) + || !TEST_ptr(script_80_s_addr = BIO_ADDR_new()) + || !TEST_true(BIO_get_fd(s_bio, &s_fd)) || !TEST_int_ge(s_fd, 0)) + goto err; + + s_info.addr = script_80_s_addr; + if (!TEST_true(BIO_sock_info(s_fd, BIO_SOCK_INFO_ADDRESS, &s_info))) + goto err; + + ok = 1; +err: + return ok; +} + +DEF_FUNC(cleanup_stateless_reset_80) +{ + BIO_ADDR_free(script_80_s_addr); + script_80_s_addr = NULL; + script_80_c_ssl = NULL; + return 1; +} + +/* + * Generate a packet in the following format: + * https://www.rfc-editor.org/rfc/rfc9000.html#name-stateless-reset + * Stateless Reset { + * Fixed Bits (2): 1 + * Unpredictable bits (38..) + * Stateless reset token (128) + * } + */ +static int script_80_send_stateless_reset(RADIX_FAULT *fault, QUIC_PKT_HDR *hdr, + unsigned char *buf, size_t len) +{ + unsigned char databuf[64]; + + if (fault->word1 == 0) + return 1; + + fault->word1 = 0; + + fprintf(stderr, "Sending stateless reset\n"); + + RAND_bytes(databuf, 64); + databuf[0] = 0x40; + memcpy(&databuf[48], script_80_reset_token.token, + sizeof(script_80_reset_token.token)); + + if (!TEST_int_eq(SSL_inject_net_dgram(script_80_c_ssl, databuf, sizeof(databuf), + NULL, script_80_s_addr), + 1)) + return 0; + + return 1; +} + +static int script_80_gen_new_conn_id(RADIX_FAULT *fault, QUIC_PKT_HDR *hdr, + unsigned char *buf, size_t len) +{ + int rc = 0; + size_t l; + unsigned char frame_buf[64]; + WPACKET wpkt; + QUIC_CONN_ID new_cid = { 0 }; + OSSL_QUIC_FRAME_NEW_CONN_ID ncid = { 0 }; + + if (fault->word0 == 0) + return 1; + + fault->word0 = 0; + + fprintf(stderr, "sending new conn id\n"); + if (!TEST_true(WPACKET_init_static_len(&wpkt, frame_buf, + sizeof(frame_buf), 0))) + return 0; + + ossl_quic_channel_get_diag_local_cid(fault->ch, &new_cid); + + ncid.seq_num = 2; + ncid.retire_prior_to = 2; + ncid.conn_id = new_cid; + memcpy(ncid.stateless_reset.token, script_80_reset_token.token, + sizeof(script_80_reset_token.token)); + + if (!TEST_true(ossl_quic_wire_encode_frame_new_conn_id(&wpkt, &ncid))) + goto err; + + if (!TEST_true(WPACKET_get_total_written(&wpkt, &l))) + goto err; + + if (!radix_fault_prepend_frame(fault, frame_buf, l)) + goto err; + + rc = 1; +err: + if (rc) + WPACKET_finish(&wpkt); + else + WPACKET_cleanup(&wpkt); + + return rc; +} + +static int script_80_inject_pkt(RADIX_FAULT *fault, QUIC_PKT_HDR *hdr, + unsigned char *buf, size_t len) +{ + if (fault->word1 == 1) + return script_80_send_stateless_reset(fault, hdr, buf, len); + else if (fault->word0 == 1) + return script_80_gen_new_conn_id(fault, hdr, buf, len); + + return 1; } -DEF_SCRIPT(script_74, "place holder for multistrem script_74") +DEF_SCRIPT(script_80, "Stateless reset detection test") { + OP_SIMPLE_PAIR_CONN(); + OP_ACCEPT_CONN_WAIT(L, S, 0); + + OP_SELECT_SSL(0, C); + OP_SELECT_SSL(1, S); + OP_FUNC(setup_stateless_reset_80); + + OP_SET_INJECT_PLAIN(S, script_80_inject_pkt); + + OP_WRITE(C, "apple", 5); + OP_CONCLUDE(C); + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); + OP_SET_INJECT_WORD(1, 0); + OP_WRITE(Sa, "apple", 5); + OP_READ_EXPECT(C, "apple", 5); + OP_SET_INJECT_WORD(0, 1); + OP_WRITE(Sa, "apple", 5); + OP_EXPECT_CONN_CLOSE_INFO(C, 0, 0, 1); + + OP_FUNC(cleanup_stateless_reset_80); } -DEF_SCRIPT(script_75, "place holder for multistrem script_75") +/* 81. Idle timeout configuration */ +DEF_SCRIPT(script_81, "Idle timeout configuration") { + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_MODIFY_VALUE_UINT(C, SSL_VALUE_QUIC_IDLE_TIMEOUT, 25000); + + OP_CONNECT_WAIT(C); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_IDLE_TIMEOUT, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 30000); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_IDLE_TIMEOUT, + SSL_VALUE_CLASS_FEATURE_NEGOTIATED, 25000); } -DEF_SCRIPT(script_76, "place holder for multistrem script_76") +/* 82. Negotiated default idle timeout if not configured */ +DEF_SCRIPT(script_82, "Negotiated default idle timeout if not configured") { + OP_SIMPLE_PAIR_CONN_ND(); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_IDLE_TIMEOUT, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 30000); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_IDLE_TIMEOUT, + SSL_VALUE_CLASS_FEATURE_NEGOTIATED, 30000); } -DEF_SCRIPT(script_77, "place holder for multistrem script_77") +/* 83. No late changes to idle timeout */ +DEF_SCRIPT(script_83, "No late changes to idle timeout") { + OP_SIMPLE_PAIR_CONN_ND(); + + OP_CANNOT_CHANGE_VALUE_UINT(C, SSL_VALUE_QUIC_IDLE_TIMEOUT, 30000, 5000); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_IDLE_TIMEOUT, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 30000); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_IDLE_TIMEOUT, + SSL_VALUE_CLASS_FEATURE_NEGOTIATED, 30000); } -DEF_SCRIPT(script_78, "place holder for multistrem script_78") +/* 84. Test query of available streams */ +DEF_FUNC(check_avail_streams_84) { + int ok = 0; + SSL *ssl; + uint64_t kind, expected, v = 0; + + F_POP(expected); + F_POP(kind); + REQUIRE_SSL(ssl); + + switch (kind) { + case 0: + if (!TEST_true(SSL_get_quic_stream_bidi_local_avail(ssl, &v))) + goto err; + break; + case 1: + if (!TEST_true(SSL_get_quic_stream_bidi_remote_avail(ssl, &v))) + goto err; + break; + case 2: + if (!TEST_true(SSL_get_quic_stream_uni_local_avail(ssl, &v))) + goto err; + break; + case 3: + if (!TEST_true(SSL_get_quic_stream_uni_remote_avail(ssl, &v))) + goto err; + break; + default: + goto err; + } + + if (!TEST_uint64_t_eq(v, expected)) + goto err; + + ok = 1; +err: + return ok; } -DEF_SCRIPT(script_79, "place holder for multistrem script_79") +DEF_FUNC(check_write_buf_stat_84) { + int ok = 0; + SSL *ssl; + uint64_t used, size, actual_used, avail; + + F_POP(used); + REQUIRE_SSL(ssl); + + if (!TEST_true(SSL_get_stream_write_buf_size(ssl, &size)) + || !TEST_true(SSL_get_stream_write_buf_used(ssl, &actual_used)) + || !TEST_true(SSL_get_stream_write_buf_avail(ssl, &avail)) + || !TEST_uint64_t_ge(size, avail) + || !TEST_uint64_t_ge(size, actual_used) + || !TEST_uint64_t_eq(avail + actual_used, size) + || !TEST_uint64_t_eq(actual_used, used)) + goto err; + + ok = 1; +err: + return ok; } -DEF_SCRIPT(script_80, "place holder for multistrem script_80") +#define CHECK_AVAIL_84(kind, expected) \ + do { \ + OP_PUSH_U64(kind); \ + OP_PUSH_U64(expected); \ + OP_SELECT_SSL(0, C); \ + OP_FUNC(check_avail_streams_84); \ + } while (0) + +DEF_SCRIPT(script_84, "Test query of available streams") { + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + CHECK_AVAIL_84(0, 100); + CHECK_AVAIL_84(1, 100); + CHECK_AVAIL_84(2, 100); + CHECK_AVAIL_84(3, 100); + + OP_NEW_STREAM(C, Ca, 0); + + CHECK_AVAIL_84(0, 99); + CHECK_AVAIL_84(1, 100); + CHECK_AVAIL_84(2, 100); + CHECK_AVAIL_84(3, 100); + + OP_NEW_STREAM(C, Cb, SSL_STREAM_FLAG_UNI); + + CHECK_AVAIL_84(0, 99); + CHECK_AVAIL_84(1, 100); + CHECK_AVAIL_84(2, 99); + CHECK_AVAIL_84(3, 100); + + OP_NEW_STREAM(S, Sc, 0); + OP_WRITE(Sc, "x", 1); + + OP_ACCEPT_STREAM_WAIT(C, Cc, 0); + OP_READ_EXPECT(Cc, "x", 1); + + CHECK_AVAIL_84(0, 99); + CHECK_AVAIL_84(1, 99); + CHECK_AVAIL_84(2, 99); + CHECK_AVAIL_84(3, 100); + + OP_NEW_STREAM(S, Sd, SSL_STREAM_FLAG_UNI); + OP_WRITE(Sd, "x", 1); + + OP_ACCEPT_STREAM_WAIT(C, Cd, 0); + OP_READ_EXPECT(Cd, "x", 1); + + CHECK_AVAIL_84(0, 99); + CHECK_AVAIL_84(1, 99); + CHECK_AVAIL_84(2, 99); + CHECK_AVAIL_84(3, 99); + + OP_PUSH_U64(0); + OP_SELECT_SSL(0, Ca); + OP_FUNC(check_write_buf_stat_84); + + OP_TICK_DISABLE(C); + OP_SET_EVENT_HANDLING_MODE(C, SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT); + OP_WRITE(Ca, "apple", 5); + OP_PUSH_U64(5); + OP_SELECT_SSL(0, Ca); + OP_FUNC(check_write_buf_stat_84); + + OP_TICK_ENABLE(C); + + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); + OP_WRITE(Sa, "orange", 6); + OP_READ_EXPECT(Ca, "orange", 6); } -DEF_SCRIPT(script_81, "place holder for multistrem script_81") +/* 85. Test SSL_poll (lite, non-blocking) */ +DEF_FUNC(script_85_poll) { + int ok = 0, ret, expected_ret = 1; + static const struct timeval timeout = { 0 }; + size_t result_count, expected_result_count = 0; + SSL_POLL_ITEM items[5] = { 0 }, *item = items; + SSL *c_a, *c_b, *c_c, *c_d, *c_conn; + size_t i; + uint64_t mode; + uint64_t expected_revents[5] = { 0 }; + + F_POP(mode); + REQUIRE_SSL_5(c_a, c_b, c_c, c_d, c_conn); + + item->desc = SSL_as_poll_descriptor(c_a); + item->events = UINT64_MAX; + item->revents = UINT64_MAX; + ++item; + + item->desc = SSL_as_poll_descriptor(c_b); + item->events = UINT64_MAX; + item->revents = UINT64_MAX; + ++item; + + item->desc = SSL_as_poll_descriptor(c_c); + item->events = UINT64_MAX; + item->revents = UINT64_MAX; + ++item; + + item->desc = SSL_as_poll_descriptor(c_d); + item->events = UINT64_MAX; + item->revents = UINT64_MAX; + ++item; + + item->desc = SSL_as_poll_descriptor(c_conn); + item->events = UINT64_MAX; + item->revents = UINT64_MAX; + ++item; + + result_count = SIZE_MAX; + ret = SSL_poll(items, OSSL_NELEM(items), sizeof(SSL_POLL_ITEM), + &timeout, 0, + &result_count); + + switch (mode) { + case 0: + /* No incoming data yet */ + expected_revents[0] = SSL_POLL_EVENT_W; + expected_revents[1] = SSL_POLL_EVENT_W; + expected_revents[2] = SSL_POLL_EVENT_W; + expected_revents[3] = SSL_POLL_EVENT_W; + expected_revents[4] = SSL_POLL_EVENT_OS; + expected_result_count = 5; + break; + case 1: + /* Expect more events */ + expected_revents[0] = SSL_POLL_EVENT_W | SSL_POLL_EVENT_R; + expected_revents[1] = SSL_POLL_EVENT_W | SSL_POLL_EVENT_ER; + expected_revents[2] = SSL_POLL_EVENT_EW; + expected_revents[3] = SSL_POLL_EVENT_W; + expected_revents[4] = SSL_POLL_EVENT_OS | SSL_POLL_EVENT_ISB; + expected_result_count = 5; + break; + default: + goto err; + } + + ok = 1; + + if (!TEST_int_eq(ret, expected_ret) + || !TEST_size_t_eq(result_count, expected_result_count)) + ok = 0; + + for (i = 0; i < OSSL_NELEM(items); ++i) + if (!TEST_uint64_t_eq(items[i].revents, expected_revents[i])) { + TEST_error("mismatch at index %zu in poll results, mode %d", + i, (int)mode); + ok = 0; + } + +err: + return ok; } -DEF_SCRIPT(script_82, "place holder for multistrem script_82") +DEF_SCRIPT(script_85, "Test SSL_poll (lite, non-blocking)") { + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + OP_NEW_STREAM(C, Ca, 0); + OP_WRITE(Ca, "flamingo", 8); + + OP_NEW_STREAM(C, Cb, 0); + OP_WRITE(Cb, "orange", 6); + + OP_NEW_STREAM(C, Cc, 0); + OP_WRITE(Cc, "Strawberry", 10); + + OP_NEW_STREAM(C, Cd, 0); + OP_WRITE(Cd, "sync", 4); + + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_ACCEPT_STREAM_WAIT(S, Sb, 0); + OP_ACCEPT_STREAM_WAIT(S, Sc, 0); + OP_ACCEPT_STREAM_WAIT(S, Sd, 0); + + /* Check nothing readable yet. */ + OP_SELECT_SSL(0, Ca); + OP_SELECT_SSL(1, Cb); + OP_SELECT_SSL(2, Cc); + OP_SELECT_SSL(3, Cd); + OP_SELECT_SSL(4, C); + OP_PUSH_U64(0); + OP_FUNC(script_85_poll); + + /* Send something that will make client sockets readable. */ + OP_READ_EXPECT(Sa, "flamingo", 8); + OP_WRITE(Sa, "herringbone", 11); + + /* Send something that will make 'b' reset. */ + OP_SET_INJECT_PLAIN(S, inject_stream_frame_plain); + + /* Ensure sync. */ + OP_READ_EXPECT(Sd, "sync", 4); + + OP_ENGINE_TICK_DISABLE(S); + OP_SET_INJECT_WORD(C_BIDI_ID(1) + 1, OSSL_QUIC_FRAME_TYPE_RESET_STREAM); + OP_WRITE(Sd, "x", 1); + OP_ENGINE_TICK_ENABLE(S); + + OP_READ_EXPECT(Cd, "x", 1); + + /* Send something that will make 'c' reset. */ + OP_SET_INJECT_PLAIN(S, inject_stream_frame_plain); + + OP_ENGINE_TICK_DISABLE(S); + OP_SET_INJECT_WORD(C_BIDI_ID(2) + 1, OSSL_QUIC_FRAME_TYPE_STOP_SENDING); + OP_NEW_STREAM(S, Sz, 0); + OP_WRITE(Sz, "z", 1); + + /* Ensure sync. */ + OP_WRITE(Sd, "x", 1); + OP_ENGINE_TICK_ENABLE(S); + + OP_READ_EXPECT(Cd, "x", 1); + + /* Check a is now readable. */ + OP_SELECT_SSL(0, Ca); + OP_SELECT_SSL(1, Cb); + OP_SELECT_SSL(2, Cc); + OP_SELECT_SSL(3, Cd); + OP_SELECT_SSL(4, C); + OP_PUSH_U64(1); + OP_FUNC(script_85_poll); } -DEF_SCRIPT(script_83, "place holder for multistrem script_83") +/* 86. Event Handling Mode Configuration */ +DEF_SCRIPT(script_86, "Event Handling Mode Configuration") { + size_t i; + + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + /* Turn on explicit handling mode. */ + OP_TICK_DISABLE(C); + OP_SET_EVENT_HANDLING_MODE(C, SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT); + + /* + * Create a new stream and write data. This won't get sent + * to the network net because we are in explicit mode + * and we haven't called SSL_handle_events(). + */ + OP_NEW_STREAM(C, Ca, 0); + OP_WRITE(Ca, "apple", 5); + + /* Put connection back into implicit handling mode. */ + OP_SET_EVENT_HANDLING_MODE(C, SSL_VALUE_EVENT_HANDLING_MODE_IMPLICIT); + + /* Override at stream level. */ + OP_SET_EVENT_HANDLING_MODE(Ca, SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT); + OP_WRITE(Ca, "orange", 6); + OP_CONCLUDE(Ca); + + /* + * Confirm the data isn't going to arrive. OP_SLEEP is always undesirable + * but we have no reasonable way to synchronise on something not arriving + * given all network traffic is essentially stopped and there are no other + * signals arriving from the peer which could be used for synchronisation. + * Slow OSes will pass this anyway (fail-open). + */ + for (i = 0; i < 20; ++i) { + OP_ACCEPT_STREAM_NONE(S, 0); + OP_SLEEP(10); + } + + /* Now let the data arrive and confirm it arrives. */ + OP_TICK_ENABLE(C); + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "appleorange", 11); + OP_EXPECT_FIN(Sa); + + /* Back into explicit mode. */ + OP_TICK_DISABLE(C); + OP_SET_EVENT_HANDLING_MODE(C, SSL_VALUE_EVENT_HANDLING_MODE_EXPLICIT); + OP_WRITE(Sa, "ok", 2); + OP_READ_FAIL(Ca); + + /* Works once event handling is done. */ + OP_TICK_ENABLE(C); + OP_READ_EXPECT(Ca, "ok", 2); } -DEF_SCRIPT(script_84, "place holder for multistrem script_84") +/* 87. Test stream reset functionality */ +DEF_SCRIPT(script_87, "Test stream reset functionality") { + OP_SIMPLE_PAIR_CONN(); + OP_ACCEPT_CONN_WAIT(L, S, 0); + OP_NEW_STREAM(C, Ca, 0); + OP_WRITE(Ca, "apple", 5); + OP_CONCLUDE(Ca); + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "apple", 5); + OP_EXPECT_FIN(Sa); + OP_WRITE(Sa, "orange", 6); + OP_READ_EXPECT(Ca, "orange", 6); + OP_CONCLUDE(Sa); + OP_EXPECT_FIN(Ca); + OP_SLEEP(1000); + OP_STREAM_RESET_FAIL(Ca, 42); } -DEF_SCRIPT(script_85, "place holder for multistrem script_85") +/* 88. Test SSL_poll (lite, non-blocking) */ +#define POLL_FMT "%s%s%s%s%s%s%s%s%s%s%s%s%s" +#define POLL_PRINTA(_revents_) \ + (_revents_) & SSL_POLL_EVENT_F ? "SSL_POLL_EVENT_F " : "", \ + (_revents_) & SSL_POLL_EVENT_EL ? "SSL_POLL_EVENT_EL " : "", \ + (_revents_) & SSL_POLL_EVENT_EC ? "SSL_POLL_EVENT_EC " : "", \ + (_revents_) & SSL_POLL_EVENT_ECD ? "SSL_POLL_EVENT_ECD " : "", \ + (_revents_) & SSL_POLL_EVENT_ER ? "SSL_POLL_EVENT_ER " : "", \ + (_revents_) & SSL_POLL_EVENT_EW ? "SSL_POLL_EVENT_EW " : "", \ + (_revents_) & SSL_POLL_EVENT_R ? "SSL_POLL_EVENT_R " : "", \ + (_revents_) & SSL_POLL_EVENT_W ? "SSL_POLL_EVENT_W " : "", \ + (_revents_) & SSL_POLL_EVENT_IC ? "SSL_POLL_EVENT_IC " : "", \ + (_revents_) & SSL_POLL_EVENT_ISB ? "SSL_POLL_EVENT_ISB " : "", \ + (_revents_) & SSL_POLL_EVENT_ISU ? "SSL_POLL_EVENT_ISU " : "", \ + (_revents_) & SSL_POLL_EVENT_OSB ? "SSL_POLL_EVENT_OSB " : "", \ + (_revents_) & SSL_POLL_EVENT_OSU ? "SSL_POLL_EVENT_OSU " : "" + +/* + * verify SSL_poll() signals SSL_POLL_EVENT_EC event + * to notify client it's time to call SSL_shutdown(). + */ +DEF_FUNC(script_88_poll) { + int ok = 0, ret, expected_ret = 1; + static const struct timeval timeout = { 0 }; + size_t result_count, processed; + SSL_POLL_ITEM items[2] = { 0 }, *item = items; + SSL *c_a, *c_conn; + size_t i; + uint64_t mode; + uint64_t expected_revents[2] = { 0 }; + + F_POP(mode); + REQUIRE_SSL_2(c_a, c_conn); + + item->desc = SSL_as_poll_descriptor(c_a); + item->events = UINT64_MAX; + item->revents = UINT64_MAX; + ++item; + + item->desc = SSL_as_poll_descriptor(c_conn); + item->events = UINT64_MAX; + item->revents = UINT64_MAX; + ++item; + + result_count = SIZE_MAX; + ret = SSL_poll(items, OSSL_NELEM(items), sizeof(SSL_POLL_ITEM), + &timeout, 0, + &result_count); + + switch (mode) { + case 0: + /* No incoming data yet */ + expected_revents[0] = SSL_POLL_EVENT_W; + expected_revents[1] = SSL_POLL_EVENT_OS; + break; + case 1: + /* Expect more events */ + expected_revents[0] = SSL_POLL_EVENT_R; + expected_revents[1] = SSL_POLL_EVENT_OS; + break; + default: + goto err; + } + + ok = 1; + + if (!TEST_int_eq(ret, expected_ret)) + ok = 0; + + /* + * Unlike script 85 which always expects all objects + * get signaled in single call to SSL_poll() we must + * assume here we can get notification for only one. + */ + processed = 0; + for (i = 0; i < OSSL_NELEM(items); ++i) { + if (items[i].revents == 0) + continue; + + processed++; + if (!TEST_uint64_t_eq(items[i].revents, expected_revents[i])) { + TEST_info("wanted: " POLL_FMT " got: " POLL_FMT, + POLL_PRINTA(expected_revents[i]), + POLL_PRINTA(items[i].revents)); + TEST_error("mismatch at index %zu in poll results, mode %d", + i, (int)mode); + ok = 0; + } + } + + if (!TEST_size_t_eq(processed, result_count)) + ok = 0; + +err: + return ok; } -DEF_SCRIPT(script_86, "place holder for multistrem script_86") +/* + * Unlike the mock (whose T-server is serviced by a dedicated background + * thread independent of script stepping), radix has no such thread here: a + * connection is only ticked between interpreter ops (do_per_op). So rather + * than busy-looping over SSL_poll()/OSSL_sleep() within a single op (which + * would starve the peer of any ticks for the whole loop), retry one + * SSL_poll()/SSL_shutdown() attempt per invocation via F_SPIN_AGAIN() so the + * interpreter ticks every object (including the peer) between attempts, same + * as any other spin-driven op. + */ +DEF_FUNC(script_88_poll_conly) { + int ok = 0, ret; + static const struct timeval timeout = { 0 }; + size_t result_count; + SSL_POLL_ITEM items[1] = { 0 }; + SSL *c_conn; + + REQUIRE_SSL(c_conn); + + result_count = SIZE_MAX; + + items[0].desc = SSL_as_poll_descriptor(c_conn); + items[0].events = UINT64_MAX; + items[0].revents = UINT64_MAX; + + ret = SSL_poll(items, OSSL_NELEM(items), sizeof(SSL_POLL_ITEM), + &timeout, 0, + &result_count); + if (!TEST_int_eq(ret, 1)) + goto err; + + if ((items[0].revents & SSL_POLL_EVENT_EC) == SSL_POLL_EVENT_EC) + SSL_shutdown(c_conn); + + if ((items[0].revents & SSL_POLL_EVENT_ECD) != SSL_POLL_EVENT_ECD) + F_SPIN_AGAIN(); + + ok = 1; +err: + return ok; } -DEF_SCRIPT(script_87, "place holder for multistrem script_87") +DEF_SCRIPT(script_88, "Test SSL_poll (lite, non-blocking)") { + OP_SIMPLE_PAIR_CONN_ND(); + OP_ACCEPT_CONN_WAIT_ND(L, S, 0); + + OP_NEW_STREAM(C, Ca, 0); + + /* Check nothing readable yet. */ + OP_SELECT_SSL(0, Ca); + OP_SELECT_SSL(1, C); + OP_PUSH_U64(0); + OP_FUNC(script_88_poll); + + OP_WRITE(Ca, "flamingo", 8); + OP_CONCLUDE(Ca); + + /* Send something that will make client sockets readable. */ + OP_ACCEPT_STREAM_WAIT(S, Sa, 0); + OP_READ_EXPECT(Sa, "flamingo", 8); + OP_WRITE(Sa, "flamingo", 8); + OP_CONCLUDE(Sa); + + OP_SELECT_SSL(0, Ca); + OP_SELECT_SSL(1, C); + OP_PUSH_U64(1); + OP_FUNC(script_88_poll); + + OP_READ_EXPECT(Ca, "flamingo", 8); + + /* + * client calls non-blocking SSL_shutdown() and gives + * server chance to run by calling sleep. + */ + OP_SHUTDOWN_ONCE(C, 0, 0, NULL); + OP_SLEEP(100); + + /* + * Here we call SSL_poll() and handle SSL_POLL_EVENT_EC + * and SSL_POLL_EVENT_ECD on connection object. Whenever + * _EC event comes we call SSL_shutdown() to keep connection + * draining. We keep calling SSL_poll()/SSL_shutdown() until + * SSL_poll() signals SSL_POLL_EVENT_ECD to let us know connection + * has dried out and con be closed. + */ + OP_SELECT_SSL(0, C); + OP_FUNC(script_88_poll_conly); } -DEF_SCRIPT(script_88, "place holder for multistrem script_88") +/* 89. Max udp payload size configuration */ +DEF_FUNC(check_udp_payload_size_bounds_89) { + int ok = 0; + SSL *ssl; + + REQUIRE_SSL(ssl); + + if (!TEST_false(SSL_set_feature_request_uint(ssl, + SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + QUIC_MIN_INITIAL_DGRAM_LEN - 1)) + || !TEST_false(SSL_set_feature_request_uint(ssl, + SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + QUIC_DEFAULT_MAX_UDP_PAYLOAD_SIZE + 1))) + goto err; + + ok = 1; +err: + return ok; } -DEF_SCRIPT(script_89, "place holder for multistrem script_89") +DEF_SCRIPT(script_89, "Max udp payload size configuration") { + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_SELECT_SSL(0, C); + OP_FUNC(check_udp_payload_size_bounds_89); + OP_MODIFY_VALUE_UINT(C, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + QUIC_DEFAULT_MAX_UDP_PAYLOAD_SIZE); + + OP_CONNECT_WAIT(C); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_MIN_INITIAL_DGRAM_LEN); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_MAX_UDP_PAYLOAD_SIZE); } -DEF_SCRIPT(script_90, "place holder for multistrem script_90") +/* 90. Negotiated default max udp payload size if not configured */ +DEF_SCRIPT(script_90, "Negotiated default max udp payload size if not configured") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_MIN_INITIAL_DGRAM_LEN); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_MIN_INITIAL_DGRAM_LEN); } -DEF_SCRIPT(script_91, "place holder for multistrem script_91") +/* 91. No late changes to max udp payload size */ +DEF_SCRIPT(script_91, "No late changes to max udp payload size") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CANNOT_CHANGE_VALUE_UINT(C, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + QUIC_MIN_INITIAL_DGRAM_LEN, QUIC_DEFAULT_MAX_UDP_PAYLOAD_SIZE); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_UDP_PAYLOAD_SIZE_MAX, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_MIN_INITIAL_DGRAM_LEN); } -DEF_SCRIPT(script_92, "place holder for multistrem script_92") +/* 92. Connection window configuration */ +DEF_SCRIPT(script_92, "Connection window configuration") { + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_MODIFY_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWCON, 800000); + + OP_CONNECT_WAIT(C); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWCON, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 768 * 1024); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWCON, + SSL_VALUE_CLASS_FEATURE_REQUEST, 800000); } -DEF_SCRIPT(script_93, "place holder for multistrem script_93") +/* 93. Negotiated default connection window if not configured */ +DEF_SCRIPT(script_93, "Negotiated default connection window if not configured") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWCON, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 768 * 1024); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWCON, + SSL_VALUE_CLASS_FEATURE_REQUEST, 768 * 1024); } -DEF_SCRIPT(script_94, "place holder for multistrem script_94") +/* 94. No late changes to connection window */ +DEF_SCRIPT(script_94, "No late changes to connection window") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CANNOT_CHANGE_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWCON, 768 * 1024, 800000); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWCON, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 768 * 1024); } -DEF_SCRIPT(script_95, "place holder for multistrem script_95") +/* 95. Bidi stream window configuration */ +DEF_SCRIPT(script_95, "Bidi stream window configuration") { + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_MODIFY_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWBSTR, 600000); + + OP_CONNECT_WAIT(C); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWBSTR, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWBSTR, + SSL_VALUE_CLASS_FEATURE_REQUEST, 600000); } -DEF_SCRIPT(script_96, "place holder for multistrem script_96") +/* 96. Negotiated default bidi stream window if not configured */ +DEF_SCRIPT(script_96, "Negotiated default bidi stream window if not configured") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWBSTR, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWBSTR, + SSL_VALUE_CLASS_FEATURE_REQUEST, 512 * 1024); } -DEF_SCRIPT(script_97, "place holder for multistrem script_97") +/* 97. No late changes to bidi stream window */ +DEF_SCRIPT(script_97, "No late changes to bidi stream window") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CANNOT_CHANGE_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWBSTR, 512 * 1024, 600000); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWBSTR, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024); } -DEF_SCRIPT(script_98, "place holder for multistrem script_98") +/* 98. Uni stream window configuration */ +DEF_SCRIPT(script_98, "Uni stream window configuration") { + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_MODIFY_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWUSTR, 600000); + + OP_CONNECT_WAIT(C); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWUSTR, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWUSTR, + SSL_VALUE_CLASS_FEATURE_REQUEST, 600000); } -DEF_SCRIPT(script_99, "place holder for multistrem script_99") +/* 99. Negotiated default uni stream window if not configured */ +DEF_SCRIPT(script_99, "Negotiated default uni stream window if not configured") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWUSTR, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWUSTR, + SSL_VALUE_CLASS_FEATURE_REQUEST, 512 * 1024); } -DEF_SCRIPT(script_100, "place holder for multistrem script_100") +/* 100. No late changes to uni stream window */ +DEF_SCRIPT(script_100, "No late changes to uni stream window") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CANNOT_CHANGE_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWUSTR, 512 * 1024, 600000); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_WINDOWUSTR, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, 512 * 1024); } -DEF_SCRIPT(script_101, "place holder for multistrem script_101") +/* 101. Ack delay exponent configuration */ +DEF_SCRIPT(script_101, "Ack delay exponent configuration") { + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_REJECT_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, + QUIC_MAX_ACK_DELAY_EXP + 1); + OP_MODIFY_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, + QUIC_DEFAULT_ACK_DELAY_EXP + 1); + + OP_CONNECT_WAIT(C); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, + SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP + 1); } -DEF_SCRIPT(script_102, "place holder for multistrem script_102") +/* 102. Negotiated default ack delay exponent if not configured */ +DEF_SCRIPT(script_102, "Negotiated default ack delay exponent if not configured") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, + SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP); } -DEF_SCRIPT(script_103, "place holder for multistrem script_103") +/* 103. No late changes to ack delay exponent */ +DEF_SCRIPT(script_103, "No late changes to ack delay exponent") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CANNOT_CHANGE_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, + QUIC_DEFAULT_ACK_DELAY_EXP, QUIC_DEFAULT_ACK_DELAY_EXP + 1); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_EXPONENT, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_ACK_DELAY_EXP); } -DEF_SCRIPT(script_104, "place holder for multistrem script_104") +/* 104. Max ack delay configuration */ +DEF_SCRIPT(script_104, "Max ack delay configuration") { + OP_NEW_SSL_L_LISTEN(L); + OP_NEW_SSL_C(C); + OP_SET_PEER_ADDR_FROM(C, L); + + OP_REJECT_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_MAX, + QUIC_MAX_MAX_ACK_DELAY + 1); + OP_MODIFY_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_MAX, + QUIC_DEFAULT_MAX_ACK_DELAY / 2); + + OP_CONNECT_WAIT(C); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_MAX, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_MAX, + SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY / 2); } -DEF_SCRIPT(script_105, "place holder for multistrem script_105") +/* 105. Negotiated default max ack delay if not configured */ +DEF_SCRIPT(script_105, "Negotiated default max ack delay if not configured") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_MAX, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_MAX, + SSL_VALUE_CLASS_FEATURE_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY); } -DEF_SCRIPT(script_106, "place holder for multistrem script_106") +/* 106. No late changes to max ack delay */ +DEF_SCRIPT(script_106, "No late changes to max ack delay") { + OP_SIMPLE_PAIR_CONN(); + + OP_SET_DEFAULT_STREAM_MODE(C, SSL_DEFAULT_STREAM_MODE_NONE); + + OP_CANNOT_CHANGE_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_MAX, + QUIC_DEFAULT_MAX_ACK_DELAY, QUIC_DEFAULT_MAX_ACK_DELAY / 2); + OP_CHECK_VALUE_UINT(C, SSL_VALUE_QUIC_ACK_DELAY_MAX, + SSL_VALUE_CLASS_FEATURE_PEER_REQUEST, QUIC_DEFAULT_MAX_ACK_DELAY); } static int inject_new_cids(RADIX_FAULT *fault, QUIC_PKT_HDR *hdr, @@ -4278,4 +5676,5 @@ static SCRIPT_INFO *const scripts[] = { USE(script_105), USE(script_106), USE(new_connid), + USE(forbidden_frame_types), }; diff --git a/test/recipes/70-test_quic_multistream.t b/test/recipes/70-test_quic_multistream.t deleted file mode 100644 index a13693ee710..00000000000 --- a/test/recipes/70-test_quic_multistream.t +++ /dev/null @@ -1,50 +0,0 @@ -#! /usr/bin/env perl -# Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved. -# -# Licensed under the Apache License 2.0 (the "License"). You may not use -# this file except in compliance with the License. You can obtain a copy -# in the file LICENSE in the source distribution or at -# https://www.openssl.org/source/license.html - -use OpenSSL::Test qw/:DEFAULT srctop_file result_dir data_file/; -use OpenSSL::Test::Utils; -use File::Temp qw(tempfile); -use File::Path 2.00 qw(rmtree mkpath); - -setup("test_quic_multistream"); - -plan skip_all => "QUIC protocol is not supported by this OpenSSL build" - if disabled('quic'); - -plan tests => 2; - -my $qlog_output; -if (!disabled('qlog')) { - $qlog_output = result_dir("qlog-output"); - print "# Writing qlog output to $qlog_output\n"; - rmtree($qlog_output, { safe => 1 }); - mkdir($qlog_output); - $ENV{QLOGDIR} = $qlog_output; -} - -$ENV{OSSL_QFILTER} = "* -quic:unknown_event quic:another_unknown_event"; - -ok(run(test(["quic_multistream_test", - srctop_file("test", "certs", "servercert.pem"), - srctop_file("test", "certs", "serverkey.pem")]))); - -SKIP: { - skip "no qlog", 1 if disabled('qlog'); - skip "not running CI tests", 1 unless $ENV{OSSL_RUN_CI_TESTS}; - - subtest "generate and check qlog output" => sub { - plan tests => 2; - ok(run(test(["quic_radix_test", - srctop_file("test", "certs", "servercert.pem"), - srctop_file("test", "certs", "serverkey.pem")])), - "running quic_radix_test to contribute qlog output"); - - ok(run(cmd([data_file("verify-qlog.py")], exe_shell => "python3")), - "running qlog verification script"); - }; -} diff --git a/test/recipes/70-test_quic_radix.t b/test/recipes/70-test_quic_radix.t index 9250a2b0df0..54de6ab1b9c 100644 --- a/test/recipes/70-test_quic_radix.t +++ b/test/recipes/70-test_quic_radix.t @@ -6,8 +6,9 @@ # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html -use OpenSSL::Test qw/:DEFAULT result_file srctop_file/; +use OpenSSL::Test qw/:DEFAULT result_file result_dir srctop_file data_file/; use OpenSSL::Test::Utils; +use File::Path 2.00 qw(rmtree); sub diagnose_failure { my ($log, $max_bytes) = @_; @@ -50,7 +51,7 @@ setup("test_quic_radix"); plan skip_all => "QUIC protocol is not supported by this OpenSSL build" if disabled('quic'); -plan tests => 1; +plan tests => 2; # Keep the test's multi-megabyte diagnostics out of the TAP pipe. my $redirect = $ENV{HARNESS_ACTIVE} && !$ENV{HARNESS_VERBOSE}; @@ -62,3 +63,26 @@ my $result = run(test(["quic_radix_test", diagnose_failure($stderr_log, 32 * 1024) if !$result && $redirect; ok($result, "running QUIC RADIX tests"); + +SKIP: { + skip "no qlog", 1 if disabled('qlog'); + skip "not running CI tests", 1 unless $ENV{OSSL_RUN_CI_TESTS}; + + subtest "generate and check qlog output" => sub { + plan tests => 2; + + my $qlog_output = result_dir("qlog-output"); + rmtree($qlog_output, { safe => 1 }); + mkdir($qlog_output); + local $ENV{QLOGDIR} = $qlog_output; + local $ENV{OSSL_QFILTER} = "* -quic:unknown_event quic:another_unknown_event"; + + ok(run(test(["quic_radix_test", + srctop_file("test", "certs", "servercert.pem"), + srctop_file("test", "certs", "serverkey.pem")])), + "running quic_radix_test to contribute qlog output"); + + ok(run(cmd([data_file("verify-qlog.py")], exe_shell => "python3")), + "running qlog verification script"); + }; +} diff --git a/test/recipes/70-test_quic_multistream_data/verify-qlog.py b/test/recipes/70-test_quic_radix_data/verify-qlog.py index d5ccae38914..735eb929d63 100755 --- a/test/recipes/70-test_quic_multistream_data/verify-qlog.py +++ b/test/recipes/70-test_quic_radix_data/verify-qlog.py @@ -179,12 +179,12 @@ def run(): "connectivity:connection_closed" ) - if num_files < 300: + if num_files < 150: raise Unexpected(qlogdir, f"unexpectedly few output files: {num_files}") for required_event in required_events: count = event_type_counts.get(required_event, 0) - if count < 100: + if count < 50: raise Unexpected(qlogdir, f"unexpectedly low count of event '{required_event}': got {count}") # For each direction, ensure that at least one of the tests we run generated |
