mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-08-23 06:53:25 +02:00
Declare QUIC record length from bytes remaining
This commit is contained in:
+8
-8
@@ -201,15 +201,15 @@ static sword32 quic_record_transfer(QuicRecord* qr, byte* buf, word32 sz)
|
||||
}
|
||||
len = qr->end - qr->start;
|
||||
|
||||
/* We check if the buf is at least RECORD_HEADER_SZ */
|
||||
if (sz < RECORD_HEADER_SZ) {
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (qr->rec_hdr_remain == 0) {
|
||||
/* start a new TLS record */
|
||||
rlen = (qr->len <= (word32)MAX_RECORD_SIZE) ?
|
||||
qr->len : (word32)MAX_RECORD_SIZE;
|
||||
/* a new TLS record needs room for its header, the body of a record
|
||||
* already started can be handed out in smaller pieces */
|
||||
if (sz < RECORD_HEADER_SZ) {
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
/* start a new TLS record over the bytes left to transfer */
|
||||
rlen = (len <= (word32)MAX_RECORD_SIZE) ?
|
||||
len : (word32)MAX_RECORD_SIZE;
|
||||
offset += add_rec_header(buf, rlen,
|
||||
(qr->level == wolfssl_encryption_early_data) ?
|
||||
application_data : handshake);
|
||||
|
||||
+285
-1
@@ -450,6 +450,72 @@ static int test_quic_record_cap(void) {
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* size of a handshake message that does not fit into a single TLS record,
|
||||
* yet stays below what the record layer accepts for one message */
|
||||
#define QUIC_SPLIT_MSG_SZ ((word32)MAX_RECORD_SIZE + 1024)
|
||||
|
||||
static int test_quic_record_split(void) {
|
||||
EXPECT_DECLS;
|
||||
static const byte tp_params[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
/* message sizes around the point where a second TLS record is needed,
|
||||
* the +1..+4 tails are shorter than a record header */
|
||||
static const word32 msg_sizes[] = {
|
||||
(word32)MAX_RECORD_SIZE - HANDSHAKE_HEADER_SZ, /* one record */
|
||||
(word32)MAX_RECORD_SIZE - HANDSHAKE_HEADER_SZ + 1,
|
||||
(word32)MAX_RECORD_SIZE - HANDSHAKE_HEADER_SZ + 2,
|
||||
(word32)MAX_RECORD_SIZE - HANDSHAKE_HEADER_SZ + 3,
|
||||
(word32)MAX_RECORD_SIZE - HANDSHAKE_HEADER_SZ + 4,
|
||||
QUIC_SPLIT_MSG_SZ
|
||||
};
|
||||
WOLFSSL_CTX * ctx = NULL;
|
||||
WOLFSSL * ssl = NULL;
|
||||
uint8_t * msg = NULL;
|
||||
size_t len = 0;
|
||||
size_t i;
|
||||
|
||||
ExpectNotNull(msg = (uint8_t*)XMALLOC(
|
||||
QUIC_SPLIT_MSG_SZ + HANDSHAKE_HEADER_SZ, NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER));
|
||||
|
||||
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
||||
ExpectTrue(wolfSSL_CTX_set_quic_method(ctx, &dummy_method)
|
||||
== WOLFSSL_SUCCESS);
|
||||
|
||||
for (i = 0; i < XELEM_CNT(msg_sizes); i++) {
|
||||
if (msg != NULL) {
|
||||
XMEMSET(msg, 0, msg_sizes[i] + HANDSHAKE_HEADER_SZ);
|
||||
len = fake_record(server_hello, msg_sizes[i], msg);
|
||||
}
|
||||
ExpectNotNull(ssl = wolfSSL_new(ctx));
|
||||
ExpectTrue(wolfSSL_set_quic_transport_params(ssl, tp_params,
|
||||
sizeof(tp_params))
|
||||
== WOLFSSL_SUCCESS);
|
||||
|
||||
/* send the ClientHello, then wait for the server flight */
|
||||
ExpectIntNE(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl, 0),
|
||||
WC_NO_ERR_TRACE(SSL_ERROR_WANT_READ));
|
||||
|
||||
ExpectTrue(provide_data(ssl, wolfssl_encryption_initial, msg, len, 0));
|
||||
|
||||
/* every record handed to the record layer must be complete, so the
|
||||
* zeroed ServerHello is parsed and rejected on its version */
|
||||
ExpectIntNE(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl, 0),
|
||||
WC_NO_ERR_TRACE(VERSION_ERROR));
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
ssl = NULL;
|
||||
}
|
||||
|
||||
wolfSSL_CTX_free(ctx);
|
||||
XFREE(msg, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
printf(" test_quic_record_split: %s\n",
|
||||
(EXPECT_SUCCESS()) ? pass : fail);
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
static int test_quic_crypt(void) {
|
||||
EXPECT_DECLS;
|
||||
WOLFSSL_CTX * ctx = NULL;
|
||||
@@ -1120,7 +1186,8 @@ typedef struct {
|
||||
char rec_log[16*1024];
|
||||
int sent_early_data;
|
||||
int accept_early_data;
|
||||
char early_data[16*1024];
|
||||
/* holds more than one TLS record worth of early data */
|
||||
char early_data[32*1024];
|
||||
size_t early_data_len;
|
||||
} QuicConversation;
|
||||
|
||||
@@ -1423,6 +1490,128 @@ static int test_quic_server_hello(int verbose) {
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* how far the ClientHello is driven past MAX_RECORD_SIZE, and the payload
|
||||
* the probe run uses to measure everything else in it */
|
||||
#define QUIC_BIG_TP_MARGIN 1024
|
||||
#define QUIC_TP_PROBE_SZ 16
|
||||
/* wolfSSL rejects a transport parameter payload above this */
|
||||
#define QUIC_TP_MAX_SZ 65535
|
||||
|
||||
/* length of the ClientHello this client sends with a payload of tp_sz
|
||||
* transport parameter bytes in it */
|
||||
static size_t quic_client_hello_len(WOLFSSL_CTX *ctx, const byte *tp,
|
||||
size_t tp_sz, int verbose)
|
||||
{
|
||||
QuicTestContext tctx;
|
||||
size_t len;
|
||||
|
||||
QuicTestContext_init(&tctx, ctx, "probe", verbose);
|
||||
wolfSSL_set_quic_transport_version(tctx.ssl, TLSX_KEY_QUIC_TP_PARAMS);
|
||||
AssertIntEQ(wolfSSL_set_quic_transport_params(tctx.ssl, tp, tp_sz),
|
||||
WOLFSSL_SUCCESS);
|
||||
AssertIntNE(wolfSSL_connect(tctx.ssl), WOLFSSL_SUCCESS);
|
||||
AssertIntEQ(wolfSSL_get_error(tctx.ssl, 0),
|
||||
WC_NO_ERR_TRACE(SSL_ERROR_WANT_READ));
|
||||
len = tctx.output.len;
|
||||
QuicTestContext_free(&tctx);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int test_quic_big_client_hello(int verbose) {
|
||||
EXPECT_DECLS;
|
||||
WOLFSSL_CTX * ctx_c = NULL;
|
||||
WOLFSSL_CTX * ctx_s = NULL;
|
||||
QuicTestContext tclient, tserver;
|
||||
QuicConversation conv;
|
||||
byte probe[QUIC_TP_PROBE_SZ];
|
||||
byte * tp_params = NULL;
|
||||
const uint8_t * peer_params = NULL;
|
||||
size_t peer_len = 0;
|
||||
size_t base_len = 0;
|
||||
size_t tp_sz = 0;
|
||||
size_t i;
|
||||
|
||||
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
||||
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
|
||||
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
|
||||
WOLFSSL_FILETYPE_PEM));
|
||||
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
|
||||
WOLFSSL_FILETYPE_PEM));
|
||||
|
||||
/* the size of a ClientHello varies a lot with the enabled key shares,
|
||||
* so measure one and size the transport parameters from that */
|
||||
XMEMSET(probe, 0x42, sizeof(probe));
|
||||
if (ctx_c != NULL) {
|
||||
base_len = quic_client_hello_len(ctx_c, probe, sizeof(probe), verbose);
|
||||
}
|
||||
ExpectTrue(base_len > (size_t)QUIC_TP_PROBE_SZ);
|
||||
ExpectTrue(base_len < (size_t)MAX_RECORD_SIZE);
|
||||
if (base_len > (size_t)QUIC_TP_PROBE_SZ &&
|
||||
base_len < (size_t)MAX_RECORD_SIZE) {
|
||||
tp_sz = (size_t)MAX_RECORD_SIZE + QUIC_BIG_TP_MARGIN
|
||||
- (base_len - (size_t)QUIC_TP_PROBE_SZ);
|
||||
}
|
||||
ExpectTrue(tp_sz > 0);
|
||||
ExpectTrue(tp_sz <= (size_t)QUIC_TP_MAX_SZ);
|
||||
/* the ClientHello still has to fit into a single handshake message */
|
||||
ExpectTrue((size_t)MAX_RECORD_SIZE + QUIC_BIG_TP_MARGIN
|
||||
< (size_t)MAX_HANDSHAKE_SZ);
|
||||
|
||||
if (tp_sz > 0) {
|
||||
ExpectNotNull(tp_params = (byte*)XMALLOC(tp_sz, NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER));
|
||||
}
|
||||
if (tp_params != NULL) {
|
||||
/* a pattern, so a mis-ordered reassembly is detected as well */
|
||||
for (i = 0; i < tp_sz; i++) {
|
||||
tp_params[i] = (byte)(i & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
QuicTestContext_init(&tclient, ctx_c, "client", verbose);
|
||||
QuicTestContext_init(&tserver, ctx_s, "server", verbose);
|
||||
/* a single transport parameter extension, the default sends both the
|
||||
* v1 and the draft one */
|
||||
wolfSSL_set_quic_transport_version(tclient.ssl, TLSX_KEY_QUIC_TP_PARAMS);
|
||||
ExpectTrue(wolfSSL_set_quic_transport_params(tclient.ssl, tp_params,
|
||||
tp_sz)
|
||||
== WOLFSSL_SUCCESS);
|
||||
|
||||
/* the ClientHello has to span more than one TLS record, or this test
|
||||
* checks nothing */
|
||||
ExpectIntNE(wolfSSL_connect(tclient.ssl), WOLFSSL_SUCCESS);
|
||||
ExpectTrue(tclient.output.len > (size_t)MAX_RECORD_SIZE);
|
||||
|
||||
/* the server reassembles the ClientHello from several TLS records */
|
||||
QuicConversation_init(&conv, &tclient, &tserver);
|
||||
conv.started = 1;
|
||||
QuicConversation_do(&conv);
|
||||
ExpectIntEQ(tclient.output.len, 0);
|
||||
ExpectIntEQ(tserver.output.len, 0);
|
||||
ExpectTrue(wolfSSL_quic_read_level(tclient.ssl)
|
||||
== wolfssl_encryption_application);
|
||||
ExpectTrue(wolfSSL_quic_read_level(tserver.ssl)
|
||||
== wolfssl_encryption_application);
|
||||
|
||||
/* and got the parameters out of it unchanged */
|
||||
wolfSSL_get_peer_quic_transport_params(tserver.ssl, &peer_params,
|
||||
&peer_len);
|
||||
ExpectIntEQ(peer_len, tp_sz);
|
||||
ExpectNotNull(peer_params);
|
||||
ExpectIntEQ(XMEMCMP(peer_params, tp_params, tp_sz), 0);
|
||||
|
||||
QuicTestContext_free(&tclient);
|
||||
QuicTestContext_free(&tserver);
|
||||
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
XFREE(tp_params, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
printf(" test_quic_big_client_hello: %s\n",
|
||||
EXPECT_SUCCESS() ? pass : fail);
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
static int test_quic_server_hello_fail(int verbose) {
|
||||
EXPECT_DECLS;
|
||||
WOLFSSL_CTX * ctx_c = NULL;
|
||||
@@ -1928,6 +2117,98 @@ static int test_quic_early_data(int verbose) {
|
||||
printf(" test_quic_early_data: %s\n", EXPECT_SUCCESS() ? pass : fail);
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* early data that does not fit into a single TLS record */
|
||||
#define QUIC_BIG_ED_SZ ((size_t)MAX_RECORD_SIZE + 1024)
|
||||
|
||||
static size_t output_level_len(const QuicTestContext *ctx,
|
||||
WOLFSSL_ENCRYPTION_LEVEL level)
|
||||
{
|
||||
const OutputBuffer * out = &ctx->output;
|
||||
size_t len = 0;
|
||||
|
||||
while (out != NULL) {
|
||||
if (out->level == level) {
|
||||
len += out->len;
|
||||
}
|
||||
out = out->next;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static int test_quic_big_early_data(int verbose) {
|
||||
EXPECT_DECLS;
|
||||
WOLFSSL_CTX * ctx_c = NULL;
|
||||
WOLFSSL_CTX * ctx_s = NULL;
|
||||
QuicTestContext tclient, tserver;
|
||||
QuicConversation conv;
|
||||
byte * early_data = NULL;
|
||||
size_t ed_written = 0;
|
||||
WOLFSSL_SESSION * session = NULL;
|
||||
size_t i;
|
||||
|
||||
ExpectNotNull(early_data = (byte*)XMALLOC(QUIC_BIG_ED_SZ, NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER));
|
||||
if (early_data != NULL) {
|
||||
/* a pattern, so a mis-ordered reassembly is detected as well */
|
||||
for (i = 0; i < QUIC_BIG_ED_SZ; i++) {
|
||||
early_data[i] = (byte)(i & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
ExpectNotNull(ctx_c = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
|
||||
wolfSSL_CTX_UseSessionTicket(ctx_c);
|
||||
ExpectNotNull(ctx_s = wolfSSL_CTX_new(wolfTLSv1_3_server_method()));
|
||||
ExpectTrue(wolfSSL_CTX_use_certificate_file(ctx_s, svrCertFile,
|
||||
WOLFSSL_FILETYPE_PEM));
|
||||
ExpectTrue(wolfSSL_CTX_use_PrivateKey_file(ctx_s, svrKeyFile,
|
||||
WOLFSSL_FILETYPE_PEM));
|
||||
|
||||
/* a first handshake, only to obtain a session ticket */
|
||||
QuicTestContext_init(&tclient, ctx_c, "client", verbose);
|
||||
QuicTestContext_init(&tserver, ctx_s, "server", verbose);
|
||||
wolfSSL_set_quic_early_data_enabled(tserver.ssl, 1);
|
||||
QuicConversation_init(&conv, &tclient, &tserver);
|
||||
QuicConversation_do(&conv);
|
||||
ExpectTrue(tclient.ticket_len > 0);
|
||||
ExpectNotNull(session = wolfSSL_get1_session(tclient.ssl));
|
||||
QuicTestContext_free(&tclient);
|
||||
QuicTestContext_free(&tserver);
|
||||
|
||||
/* resume, sending early data over more than one TLS record */
|
||||
QuicTestContext_init(&tserver, ctx_s, "server", verbose);
|
||||
QuicTestContext_init(&tclient, ctx_c, "client", verbose);
|
||||
ExpectIntEQ(wolfSSL_set_session(tclient.ssl, session), WOLFSSL_SUCCESS);
|
||||
wolfSSL_set_quic_early_data_enabled(tserver.ssl, 1);
|
||||
QuicConversation_init(&conv, &tclient, &tserver);
|
||||
/* make QuicConversation_do() use wolfSSL_read_early_data() */
|
||||
conv.accept_early_data = 1;
|
||||
QuicConversation_start(&conv, early_data, QUIC_BIG_ED_SZ, &ed_written);
|
||||
ExpectIntEQ(ed_written, QUIC_BIG_ED_SZ);
|
||||
/* the early data has to span more than one record, or the split path
|
||||
* this exercises is never reached */
|
||||
ExpectTrue(output_level_len(&tclient, wolfssl_encryption_early_data)
|
||||
> (size_t)MAX_RECORD_SIZE);
|
||||
|
||||
QuicConversation_do(&conv);
|
||||
ExpectIntEQ(wolfSSL_get_early_data_status(tclient.ssl),
|
||||
WOLFSSL_EARLY_DATA_ACCEPTED);
|
||||
/* the server reassembled it byte-identically */
|
||||
ExpectIntEQ(conv.early_data_len, QUIC_BIG_ED_SZ);
|
||||
ExpectIntEQ(XMEMCMP(conv.early_data, early_data, QUIC_BIG_ED_SZ), 0);
|
||||
|
||||
QuicTestContext_free(&tclient);
|
||||
QuicTestContext_free(&tserver);
|
||||
|
||||
wolfSSL_SESSION_free(session);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
XFREE(early_data, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
printf(" test_quic_big_early_data: %s\n",
|
||||
EXPECT_SUCCESS() ? pass : fail);
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#endif /* WOLFSSL_EARLY_DATA */
|
||||
|
||||
static int new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
|
||||
@@ -2049,11 +2330,13 @@ int QuicTest(void)
|
||||
#ifndef NO_WOLFSSL_CLIENT
|
||||
if ((ret = test_provide_quic_data()) != TEST_SUCCESS) goto leave;
|
||||
if ((ret = test_quic_record_cap()) != TEST_SUCCESS) goto leave;
|
||||
if ((ret = test_quic_record_split()) != TEST_SUCCESS) goto leave;
|
||||
if ((ret = test_quic_crypt()) != TEST_SUCCESS) goto leave;
|
||||
if ((ret = test_quic_client_hello(verbose)) != TEST_SUCCESS) goto leave;
|
||||
#endif
|
||||
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
|
||||
if ((ret = test_quic_server_hello(verbose)) != TEST_SUCCESS) goto leave;
|
||||
if ((ret = test_quic_big_client_hello(verbose)) != TEST_SUCCESS) goto leave;
|
||||
if ((ret = test_quic_server_hello_fail(verbose)) != TEST_SUCCESS) goto leave;
|
||||
if ((ret = test_quic_key_update_rejected(verbose)) != TEST_SUCCESS) goto leave;
|
||||
#ifdef REALLY_HAVE_ALPN_AND_SNI
|
||||
@@ -2064,6 +2347,7 @@ int QuicTest(void)
|
||||
if ((ret = test_quic_resumption(verbose)) != TEST_SUCCESS) goto leave;
|
||||
#ifdef WOLFSSL_EARLY_DATA
|
||||
if ((ret = test_quic_early_data(verbose)) != TEST_SUCCESS) goto leave;
|
||||
if ((ret = test_quic_big_early_data(verbose)) != TEST_SUCCESS) goto leave;
|
||||
#endif /* WOLFSSL_EARLY_DATA */
|
||||
if ((ret = test_quic_session_export(verbose)) != TEST_SUCCESS) goto leave;
|
||||
#endif /* HAVE_SESSION_TICKET */
|
||||
|
||||
Reference in New Issue
Block a user