summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorNeil Horman <nhorman@openssl.org>2024-01-23 09:49:27 -0500
committerTomas Mraz <tomas@openssl.org>2024-02-14 18:04:31 +0100
commit09a50376fba61c3d9287aac1f8880f1ec6b6ca0a (patch)
treee02cd50d5d27bf67b744f713bf49abcca594762e /test
parent81619f36bd84a375db8de4b185e09aebd3d6a029 (diff)
Add QUIC stateless reset test
QUIC supports the concept of stateless reset, in which a specially crafted frame is sent to a client informing it that the QUIC state information is no longer available, and the connection should be closed immediately. Test for proper client support here Reviewed-by: Hugo Landau <hlandau@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/23559)
Diffstat (limited to 'test')
-rw-r--r--test/quic_multistream_test.c117
1 files changed, 115 insertions, 2 deletions
diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c
index 22a753ad67..8d6d42b2e3 100644
--- a/test/quic_multistream_test.c
+++ b/test/quic_multistream_test.c
@@ -10,6 +10,7 @@
#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"
@@ -348,6 +349,7 @@ 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 int check_rejected(struct helper *h, struct helper_local *hl)
{
@@ -515,7 +517,7 @@ static int *s_checked_out_p(struct helper *h, int thread_idx)
static QUIC_TSERVER *s_lock(struct helper *h, struct helper_local *hl)
{
- int *p_checked_out = s_checked_out_p(h, hl->thread_idx);
+ 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;
@@ -5050,6 +5052,116 @@ static const struct script_op script_78[] = {
OP_END
};
+static QUIC_STATELESS_RESET_TOKEN test_reset_token = {
+ { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
+ 0xde, 0xad, 0xbe, 0xef }};
+/*
+ * 80. stateless reset
+ * 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_79_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;
+
+ RAND_bytes(databuf, 64);
+ databuf[0] = 0x40;
+ memcpy(&databuf[48], test_reset_token.token,
+ sizeof(test_reset_token.token));
+
+ if (!SSL_inject_net_dgram(h->c_conn, databuf, sizeof(databuf),
+ NULL, h->s_net_bio_addr))
+ return 1;
+
+ return 1;
+}
+
+static int script_79_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;
+
+ 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_79_inject_pkt(struct helper *h, QUIC_PKT_HDR *hdr,
+ unsigned char *buf, size_t len)
+{
+ if (h->inject_word1 == 1)
+ return script_79_send_stateless_reset(h, hdr, buf, len);
+ else if (h->inject_word0 == 1)
+ return script_79_gen_new_conn_id(h, hdr, buf, len);
+
+ return 1;
+}
+
+static const struct script_op script_79[] = {
+ OP_S_SET_INJECT_PLAIN (script_79_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, 0)
+ OP_END
+};
+
static const struct script_op *const scripts[] = {
script_1,
script_2,
@@ -5128,7 +5240,8 @@ static const struct script_op *const scripts[] = {
script_75,
script_76,
script_77,
- script_78
+ script_78,
+ script_79,
};
static int test_script(int idx)