Skip to content

Commit

Permalink
Add QUIC stateless reset test
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Tomas Mraz <[email protected]>
(Merged from openssl#23559)
  • Loading branch information
nhorman authored and t8m committed Feb 14, 2024
1 parent 81619f3 commit 09a5037
Showing 1 changed file with 115 additions and 2 deletions.
117 changes: 115 additions & 2 deletions test/quic_multistream_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 09a5037

Please sign in to comment.