DTLS 1.3: receive-side support for RequestConnectionId/NewConnectionId

Implements the receive-side of RFC 9147 § 9. On NewConnectionId, if
usage is cid_immediate, switches our TX CID to the first usable CID;
if usage is cid_spare, discards it.

RequestConnectionId is parsed and ignored (responding is SHOULD in the
RFC).
This commit is contained in:
Mattia Moffa
2026-06-12 22:30:00 +02:00
parent 0597ab2f96
commit 3b080b7e8b
7 changed files with 541 additions and 2 deletions
+22
View File
@@ -1407,6 +1407,28 @@ int wolfSSL_dtls_cid_set(WOLFSSL* ssl, unsigned char* cid, unsigned int size)
return WOLFSSL_SUCCESS;
}
/* Replace the CID we use when sending records, after the peer provided a new
* one in a NewConnectionId message (RFC 9147 Section 9). */
int DtlsCidReplaceTx(WOLFSSL* ssl, const byte* cid, byte size)
{
CIDInfo* cidInfo;
ConnectionID* newCid;
if (ssl == NULL || cid == NULL || size == 0)
return BAD_FUNC_ARG;
cidInfo = DtlsCidGetInfo(ssl);
if (cidInfo == NULL)
return BAD_STATE_E;
newCid = DtlsCidNew(cid, size, ssl->heap);
if (newCid == NULL)
return MEMORY_ERROR;
XFREE(cidInfo->tx, ssl->heap, DYNAMIC_TYPE_TLSX);
cidInfo->tx = newCid;
return 0;
}
int wolfSSL_dtls_cid_get_rx_size(WOLFSSL* ssl, unsigned int* size)
{
return DtlsCidGetSize(ssl, size, 1);
+103
View File
@@ -230,6 +230,8 @@ static byte Dtls13TypeIsEncrypted(enum HandShakeType hs_type)
case finished:
case certificate_status:
case key_update:
case request_connection_id:
case new_connection_id:
case change_cipher_hs:
case message_hash:
case no_shake:
@@ -330,6 +332,11 @@ static byte Dtls13RtxMsgNeedsAck(WOLFSSL* ssl, enum HandShakeType hs)
if (hs == session_ticket || hs == key_update)
return 1;
#ifdef WOLFSSL_DTLS_CID
if (hs == request_connection_id || hs == new_connection_id)
return 1;
#endif
return 0;
}
@@ -1807,6 +1814,8 @@ int Dtls13CheckEpoch(WOLFSSL* ssl, enum HandShakeType type)
case change_cipher_hs:
case key_update:
case session_ticket:
case request_connection_id:
case new_connection_id:
if (!w64GTE(ssl->keys.curEpoch64, t0Epoch)) {
WOLFSSL_MSG("Msg should be epoch 3+");
WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E);
@@ -2916,6 +2925,100 @@ int DoDtls13KeyUpdateAck(WOLFSSL* ssl)
return ret;
}
#ifdef WOLFSSL_DTLS_CID
/* RequestConnectionId: struct { uint8 num_cids; } (RFC 9147 Section 9).
* Responding with NewConnectionId is a SHOULD; we never send records with a
* CID of our choosing, so we ignore the request. */
int DoDtls13RequestConnectionId(WOLFSSL* ssl, const byte* input,
word32* inOutIdx, word32 size)
{
(void)ssl;
(void)input;
if (size != OPAQUE8_LEN) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}
*inOutIdx += size;
return 0;
}
/* NewConnectionId:
* struct {
* ConnectionId cids<0..2^16-1>;
* ConnectionIdUsage usage;
* } (RFC 9147 Section 9), where ConnectionId is opaque<0..2^8-1>. */
int DoDtls13NewConnectionId(WOLFSSL* ssl, const byte* input,
word32* inOutIdx, word32 size)
{
word32 idx = *inOutIdx;
const byte* newCid = NULL;
byte newCidLen = 0;
word16 cidsLen;
word32 i;
byte usage;
int ret;
if (size < OPAQUE16_LEN + OPAQUE8_LEN) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}
ato16(input + idx, &cidsLen);
idx += OPAQUE16_LEN;
if ((word32)cidsLen + OPAQUE16_LEN + OPAQUE8_LEN != size) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}
/* walk the cids list, remembering the first non-empty CID */
for (i = 0; i < cidsLen;) {
byte cidLen = input[idx + i];
i += OPAQUE8_LEN;
if (i + cidLen > cidsLen) {
WOLFSSL_ERROR_VERBOSE(BUFFER_ERROR);
return BUFFER_ERROR;
}
if (newCid == NULL && cidLen > 0) {
newCid = input + idx + i;
newCidLen = cidLen;
}
i += cidLen;
}
idx += cidsLen;
usage = input[idx];
idx += OPAQUE8_LEN;
if (usage != cid_immediate && usage != cid_spare) {
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
if (usage == cid_immediate) {
/* one of the new CIDs MUST be used immediately for all future
* records */
if (newCid == NULL) {
WOLFSSL_ERROR_VERBOSE(INVALID_PARAMETER);
return INVALID_PARAMETER;
}
/* replace before the ACK for this record is sent so that the ACK
* already uses the new CID */
ret = DtlsCidReplaceTx(ssl, newCid, newCidLen);
if (ret != 0)
return ret;
}
/* cid_spare: we MAY simply discard the CIDs and keep using the
* current one */
*inOutIdx = idx;
return 0;
}
#endif /* WOLFSSL_DTLS_CID */
int DoDtls13Ack(WOLFSSL* ssl, const byte* input, word32 inputSize,
word32* processedSize)
{
+10
View File
@@ -11886,6 +11886,8 @@ int MsgCheckEncryption(WOLFSSL* ssl, byte type, byte encrypted)
case finished:
case certificate_status:
case key_update:
case request_connection_id:
case new_connection_id:
if (!encrypted) {
WOLFSSL_MSG("Message always has to be encrypted");
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
@@ -11946,6 +11948,8 @@ int MsgCheckEncryption(WOLFSSL* ssl, byte type, byte encrypted)
case key_update:
case encrypted_extensions:
case end_of_early_data:
case request_connection_id:
case new_connection_id:
case message_hash:
case no_shake:
default:
@@ -11994,6 +11998,8 @@ static int MsgCheckBoundary(const WOLFSSL* ssl, byte type,
case certificate_status:
case key_update:
case change_cipher_hs:
case request_connection_id:
case new_connection_id:
break;
case server_hello_done:
case message_hash:
@@ -12031,6 +12037,8 @@ static int MsgCheckBoundary(const WOLFSSL* ssl, byte type,
case hello_retry_request:
case encrypted_extensions:
case key_update:
case request_connection_id:
case new_connection_id:
case message_hash:
case no_shake:
default:
@@ -12067,6 +12075,8 @@ static int MsgCheckBoundary(const WOLFSSL* ssl, byte type,
case key_update:
case change_cipher_hs:
break;
case request_connection_id:
case new_connection_id:
case message_hash:
case no_shake:
default:
+70 -2
View File
@@ -13620,6 +13620,54 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type)
break;
#endif /* WOLFSSL_DTLS13 && !WOLFSSL_NO_TLS12*/
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
case request_connection_id:
case new_connection_id:
{
CIDInfo* cidInfo = ssl->dtlsCidInfo;
/* DTLS 1.3 only (RFC 9147) */
if (!ssl->options.dtls) {
WOLFSSL_MSG("CID message received but not DTLS");
WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E);
return SANITY_MSG_E;
}
/* RFC 9147 Section 9: if CIDs were not negotiated, MUST abort
* with an unexpected_message alert */
if (cidInfo == NULL || !cidInfo->negotiated) {
WOLFSSL_MSG("CID message received but CID not negotiated");
WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E);
return SANITY_MSG_E;
}
if (ssl->options.handShakeState != HANDSHAKE_DONE) {
WOLFSSL_MSG("CID message received out of order");
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
return OUT_OF_ORDER_E;
}
if (type == request_connection_id) {
/* the peer MUST NOT request CIDs while sending an empty
* CID itself */
if (cidInfo->rx == NULL || cidInfo->rx->length == 0) {
WOLFSSL_MSG("RequestConnectionId from peer sending an "
"empty CID");
WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E);
return SANITY_MSG_E;
}
}
else {
/* the peer MUST NOT issue CIDs after negotiating receiving
* an empty CID */
if (cidInfo->tx == NULL || cidInfo->tx->length == 0) {
WOLFSSL_MSG("NewConnectionId from peer that negotiated "
"an empty CID");
WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E);
return SANITY_MSG_E;
}
}
break;
}
#endif /* WOLFSSL_DTLS13 && WOLFSSL_DTLS_CID */
default:
WOLFSSL_MSG("Unknown message type");
WOLFSSL_ERROR_VERBOSE(SANITY_MSG_E);
@@ -13682,7 +13730,11 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (ssl->options.handShakeState == HANDSHAKE_DONE &&
type != session_ticket && type != certificate_request &&
type != certificate && type != key_update && type != finished) {
type != certificate && type != key_update && type != finished
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
&& type != request_connection_id && type != new_connection_id
#endif
) {
WOLFSSL_MSG("HandShake message after handshake complete");
SendAlert(ssl, alert_fatal, unexpected_message);
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
@@ -13865,6 +13917,18 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ret = DoTls13KeyUpdate(ssl, input, inOutIdx, size);
break;
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
case request_connection_id:
WOLFSSL_MSG("processing request connection id");
ret = DoDtls13RequestConnectionId(ssl, input, inOutIdx, size);
break;
case new_connection_id:
WOLFSSL_MSG("processing new connection id");
ret = DoDtls13NewConnectionId(ssl, input, inOutIdx, size);
break;
#endif /* WOLFSSL_DTLS13 && WOLFSSL_DTLS_CID */
#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_NO_TLS12) && \
!defined(NO_WOLFSSL_CLIENT)
case hello_verify_request:
@@ -13897,7 +13961,11 @@ int DoTls13HandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
}
#endif
if (ret == 0 && type != client_hello && type != session_ticket &&
type != key_update) {
type != key_update
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
&& type != request_connection_id && type != new_connection_id
#endif
) {
ret = HashInput(ssl, input + inIdx, (int)size);
}
+313
View File
@@ -680,6 +680,319 @@ int test_wolfSSL_dtls_set_pending_peer_not_newest(void)
return EXPECT_RESULT();
}
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
/* Set up a DTLS 1.3 connection, optionally negotiating CID, and drain all
* post-handshake messages (session tickets, ACKs) so both buffers are empty. */
static int test_dtls13_cid_setup(struct test_memio_ctx* test_ctx,
WOLFSSL_CTX** ctx_c, WOLFSSL_CTX** ctx_s, WOLFSSL** ssl_c,
WOLFSSL** ssl_s, int useCid)
{
EXPECT_DECLS;
unsigned char client_cid[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
unsigned char server_cid[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte readBuf[16];
int i;
XMEMSET(test_ctx, 0, sizeof(*test_ctx));
ExpectIntEQ(test_memio_setup(test_ctx, ctx_c, ctx_s, ssl_c, ssl_s,
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), 0);
if (useCid) {
ExpectIntEQ(wolfSSL_dtls_cid_use(*ssl_c), 1);
ExpectIntEQ(wolfSSL_dtls_cid_set(*ssl_c, server_cid,
sizeof(server_cid)), 1);
ExpectIntEQ(wolfSSL_dtls_cid_use(*ssl_s), 1);
ExpectIntEQ(wolfSSL_dtls_cid_set(*ssl_s, client_cid,
sizeof(client_cid)), 1);
}
ExpectIntEQ(test_memio_do_handshake(*ssl_c, *ssl_s, 10, NULL), 0);
for (i = 0; i < 5 && EXPECT_SUCCESS() &&
(test_ctx->c_len > 0 || test_ctx->s_len > 0); i++) {
if (test_ctx->c_len > 0)
ExpectIntEQ(wolfSSL_read(*ssl_c, readBuf, sizeof(readBuf)), -1);
if (test_ctx->s_len > 0)
ExpectIntEQ(wolfSSL_read(*ssl_s, readBuf, sizeof(readBuf)), -1);
}
ExpectIntEQ(test_ctx->c_len, 0);
ExpectIntEQ(test_ctx->s_len, 0);
return EXPECT_RESULT();
}
/* Build a post-handshake handshake message of type hsType with the given body
* and encrypt it with the client's current traffic keys. The message sequence
* number is the one the server expects next. */
static int test_dtls13_build_post_hs_msg(WOLFSSL* ssl_c, WOLFSSL* ssl_s,
byte hsType, const byte* body, word16 bodyLen, byte* rec, int* recSz)
{
EXPECT_DECLS;
byte msg[64];
size_t idx = 0;
ExpectIntLE(DTLS_HANDSHAKE_HEADER_SZ + bodyLen, sizeof(msg));
msg[idx++] = hsType;
c32to24(bodyLen, msg + idx);
idx += 3;
c16toa(ssl_s->keys.dtls_expected_peer_handshake_number, msg + idx);
idx += 2;
/* fragment_offset */
c32to24(0, msg + idx);
idx += 3;
/* fragment_length */
c32to24(bodyLen, msg + idx);
idx += 3;
XMEMCPY(msg + idx, body, bodyLen);
idx += bodyLen;
ExpectIntGT(*recSz = BuildTls13Message(ssl_c, rec, *recSz, msg, (int)idx,
handshake, 0, 0, 0), 0);
return EXPECT_RESULT();
}
/* Inject a crafted post-handshake message into the server, expect it to fail
* with expErr and to alert the client with a fatal alert of type expAlert. */
static int test_dtls13_post_hs_cid_msg_err(byte hsType, const byte* body,
word16 bodyLen, int useCid, int expErr, int expAlert)
{
EXPECT_DECLS;
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
WOLFSSL_ALERT_HISTORY h;
byte rec[256];
int recSz = (int)sizeof(rec);
byte readBuf[16];
ExpectIntEQ(test_dtls13_cid_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, useCid), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_build_post_hs_msg(ssl_c, ssl_s, hsType, body,
bodyLen, rec, &recSz), TEST_SUCCESS);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)rec,
recSz), 0);
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), expErr);
/* the server must send a fatal alert */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
XMEMSET(&h, 0, sizeof(h));
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
ExpectIntEQ(h.last_rx.level, alert_fatal);
ExpectIntEQ(h.last_rx.code, expAlert);
wolfSSL_free(ssl_s);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_s);
wolfSSL_CTX_free(ctx_c);
return EXPECT_RESULT();
}
#endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES && WOLFSSL_DTLS13 &&
* WOLFSSL_DTLS_CID */
int test_dtls13_new_connection_id(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
unsigned char server_cid[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
/* one 3-byte CID, usage cid_spare */
const byte spareBody[] = { 0x00, 0x04, 0x03, 0xaa, 0xbb, 0xcc, 0x01 };
/* one zero-length CID followed by a 3-byte CID, usage cid_immediate */
const byte immBody[] = { 0x00, 0x05, 0x00, 0x03, 0x11, 0x22, 0x33, 0x00 };
const byte newCid[] = { 0x11, 0x22, 0x33 };
unsigned char cidBuf[DTLS_CID_MAX_SIZE];
unsigned int cidSz = 0;
byte rec[256];
int recSz = (int)sizeof(rec);
byte readBuf[16];
const byte* parsedCid = NULL;
/* usage cid_spare: the new CID may be discarded, ours must not change */
ExpectIntEQ(test_dtls13_cid_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, 1), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_build_post_hs_msg(ssl_c, ssl_s, new_connection_id,
spareBody, sizeof(spareBody), rec, &recSz), TEST_SUCCESS);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)rec,
recSz), 0);
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* the server ACKed the message */
ExpectIntGT(test_ctx.c_len, 0);
ExpectIntEQ(wolfSSL_dtls_cid_get_tx_size(ssl_s, &cidSz), 1);
ExpectIntEQ(cidSz, sizeof(server_cid));
ExpectIntEQ(wolfSSL_dtls_cid_get_tx(ssl_s, cidBuf, sizeof(cidBuf)), 1);
ExpectBufEQ(cidBuf, server_cid, sizeof(server_cid));
/* duplicate delivery: the retransmitted record must be dropped */
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)rec,
recSz), 0);
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
/* connection must still work in both directions */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(wolfSSL_write(ssl_c, "test", 5), 5);
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), 5);
ExpectStrEQ(readBuf, "test");
ExpectIntEQ(wolfSSL_write(ssl_s, "back", 5), 5);
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), 5);
ExpectStrEQ(readBuf, "back");
wolfSSL_free(ssl_s);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_s);
wolfSSL_CTX_free(ctx_c);
ssl_c = ssl_s = NULL;
ctx_c = ctx_s = NULL;
/* usage cid_immediate: the first non-empty CID must be used for all
* records sent from now on, including the ACK of this message */
ExpectIntEQ(test_dtls13_cid_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, 1), TEST_SUCCESS);
recSz = (int)sizeof(rec);
ExpectIntEQ(test_dtls13_build_post_hs_msg(ssl_c, ssl_s, new_connection_id,
immBody, sizeof(immBody), rec, &recSz), TEST_SUCCESS);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)rec,
recSz), 0);
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
cidSz = 0;
ExpectIntEQ(wolfSSL_dtls_cid_get_tx_size(ssl_s, &cidSz), 1);
ExpectIntEQ(cidSz, sizeof(newCid));
ExpectIntEQ(wolfSSL_dtls_cid_get_tx(ssl_s, cidBuf, sizeof(cidBuf)), 1);
ExpectBufEQ(cidBuf, newCid, sizeof(newCid));
/* the ACK record already carries the new CID */
ExpectIntGT(test_ctx.c_len, 0);
ExpectNotNull(parsedCid = wolfSSL_dtls_cid_parse(test_ctx.c_buff,
(unsigned int)test_ctx.c_len, sizeof(newCid)));
if (parsedCid != NULL)
ExpectBufEQ(parsedCid, newCid, sizeof(newCid));
wolfSSL_free(ssl_s);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_s);
wolfSSL_CTX_free(ctx_c);
#endif
return EXPECT_RESULT();
}
int test_dtls13_new_connection_id_not_negotiated(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
/* one 3-byte CID, usage cid_spare */
const byte body[] = { 0x00, 0x04, 0x03, 0xaa, 0xbb, 0xcc, 0x01 };
/* RFC 9147 Section 9: receiving a CID message when CIDs were not
* negotiated must be answered with an unexpected_message alert */
ExpectIntEQ(test_dtls13_post_hs_cid_msg_err(new_connection_id, body,
sizeof(body), 0, WC_NO_ERR_TRACE(SANITY_MSG_E),
unexpected_message), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_post_hs_cid_msg_err(request_connection_id,
(const byte*)"\x02", 1, 0, WC_NO_ERR_TRACE(SANITY_MSG_E),
unexpected_message), TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
int test_dtls13_request_connection_id(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
const byte body[] = { 0x02 }; /* num_cids */
byte rec[256];
int recSz = (int)sizeof(rec);
byte readBuf[16];
/* the request is ACKed but ignored: we never send NewConnectionId */
ExpectIntEQ(test_dtls13_cid_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, 1), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_build_post_hs_msg(ssl_c, ssl_s,
request_connection_id, body, sizeof(body), rec, &recSz),
TEST_SUCCESS);
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)rec,
recSz), 0);
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntGT(test_ctx.c_len, 0);
/* nothing but the ACK reaches the client */
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
ExpectIntEQ(test_ctx.c_len, 0);
ExpectIntEQ(test_ctx.s_len, 0);
/* connection must still work in both directions */
ExpectIntEQ(wolfSSL_write(ssl_c, "test", 5), 5);
ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), 5);
ExpectStrEQ(readBuf, "test");
ExpectIntEQ(wolfSSL_write(ssl_s, "back", 5), 5);
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), 5);
ExpectStrEQ(readBuf, "back");
wolfSSL_free(ssl_s);
wolfSSL_free(ssl_c);
wolfSSL_CTX_free(ctx_s);
wolfSSL_CTX_free(ctx_c);
#endif
return EXPECT_RESULT();
}
int test_dtls13_cid_msg_malformed(void)
{
EXPECT_DECLS;
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
defined(WOLFSSL_DTLS13) && defined(WOLFSSL_DTLS_CID)
/* cids length exceeding the body */
const byte truncated[] = { 0x00, 0x10, 0x03, 0x11, 0x22, 0x33, 0x01 };
/* CID length exceeding the cids vector */
const byte innerOverrun[] = { 0x00, 0x03, 0x05, 0x11, 0x22, 0x01 };
/* RequestConnectionId must be exactly one byte */
const byte reqTooLong[] = { 0x02, 0x00 };
/* invalid usage */
const byte badUsage[] = { 0x00, 0x04, 0x03, 0x11, 0x22, 0x33, 0x02 };
/* cid_immediate with no CID to use */
const byte immEmpty[] = { 0x00, 0x00, 0x00 };
const byte immZeroLenCid[] = { 0x00, 0x01, 0x00, 0x00 };
ExpectIntEQ(test_dtls13_post_hs_cid_msg_err(new_connection_id, truncated,
sizeof(truncated), 1, WC_NO_ERR_TRACE(BUFFER_ERROR),
decode_error), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_post_hs_cid_msg_err(new_connection_id,
innerOverrun, sizeof(innerOverrun), 1,
WC_NO_ERR_TRACE(BUFFER_ERROR), decode_error), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_post_hs_cid_msg_err(request_connection_id,
reqTooLong, sizeof(reqTooLong), 1, WC_NO_ERR_TRACE(BUFFER_ERROR),
decode_error), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_post_hs_cid_msg_err(new_connection_id, badUsage,
sizeof(badUsage), 1, WC_NO_ERR_TRACE(INVALID_PARAMETER),
illegal_parameter), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_post_hs_cid_msg_err(new_connection_id, immEmpty,
sizeof(immEmpty), 1, WC_NO_ERR_TRACE(INVALID_PARAMETER),
illegal_parameter), TEST_SUCCESS);
ExpectIntEQ(test_dtls13_post_hs_cid_msg_err(new_connection_id,
immZeroLenCid, sizeof(immZeroLenCid), 1,
WC_NO_ERR_TRACE(INVALID_PARAMETER), illegal_parameter),
TEST_SUCCESS);
#endif
return EXPECT_RESULT();
}
int test_dtls_version_checking(void)
{
+8
View File
@@ -26,6 +26,10 @@ int test_dtls12_basic_connection_id(void);
int test_wolfSSL_dtls_cid_parse(void);
int test_wolfSSL_dtls_set_pending_peer(void);
int test_wolfSSL_dtls_set_pending_peer_not_newest(void);
int test_dtls13_new_connection_id(void);
int test_dtls13_new_connection_id_not_negotiated(void);
int test_dtls13_request_connection_id(void);
int test_dtls13_cid_msg_malformed(void);
int test_dtls_version_checking(void);
int test_dtls_short_ciphertext(void);
int test_dtls12_record_length_mismatch(void);
@@ -107,6 +111,10 @@ int test_WOLFSSL_dtls_version_alert(void);
TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_cid_parse), \
TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_pending_peer), \
TEST_DECL_GROUP("dtls", test_wolfSSL_dtls_set_pending_peer_not_newest),\
TEST_DECL_GROUP("dtls", test_dtls13_new_connection_id), \
TEST_DECL_GROUP("dtls", test_dtls13_new_connection_id_not_negotiated), \
TEST_DECL_GROUP("dtls", test_dtls13_request_connection_id), \
TEST_DECL_GROUP("dtls", test_dtls13_cid_msg_malformed), \
TEST_DECL_GROUP("dtls", test_dtls_version_checking), \
TEST_DECL_GROUP("dtls", test_dtls_short_ciphertext), \
TEST_DECL_GROUP("dtls", test_dtls12_record_length_mismatch), \
+15
View File
@@ -3894,6 +3894,7 @@ WOLFSSL_LOCAL int TLSX_ConnectionID_Parse(WOLFSSL* ssl, const byte* input,
WOLFSSL_LOCAL void DtlsCIDOnExtensionsParsed(WOLFSSL* ssl);
WOLFSSL_LOCAL byte DtlsCIDCheck(WOLFSSL* ssl, const byte* input,
word16 inputSize);
WOLFSSL_LOCAL int DtlsCidReplaceTx(WOLFSSL* ssl, const byte* cid, byte size);
WOLFSSL_LOCAL int Dtls13UnifiedHeaderCIDPresent(byte flags);
#endif /* WOLFSSL_DTLS_CID */
WOLFSSL_LOCAL byte DtlsGetCidTxSize(WOLFSSL* ssl);
@@ -6089,6 +6090,12 @@ typedef struct CIDInfo {
ConnectionID* rx;
byte negotiated : 1;
} CIDInfo;
/* ConnectionIdUsage of the NewConnectionId message (RFC 9147 Section 9) */
enum ConnectionIdUsage {
cid_immediate = 0,
cid_spare = 1
};
#endif /* WOLFSSL_DTLS_CID */
/* The idea is to reuse the context suites object whenever possible to save
@@ -6794,6 +6801,8 @@ enum HandShakeType {
end_of_early_data = 5,
hello_retry_request = 6,
encrypted_extensions = 8,
request_connection_id = 9, /* DTLS v1.3 addition (RFC 9147) */
new_connection_id = 10, /* DTLS v1.3 addition (RFC 9147) */
certificate = 11,
server_key_exchange = 12,
certificate_request = 13,
@@ -7442,6 +7451,12 @@ WOLFSSL_LOCAL int Dtls13HandshakeAddHeader(WOLFSSL* ssl, byte* output,
#define EE_MASK (0x3)
WOLFSSL_LOCAL int Dtls13FragmentsContinue(WOLFSSL* ssl);
WOLFSSL_LOCAL int DoDtls13KeyUpdateAck(WOLFSSL* ssl);
#ifdef WOLFSSL_DTLS_CID
WOLFSSL_LOCAL int DoDtls13RequestConnectionId(WOLFSSL* ssl, const byte* input,
word32* inOutIdx, word32 size);
WOLFSSL_LOCAL int DoDtls13NewConnectionId(WOLFSSL* ssl, const byte* input,
word32* inOutIdx, word32 size);
#endif /* WOLFSSL_DTLS_CID */
WOLFSSL_LOCAL int DoDtls13Ack(WOLFSSL* ssl, const byte* input, word32 inputSize,
word32* processedSize);
WOLFSSL_LOCAL int Dtls13ReconstructEpochNumber(WOLFSSL* ssl, byte epochBits,