forked from wolfSSL/wolfssl
Merge pull request #6700 from julek-wolfssl/dtls13-downgrade-acks
DTLS 1.3: do not send ACKs until we negotiate 1.3 (through SH)
This commit is contained in:
@@ -91,7 +91,7 @@ set -e
|
|||||||
|
|
||||||
if [ -d ./async ];
|
if [ -d ./async ];
|
||||||
then
|
then
|
||||||
echo "\n\nUsing existing async repo\n\n"
|
echo "Using existing async repo"
|
||||||
else
|
else
|
||||||
# make a clone of the wolfAsyncCrypt repository
|
# make a clone of the wolfAsyncCrypt repository
|
||||||
git clone --depth 1 $ASYNC_REPO async
|
git clone --depth 1 $ASYNC_REPO async
|
||||||
|
@@ -75,6 +75,7 @@ void DtlsResetState(WOLFSSL* ssl)
|
|||||||
ssl->options.connectState = CONNECT_BEGIN;
|
ssl->options.connectState = CONNECT_BEGIN;
|
||||||
ssl->options.acceptState = ACCEPT_BEGIN;
|
ssl->options.acceptState = ACCEPT_BEGIN;
|
||||||
ssl->options.handShakeState = NULL_STATE;
|
ssl->options.handShakeState = NULL_STATE;
|
||||||
|
ssl->options.seenUnifiedHdr = 0;
|
||||||
ssl->msgsReceived.got_client_hello = 0;
|
ssl->msgsReceived.got_client_hello = 0;
|
||||||
ssl->keys.dtls_handshake_number = 0;
|
ssl->keys.dtls_handshake_number = 0;
|
||||||
ssl->keys.dtls_expected_peer_handshake_number = 0;
|
ssl->keys.dtls_expected_peer_handshake_number = 0;
|
||||||
|
48
src/dtls13.c
48
src/dtls13.c
@@ -352,6 +352,7 @@ int Dtls13ProcessBufferedMessages(WOLFSSL* ssl)
|
|||||||
WOLFSSL_ENTER("Dtls13ProcessBufferedMessages");
|
WOLFSSL_ENTER("Dtls13ProcessBufferedMessages");
|
||||||
|
|
||||||
while (msg != NULL) {
|
while (msg != NULL) {
|
||||||
|
int downgraded = 0;
|
||||||
idx = 0;
|
idx = 0;
|
||||||
|
|
||||||
/* message not in order */
|
/* message not in order */
|
||||||
@@ -362,8 +363,18 @@ int Dtls13ProcessBufferedMessages(WOLFSSL* ssl)
|
|||||||
if (!msg->ready)
|
if (!msg->ready)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ret = DoTls13HandShakeMsgType(ssl, msg->fullMsg, &idx, msg->type,
|
/* We may have DTLS <=1.2 msgs stored from before we knew which version
|
||||||
msg->sz, msg->sz);
|
* we were going to use. Interpret correctly. */
|
||||||
|
if (IsAtLeastTLSv1_3(ssl->version)) {
|
||||||
|
ret = DoTls13HandShakeMsgType(ssl, msg->fullMsg, &idx, msg->type,
|
||||||
|
msg->sz, msg->sz);
|
||||||
|
if (!IsAtLeastTLSv1_3(ssl->version))
|
||||||
|
downgraded = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = DoHandShakeMsgType(ssl, msg->fullMsg, &idx, msg->type,
|
||||||
|
msg->sz, msg->sz);
|
||||||
|
}
|
||||||
|
|
||||||
/* processing certificate_request triggers a connect. The error came
|
/* processing certificate_request triggers a connect. The error came
|
||||||
* from there, the message can be considered processed successfully.
|
* from there, the message can be considered processed successfully.
|
||||||
@@ -371,7 +382,13 @@ int Dtls13ProcessBufferedMessages(WOLFSSL* ssl)
|
|||||||
* waiting to flush the output buffer. */
|
* waiting to flush the output buffer. */
|
||||||
if ((ret == 0 || ret == WANT_WRITE) || (msg->type == certificate_request &&
|
if ((ret == 0 || ret == WANT_WRITE) || (msg->type == certificate_request &&
|
||||||
ssl->options.handShakeDone && ret == WC_PENDING_E)) {
|
ssl->options.handShakeDone && ret == WC_PENDING_E)) {
|
||||||
Dtls13MsgWasProcessed(ssl, (enum HandShakeType)msg->type);
|
if (IsAtLeastTLSv1_3(ssl->version))
|
||||||
|
Dtls13MsgWasProcessed(ssl, (enum HandShakeType)msg->type);
|
||||||
|
else if (downgraded)
|
||||||
|
/* DoHandShakeMsgType normally handles the hs number but if
|
||||||
|
* DoTls13HandShakeMsgType processed 1.2 msgs then this wasn't
|
||||||
|
* incremented. */
|
||||||
|
ssl->keys.dtls_expected_peer_handshake_number++;
|
||||||
|
|
||||||
ssl->dtls_rx_msg_list = msg->next;
|
ssl->dtls_rx_msg_list = msg->next;
|
||||||
DtlsMsgDelete(msg, ssl->heap);
|
DtlsMsgDelete(msg, ssl->heap);
|
||||||
@@ -625,7 +642,7 @@ static void Dtls13RtxRecordUnlink(WOLFSSL* ssl, Dtls13RtxRecord** prevNext,
|
|||||||
*prevNext = r->next;
|
*prevNext = r->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Dtls13RtxFlushBuffered(WOLFSSL* ssl, byte keepNewSessionTicket)
|
void Dtls13RtxFlushBuffered(WOLFSSL* ssl, byte keepNewSessionTicket)
|
||||||
{
|
{
|
||||||
Dtls13RtxRecord *r, **prevNext;
|
Dtls13RtxRecord *r, **prevNext;
|
||||||
|
|
||||||
@@ -806,10 +823,16 @@ static int Dtls13RtxMsgRecvd(WOLFSSL* ssl, enum HandShakeType hs,
|
|||||||
Dtls13MaybeSaveClientHello(ssl);
|
Dtls13MaybeSaveClientHello(ssl);
|
||||||
|
|
||||||
/* In the handshake, receiving part of the next flight, acknowledge the
|
/* In the handshake, receiving part of the next flight, acknowledge the
|
||||||
sent flight. The only exception is, on the server side, receiving the
|
* sent flight. */
|
||||||
last client flight does not ACK any sent new_session_ticket
|
/* On the server side, receiving the last client flight does not ACK any
|
||||||
messages. */
|
* sent new_session_ticket messages. */
|
||||||
Dtls13RtxFlushBuffered(ssl, 1);
|
/* We don't want to clear the buffer until we have done version
|
||||||
|
* negotiation in the SH or have received a unified header in the
|
||||||
|
* DTLS record. */
|
||||||
|
if (ssl->options.serverState >= SERVER_HELLO_COMPLETE ||
|
||||||
|
ssl->options.seenUnifiedHdr)
|
||||||
|
/* Use 1.2 API to clear 1.2 buffers too */
|
||||||
|
DtlsMsgPoolReset(ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssl->keys.dtls_peer_handshake_number <
|
if (ssl->keys.dtls_peer_handshake_number <
|
||||||
@@ -853,6 +876,8 @@ static int Dtls13RtxMsgRecvd(WOLFSSL* ssl, enum HandShakeType hs,
|
|||||||
void Dtls13FreeFsmResources(WOLFSSL* ssl)
|
void Dtls13FreeFsmResources(WOLFSSL* ssl)
|
||||||
{
|
{
|
||||||
Dtls13RtxFlushAcks(ssl);
|
Dtls13RtxFlushAcks(ssl);
|
||||||
|
/* Use 1.2 API to clear 1.2 buffers too */
|
||||||
|
DtlsMsgPoolReset(ssl);
|
||||||
Dtls13RtxFlushBuffered(ssl, 0);
|
Dtls13RtxFlushBuffered(ssl, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2471,7 +2496,12 @@ int Dtls13RtxTimeout(WOLFSSL* ssl)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (ssl->dtls13Rtx.seenRecords != NULL) {
|
/* We don't want to send acks until we have done version
|
||||||
|
* negotiation in the SH or have received a unified header in the
|
||||||
|
* DTLS record. */
|
||||||
|
if (ssl->dtls13Rtx.seenRecords != NULL &&
|
||||||
|
(ssl->options.serverState >= SERVER_HELLO_COMPLETE ||
|
||||||
|
ssl->options.seenUnifiedHdr)) {
|
||||||
ssl->dtls13Rtx.sendAcks = 0;
|
ssl->dtls13Rtx.sendAcks = 0;
|
||||||
/* reset fast timeout as we are sending ACKs */
|
/* reset fast timeout as we are sending ACKs */
|
||||||
ssl->dtls13FastTimeout = 0;
|
ssl->dtls13FastTimeout = 0;
|
||||||
|
@@ -9185,6 +9185,10 @@ void DtlsMsgPoolReset(WOLFSSL* ssl)
|
|||||||
ssl->dtls_tx_msg = NULL;
|
ssl->dtls_tx_msg = NULL;
|
||||||
ssl->dtls_tx_msg_list_sz = 0;
|
ssl->dtls_tx_msg_list_sz = 0;
|
||||||
}
|
}
|
||||||
|
#ifdef WOLFSSL_DTLS13
|
||||||
|
/* Clear DTLS 1.3 buffer too */
|
||||||
|
Dtls13RtxFlushBuffered(ssl, 1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -10740,6 +10744,7 @@ static int GetDtlsRecordHeader(WOLFSSL* ssl, word32* inOutIdx,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (Dtls13IsUnifiedHeader(*(ssl->buffers.inputBuffer.buffer + *inOutIdx))) {
|
if (Dtls13IsUnifiedHeader(*(ssl->buffers.inputBuffer.buffer + *inOutIdx))) {
|
||||||
|
ssl->options.seenUnifiedHdr = 1; /* We can send ACKs to the peer */
|
||||||
|
|
||||||
/* version 1.3 already negotiated */
|
/* version 1.3 already negotiated */
|
||||||
if (ssl->options.tls1_3) {
|
if (ssl->options.tls1_3) {
|
||||||
@@ -15678,6 +15683,12 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type)
|
|||||||
WOLFSSL_ERROR_VERBOSE(DUPLICATE_MSG_E);
|
WOLFSSL_ERROR_VERBOSE(DUPLICATE_MSG_E);
|
||||||
return DUPLICATE_MSG_E;
|
return DUPLICATE_MSG_E;
|
||||||
}
|
}
|
||||||
|
if (ssl->msgsReceived.got_hello_retry_request) {
|
||||||
|
WOLFSSL_MSG("Received HelloVerifyRequest after a "
|
||||||
|
"HelloRetryRequest");
|
||||||
|
WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
|
||||||
|
return VERSION_ERROR;
|
||||||
|
}
|
||||||
ssl->msgsReceived.got_hello_verify_request = 1;
|
ssl->msgsReceived.got_hello_verify_request = 1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -16050,7 +16061,7 @@ static int SanityCheckMsgReceived(WOLFSSL* ssl, byte type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
|
||||||
byte type, word32 size, word32 totalSz)
|
byte type, word32 size, word32 totalSz)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
12
src/ssl.c
12
src/ssl.c
@@ -12447,7 +12447,7 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
|
|||||||
return WOLFSSL_FATAL_ERROR;
|
return WOLFSSL_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
/* if resumption failed, reset needed state */
|
/* if resumption failed, reset needed state */
|
||||||
else if (neededState == SERVER_FINISHED_COMPLETE)
|
else if (neededState == SERVER_FINISHED_COMPLETE) {
|
||||||
if (!ssl->options.resuming) {
|
if (!ssl->options.resuming) {
|
||||||
#ifdef WOLFSSL_DTLS
|
#ifdef WOLFSSL_DTLS
|
||||||
if (IsDtlsNotSctpMode(ssl))
|
if (IsDtlsNotSctpMode(ssl))
|
||||||
@@ -12456,17 +12456,19 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
|
|||||||
#endif
|
#endif
|
||||||
neededState = SERVER_HELLODONE_COMPLETE;
|
neededState = SERVER_HELLODONE_COMPLETE;
|
||||||
}
|
}
|
||||||
#ifdef WOLFSSL_DTLS13
|
}
|
||||||
|
|
||||||
|
#ifdef WOLFSSL_DTLS13
|
||||||
if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)
|
if (ssl->options.dtls && IsAtLeastTLSv1_3(ssl->version)
|
||||||
&& ssl->dtls13Rtx.sendAcks == 1) {
|
&& ssl->dtls13Rtx.sendAcks == 1
|
||||||
ssl->dtls13Rtx.sendAcks = 0;
|
&& ssl->options.seenUnifiedHdr) {
|
||||||
/* we aren't negotiated the version yet, so we aren't sure
|
/* we aren't negotiated the version yet, so we aren't sure
|
||||||
* the other end can speak v1.3. On the other side we have
|
* the other end can speak v1.3. On the other side we have
|
||||||
* received a unified records, assuming that the
|
* received a unified records, assuming that the
|
||||||
* ServerHello got lost, we will send an empty ACK. In case
|
* ServerHello got lost, we will send an empty ACK. In case
|
||||||
* the server is a DTLS with version less than 1.3, it
|
* the server is a DTLS with version less than 1.3, it
|
||||||
* should just ignore the message */
|
* should just ignore the message */
|
||||||
|
ssl->dtls13Rtx.sendAcks = 0;
|
||||||
if ((ssl->error = SendDtls13Ack(ssl)) < 0) {
|
if ((ssl->error = SendDtls13Ack(ssl)) < 0) {
|
||||||
if (ssl->error == WANT_WRITE)
|
if (ssl->error == WANT_WRITE)
|
||||||
ssl->dtls13SendingAckOrRtx = 1;
|
ssl->dtls13SendingAckOrRtx = 1;
|
||||||
@@ -12474,8 +12476,6 @@ int wolfSSL_DTLS_SetCookieSecret(WOLFSSL* ssl,
|
|||||||
return WOLFSSL_FATAL_ERROR;
|
return WOLFSSL_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* WOLFSSL_DTLS13 */
|
#endif /* WOLFSSL_DTLS13 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5088,6 +5088,13 @@ int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
|||||||
WOLFSSL_MSG("HelloRetryRequest format");
|
WOLFSSL_MSG("HelloRetryRequest format");
|
||||||
*extMsgType = hello_retry_request;
|
*extMsgType = hello_retry_request;
|
||||||
|
|
||||||
|
if (ssl->msgsReceived.got_hello_verify_request) {
|
||||||
|
WOLFSSL_MSG("Received HelloRetryRequest after a "
|
||||||
|
"HelloVerifyRequest");
|
||||||
|
WOLFSSL_ERROR_VERBOSE(VERSION_ERROR);
|
||||||
|
return VERSION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
/* A HelloRetryRequest comes in as an ServerHello for MiddleBox compat.
|
/* A HelloRetryRequest comes in as an ServerHello for MiddleBox compat.
|
||||||
* Found message to be a HelloRetryRequest.
|
* Found message to be a HelloRetryRequest.
|
||||||
* Don't allow more than one HelloRetryRequest or ServerHello.
|
* Don't allow more than one HelloRetryRequest or ServerHello.
|
||||||
|
235
tests/api.c
235
tests/api.c
@@ -5597,7 +5597,7 @@ static WC_INLINE int test_ssl_memio_write_cb(WOLFSSL *ssl, char *data, int sz,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((unsigned)(*len + sz) > TEST_SSL_MEMIO_BUF_SZ)
|
if ((unsigned)(*len + sz) > TEST_SSL_MEMIO_BUF_SZ)
|
||||||
return WOLFSSL_CBIO_ERR_WANT_READ;
|
return WOLFSSL_CBIO_ERR_WANT_WRITE;
|
||||||
|
|
||||||
XMEMCPY(buf + *len, data, sz);
|
XMEMCPY(buf + *len, data, sz);
|
||||||
*len += sz;
|
*len += sz;
|
||||||
@@ -64662,6 +64662,237 @@ static int test_dtls_downgrade_scr(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
|
||||||
|
static int test_dtls_client_hello_timeout_downgrade_read_cb(WOLFSSL *ssl,
|
||||||
|
char *data, int sz, void *ctx)
|
||||||
|
{
|
||||||
|
static int call_counter = 0;
|
||||||
|
call_counter++;
|
||||||
|
(void)ssl;
|
||||||
|
(void)data;
|
||||||
|
(void)sz;
|
||||||
|
(void)ctx;
|
||||||
|
switch (call_counter) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
return WOLFSSL_CBIO_ERR_TIMEOUT;
|
||||||
|
case 3:
|
||||||
|
return WOLFSSL_CBIO_ERR_WANT_READ;
|
||||||
|
default:
|
||||||
|
AssertIntLE(call_counter, 3);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Make sure we don't send acks before getting a server hello */
|
||||||
|
static int test_dtls_client_hello_timeout_downgrade(void)
|
||||||
|
{
|
||||||
|
EXPECT_DECLS;
|
||||||
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
|
||||||
|
WOLFSSL_CTX *ctx_c = NULL;
|
||||||
|
WOLFSSL_CTX *ctx_s = NULL;
|
||||||
|
WOLFSSL *ssl_c = NULL;
|
||||||
|
WOLFSSL *ssl_s = NULL;
|
||||||
|
struct test_memio_ctx test_ctx;
|
||||||
|
DtlsRecordLayerHeader* dtlsRH;
|
||||||
|
size_t len;
|
||||||
|
byte sequence_number[8];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||||
|
|
||||||
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
||||||
|
wolfDTLS_client_method, wolfDTLSv1_2_server_method), 0);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
/* First time simulate timeout in IO layer */
|
||||||
|
/* CH1 */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* HVR */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* CH2 */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* SH flight */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* Drop the SH */
|
||||||
|
dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.c_buff);
|
||||||
|
len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
|
||||||
|
XMEMMOVE(test_ctx.c_buff, test_ctx.c_buff +
|
||||||
|
sizeof(DtlsRecordLayerHeader) + len, test_ctx.c_len -
|
||||||
|
(sizeof(DtlsRecordLayerHeader) + len));
|
||||||
|
test_ctx.c_len -= sizeof(DtlsRecordLayerHeader) + len;
|
||||||
|
/* Read the remainder of the flight */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
wolfSSL_SSLSetIORecv(ssl_c,
|
||||||
|
test_dtls_client_hello_timeout_downgrade_read_cb);
|
||||||
|
/* CH3 */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
wolfSSL_SSLSetIORecv(ssl_c, test_memio_read_cb);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Second time call wolfSSL_dtls_got_timeout */
|
||||||
|
/* CH1 */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* HVR */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* CH2 */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* SH flight */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* Drop the SH */
|
||||||
|
dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.c_buff);
|
||||||
|
len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
|
||||||
|
XMEMMOVE(test_ctx.c_buff, test_ctx.c_buff +
|
||||||
|
sizeof(DtlsRecordLayerHeader) + len, test_ctx.c_len -
|
||||||
|
(sizeof(DtlsRecordLayerHeader) + len));
|
||||||
|
test_ctx.c_len -= sizeof(DtlsRecordLayerHeader) + len;
|
||||||
|
/* Read the remainder of the flight */
|
||||||
|
ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
/* Quick timeout should be set as we received at least one msg */
|
||||||
|
ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl_c), 1);
|
||||||
|
ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);
|
||||||
|
/* Quick timeout should be cleared after a quick timeout */
|
||||||
|
/* CH3 */
|
||||||
|
ExpectIntEQ(wolfSSL_dtls13_use_quick_timeout(ssl_c), 0);
|
||||||
|
ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse out to make sure we got exactly one ClientHello message */
|
||||||
|
XMEMSET(&sequence_number, 0, sizeof(sequence_number));
|
||||||
|
/* Second ClientHello after HVR */
|
||||||
|
sequence_number[7] = 2;
|
||||||
|
dtlsRH = (DtlsRecordLayerHeader*)test_ctx.s_buff;
|
||||||
|
ExpectIntEQ(dtlsRH->type, handshake);
|
||||||
|
ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
|
||||||
|
ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
|
||||||
|
ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
|
||||||
|
sizeof(sequence_number)), 0);
|
||||||
|
len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
|
||||||
|
ExpectIntEQ(sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len);
|
||||||
|
|
||||||
|
/* Connection should be able to continue */
|
||||||
|
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||||
|
|
||||||
|
wolfSSL_free(ssl_c);
|
||||||
|
wolfSSL_free(ssl_s);
|
||||||
|
wolfSSL_CTX_free(ctx_c);
|
||||||
|
wolfSSL_CTX_free(ctx_s);
|
||||||
|
ssl_c = NULL;
|
||||||
|
ssl_s = NULL;
|
||||||
|
ctx_c = NULL;
|
||||||
|
ctx_s = NULL;
|
||||||
|
if (!EXPECT_SUCCESS())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return EXPECT_RESULT();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
|
||||||
|
static int test_dtls_client_hello_timeout_read_cb(WOLFSSL *ssl, char *data,
|
||||||
|
int sz, void *ctx)
|
||||||
|
{
|
||||||
|
static int call_counter = 0;
|
||||||
|
call_counter++;
|
||||||
|
(void)ssl;
|
||||||
|
(void)data;
|
||||||
|
(void)sz;
|
||||||
|
(void)ctx;
|
||||||
|
switch (call_counter) {
|
||||||
|
case 1:
|
||||||
|
return WOLFSSL_CBIO_ERR_TIMEOUT;
|
||||||
|
case 2:
|
||||||
|
return WOLFSSL_CBIO_ERR_WANT_READ;
|
||||||
|
default:
|
||||||
|
AssertIntLE(call_counter, 2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Make sure we don't send acks before getting a server hello */
|
||||||
|
static int test_dtls_client_hello_timeout(void)
|
||||||
|
{
|
||||||
|
EXPECT_DECLS;
|
||||||
|
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13)
|
||||||
|
WOLFSSL *ssl_c = NULL;
|
||||||
|
WOLFSSL_CTX *ctx_c = NULL;
|
||||||
|
struct test_memio_ctx test_ctx;
|
||||||
|
DtlsRecordLayerHeader* dtlsRH;
|
||||||
|
size_t idx;
|
||||||
|
size_t len;
|
||||||
|
byte sequence_number[8];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||||
|
|
||||||
|
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
|
||||||
|
wolfDTLSv1_3_client_method, NULL), 0);
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
/* First time simulate timeout in IO layer */
|
||||||
|
wolfSSL_SSLSetIORecv(ssl_c, test_dtls_client_hello_timeout_read_cb);
|
||||||
|
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Second time call wolfSSL_dtls_got_timeout */
|
||||||
|
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
|
||||||
|
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||||
|
ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), WOLFSSL_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse out to make sure we got exactly two ClientHello messages */
|
||||||
|
idx = 0;
|
||||||
|
XMEMSET(&sequence_number, 0, sizeof(sequence_number));
|
||||||
|
/* First ClientHello */
|
||||||
|
dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.s_buff + idx);
|
||||||
|
ExpectIntEQ(dtlsRH->type, handshake);
|
||||||
|
ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
|
||||||
|
ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
|
||||||
|
ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
|
||||||
|
sizeof(sequence_number)), 0);
|
||||||
|
len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
|
||||||
|
ExpectIntLT(idx + sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len);
|
||||||
|
idx += sizeof(DtlsRecordLayerHeader) + len;
|
||||||
|
/* Second ClientHello */
|
||||||
|
sequence_number[7] = 1;
|
||||||
|
dtlsRH = (DtlsRecordLayerHeader*)(test_ctx.s_buff + idx);
|
||||||
|
ExpectIntEQ(dtlsRH->type, handshake);
|
||||||
|
ExpectIntEQ(dtlsRH->pvMajor, DTLS_MAJOR);
|
||||||
|
ExpectIntEQ(dtlsRH->pvMinor, DTLSv1_2_MINOR);
|
||||||
|
ExpectIntEQ(XMEMCMP(sequence_number, dtlsRH->sequence_number,
|
||||||
|
sizeof(sequence_number)), 0);
|
||||||
|
len = (size_t)((dtlsRH->length[0] << 8) | dtlsRH->length[1]);
|
||||||
|
ExpectIntEQ(idx + sizeof(DtlsRecordLayerHeader) + len, test_ctx.s_len);
|
||||||
|
|
||||||
|
wolfSSL_free(ssl_c);
|
||||||
|
wolfSSL_CTX_free(ctx_c);
|
||||||
|
ssl_c = NULL;
|
||||||
|
ctx_c = NULL;
|
||||||
|
if (!EXPECT_SUCCESS())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return EXPECT_RESULT();
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*
|
/*----------------------------------------------------------------------------*
|
||||||
| Main
|
| Main
|
||||||
*----------------------------------------------------------------------------*/
|
*----------------------------------------------------------------------------*/
|
||||||
@@ -65922,6 +66153,8 @@ TEST_CASE testCases[] = {
|
|||||||
TEST_DECL(test_session_ticket_hs_update),
|
TEST_DECL(test_session_ticket_hs_update),
|
||||||
TEST_DECL(test_dtls_downgrade_scr_server),
|
TEST_DECL(test_dtls_downgrade_scr_server),
|
||||||
TEST_DECL(test_dtls_downgrade_scr),
|
TEST_DECL(test_dtls_downgrade_scr),
|
||||||
|
TEST_DECL(test_dtls_client_hello_timeout_downgrade),
|
||||||
|
TEST_DECL(test_dtls_client_hello_timeout),
|
||||||
/* This test needs to stay at the end to clean up any caches allocated. */
|
/* This test needs to stay at the end to clean up any caches allocated. */
|
||||||
TEST_DECL(test_wolfSSL_Cleanup)
|
TEST_DECL(test_wolfSSL_Cleanup)
|
||||||
};
|
};
|
||||||
|
@@ -119,6 +119,17 @@ cleanup:
|
|||||||
/* This set of memio functions allows for more fine tuned control of the TLS
|
/* This set of memio functions allows for more fine tuned control of the TLS
|
||||||
* connection operations. For new tests, try to use ssl_memio first. */
|
* connection operations. For new tests, try to use ssl_memio first. */
|
||||||
|
|
||||||
|
/* To dump the memory in gdb use
|
||||||
|
* dump memory client.bin test_ctx.c_buff test_ctx.c_buff+test_ctx.c_len
|
||||||
|
* dump memory server.bin test_ctx.s_buff test_ctx.s_buff+test_ctx.s_len
|
||||||
|
* This can be imported into Wireshark by transforming the file with
|
||||||
|
* od -Ax -tx1 -v client.bin > client.bin.hex
|
||||||
|
* od -Ax -tx1 -v server.bin > server.bin.hex
|
||||||
|
* And then loading test_output.dump.hex into Wireshark using the
|
||||||
|
* "Import from Hex Dump..." option ion and selecting the TCP
|
||||||
|
* encapsulation option.
|
||||||
|
*/
|
||||||
|
|
||||||
#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES
|
#define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES
|
||||||
|
|
||||||
#define TEST_MEMIO_BUF_SZ (64 * 1024)
|
#define TEST_MEMIO_BUF_SZ (64 * 1024)
|
||||||
@@ -157,7 +168,7 @@ static WC_INLINE int test_memio_write_cb(WOLFSSL *ssl, char *data, int sz,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((unsigned)(*len + sz) > TEST_MEMIO_BUF_SZ)
|
if ((unsigned)(*len + sz) > TEST_MEMIO_BUF_SZ)
|
||||||
return WOLFSSL_CBIO_ERR_WANT_READ;
|
return WOLFSSL_CBIO_ERR_WANT_WRITE;
|
||||||
|
|
||||||
XMEMCPY(buf + *len, data, sz);
|
XMEMCPY(buf + *len, data, sz);
|
||||||
*len += sz;
|
*len += sz;
|
||||||
|
@@ -2135,6 +2135,9 @@ WOLFSSL_LOCAL void InitSSL_CTX_Suites(WOLFSSL_CTX* ctx);
|
|||||||
WOLFSSL_LOCAL int InitSSL_Suites(WOLFSSL* ssl);
|
WOLFSSL_LOCAL int InitSSL_Suites(WOLFSSL* ssl);
|
||||||
WOLFSSL_LOCAL int InitSSL_Side(WOLFSSL* ssl, word16 side);
|
WOLFSSL_LOCAL int InitSSL_Side(WOLFSSL* ssl, word16 side);
|
||||||
|
|
||||||
|
|
||||||
|
WOLFSSL_LOCAL int DoHandShakeMsgType(WOLFSSL* ssl, byte* input,
|
||||||
|
word32* inOutIdx, byte type, word32 size, word32 totalSz);
|
||||||
/* for sniffer */
|
/* for sniffer */
|
||||||
WOLFSSL_LOCAL int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
WOLFSSL_LOCAL int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
|
||||||
word32 size, word32 totalSz, int sniff);
|
word32 size, word32 totalSz, int sniff);
|
||||||
@@ -4607,6 +4610,7 @@ struct Options {
|
|||||||
word16 tls:1; /* using TLS ? */
|
word16 tls:1; /* using TLS ? */
|
||||||
word16 tls1_1:1; /* using TLSv1.1+ ? */
|
word16 tls1_1:1; /* using TLSv1.1+ ? */
|
||||||
word16 tls1_3:1; /* using TLSv1.3+ ? */
|
word16 tls1_3:1; /* using TLSv1.3+ ? */
|
||||||
|
word16 seenUnifiedHdr:1; /* received msg with unified header */
|
||||||
word16 dtls:1; /* using datagrams ? */
|
word16 dtls:1; /* using datagrams ? */
|
||||||
word16 dtlsStateful:1; /* allow stateful processing ? */
|
word16 dtlsStateful:1; /* allow stateful processing ? */
|
||||||
word16 connReset:1; /* has the peer reset */
|
word16 connReset:1; /* has the peer reset */
|
||||||
@@ -6532,6 +6536,8 @@ WOLFSSL_LOCAL int Dtls13HashHandshake(WOLFSSL* ssl, const byte* input,
|
|||||||
WOLFSSL_LOCAL int Dtls13HashClientHello(const WOLFSSL* ssl, byte* hash,
|
WOLFSSL_LOCAL int Dtls13HashClientHello(const WOLFSSL* ssl, byte* hash,
|
||||||
int* hashSz, const byte* body, word32 length, CipherSpecs* specs);
|
int* hashSz, const byte* body, word32 length, CipherSpecs* specs);
|
||||||
WOLFSSL_LOCAL void Dtls13FreeFsmResources(WOLFSSL* ssl);
|
WOLFSSL_LOCAL void Dtls13FreeFsmResources(WOLFSSL* ssl);
|
||||||
|
WOLFSSL_LOCAL void Dtls13RtxFlushBuffered(WOLFSSL* ssl,
|
||||||
|
byte keepNewSessionTicket);
|
||||||
WOLFSSL_LOCAL int Dtls13RtxTimeout(WOLFSSL* ssl);
|
WOLFSSL_LOCAL int Dtls13RtxTimeout(WOLFSSL* ssl);
|
||||||
WOLFSSL_LOCAL int Dtls13ProcessBufferedMessages(WOLFSSL* ssl);
|
WOLFSSL_LOCAL int Dtls13ProcessBufferedMessages(WOLFSSL* ssl);
|
||||||
WOLFSSL_LOCAL int Dtls13CheckAEADFailLimit(WOLFSSL* ssl);
|
WOLFSSL_LOCAL int Dtls13CheckAEADFailLimit(WOLFSSL* ssl);
|
||||||
|
Reference in New Issue
Block a user