mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 12:20:52 +02:00
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:
+22
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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), \
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user