/* * Copyright 2023 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 #include #include #include #include "internal/quic_tserver.h" #include "internal/quic_ssl.h" #include "internal/quic_error.h" #include "testutil.h" #include "helpers/quictestlib.h" #if defined(OPENSSL_THREADS) # include "internal/thread_arch.h" #endif static const char *certfile, *keyfile; #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; }; #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; BIO_ADDR *s_net_bio_addr; QUIC_TSERVER *s; 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; #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); uint64_t inject_word0, inject_word1; uint64_t scratch0, scratch1; }; struct helper_local { struct helper *h; LHASH_OF(STREAM_INFO) *c_streams; int thread_idx; }; struct script_op { uint32_t op; const void *arg0; size_t arg1; int (*check_func)(struct helper *h, const struct script_op *op); 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); }; #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_DETACH 12 #define OPK_C_ATTACH 13 #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 EXPECT_CONN_CLOSE_APP (1U << 0) #define EXPECT_CONN_CLOSE_REMOTE (1U << 1) #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_DETACH(stream_name) \ {OPK_C_DETACH, NULL, 0, NULL, #stream_name}, #define OP_C_ATTACH(stream_name) \ {OPK_C_ATTACH, 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_UNI(stream_name, expect_id) \ {OPK_C_NEW_STREAM, NULL, 1, 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_WAIT() \ {OPK_C_SHUTDOWN_WAIT, NULL, 0, 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) \ {OPK_S_READ_FAIL, NULL, 0, NULL, #stream_name}, #define OP_C_STREAM_RESET(stream_name, aec) \ {OPK_C_STREAM_RESET, 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}, 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 int skip_time_ms(struct helper *h, const struct script_op *op) { if (!TEST_true(CRYPTO_THREAD_write_lock(h->time_lock))) return 0; h->time_slip = ossl_time_add(h->time_slip, ossl_ms2time(op->arg2)); CRYPTO_THREAD_unlock(h->time_lock); return 1; } static int check_rejected(struct helper *h, const struct script_op *op) { uint64_t stream_id = op->arg2; if (!ossl_quic_tserver_stream_has_peer_stop_sending(h->s, stream_id, NULL) || !ossl_quic_tserver_stream_has_peer_reset_stream(h->s, stream_id, NULL)) { h->check_spin_again = 1; return 0; } return 1; } static int check_stream_reset(struct helper *h, const struct script_op *op) { uint64_t stream_id = op->arg2, aec = 0; if (!ossl_quic_tserver_stream_has_peer_reset_stream(h->s, stream_id, &aec)) { h->check_spin_again = 1; return 0; } return TEST_uint64_t_eq(aec, 42); } static int check_stream_stopped(struct helper *h, const struct script_op *op) { uint64_t stream_id = op->arg2; if (!ossl_quic_tserver_stream_has_peer_stop_sending(h->s, stream_id, NULL)) { h->check_spin_again = 1; return 0; } return 1; } static int override_key_update(struct helper *h, const struct script_op *op) { QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); ossl_quic_channel_set_txku_threshold_override(ch, op->arg2); return 1; } static int trigger_key_update(struct helper *h, const struct script_op *op) { if (!TEST_true(SSL_key_update(h->c_conn, SSL_KEY_UPDATE_REQUESTED))) return 0; return 1; } static int check_key_update_ge(struct helper *h, const struct script_op *op) { QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); int64_t txke = (int64_t)ossl_quic_channel_get_tx_key_epoch(ch); int64_t rxke = (int64_t)ossl_quic_channel_get_rx_key_epoch(ch); int64_t diff = txke - rxke; /* * TXKE must always be equal to or ahead of RXKE. * It can be ahead of RXKE by at most 1. */ if (!TEST_int64_t_ge(diff, 0) || !TEST_int64_t_le(diff, 1)) return 0; /* Caller specifies a minimum number of RXKEs which must have happened. */ if (!TEST_uint64_t_ge((uint64_t)rxke, op->arg2)) return 0; return 1; } static int check_key_update_lt(struct helper *h, const struct script_op *op) { QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); uint64_t txke = ossl_quic_channel_get_tx_key_epoch(ch); /* Caller specifies a maximum number of TXKEs which must have happened. */ if (!TEST_uint64_t_lt(txke, op->arg2)) return 0; return 1; } 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; } #endif static void helper_cleanup(struct helper *h) { #if defined(OPENSSL_THREADS) join_threads(h->threads, h->num_threads); 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); 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; SSL_CTX_free(h->c_ctx); h->c_ctx = NULL; CRYPTO_THREAD_lock_free(h->time_lock); h->time_lock = NULL; } static int helper_init(struct helper *h, int free_order, int need_injector) { short port = 8186; struct in_addr ina = {0}; QUIC_TSERVER_ARGS s_args = {0}; memset(h, 0, sizeof(*h)); h->c_fd = -1; h->s_fd = -1; h->free_order = free_order; h->need_injector = need_injector; h->time_slip = ossl_time_zero(); 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_addr = BIO_ADDR_new())) goto err; if (!TEST_true(BIO_ADDR_rawmake(h->s_net_bio_addr, AF_INET, &ina, sizeof(ina), htons(port)))) goto err; if (!TEST_true(BIO_bind(h->s_fd, h->s_net_bio_addr, 0))) 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 = ossl_quic_tserver_new(&s_args, certfile, keyfile))) goto err; if (need_injector) { h->qtf = qtest_create_injector(h->s); if (!TEST_ptr(h->qtf)) goto err; BIO_set_data(h->s_qtf_wbio, h->qtf); } if (!need_injector) 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; 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_conn_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, 0))) goto err; h->start_time = ossl_time_now(); h->init = 1; return 1; err: 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; 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 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 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; #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 SPIN_AGAIN() { OSSL_sleep(1); no_advance = 1; continue; } for (;;) { SSL *c_tgt = h->c_conn; uint64_t s_stream_id = UINT64_MAX; 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(8000)); } 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) ossl_quic_tserver_tick(h->s); if (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_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_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_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; } 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_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 = op->check_func(h, op); if (h->check_spin_again) { h->check_spin_again = 0; 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, 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 (!TEST_true((ret == 1 || op->arg1 > 0) || (!h->blocking && is_want(h->c_conn, ret)))) goto out; if (!h->blocking && ret < 0) SPIN_AGAIN(); } break; case OPK_C_WRITE: { size_t bytes_written = 0; if (!TEST_ptr(c_tgt)) goto out; if (!TEST_true(SSL_write_ex(c_tgt, op->arg0, op->arg1, &bytes_written)) || !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(h->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(h->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) SPIN_AGAIN(); } break; case OPK_C_READ_EXPECT: { size_t bytes_read = 0; if (op->arg1 > 0 && tmp_buf == NULL && !TEST_ptr(tmp_buf = OPENSSL_malloc(op->arg1))) goto out; if (!SSL_read_ex(c_tgt, tmp_buf + offset, op->arg1 - offset, &bytes_read)) SPIN_AGAIN(); if (bytes_read + offset != op->arg1) { offset += bytes_read; 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(h->s, s_stream_id, tmp_buf + offset, op->arg1 - offset, &bytes_read))) goto out; if (bytes_read + offset != op->arg1) { offset += bytes_read; 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; if (!TEST_false(SSL_read_ex(c_tgt, buf, sizeof(buf), &bytes_read)) || !TEST_size_t_eq(bytes_read, 0)) goto out; if (is_want(c_tgt, 0)) SPIN_AGAIN(); if (!TEST_int_eq(SSL_get_error(c_tgt, 0), SSL_ERROR_ZERO_RETURN)) 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(h->s, s_stream_id)) SPIN_AGAIN(); } break; case OPK_C_DETACH: { SSL *c_stream; if (!TEST_ptr_null(c_tgt)) goto out; /* don't overwrite existing stream with same name */ if (!TEST_ptr(c_stream = ossl_quic_detach_stream(h->c_conn))) goto out; if (!TEST_true(helper_local_set_c_stream(&hl, op->stream_name, c_stream))) goto out; } break; case OPK_C_ATTACH: { if (!TEST_ptr(c_tgt)) goto out; if (!TEST_true(ossl_quic_attach_stream(h->c_conn, c_tgt))) goto out; if (!TEST_true(helper_local_set_c_stream(&hl, op->stream_name, NULL))) goto out; } break; case OPK_C_NEW_STREAM: { SSL *c_stream; uint64_t flags = 0; if (!TEST_ptr_null(c_tgt)) goto out; /* don't overwrite existing stream with same name */ if (op->arg1 != 0) flags |= SSL_STREAM_FLAG_UNI; if (!TEST_ptr(c_stream = SSL_new_stream(h->c_conn, flags))) goto out; 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_true(ossl_quic_tserver_stream_new(h->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 ((c_stream = SSL_accept_stream(h->c_conn, 0)) == NULL) 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; new_stream_id = ossl_quic_tserver_pop_incoming_stream(h->s); if (new_stream_id == UINT64_MAX) 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, 0))) { 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_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, 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, op->arg1, 0))) goto out; } break; case OPK_C_SHUTDOWN_WAIT: { int ret; QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); ossl_quic_channel_set_inhibit_tick(ch, 0); if (!TEST_ptr(c_tgt)) goto out; ret = SSL_shutdown_ex(c_tgt, 0, NULL, 0); if (!TEST_int_ge(ret, 0)) goto out; if (ret == 0) SPIN_AGAIN(); } 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 (!SSL_get_conn_close_info(c_tgt, &cc_info, sizeof(cc_info))) SPIN_AGAIN(); if (!TEST_int_eq(expect_app, !cc_info.is_transport) || !TEST_int_eq(expect_remote, !cc_info.is_local) || !TEST_uint64_t_eq(error_code, cc_info.error_code)) 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(h->s)) { ossl_quic_tserver_ping(h->s); SPIN_AGAIN(); } if (!TEST_ptr(tc = ossl_quic_tserver_get_terminate_cause(h->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_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_true(helper_set_s_stream(h, op->stream_name, UINT64_MAX))) goto out; } break; case OPK_C_WRITE_FAIL: { size_t bytes_written = 0; if (!TEST_ptr(c_tgt)) goto out; if (!TEST_false(SSL_write_ex(c_tgt, "apple", 5, &bytes_written))) 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(h->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]; if (!TEST_ptr(c_tgt)) goto out; if (!TEST_false(SSL_read_ex(c_tgt, buf, sizeof(buf), &bytes_read))) goto out; } break; case OPK_C_READ_FAIL_WAIT: { size_t bytes_read = 0; char buf[1]; if (!TEST_ptr(c_tgt)) goto out; if (!TEST_false(SSL_read_ex(c_tgt, buf, sizeof(buf), &bytes_read))) goto out; if (is_want(c_tgt, 0)) SPIN_AGAIN(); } break; case OPK_S_READ_FAIL: { size_t bytes_read = 0; unsigned char buf[1]; if (!TEST_uint64_t_ne(s_stream_id, UINT64_MAX)) goto out; if (!TEST_false(ossl_quic_tserver_read(h->s, s_stream_id, buf, sizeof(buf), &bytes_read))) goto out; } break; case OPK_C_STREAM_RESET: { SSL_STREAM_RESET_ARGS args = {0}; if (!TEST_ptr(c_tgt)) goto out; args.quic_error_code = op->arg2; if (!TEST_true(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_zalloc(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 = 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); } break; case OPK_C_EXPECT_SSL_ERR: { if (!TEST_size_t_eq((size_t)SSL_get_error(c_tgt, 0), op->arg1)) goto out; } break; case OPK_EXPECT_ERR_REASON: { if (!TEST_size_t_eq((size_t)ERR_GET_REASON(ERR_get_error()), op->arg1)) goto out; } break; case OPK_EXPECT_ERR_LIB: { if (!TEST_size_t_eq((size_t)ERR_GET_LIB(ERR_get_error()), op->arg1)) goto out; } 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_SET_INJECT_WORD: 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_channel_set_inhibit_tick(ch, 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; default: TEST_error("unknown op"); goto out; } } out: if (!testresult) { size_t i; 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]); } 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 testresult = 0; struct helper h; if (!TEST_true(helper_init(&h, free_order, 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[] = { 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_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 }; /* 2. Multi-stream test */ static const struct script_op script_2[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_INCOMING_STREAM_POLICY(SSL_INCOMING_STREAM_POLICY_ACCEPT) OP_C_WRITE (DEFAULT, "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 (DEFAULT, "orange", 6) OP_C_NEW_STREAM_BIDI (b, C_BIDI_ID(1)) OP_C_WRITE (b, "flamingo", 8) OP_C_CONCLUDE (b) OP_S_BIND_STREAM_ID (b, C_BIDI_ID(1)) OP_S_READ_EXPECT (b, "flamingo", 8) OP_S_EXPECT_FIN (b) OP_S_WRITE (b, "gargoyle", 8) OP_S_CONCLUDE (b) OP_C_READ_EXPECT (b, "gargoyle", 8) OP_C_EXPECT_FIN (b) OP_C_NEW_STREAM_UNI (c, C_UNI_ID(0)) OP_C_WRITE (c, "elephant", 8) OP_C_CONCLUDE (c) OP_S_BIND_STREAM_ID (c, C_UNI_ID(0)) OP_S_READ_EXPECT (c, "elephant", 8) OP_S_EXPECT_FIN (c) OP_S_WRITE_FAIL (c) OP_C_ACCEPT_STREAM_NONE () OP_S_NEW_STREAM_BIDI (d, S_BIDI_ID(0)) OP_S_WRITE (d, "frog", 4) OP_S_CONCLUDE (d) OP_C_ACCEPT_STREAM_WAIT (d) OP_C_ACCEPT_STREAM_NONE () OP_C_READ_EXPECT (d, "frog", 4) OP_C_EXPECT_FIN (d) OP_S_NEW_STREAM_BIDI (e, S_BIDI_ID(1)) OP_S_WRITE (e, "mixture", 7) OP_S_CONCLUDE (e) OP_C_ACCEPT_STREAM_WAIT (e) OP_C_READ_EXPECT (e, "mixture", 7) OP_C_EXPECT_FIN (e) OP_C_WRITE (e, "ramble", 6) OP_S_READ_EXPECT (e, "ramble", 6) OP_C_CONCLUDE (e) OP_S_EXPECT_FIN (e) OP_S_NEW_STREAM_UNI (f, S_UNI_ID(0)) OP_S_WRITE (f, "yonder", 6) OP_S_CONCLUDE (f) OP_C_ACCEPT_STREAM_WAIT (f) OP_C_ACCEPT_STREAM_NONE () OP_C_READ_EXPECT (f, "yonder", 6) OP_C_EXPECT_FIN (f) OP_C_WRITE_FAIL (f) OP_C_SET_INCOMING_STREAM_POLICY(SSL_INCOMING_STREAM_POLICY_REJECT) OP_S_NEW_STREAM_BIDI (g, S_BIDI_ID(2)) OP_S_WRITE (g, "unseen", 6) OP_S_CONCLUDE (g) OP_C_ACCEPT_STREAM_NONE () OP_C_SET_INCOMING_STREAM_POLICY(SSL_INCOMING_STREAM_POLICY_AUTO) OP_S_NEW_STREAM_BIDI (h, S_BIDI_ID(3)) OP_S_WRITE (h, "UNSEEN", 6) OP_S_CONCLUDE (h) OP_C_ACCEPT_STREAM_NONE () /* * Streams g, h should have been rejected, so server should have got * STOP_SENDING/RESET_STREAM. */ OP_CHECK (check_rejected, S_BIDI_ID(2)) OP_CHECK (check_rejected, S_BIDI_ID(3)) OP_END }; /* 3. Default stream detach/reattach test */ static const struct script_op script_3[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_C_DETACH (a) /* DEFAULT becomes stream 'a' */ OP_C_WRITE_FAIL (DEFAULT) OP_C_WRITE (a, "by", 2) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "appleby", 7) OP_S_WRITE (a, "hello", 5) OP_C_READ_EXPECT (a, "hello", 5) OP_C_WRITE_FAIL (DEFAULT) OP_C_ATTACH (a) OP_C_WRITE (DEFAULT, "is here", 7) OP_S_READ_EXPECT (a, "is here", 7) OP_C_DETACH (a) OP_C_CONCLUDE (a) OP_S_EXPECT_FIN (a) OP_END }; /* 4. Default stream mode test */ static const struct script_op script_4[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_C_WRITE_FAIL (DEFAULT) OP_S_NEW_STREAM_BIDI (a, S_BIDI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_READ_FAIL (DEFAULT) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "apple", 5) OP_C_ATTACH (a) OP_C_WRITE (DEFAULT, "orange", 6) OP_S_READ_EXPECT (a, "orange", 6) OP_END }; /* 5. Test stream reset functionality */ static const struct script_op script_5[] = { 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_NEW_STREAM_BIDI (b, C_BIDI_ID(1)) OP_C_WRITE (a, "apple", 5) OP_C_STREAM_RESET (a, 42) OP_C_WRITE (b, "strawberry", 10) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_BIND_STREAM_ID (b, C_BIDI_ID(1)) OP_S_READ_EXPECT (b, "strawberry", 10) /* Reset disrupts read of already sent data */ OP_S_READ_FAIL (a) OP_CHECK (check_stream_reset, C_BIDI_ID(0)) OP_END }; /* 6. Test STOP_SENDING functionality */ static const struct script_op script_6[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_S_NEW_STREAM_BIDI (a, S_BIDI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_FREE_STREAM (a) OP_C_ACCEPT_STREAM_NONE () OP_CHECK (check_stream_stopped, S_BIDI_ID(0)) OP_END }; /* 7. Unidirectional default stream mode test (client sends first) */ static const struct script_op script_7[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_AUTO_UNI) OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_UNI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_S_WRITE_FAIL (a) OP_END }; /* 8. Unidirectional default stream mode test (server sends first) */ static const struct script_op script_8[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_AUTO_UNI) OP_S_NEW_STREAM_UNI (a, S_UNI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_READ_EXPECT (DEFAULT, "apple", 5) OP_C_WRITE_FAIL (DEFAULT) OP_END }; /* 9. Unidirectional default stream mode test (server sends first on bidi) */ static const struct script_op script_9[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_AUTO_UNI) OP_S_NEW_STREAM_BIDI (a, S_BIDI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_READ_EXPECT (DEFAULT, "apple", 5) OP_C_WRITE (DEFAULT, "orange", 6) OP_S_READ_EXPECT (a, "orange", 6) OP_END }; /* 10. Shutdown */ static const struct script_op script_10[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_C_SHUTDOWN_WAIT () OP_C_EXPECT_CONN_CLOSE_INFO(0, 1, 0) OP_S_EXPECT_CONN_CLOSE_INFO(0, 1, 1) OP_END }; /* 11. Many threads accepted on the same client connection */ static const struct script_op script_11_child[] = { OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "foo", 3) OP_C_EXPECT_FIN (a) OP_END }; static const struct script_op script_11[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_NEW_THREAD (5, script_11_child) OP_S_NEW_STREAM_BIDI (a, ANY_ID) OP_S_WRITE (a, "foo", 3) OP_S_CONCLUDE (a) OP_S_NEW_STREAM_BIDI (b, ANY_ID) OP_S_WRITE (b, "foo", 3) OP_S_CONCLUDE (b) OP_S_NEW_STREAM_BIDI (c, ANY_ID) OP_S_WRITE (c, "foo", 3) OP_S_CONCLUDE (c) OP_S_NEW_STREAM_BIDI (d, ANY_ID) OP_S_WRITE (d, "foo", 3) OP_S_CONCLUDE (d) OP_S_NEW_STREAM_BIDI (e, ANY_ID) OP_S_WRITE (e, "foo", 3) OP_S_CONCLUDE (e) OP_END }; /* 12. Many threads initiated on the same client connection */ static const struct script_op script_12_child[] = { OP_C_NEW_STREAM_BIDI (a, ANY_ID) OP_C_WRITE (a, "foo", 3) OP_C_CONCLUDE (a) OP_C_FREE_STREAM (a) OP_END }; static const struct script_op script_12[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_NEW_THREAD (5, script_12_child) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "foo", 3) OP_S_EXPECT_FIN (a) OP_S_BIND_STREAM_ID (b, C_BIDI_ID(1)) OP_S_READ_EXPECT (b, "foo", 3) OP_S_EXPECT_FIN (b) OP_S_BIND_STREAM_ID (c, C_BIDI_ID(2)) OP_S_READ_EXPECT (c, "foo", 3) OP_S_EXPECT_FIN (c) OP_S_BIND_STREAM_ID (d, C_BIDI_ID(3)) OP_S_READ_EXPECT (d, "foo", 3) OP_S_EXPECT_FIN (d) OP_S_BIND_STREAM_ID (e, C_BIDI_ID(4)) OP_S_READ_EXPECT (e, "foo", 3) OP_S_EXPECT_FIN (e) OP_END }; /* 13. Many threads accepted on the same client connection (stress test) */ static const struct script_op script_13_child[] = { OP_BEGIN_REPEAT (10) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "foo", 3) OP_C_EXPECT_FIN (a) OP_C_FREE_STREAM (a) OP_END_REPEAT () OP_END }; static const struct script_op script_13[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_NEW_THREAD (5, script_13_child) OP_BEGIN_REPEAT (50) OP_S_NEW_STREAM_BIDI (a, ANY_ID) OP_S_WRITE (a, "foo", 3) OP_S_CONCLUDE (a) OP_S_UNBIND_STREAM_ID (a) OP_END_REPEAT () OP_END }; /* 14. Many threads initiating on the same client connection (stress test) */ static const struct script_op script_14_child[] = { OP_BEGIN_REPEAT (10) OP_C_NEW_STREAM_BIDI (a, ANY_ID) OP_C_WRITE (a, "foo", 3) OP_C_CONCLUDE (a) OP_C_FREE_STREAM (a) OP_END_REPEAT () OP_END }; static const struct script_op script_14[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_NEW_THREAD (5, script_14_child) OP_BEGIN_REPEAT (50) OP_S_ACCEPT_STREAM_WAIT (a) OP_S_READ_EXPECT (a, "foo", 3) OP_S_EXPECT_FIN (a) OP_S_UNBIND_STREAM_ID (a) OP_END_REPEAT () OP_END }; /* 15. Client sending large number of streams, MAX_STREAMS test */ static const struct script_op script_15[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) /* * This will cause a protocol violation to be raised by the server if we are * not handling the stream limit correctly on the TX side. */ OP_BEGIN_REPEAT (200) OP_C_NEW_STREAM_BIDI (a, ANY_ID) OP_C_WRITE (a, "foo", 3) OP_C_CONCLUDE (a) OP_C_FREE_STREAM (a) OP_END_REPEAT () /* Prove the connection is still good. */ OP_S_NEW_STREAM_BIDI (a, S_BIDI_ID(0)) OP_S_WRITE (a, "bar", 3) OP_S_CONCLUDE (a) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "bar", 3) OP_C_EXPECT_FIN (a) /* * Drain the queue of incoming streams. We should be able to get all 200 * even though only 100 can be initiated at a time. */ OP_BEGIN_REPEAT (200) OP_S_ACCEPT_STREAM_WAIT (b) OP_S_READ_EXPECT (b, "foo", 3) OP_S_EXPECT_FIN (b) OP_S_UNBIND_STREAM_ID (b) OP_END_REPEAT () OP_END }; /* 16. Server sending large number of streams, MAX_STREAMS test */ static const struct script_op script_16[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) /* * This will cause a protocol violation to be raised by the client if we are * not handling the stream limit correctly on the TX side. */ OP_BEGIN_REPEAT (200) OP_S_NEW_STREAM_BIDI (a, ANY_ID) OP_S_WRITE (a, "foo", 3) OP_S_CONCLUDE (a) OP_S_UNBIND_STREAM_ID (a) OP_END_REPEAT () /* Prove that the connection is still good. */ OP_C_NEW_STREAM_BIDI (a, ANY_ID) OP_C_WRITE (a, "bar", 3) OP_C_CONCLUDE (a) OP_S_ACCEPT_STREAM_WAIT (b) OP_S_READ_EXPECT (b, "bar", 3) OP_S_EXPECT_FIN (b) /* Drain the queue of incoming streams. */ OP_BEGIN_REPEAT (200) OP_C_ACCEPT_STREAM_WAIT (b) OP_C_READ_EXPECT (b, "foo", 3) OP_C_EXPECT_FIN (b) OP_C_FREE_STREAM (b) OP_END_REPEAT () OP_END }; /* 17. Key update test - unlimited */ static const struct script_op script_17[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_CHECK (override_key_update, 1) OP_BEGIN_REPEAT (200) OP_C_WRITE (DEFAULT, "apple", 5) OP_S_READ_EXPECT (a, "apple", 5) /* * TXKU frequency is bounded by RTT because a previous TXKU needs to be * acknowledged by the peer first before another one can be begin. By * waiting this long, we eliminate any such concern and ensure as many key * updates as possible can occur for the purposes of this test. */ OP_CHECK (skip_time_ms, 100) OP_END_REPEAT () /* At least 5 RXKUs detected */ OP_CHECK (check_key_update_ge, 5) /* * Prove the connection is still healthy by sending something in both * directions. */ OP_C_WRITE (DEFAULT, "xyzzy", 5) OP_S_READ_EXPECT (a, "xyzzy", 5) OP_S_WRITE (a, "plugh", 5) OP_C_READ_EXPECT (DEFAULT, "plugh", 5) OP_END }; /* 18. Key update test - RTT-bounded */ static const struct script_op script_18[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_CHECK (override_key_update, 1) OP_BEGIN_REPEAT (200) OP_C_WRITE (DEFAULT, "apple", 5) OP_S_READ_EXPECT (a, "apple", 5) OP_CHECK (skip_time_ms, 8) OP_END_REPEAT () /* * This time we simulate far less time passing between writes, so there are * fewer opportunities to initiate TXKUs. Note that we ask for a TXKU every * 1 packet above, which is absurd; thus this ensures we only actually * generate TXKUs when we are allowed to. */ OP_CHECK (check_key_update_lt, 240) /* * Prove the connection is still healthy by sending something in both * directions. */ OP_C_WRITE (DEFAULT, "xyzzy", 5) OP_S_READ_EXPECT (a, "xyzzy", 5) OP_S_WRITE (a, "plugh", 5) OP_C_READ_EXPECT (DEFAULT, "plugh", 5) OP_END }; /* 19. Key update test - artificially triggered */ static const struct script_op script_19[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_C_WRITE (DEFAULT, "orange", 6) OP_S_READ_EXPECT (a, "orange", 6) OP_S_WRITE (a, "strawberry", 10) OP_C_READ_EXPECT (DEFAULT, "strawberry", 10) OP_CHECK (check_key_update_lt, 1) OP_CHECK (trigger_key_update, 0) OP_C_WRITE (DEFAULT, "orange", 6) OP_S_READ_EXPECT (a, "orange", 6) OP_S_WRITE (a, "ok", 2) OP_C_READ_EXPECT (DEFAULT, "ok", 2) OP_CHECK (check_key_update_ge, 1) OP_END }; /* 20. Multiple threads accept stream with socket forcibly closed (error test) */ static const struct script_op script_20_child[] = { OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "foo", 3) OP_SLEEP (500) OP_C_READ_FAIL_WAIT (a) OP_C_EXPECT_SSL_ERR (a, SSL_ERROR_SYSCALL) OP_EXPECT_ERR_LIB (ERR_LIB_SYS) OP_EXPECT_ERR_REASON (SSL_R_QUIC_NETWORK_ERROR) OP_C_FREE_STREAM (a) OP_END }; static const struct script_op script_20[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_NEW_THREAD (5, script_20_child) OP_BEGIN_REPEAT (5) OP_S_NEW_STREAM_BIDI (a, ANY_ID) OP_S_WRITE (a, "foo", 3) OP_S_UNBIND_STREAM_ID (a) OP_END_REPEAT () OP_SLEEP (100) OP_C_CLOSE_SOCKET () 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[8]; 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; 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[] = { OP_S_SET_INJECT_PLAIN (script_21_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (QUIC_PKT_TYPE_1RTT, OSSL_QUIC_VLINT_MAX) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_FRAME_ENCODING_ERROR,0,0) OP_END }; /* 22. Fault injection - non-zero packet header reserved bits */ static int script_22_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) { if (h->inject_word0 == 0) return 1; hdr->reserved = 1; return 1; } static const struct script_op script_22[] = { OP_S_SET_INJECT_PLAIN (script_22_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) 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, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_PROTOCOL_VIOLATION,0,0) OP_END }; /* 23. Fault injection - empty NEW_TOKEN */ static int script_23_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) { int ok = 0; WPACKET wpkt; unsigned char frame_buf[16]; size_t written; if (h->inject_word0 == 0) 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, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN)) || !TEST_true(WPACKET_quic_write_vlint(&wpkt, 0))) 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_23[] = { OP_S_SET_INJECT_PLAIN (script_23_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) 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, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_FRAME_ENCODING_ERROR,0,0) OP_END }; /* 24. Fault injection - excess value of MAX_STREAMS_BIDI */ static int script_24_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) { int ok = 0; WPACKET wpkt; unsigned char frame_buf[16]; size_t written; if (h->inject_word0 == 0) 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, (((uint64_t)1) << 60) + 1))) 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_24[] = { OP_S_SET_INJECT_PLAIN (script_24_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (1, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_FRAME_ENCODING_ERROR,0,0) OP_END }; /* 25. Fault injection - excess value of MAX_STREAMS_UNI */ static const struct script_op script_25[] = { OP_S_SET_INJECT_PLAIN (script_24_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (1, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_FRAME_ENCODING_ERROR,0,0) OP_END }; /* 26. Fault injection - excess value of STREAMS_BLOCKED_BIDI */ static const struct script_op script_26[] = { OP_S_SET_INJECT_PLAIN (script_24_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (1, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_LIMIT_ERROR,0,0) OP_END }; /* 27. Fault injection - excess value of STREAMS_BLOCKED_UNI */ static const struct script_op script_27[] = { OP_S_SET_INJECT_PLAIN (script_24_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (1, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_LIMIT_ERROR,0,0) 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) 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[] = { OP_S_SET_INJECT_PLAIN (script_28_inject_plain) 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, "orange", 6) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "orange", 6) OP_C_NEW_STREAM_UNI (b, C_UNI_ID(0)) OP_C_WRITE (b, "apple", 5) OP_S_BIND_STREAM_ID (b, C_UNI_ID(0)) OP_S_READ_EXPECT (b, "apple", 5) OP_SET_INJECT_WORD (C_UNI_ID(0) + 1, OSSL_QUIC_FRAME_TYPE_RESET_STREAM) OP_S_WRITE (a, "fruit", 5) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 29. Fault injection - received RESET_STREAM for nonexistent send-only stream */ static const struct script_op script_29[] = { OP_S_SET_INJECT_PLAIN (script_28_inject_plain) 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, "orange", 6) OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "orange", 6) OP_C_NEW_STREAM_UNI (b, C_UNI_ID(0)) OP_C_WRITE (b, "apple", 5) OP_S_BIND_STREAM_ID (b, C_UNI_ID(0)) OP_S_READ_EXPECT (b, "apple", 5) OP_SET_INJECT_WORD (C_UNI_ID(1) + 1, OSSL_QUIC_FRAME_TYPE_RESET_STREAM) OP_S_WRITE (a, "fruit", 5) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 30. Fault injection - received STOP_SENDING for receive-only stream */ static const struct script_op script_30[] = { OP_S_SET_INJECT_PLAIN (script_28_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_S_NEW_STREAM_UNI (a, S_UNI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (S_UNI_ID(0) + 1, OSSL_QUIC_FRAME_TYPE_STOP_SENDING) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 31. Fault injection - received STOP_SENDING for nonexistent receive-only stream */ static const struct script_op script_31[] = { OP_S_SET_INJECT_PLAIN (script_28_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_S_NEW_STREAM_UNI (a, S_UNI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (C_UNI_ID(0) + 1, OSSL_QUIC_FRAME_TYPE_STOP_SENDING) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 32. Fault injection - STREAM frame for nonexistent stream */ static int script_32_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) { int ok = 0; WPACKET wpkt; unsigned char frame_buf[64]; size_t written; uint64_t type = OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN, offset, flen, i; switch (h->inject_word1) { default: return 0; case 0: return 1; case 1: offset = 0; flen = 0; break; case 2: offset = (((uint64_t)1)<<62) - 1; flen = 5; break; case 3: offset = 1 * 1024 * 1024 * 1024; /* 1G */ flen = 5; break; } if (!TEST_true(WPACKET_init_static_len(&wpkt, frame_buf, sizeof(frame_buf), 0))) return 0; if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, type)) || !TEST_true(WPACKET_quic_write_vlint(&wpkt, /* stream ID */ h->inject_word0 - 1)) || !TEST_true(WPACKET_quic_write_vlint(&wpkt, offset)) || !TEST_true(WPACKET_quic_write_vlint(&wpkt, flen))) goto err; for (i = 0; i < flen; ++i) if (!TEST_true(WPACKET_put_bytes_u8(&wpkt, 0x42))) 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_32[] = { OP_S_SET_INJECT_PLAIN (script_32_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_S_NEW_STREAM_UNI (a, S_UNI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (C_UNI_ID(0) + 1, 1) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 33. Fault injection - STREAM frame with illegal offset */ static const struct script_op script_33[] = { OP_S_SET_INJECT_PLAIN (script_32_inject_plain) 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_SET_INJECT_WORD (C_BIDI_ID(0) + 1, 2) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_FRAME_ENCODING_ERROR,0,0) OP_END }; /* 34. Fault injection - STREAM frame which exceeds FC */ static const struct script_op script_34[] = { OP_S_SET_INJECT_PLAIN (script_32_inject_plain) 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_SET_INJECT_WORD (C_BIDI_ID(0) + 1, 3) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_FLOW_CONTROL_ERROR,0,0) OP_END }; /* 35. Fault injection - MAX_STREAM_DATA for receive-only stream */ static const struct script_op script_35[] = { OP_S_SET_INJECT_PLAIN (script_28_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_S_NEW_STREAM_UNI (a, S_UNI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (S_UNI_ID(0) + 1, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 36. Fault injection - MAX_STREAM_DATA for nonexistent stream */ static const struct script_op script_36[] = { OP_S_SET_INJECT_PLAIN (script_28_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_S_NEW_STREAM_UNI (a, S_UNI_ID(0)) OP_S_WRITE (a, "apple", 5) OP_C_ACCEPT_STREAM_WAIT (a) OP_C_READ_EXPECT (a, "apple", 5) OP_SET_INJECT_WORD (C_BIDI_ID(0) + 1, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 37. Fault injection - STREAM_DATA_BLOCKED for send-only stream */ static const struct script_op script_37[] = { OP_S_SET_INJECT_PLAIN (script_28_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_C_NEW_STREAM_UNI (a, C_UNI_ID(0)) OP_C_WRITE (a, "apple", 5) OP_S_BIND_STREAM_ID (a, C_UNI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_S_NEW_STREAM_UNI (b, S_UNI_ID(0)) OP_SET_INJECT_WORD (C_UNI_ID(0) + 1, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED) OP_S_WRITE (b, "orange", 5) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 38. Fault injection - STREAM_DATA_BLOCKED for non-existent stream */ static const struct script_op script_38[] = { OP_S_SET_INJECT_PLAIN (script_28_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) OP_S_NEW_STREAM_UNI (b, S_UNI_ID(0)) OP_SET_INJECT_WORD (C_BIDI_ID(0) + 1, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED) OP_S_WRITE (b, "orange", 5) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_STREAM_STATE_ERROR,0,0) OP_END }; /* 39. Fault injection - NEW_CONN_ID with zero-len CID */ static int script_39_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) { int ok = 0; WPACKET wpkt; unsigned char frame_buf[64]; size_t i, written; if (h->inject_word1 == 0) 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, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID)) || !TEST_true(WPACKET_quic_write_vlint(&wpkt, 0)) /* seq no */ || !TEST_true(WPACKET_quic_write_vlint(&wpkt, 0)) /* retire prior to */ || !TEST_true(WPACKET_put_bytes_u8(&wpkt, 0))) /* len */ goto err; for (i = 0; i < QUIC_STATELESS_RESET_TOKEN_LEN; ++i) if (!TEST_true(WPACKET_put_bytes_u8(&wpkt, 0x42))) 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_39[] = { OP_S_SET_INJECT_PLAIN (script_39_inject_plain) 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_SET_INJECT_WORD (0, 1) OP_S_WRITE (a, "orange", 5) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_FRAME_ENCODING_ERROR,0,0) OP_END }; /* 40. Shutdown flush test */ static const unsigned char script_40_data[1024] = "strawberry"; static const struct script_op script_40[] = { 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_C_INHIBIT_TICK (1) OP_C_SET_WRITE_BUF_SIZE (a, 1024 * 100 * 3) OP_BEGIN_REPEAT (100) OP_C_WRITE (a, script_40_data, sizeof(script_40_data)) OP_END_REPEAT () OP_C_CONCLUDE (a) OP_C_SHUTDOWN_WAIT () /* disengages tick inhibition */ OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) OP_S_READ_EXPECT (a, "apple", 5) OP_BEGIN_REPEAT (100) OP_S_READ_EXPECT (a, script_40_data, sizeof(script_40_data)) OP_END_REPEAT () OP_S_EXPECT_FIN (a) OP_C_EXPECT_CONN_CLOSE_INFO(0, 1, 0) OP_S_EXPECT_CONN_CLOSE_INFO(0, 1, 1) OP_END }; /* 41. Fault injection - PATH_CHALLENGE yields PATH_RESPONSE */ static const uint64_t path_challenge = UINT64_C(0xbdeb9451169c83aa); static int script_41_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) { int ok = 0; WPACKET wpkt; unsigned char frame_buf[16]; size_t written; if (h->inject_word0 == 0) 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, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE)) || !TEST_true(WPACKET_put_bytes_u64(&wpkt, path_challenge))) goto err; if (!TEST_true(WPACKET_get_total_written(&wpkt, &written)) || !TEST_size_t_eq(written, 9)) goto err; if (!qtest_fault_prepend_frame(h->qtf, frame_buf, written)) goto err; --h->inject_word0; ok = 1; err: if (ok) WPACKET_finish(&wpkt); else WPACKET_cleanup(&wpkt); return ok; } static void script_41_trace(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg) { uint64_t frame_type, frame_data; int was_minimal; struct helper *h = arg; PACKET pkt; if (version != OSSL_QUIC1_VERSION || content_type != SSL3_RT_QUIC_FRAME_FULL || len < 1) return; if (!TEST_true(PACKET_buf_init(&pkt, buf, len))) { ++h->scratch1; return; } if (!TEST_true(ossl_quic_wire_peek_frame_header(&pkt, &frame_type, &was_minimal))) { ++h->scratch1; return; } if (frame_type != OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE) return; if (!TEST_true(ossl_quic_wire_decode_frame_path_response(&pkt, &frame_data)) || !TEST_uint64_t_eq(frame_data, path_challenge)) { ++h->scratch1; return; } ++h->scratch0; } static int script_41_setup(struct helper *h, const struct script_op *op) { ossl_quic_tserver_set_msg_callback(h->s, script_41_trace, h); return 1; } static int script_41_check(struct helper *h, const struct script_op *op) { /* At least one valid challenge/response echo? */ if (!TEST_uint64_t_gt(h->scratch0, 0)) return 0; /* No failed tests? */ if (!TEST_uint64_t_eq(h->scratch1, 0)) return 0; return 1; } static const struct script_op script_41[] = { OP_S_SET_INJECT_PLAIN (script_41_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_CHECK (script_41_setup, 0) OP_C_WRITE (DEFAULT, "apple", 5) 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, "orange", 6) OP_C_READ_EXPECT (DEFAULT, "orange", 6) OP_C_WRITE (DEFAULT, "strawberry", 10) OP_S_READ_EXPECT (a, "strawberry", 10) OP_CHECK (script_41_check, 0) OP_END }; /* 42. Fault injection - CRYPTO frame with illegal offset */ static int script_42_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) { int ok = 0; unsigned char frame_buf[64]; size_t written; WPACKET wpkt; if (h->inject_word0 == 0) return 1; --h->inject_word0; if (!TEST_true(WPACKET_init_static_len(&wpkt, frame_buf, sizeof(frame_buf), 0))) return 0; if (!TEST_true(WPACKET_quic_write_vlint(&wpkt, OSSL_QUIC_FRAME_TYPE_CRYPTO)) || !TEST_true(WPACKET_quic_write_vlint(&wpkt, h->inject_word1)) || !TEST_true(WPACKET_quic_write_vlint(&wpkt, 1)) || !TEST_true(WPACKET_put_bytes_u8(&wpkt, 0x42))) 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_42[] = { OP_S_SET_INJECT_PLAIN (script_42_inject_plain) 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_SET_INJECT_WORD (1, (((uint64_t)1) << 62) - 1) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_FRAME_ENCODING_ERROR,0,0) OP_END }; /* 43. Fault injection - CRYPTO frame exceeding FC */ static const struct script_op script_43[] = { OP_S_SET_INJECT_PLAIN (script_42_inject_plain) 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_SET_INJECT_WORD (1, 0x100000 /* 1 MiB */) OP_S_WRITE (a, "orange", 6) OP_C_EXPECT_CONN_CLOSE_INFO(QUIC_ERR_CRYPTO_BUFFER_EXCEEDED,0,0) OP_END }; /* 44. Fault injection - PADDING */ static int script_44_inject_plain(struct helper *h, QUIC_PKT_HDR *hdr, unsigned char *buf, size_t len) { int ok = 0; WPACKET wpkt; unsigned char frame_buf[16]; size_t written; if (h->inject_word0 == 0) return 1; if (!TEST_true(WPACKET_init_static_len(&wpkt, frame_buf, sizeof(frame_buf), 0))) return 0; if (!TEST_true(ossl_quic_wire_encode_padding(&wpkt, 1))) 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_44[] = { OP_S_SET_INJECT_PLAIN (script_44_inject_plain) OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () OP_C_WRITE (DEFAULT, "apple", 5) 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, "Strawberry", 10) OP_C_READ_EXPECT (DEFAULT, "Strawberry", 10) 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, }; static int test_script(int idx) { int script_idx = idx >> 1; int free_order = idx & 1; char script_name[64]; snprintf(script_name, sizeof(script_name), "script %d", script_idx + 1); TEST_info("Running script %d (order=%d)", script_idx + 1, free_order); return run_script(scripts[script_idx], script_name, free_order); } /* 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(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, QUIC_ERR_FRAME_ENCODING_ERROR }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_VLINT_MAX, QUIC_ERR_FRAME_ENCODING_ERROR }, { QUIC_PKT_TYPE_1RTT, OSSL_QUIC_VLINT_MAX, QUIC_ERR_FRAME_ENCODING_ERROR }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAM, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_RESET_STREAM, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STOP_SENDING, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_DATA, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_INITIAL, OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAM, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_RESET_STREAM, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STOP_SENDING, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_NEW_TOKEN, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_DATA, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP, QUIC_ERR_PROTOCOL_VIOLATION }, { QUIC_PKT_TYPE_HANDSHAKE, OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE, 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, 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); } OPT_TEST_DECLARE_USAGE("certfile privkeyfile\n") int setup_tests(void) { 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); return 1; }