diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 1bca8d59f..e63918860 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -46,6 +46,8 @@ jobs: '--enable-ascon CPPFLAGS=-DWOLFSSL_ASCON_UNROLL --enable-experimental', '--enable-all CPPFLAGS=''-DNO_AES_192 -DNO_AES_256'' ', '--enable-sniffer --enable-curve25519 --enable-curve448 --enable-enckeys CFLAGS=-DWOLFSSL_DH_EXTRA', + '--enable-dtls --enable-dtls13 --enable-dtls-frag-ch + --enable-dtls-mtu CPPFLAGS=-DWOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS', ] name: make check if: github.repository_owner == 'wolfssl' diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras index dc86b99ef..d2fe4da1b 100644 --- a/.wolfssl_known_macro_extras +++ b/.wolfssl_known_macro_extras @@ -659,6 +659,7 @@ WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC WOLFSSL_DILITHIUM_VERIFY_SMALL_MEM WOLFSSL_DISABLE_EARLY_SANITY_CHECKS WOLFSSL_DTLS_DISALLOW_FUTURE +WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT WOLFSSL_DUMP_MEMIO_STREAM WOLFSSL_DUP_CERTPOL diff --git a/src/internal.c b/src/internal.c index aa64178d4..6d3c780e2 100644 --- a/src/internal.c +++ b/src/internal.c @@ -86,6 +86,8 @@ * WOLFSSL_NO_INIT_CTX_KEY * Allows SSL objects to be created from a CTX without a loaded key/cert * pair + * WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS: + * When defined, allows DTLS records to span across multiple datagrams. */ #ifndef WOLFCRYPT_ONLY @@ -11622,6 +11624,18 @@ int EarlySanityCheckMsgReceived(WOLFSSL* ssl, byte type, word32 msgSz) return ret; } +static int RecordsCanSpanReads(WOLFSSL *ssl) +{ +#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) + /* Only case where we return 0: DTLS mode (not SCTP) and can't span datagrams */ + if (IsDtlsNotSctpMode(ssl)) { + return 0; + } +#endif + (void)ssl; + return 1; +} + #ifdef WOLFSSL_DTLS13 static int GetInputData(WOLFSSL *ssl, word32 size); static int GetDtls13RecordHeader(WOLFSSL* ssl, word32* inOutIdx, @@ -11681,6 +11695,10 @@ static int GetDtls13RecordHeader(WOLFSSL* ssl, word32* inOutIdx, } if (readSize < ssl->dtls13CurRlLength + DTLS13_RN_MASK_SIZE) { + if (!RecordsCanSpanReads(ssl)) { + WOLFSSL_MSG("Partial record received"); + return DTLS_PARTIAL_RECORD_READ; + } /* when using DTLS over a medium that does not guarantee that a full * message is received in a single read, we may end up without the full * header and minimum ciphertext to decrypt record sequence numbers */ @@ -11773,6 +11791,10 @@ static int GetDtlsRecordHeader(WOLFSSL* ssl, word32* inOutIdx, /* not a unified header, check that we have at least * DTLS_RECORD_HEADER_SZ */ if (ssl->buffers.inputBuffer.length - *inOutIdx < DTLS_RECORD_HEADER_SZ) { + if (!RecordsCanSpanReads(ssl)) { + WOLFSSL_MSG("Partial record received"); + return DTLS_PARTIAL_RECORD_READ; + } ret = GetInputData(ssl, DTLS_RECORD_HEADER_SZ); /* Check if Dtls13RtxTimeout(ssl) returned socket error */ if (ret == WC_NO_ERR_TRACE(SOCKET_ERROR_E)) @@ -21549,9 +21571,18 @@ static int GetInputData(WOLFSSL *ssl, word32 size) return RECV_OVERFLOW_E; } + if ((word32)in < size) { + if (!RecordsCanSpanReads(ssl)) { + WOLFSSL_MSG("DTLS: Received partial record, ignoring"); +#ifdef WOLFSSL_DTLS_DROP_STATS + ssl->replayDropCount++; +#endif /* WOLFSSL_DTLS_DROP_STATS */ + continue; + } + } + ssl->buffers.inputBuffer.length += (word32)in; inSz -= in; - } while (ssl->buffers.inputBuffer.length < size); #ifdef WOLFSSL_DEBUG_TLS @@ -21720,7 +21751,8 @@ static int DtlsShouldDrop(WOLFSSL* ssl, int retcode) if ((ssl->options.handShakeDone && retcode != 0) || retcode == WC_NO_ERR_TRACE(SEQUENCE_ERROR) - || retcode == WC_NO_ERR_TRACE(DTLS_CID_ERROR)) { + || retcode == WC_NO_ERR_TRACE(DTLS_CID_ERROR) + || retcode == WC_NO_ERR_TRACE(DTLS_PARTIAL_RECORD_READ)) { WOLFSSL_MSG_EX("Silently dropping DTLS message: %d", retcode); return 1; } @@ -21827,7 +21859,138 @@ static void dtlsProcessPendingPeer(WOLFSSL* ssl, int deprotected) } } #endif +static int DoDecrypt(WOLFSSL *ssl) +{ + int ret; + int atomicUser = 0; + bufferStatic* in = &ssl->buffers.inputBuffer; +#ifdef ATOMIC_USER + if (ssl->ctx->DecryptVerifyCb) + atomicUser = 1; +#endif + + ret = SanityCheckCipherText(ssl, ssl->curSize); + if (ret < 0) { + return ret; + } + + if (atomicUser) { +#ifdef ATOMIC_USER +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + ret = ssl->ctx->VerifyDecryptCb(ssl, + in->buffer + in->idx, in->buffer + in->idx, + ssl->curSize - MacSize(ssl), + ssl->curRL.type, 1, &ssl->keys.padSz, + ssl->DecryptVerifyCtx); + } + else +#endif + { + ret = ssl->ctx->DecryptVerifyCb(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize, ssl->curRL.type, 1, + &ssl->keys.padSz, ssl->DecryptVerifyCtx); + } +#endif /* ATOMIC_USER */ + } + else { + if (!ssl->options.tls1_3) { +#ifndef WOLFSSL_NO_TLS12 +#if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) + if (ssl->options.startedETMRead) { + word32 digestSz = MacSize(ssl); + ret = DecryptTls(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize - (word16)digestSz); + if (ret == 0) { + byte invalid = 0; + byte padding = (byte)-1; + word32 i; + word32 off = in->idx + ssl->curSize - digestSz - 1; + + /* Last of padding bytes - indicates length. */ + ssl->keys.padSz = in->buffer[off]; + /* Constant time checking of padding - don't leak + * the length of the data. + */ + /* Compare max pad bytes or at most data + pad. */ + for (i = 1; i < MAX_PAD_SIZE && off >= i; i++) { + /* Mask on indicates this is expected to be a + * padding byte. + */ + padding &= ctMaskLTE((int)i, + (int)ssl->keys.padSz); + /* When this is a padding byte and not equal + * to length then mask is set. + */ + invalid |= padding & + ctMaskNotEq(in->buffer[off - i], + (int)ssl->keys.padSz); + } + /* If mask is set then there was an error. */ + if (invalid) { + ret = DECRYPT_ERROR; + } + ssl->keys.padSz += 1; + ssl->keys.decryptedCur = 1; + } + } + else +#endif + { + ret = DecryptTls(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize); + } +#else + ret = DECRYPT_ERROR; +#endif + } + else + { + #ifdef WOLFSSL_TLS13 + byte *aad = (byte*)&ssl->curRL; + word16 aad_size = RECORD_HEADER_SZ; + #ifdef WOLFSSL_DTLS13 + if (ssl->options.dtls) { + /* aad now points to the record header */ + aad = ssl->dtls13CurRL; + aad_size = ssl->dtls13CurRlLength; + } + #endif /* WOLFSSL_DTLS13 */ + /* Don't send an alert for DTLS. We will just drop it + * silently later. */ + ret = DecryptTls13(ssl, + in->buffer + in->idx, + in->buffer + in->idx, + ssl->curSize, + aad, aad_size); + #else + ret = DECRYPT_ERROR; + #endif /* WOLFSSL_TLS13 */ + } + (void)in; + } + return ret; +} + +#ifdef WOLFSSL_DTLS +static void DropAndRestartProcessReply(WOLFSSL* ssl) +{ + ssl->options.processReply = doProcessInit; + ssl->buffers.inputBuffer.length = 0; + ssl->buffers.inputBuffer.idx = 0; +#ifdef WOLFSSL_DTLS_DROP_STATS + if (ssl->options.dtls) + ssl->replayDropCount++; +#endif /* WOLFSSL_DTLS_DROP_STATS */ +} +#endif /* WOLFSSL_DTLS */ /* Process input requests. Return 0 is done, 1 is call again to complete, and negative number is error. If allowSocketErr is set, SOCKET_ERROR_E in ssl->error will be whitelisted. This is useful when the connection has been @@ -21937,6 +22100,11 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) used = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx; if (used < readSz) { + if (used > 0 && !RecordsCanSpanReads(ssl)) { + WOLFSSL_MSG("DTLS: Partial record in buffer, dropping"); + DropAndRestartProcessReply(ssl); + continue; + } if ((ret = GetInputData(ssl, (word32)readSz)) < 0) return ret; } @@ -22036,13 +22204,7 @@ static int DoProcessReplyEx(WOLFSSL* ssl, int allowSocketErr) dtlsProcessPendingPeer(ssl, 0); #endif if (ssl->options.dtls && DtlsShouldDrop(ssl, ret)) { - ssl->options.processReply = doProcessInit; - ssl->buffers.inputBuffer.length = 0; - ssl->buffers.inputBuffer.idx = 0; -#ifdef WOLFSSL_DTLS_DROP_STATS - ssl->replayDropCount++; -#endif /* WOLFSSL_DTLS_DROP_STATS */ - + DropAndRestartProcessReply(ssl); #ifdef WOLFSSL_DTLS13 /* return to send ACKS and shortcut rtx timer */ if (IsAtLeastTLSv1_3(ssl->version) @@ -22104,9 +22266,15 @@ default: /* read ahead may already have */ used = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx; - if (used < ssl->curSize) + if (used < ssl->curSize) { + if (!RecordsCanSpanReads(ssl)) { + WOLFSSL_MSG("Partial record received, dropping"); + DropAndRestartProcessReply(ssl); + continue; + } if ((ret = GetInputData(ssl, ssl->curSize)) < 0) return ret; + } #endif } @@ -22157,9 +22325,7 @@ default: /* If in DTLS mode, if the decrypt fails for any * reason, pretend the datagram never happened. */ if (ssl->options.dtls) { - ssl->options.processReply = doProcessInit; - ssl->buffers.inputBuffer.idx = - ssl->buffers.inputBuffer.length; + DropAndRestartProcessReply(ssl); return HandleDTLSDecryptFailed(ssl); } #endif /* WOLFSSL_DTLS */ @@ -22183,118 +22349,7 @@ default: (!IsAtLeastTLSv1_3(ssl->version) || ssl->curRL.type != change_cipher_spec)) { - bufferStatic* in = &ssl->buffers.inputBuffer; - - ret = SanityCheckCipherText(ssl, ssl->curSize); - if (ret < 0) { - #ifdef WOLFSSL_EXTRA_ALERTS - SendAlert(ssl, alert_fatal, bad_record_mac); - #endif - return ret; - } - - if (atomicUser) { - #ifdef ATOMIC_USER - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - ret = ssl->ctx->VerifyDecryptCb(ssl, - in->buffer + in->idx, in->buffer + in->idx, - ssl->curSize - MacSize(ssl), - ssl->curRL.type, 1, &ssl->keys.padSz, - ssl->DecryptVerifyCtx); - } - else - #endif - { - ret = ssl->ctx->DecryptVerifyCb(ssl, - in->buffer + in->idx, - in->buffer + in->idx, - ssl->curSize, ssl->curRL.type, 1, - &ssl->keys.padSz, ssl->DecryptVerifyCtx); - } - #endif /* ATOMIC_USER */ - } - else { - if (!ssl->options.tls1_3) { - #ifndef WOLFSSL_NO_TLS12 - #if defined(HAVE_ENCRYPT_THEN_MAC) && !defined(WOLFSSL_AEAD_ONLY) - if (ssl->options.startedETMRead) { - word32 digestSz = MacSize(ssl); - ret = DecryptTls(ssl, - in->buffer + in->idx, - in->buffer + in->idx, - ssl->curSize - (word16)digestSz); - if (ret == 0) { - byte invalid = 0; - byte padding = (byte)-1; - word32 i; - word32 off = in->idx + ssl->curSize - digestSz - 1; - - /* Last of padding bytes - indicates length. */ - ssl->keys.padSz = in->buffer[off]; - /* Constant time checking of padding - don't leak - * the length of the data. - */ - /* Compare max pad bytes or at most data + pad. */ - for (i = 1; i < MAX_PAD_SIZE && off >= i; i++) { - /* Mask on indicates this is expected to be a - * padding byte. - */ - padding &= ctMaskLTE((int)i, - (int)ssl->keys.padSz); - /* When this is a padding byte and not equal - * to length then mask is set. - */ - invalid |= padding & - ctMaskNotEq(in->buffer[off - i], - (int)ssl->keys.padSz); - } - /* If mask is set then there was an error. */ - if (invalid) { - ret = DECRYPT_ERROR; - } - ssl->keys.padSz += 1; - ssl->keys.decryptedCur = 1; - } - } - else - #endif - { - ret = DecryptTls(ssl, - in->buffer + in->idx, - in->buffer + in->idx, - ssl->curSize); - } - #else - ret = DECRYPT_ERROR; - #endif - } - else - { - #ifdef WOLFSSL_TLS13 - byte *aad = (byte*)&ssl->curRL; - word16 aad_size = RECORD_HEADER_SZ; - #ifdef WOLFSSL_DTLS13 - if (ssl->options.dtls) { - /* aad now points to the record header */ - aad = ssl->dtls13CurRL; - aad_size = ssl->dtls13CurRlLength; - } - #endif /* WOLFSSL_DTLS13 */ - /* Don't send an alert for DTLS. We will just drop it - * silently later. */ - ret = DecryptTls13(ssl, - in->buffer + in->idx, - in->buffer + in->idx, - ssl->curSize, - aad, aad_size); - #else - ret = DECRYPT_ERROR; - #endif /* WOLFSSL_TLS13 */ - } - (void)in; - } - + ret = DoDecrypt(ssl); #ifdef WOLFSSL_ASYNC_CRYPT if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) return ret; @@ -22323,9 +22378,7 @@ default: /* If in DTLS mode, if the decrypt fails for any * reason, pretend the datagram never happened. */ if (ssl->options.dtls) { - ssl->options.processReply = doProcessInit; - ssl->buffers.inputBuffer.idx = - ssl->buffers.inputBuffer.length; + DropAndRestartProcessReply(ssl); return HandleDTLSDecryptFailed(ssl); } #endif /* WOLFSSL_DTLS */ @@ -22393,9 +22446,7 @@ default: /* If in DTLS mode, if the decrypt fails for any * reason, pretend the datagram never happened. */ if (ssl->options.dtls) { - ssl->options.processReply = doProcessInit; - ssl->buffers.inputBuffer.idx = - ssl->buffers.inputBuffer.length; + DropAndRestartProcessReply(ssl); return HandleDTLSDecryptFailed(ssl); } #endif /* WOLFSSL_DTLS */ diff --git a/tests/api.c b/tests/api.c index 1648ea0e7..37717fdf0 100644 --- a/tests/api.c +++ b/tests/api.c @@ -7475,22 +7475,33 @@ static WC_INLINE int test_ssl_memio_write_cb(WOLFSSL *ssl, char *data, int sz, struct test_ssl_memio_ctx *test_ctx; byte *buf; int *len; + int *msg_sizes; + int *msg_count; test_ctx = (struct test_ssl_memio_ctx*)ctx; if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { buf = test_ctx->c_buff; len = &test_ctx->c_len; + msg_sizes = test_ctx->c_msg_sizes; + msg_count = &test_ctx->c_msg_count; } else { buf = test_ctx->s_buff; len = &test_ctx->s_len; + msg_sizes = test_ctx->s_msg_sizes; + msg_count = &test_ctx->s_msg_count; } if ((unsigned)(*len + sz) > TEST_SSL_MEMIO_BUF_SZ) return WOLFSSL_CBIO_ERR_WANT_WRITE; + if (*msg_count >= TEST_MEMIO_MAX_MSGS) + return WOLFSSL_CBIO_ERR_WANT_WRITE; + XMEMCPY(buf + *len, data, sz); + msg_sizes[*msg_count] = sz; + (*msg_count)++; *len += sz; #ifdef WOLFSSL_DUMP_MEMIO_STREAM @@ -7521,27 +7532,63 @@ static WC_INLINE int test_ssl_memio_read_cb(WOLFSSL *ssl, char *data, int sz, int read_sz; byte *buf; int *len; + int *msg_sizes; + int *msg_count; + int *msg_pos; + int is_dtls; test_ctx = (struct test_ssl_memio_ctx*)ctx; + is_dtls = wolfSSL_dtls(ssl); if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { buf = test_ctx->s_buff; len = &test_ctx->s_len; + msg_sizes = test_ctx->s_msg_sizes; + msg_count = &test_ctx->s_msg_count; + msg_pos = &test_ctx->s_msg_pos; } else { buf = test_ctx->c_buff; len = &test_ctx->c_len; + msg_sizes = test_ctx->c_msg_sizes; + msg_count = &test_ctx->c_msg_count; + msg_pos = &test_ctx->c_msg_pos; } - if (*len == 0) + if (*len == 0 || *msg_pos >= *msg_count) return WOLFSSL_CBIO_ERR_WANT_READ; - read_sz = sz < *len ? sz : *len; + /* Calculate how much we can read from current message */ + read_sz = msg_sizes[*msg_pos]; + if (read_sz > sz) + read_sz = sz; - XMEMCPY(data, buf, read_sz); - XMEMMOVE(buf, buf + read_sz, *len - read_sz); + if (read_sz > *len) + return WOLFSSL_CBIO_ERR_GENERAL; + /* Copy data from current message */ + XMEMCPY(data, buf, (size_t)read_sz); + /* remove the read data from the buffer */ + XMEMMOVE(buf, buf + read_sz, (size_t)(*len - read_sz)); *len -= read_sz; + msg_sizes[*msg_pos] -= read_sz; + + /* if we are on dtls, discard the rest of the message */ + if (is_dtls && msg_sizes[*msg_pos] > 0) { + XMEMMOVE(buf, buf + msg_sizes[*msg_pos], (size_t)(*len - msg_sizes[*msg_pos])); + *len -= msg_sizes[*msg_pos]; + msg_sizes[*msg_pos] = 0; + } + + /* If we've read the entire message */ + if (msg_sizes[*msg_pos] == 0) { + /* Move to next message */ + (*msg_pos)++; + if (*msg_pos >= *msg_count) { + *msg_pos = 0; + *msg_count = 0; + } + } return read_sz; } @@ -60993,7 +61040,7 @@ static int test_wolfSSL_dtls_stateless2(void) ExpectFalse(wolfSSL_is_stateful(ssl_s)); ExpectIntNE(test_ctx.c_len, 0); /* consume HRR */ - test_ctx.c_len = 0; + test_memio_clear_buffer(&test_ctx, 1); /* send CH1 */ ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_FATAL_ERROR); ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR), @@ -61051,7 +61098,7 @@ static int test_wolfSSL_dtls_stateless_maxfrag(void) ExpectIntNE(test_ctx.c_len, 0); /* consume HRR from buffer */ - test_ctx.c_len = 0; + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); wolfSSL_free(ssl_c2); @@ -61106,7 +61153,8 @@ static int _test_wolfSSL_dtls_stateless_resume(byte useticket, byte bad) wolfSSL_free(ssl_s); ssl_s = NULL; - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 1); + test_memio_clear_buffer(&test_ctx, 0); /* make resumption invalid */ if (bad && (sess != NULL)) { if (useticket) { @@ -61189,7 +61237,7 @@ static int test_wolfSSL_dtls_stateless_downgrade(void) (ssl_s->error == WC_NO_ERR_TRACE(WANT_READ))); ExpectIntNE(test_ctx.c_len, 0); /* consume HRR */ - test_ctx.c_len = 0; + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); wolfSSL_free(ssl_c2); @@ -61939,11 +61987,11 @@ static int test_extra_alerts_wrong_cs(void) WOLFSSL_ERROR_WANT_READ); /* consume CH */ - test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); /* inject SH */ - XMEMCPY(test_ctx.c_buff, test_extra_alerts_wrong_cs_sh, - sizeof(test_extra_alerts_wrong_cs_sh)); - test_ctx.c_len = sizeof(test_extra_alerts_wrong_cs_sh); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, + (const char *)test_extra_alerts_wrong_cs_sh, + sizeof(test_extra_alerts_wrong_cs_sh)), 0); ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); ExpectIntNE(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)), @@ -62003,11 +62051,11 @@ static int test_wrong_cs_downgrade(void) WOLFSSL_ERROR_WANT_READ); /* consume CH */ - test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); /* inject SH */ - XMEMCPY(test_ctx.c_buff, test_wrong_cs_downgrade_sh, - sizeof(test_wrong_cs_downgrade_sh)); - test_ctx.c_len = sizeof(test_wrong_cs_downgrade_sh); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, + (const char *)test_wrong_cs_downgrade_sh, + sizeof(test_wrong_cs_downgrade_sh)), 0); ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS); #ifdef OPENSSL_EXTRA @@ -62034,14 +62082,7 @@ static int test_wrong_cs_downgrade(void) #if !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_EXTRA_ALERTS) && \ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_SP_MATH) -static void test_remove_msg(byte *msg, int tail_len, int *len, int msg_length) -{ - tail_len -= msg_length; - XMEMMOVE(msg, msg + msg_length, tail_len); - *len = *len - msg_length; -} - -static int test_remove_hs_msg_from_buffer(byte *buf, int *len, byte type, +static int test_remove_hs_msg_from_buffer(struct test_memio_ctx *test_ctx, byte type, byte *found) { const unsigned int _HANDSHAKE_HEADER_SZ = 4; @@ -62050,16 +62091,17 @@ static int test_remove_hs_msg_from_buffer(byte *buf, int *len, byte type, const int _change_cipher = 20; const int _handshake = 22; unsigned int tail_len; - byte *idx, *curr; + byte *idx; + int curr; word8 currType; word16 rLength; word32 hLength; - idx = buf; - tail_len = (unsigned int)*len; + idx = test_ctx->c_buff; + tail_len = (unsigned int)test_ctx->c_len; *found = 0; while (tail_len > _RECORD_HEADER_SZ) { - curr = idx; + curr = (int)(idx - test_ctx->c_buff); currType = *idx; ato16(idx + 3, &rLength); idx += _RECORD_HEADER_SZ; @@ -62072,8 +62114,8 @@ static int test_remove_hs_msg_from_buffer(byte *buf, int *len, byte type, if (rLength != 1) return -1; /* match */ - test_remove_msg(curr, *len - (int)(curr - buf), - len, _RECORD_HEADER_SZ + 1); + test_memio_remove_from_buffer(test_ctx, 1, curr, + _RECORD_HEADER_SZ + rLength); *found = 1; return 0; } @@ -62098,7 +62140,7 @@ static int test_remove_hs_msg_from_buffer(byte *buf, int *len, byte type, } /* match */ - test_remove_msg(curr, *len - (int)(curr - buf), len, + test_memio_remove_from_buffer(test_ctx, 1, curr, hLength + _RECORD_HEADER_SZ); *found = 1; return 0; @@ -62141,8 +62183,7 @@ static int test_remove_hs_message(byte hs_message_type, ExpectIntEQ(wolfSSL_accept(ssl_s), WOLFSSL_SUCCESS); } - ExpectIntEQ(test_remove_hs_msg_from_buffer(test_ctx.c_buff, - &test_ctx.c_len, hs_message_type, &found), 0); + ExpectIntEQ(test_remove_hs_msg_from_buffer(&test_ctx, hs_message_type, &found), 0); if (!found) { wolfSSL_free(ssl_c); @@ -64155,8 +64196,11 @@ static int test_dtls_no_extensions(void) ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s, NULL, wolfDTLS_server_method), 0); - XMEMCPY(test_ctx.s_buff, chNoExtensions, sizeof(chNoExtensions)); - test_ctx.s_len = sizeof(chNoExtensions); + test_memio_clear_buffer(&test_ctx, 0); + ExpectIntEQ( + test_memio_inject_message(&test_ctx, 1, + (const char *)chNoExtensions, sizeof(chNoExtensions)), 0); + #ifdef OPENSSL_EXTRA if (i > 0) { @@ -64195,8 +64239,9 @@ static int test_tls_alert_no_server_hello(void) ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL, wolfTLSv1_2_client_method, NULL), 0); - XMEMCPY(test_ctx.c_buff, alert_msg, sizeof(alert_msg)); - test_ctx.c_len = sizeof(alert_msg); + test_memio_clear_buffer(&test_ctx, 1); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, + (const char *)alert_msg, sizeof(alert_msg)), 0); ExpectIntEQ(wolfSSL_connect(ssl_c), -1); ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WC_NO_ERR_TRACE(FATAL_ERROR)); @@ -64265,14 +64310,15 @@ static int test_TLSX_CA_NAMES_bad_extension(void) switch (i) { case 0: - XMEMCPY(test_ctx.c_buff, shBadCaNamesExt, - sizeof(shBadCaNamesExt)); - test_ctx.c_len = sizeof(shBadCaNamesExt); + test_memio_clear_buffer(&test_ctx, 0); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, + (const char *)shBadCaNamesExt, sizeof(shBadCaNamesExt)), 0); break; case 1: - XMEMCPY(test_ctx.c_buff, shBadCaNamesExt2, - sizeof(shBadCaNamesExt2)); - test_ctx.c_len = sizeof(shBadCaNamesExt2); + test_memio_clear_buffer(&test_ctx, 0); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, + (const char *)shBadCaNamesExt2, + sizeof(shBadCaNamesExt2)), 0); break; } @@ -64672,14 +64718,9 @@ static int test_dtls_client_hello_timeout_downgrade(void) 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]); if (EXPECT_SUCCESS()) { - XMEMMOVE(test_ctx.c_buff, test_ctx.c_buff + - sizeof(DtlsRecordLayerHeader) + len, test_ctx.c_len - - (sizeof(DtlsRecordLayerHeader) + len)); + ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); } - 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); @@ -64705,14 +64746,9 @@ static int test_dtls_client_hello_timeout_downgrade(void) 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]); if (EXPECT_SUCCESS()) { - XMEMMOVE(test_ctx.c_buff, test_ctx.c_buff + - sizeof(DtlsRecordLayerHeader) + len, test_ctx.c_len - - (sizeof(DtlsRecordLayerHeader) + len)); + ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); } - 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); @@ -64894,11 +64930,8 @@ static int test_dtls_dropped_ccs(void) ExpectIntEQ(len, 1); ExpectIntEQ(dtlsRH->type, change_cipher_spec); if (EXPECT_SUCCESS()) { - XMEMMOVE(test_ctx.c_buff, test_ctx.c_buff + - sizeof(DtlsRecordLayerHeader) + len, test_ctx.c_len - - (sizeof(DtlsRecordLayerHeader) + len)); + ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, 0), 0); } - test_ctx.c_len -= sizeof(DtlsRecordLayerHeader) + len; /* Client rtx flight */ ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); @@ -65291,6 +65324,7 @@ static int test_dtls_frag_ch(void) WOLFSSL *ssl_s = NULL; struct test_memio_ctx test_ctx; static unsigned int DUMMY_MTU = 256; + unsigned int len; unsigned char four_frag_CH[] = { 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x01, 0x00, 0x02, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -65397,8 +65431,16 @@ static int test_dtls_frag_ch(void) /* Reject fragmented first CH */ ExpectIntEQ(test_dtls_frag_ch_count_records(four_frag_CH, sizeof(four_frag_CH)), 4); - XMEMCPY(test_ctx.s_buff, four_frag_CH, sizeof(four_frag_CH)); - test_ctx.s_len = sizeof(four_frag_CH); + len = sizeof(four_frag_CH); + test_memio_clear_buffer(&test_ctx, 0); + while (len > 0 && EXPECT_SUCCESS()) { + unsigned int inj_len = len > DUMMY_MTU ? DUMMY_MTU : len; + unsigned char *idx = four_frag_CH + sizeof(four_frag_CH) - len; + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char *)idx, + inj_len), 0); + len -= inj_len; + } + ExpectIntEQ(test_ctx.s_len, sizeof(four_frag_CH)); while (test_ctx.s_len > 0 && EXPECT_SUCCESS()) { int s_len = test_ctx.s_len; ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); @@ -65492,11 +65534,11 @@ static int test_dtls_empty_keyshare_with_cookie(void) XMEMSET(&sequence_number, 0, sizeof(sequence_number)); XMEMSET(&test_ctx, 0, sizeof(test_ctx)); - XMEMCPY(test_ctx.s_buff, ch_empty_keyshare_with_cookie, - sizeof(ch_empty_keyshare_with_cookie)); - test_ctx.s_len = sizeof(ch_empty_keyshare_with_cookie); ExpectIntEQ(test_memio_setup(&test_ctx, NULL, &ctx_s, NULL, &ssl_s, NULL, wolfDTLSv1_3_server_method), 0); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, + (const char *)ch_empty_keyshare_with_cookie, + sizeof(ch_empty_keyshare_with_cookie)), 0); /* CH1 */ ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); @@ -65611,7 +65653,7 @@ static int test_dtls12_missing_finished(void) /* Server second flight with finished */ ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); /* Let's clear the output */ - test_ctx.c_len = 0; + test_memio_clear_buffer(&test_ctx, 1); /* Let's send some app data */ ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), sizeof(test_str)); @@ -65667,7 +65709,7 @@ static int test_dtls13_missing_finished_client(void) ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); /* Let's clear the output */ - test_ctx.c_len = 0; + test_memio_clear_buffer(&test_ctx, 1); /* Let's send some app data */ ExpectIntEQ(wolfSSL_write(ssl_s, test_str, sizeof(test_str)), sizeof(test_str)); @@ -65731,7 +65773,7 @@ static int test_dtls13_missing_finished_server(void) ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); /* Let's clear the output */ - test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); /* We should signal that the handshake is done */ ExpectTrue(wolfSSL_is_init_finished(ssl_c)); /* Let's send some app data */ @@ -66086,8 +66128,10 @@ static int test_tls_multi_handshakes_one_record(void) WOLFSSL *ssl_c = NULL, *ssl_s = NULL; RecordLayerHeader* rh = NULL; byte *len ; - int newRecIdx = RECORD_HEADER_SZ; - int idx = 0; + int newRecIdx; + int idx; + byte buff[64 * 1024]; + word16 recLen; XMEMSET(&test_ctx, 0, sizeof(test_ctx)); @@ -66099,9 +66143,14 @@ static int test_tls_multi_handshakes_one_record(void) ExpectIntEQ(wolfSSL_accept(ssl_s), -1); ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + XMEMSET(buff, 0, sizeof(buff)); + rh = (RecordLayerHeader*)(test_ctx.c_buff); + len = &rh->length[0]; + ato16((const byte*)len, &recLen); + XMEMCPY(buff, test_ctx.c_buff, RECORD_HEADER_SZ + recLen); + newRecIdx = idx = RECORD_HEADER_SZ + recLen; /* Combine server handshake msgs into one record */ while (idx < test_ctx.c_len) { - word16 recLen; rh = (RecordLayerHeader*)(test_ctx.c_buff + idx); len = &rh->length[0]; @@ -66109,20 +66158,23 @@ static int test_tls_multi_handshakes_one_record(void) ato16((const byte*)len, &recLen); idx += RECORD_HEADER_SZ; - XMEMMOVE(test_ctx.c_buff + newRecIdx, test_ctx.c_buff + idx, + XMEMCPY(buff + newRecIdx, test_ctx.c_buff + idx, (size_t)recLen); newRecIdx += recLen; idx += recLen; } - rh = (RecordLayerHeader*)(test_ctx.c_buff); + rh = (RecordLayerHeader*)(buff); len = &rh->length[0]; c16toa((word16)newRecIdx - RECORD_HEADER_SZ, len); - test_ctx.c_len = newRecIdx; + test_memio_clear_buffer(&test_ctx, 1); + test_memio_inject_message(&test_ctx, 1, (const char*)buff, newRecIdx); ExpectIntEQ(wolfSSL_connect(ssl_c), -1); ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + 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); @@ -66926,7 +66978,7 @@ static int test_wolfSSL_inject(void) if (test_ctx.s_len > 0) { ExpectIntEQ(wolfSSL_inject(ssl_s, test_ctx.s_buff, test_ctx.s_len), 1); - test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); } if (wolfSSL_negotiate(ssl_s) != 1) { ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), @@ -66936,7 +66988,7 @@ static int test_wolfSSL_inject(void) if (test_ctx.c_len > 0) { ExpectIntEQ(wolfSSL_inject(ssl_c, test_ctx.c_buff, test_ctx.c_len), 1); - test_ctx.c_len = 0; + test_memio_clear_buffer(&test_ctx, 1); } wolfSSL_SetLoggingPrefix(NULL); } @@ -68078,6 +68130,13 @@ TEST_CASE testCases[] = { /* Can't memory test as client/server hangs. */ TEST_DECL(test_dtls_msg_from_other_peer), TEST_DECL(test_dtls_ipv6_check), + TEST_DECL(test_dtls_short_ciphertext), + TEST_DECL(test_dtls12_record_length_mismatch), + TEST_DECL(test_dtls12_short_read), + TEST_DECL(test_dtls13_longer_length), + TEST_DECL(test_dtls13_short_read), + TEST_DECL(test_records_span_network_boundaries), + TEST_DECL(test_dtls_record_cross_boundaries), TEST_DECL(test_wolfSSL_SCR_after_resumption), TEST_DECL(test_dtls_no_extensions), TEST_DECL(test_tls_alert_no_server_hello), diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c index 16a2b6856..503e66c31 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -140,7 +140,8 @@ int test_dtls12_basic_connection_id(void) ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); ExpectNull(CLIENT_CID()); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); ExpectNull(CLIENT_CID()); } @@ -156,7 +157,8 @@ int test_dtls12_basic_connection_id(void) ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); ExpectNull(CLIENT_CID()); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); ExpectNull(CLIENT_CID()); } @@ -166,7 +168,8 @@ int test_dtls12_basic_connection_id(void) ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); ExpectNull(SERVER_CID()); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); ExpectNull(SERVER_CID()); } @@ -176,7 +179,8 @@ int test_dtls12_basic_connection_id(void) ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); ExpectNotNull(CLIENT_CID()); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); ExpectNotNull(CLIENT_CID()); } @@ -185,7 +189,8 @@ int test_dtls12_basic_connection_id(void) ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); ExpectNotNull(SERVER_CID()); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); ExpectNotNull(SERVER_CID()); } @@ -296,7 +301,8 @@ int test_dtls12_basic_connection_id(void) ExpectNotNull(SERVER_CID()); ExpectIntEQ(wolfSSL_SSL_renegotiate_pending(ssl_s), 1); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); ExpectNotNull(SERVER_CID()); } @@ -309,7 +315,8 @@ int test_dtls12_basic_connection_id(void) ExpectNotNull(CLIENT_CID()); ExpectIntEQ(wolfSSL_SSL_renegotiate_pending(ssl_c), 1); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); ExpectNotNull(CLIENT_CID()); } @@ -319,7 +326,8 @@ int test_dtls12_basic_connection_id(void) ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); ExpectNotNull(SERVER_CID()); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); ExpectNotNull(SERVER_CID()); } @@ -329,7 +337,8 @@ int test_dtls12_basic_connection_id(void) ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); ExpectNotNull(CLIENT_CID()); if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; + test_memio_clear_buffer(&test_ctx, 0); + test_memio_clear_buffer(&test_ctx, 1); ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_c), 1); ExpectNotNull(CLIENT_CID()); } @@ -337,8 +346,7 @@ int test_dtls12_basic_connection_id(void) (int)XSTRLEN(params[i])), XSTRLEN(params[i])); /* Server second flight */ wolfSSL_SetLoggingPrefix("server"); - ExpectIntEQ(wolfSSL_negotiate(ssl_s), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), APP_DATA_READY); + ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); XMEMSET(readBuf, 0, sizeof(readBuf)); ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), XSTRLEN(params[i])); @@ -347,19 +355,11 @@ int test_dtls12_basic_connection_id(void) ExpectIntEQ(wolfSSL_write(ssl_s, params[i], (int)XSTRLEN(params[i])), XSTRLEN(params[i])); } - ExpectIntEQ(wolfSSL_negotiate(ssl_s), 1); - ExpectNotNull(SERVER_CID()); - if (run_params[j].drop) { - test_ctx.c_len = test_ctx.s_len = 0; - ExpectIntEQ(wolfSSL_dtls_got_timeout(ssl_s), 1); - ExpectNotNull(SERVER_CID()); - } /* Test loading old epoch */ /* Client complete connection */ wolfSSL_SetLoggingPrefix("client"); if (!run_params[j].drop) { - ExpectIntEQ(wolfSSL_negotiate(ssl_c), -1); - ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), APP_DATA_READY); + ExpectIntEQ(wolfSSL_negotiate(ssl_c), 1); XMEMSET(readBuf, 0, sizeof(readBuf)); ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), XSTRLEN(params[i])); @@ -776,3 +776,491 @@ int test_dtls_version_checking(void) #endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES && WOLFSSL_DTLS */ return EXPECT_RESULT(); } + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) +static int test_dtls_shutdown(WOLFSSL *s, WOLFSSL *c, WOLFSSL_CTX *cc, WOLFSSL_CTX *cs) +{ + EXPECT_DECLS; + /* Cleanup */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_shutdown(c), WOLFSSL_SHUTDOWN_NOT_DONE); + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_shutdown(s), WOLFSSL_SHUTDOWN_NOT_DONE); + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_shutdown(c), 1); + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_shutdown(s), 1); + + wolfSSL_SetLoggingPrefix(NULL); + wolfSSL_free(c); + wolfSSL_CTX_free(cc); + wolfSSL_free(s); + wolfSSL_CTX_free(cs); + return EXPECT_RESULT(); +} + +static int test_dtls_communication(WOLFSSL *s, WOLFSSL *c) +{ + EXPECT_DECLS; + unsigned char readBuf[50]; + + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(c, "client message", 14), 14); + + wolfSSL_SetLoggingPrefix("server"); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(s, readBuf, sizeof(readBuf)), 14); + ExpectStrEQ(readBuf, "client message"); + + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_write(s, "server message", 14), 14); + + wolfSSL_SetLoggingPrefix("client"); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(c, readBuf, sizeof(readBuf)), 14); + ExpectStrEQ(readBuf, "server message"); + + /* this extra round is consuming newSessionTicket and acks */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(c, "client message 2", 16), 16); + + wolfSSL_SetLoggingPrefix("server"); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(s, readBuf, sizeof(readBuf)), 16); + ExpectStrEQ(readBuf, "client message 2"); + + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_write(s, "server message 2", 16), 16); + + wolfSSL_SetLoggingPrefix("client"); + XMEMSET(readBuf, 0, sizeof(readBuf)); + ExpectIntEQ(wolfSSL_read(c, readBuf, sizeof(readBuf)), 16); + ExpectStrEQ(readBuf, "server message 2"); + + return EXPECT_RESULT(); +} + +#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) +int test_dtls13_longer_length(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + int seq16bit = 0; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Setup DTLS contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), + 0); + + /* Complete handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Create good record with length mismatch */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(ssl_c, "client message", 14), 14); + + /* check client wrote the record */ + ExpectIntGT(test_ctx.s_len, 14); + /* check length is included in the record header */ + ExpectIntGT(test_ctx.s_buff[0x0] & (1 << 2), 0); + seq16bit = (test_ctx.s_buff[0x0] & (1 << 3)) != 0; + /* big endian, modify LSB byte */ + seq16bit *= 2; + /* modify length to be bigger */ + test_ctx.s_buff[0x2 + seq16bit] = 0xff; + + /* Try to read the malformed record */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_ctx.s_len, 0); + + ExpectIntEQ(test_dtls_communication(ssl_s, ssl_c), TEST_SUCCESS); + ExpectIntEQ(test_dtls_shutdown(ssl_s, ssl_c, ctx_c, ctx_s), TEST_SUCCESS); + + return EXPECT_RESULT(); +} +#else +int test_dtls13_longer_length(void) +{ + return TEST_SKIPPED; +} +#endif /* WOLFSSL_DTLS13 && !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) */ + +#if defined(WOLFSSL_DTLS13) && !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) +int test_dtls13_short_read(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + int i; + + /* we setup two test, in the first one the server reads just two bytes of + * the header, in the second one it reads just the header (5) */ + for (i = 0; i < 2; i++) { + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Setup DTLS contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method), + 0); + + /* Complete handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* create a good record in the buffer */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(ssl_c, "client message", 14), 14); + + /* check client wrote the record */ + ExpectIntGT(test_ctx.s_len, 14); + /* return less data */ + ExpectIntEQ( + test_memio_modify_message_len(&test_ctx, 0, 0, i == 0 ? 2 : 5), 0); + /* Try to read the malformed record */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_ctx.s_len, 0); + + ExpectIntEQ(test_dtls_communication(ssl_s, ssl_c), TEST_SUCCESS); + ExpectIntEQ(test_dtls_shutdown(ssl_s, ssl_c, ctx_c, ctx_s), + TEST_SUCCESS); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + } + + return EXPECT_RESULT(); +} +#else +int test_dtls13_short_read(void) +{ + return TEST_SKIPPED; +} +#endif /* WOLFSSL_DTLS13 && !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) */ + +#if !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) +int test_dtls12_short_read(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + int i; + + for (i = 0; i < 3; i++) { + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Setup DTLS contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), + 0); + /* Complete handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* create a good record in the buffer */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(ssl_c, "bad", 3), 3); + + /* check client wrote the record */ + ExpectIntGT(test_ctx.s_len, 13 + 3); + /* return less data */ + switch (i) { + case 0: + ExpectIntEQ(test_memio_modify_message_len(&test_ctx, 0, 0, 2), 0); + break; + case 1: + ExpectIntEQ(test_memio_modify_message_len(&test_ctx, 0, 0, 13), 0); + break; + case 2: + ExpectIntEQ(test_memio_modify_message_len(&test_ctx, 0, 0, 15), 0); + break; + } + + /* Try to read the malformed record */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_ctx.s_len, 0); + + ExpectIntEQ(test_dtls_communication(ssl_s, ssl_c), TEST_SUCCESS); + ExpectIntEQ(test_dtls_shutdown(ssl_s, ssl_c, ctx_c, ctx_s), + TEST_SUCCESS); + ssl_c = ssl_s = NULL; + ctx_c = ctx_s = NULL; + } + + return EXPECT_RESULT(); +} +#else +int test_dtls12_short_read(void) +{ + return TEST_SKIPPED; +} +#endif /* !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) */ + +#if !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) +int test_dtls12_record_length_mismatch(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Setup DTLS contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), + 0); + + /* Complete handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* write a message from client */ + ExpectIntEQ(wolfSSL_write(ssl_c, "bad", 3), 3); + + /* check that the message is written in the buffer */ + ExpectIntGT(test_ctx.s_len, 14); + /* modify the length field to be bigger than the content */ + test_ctx.s_buff[12] = 0xff; + + /* Try to read the malformed record */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_ctx.s_len, 0); + + ExpectIntEQ(test_dtls_communication(ssl_s, ssl_c), TEST_SUCCESS); + ExpectIntEQ(test_dtls_shutdown(ssl_s, ssl_c, ctx_c, ctx_s), TEST_SUCCESS); + + return EXPECT_RESULT(); +} + +int test_dtls_record_cross_boundaries(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[100]; + int rec0_len, rec1_len; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Setup DTLS contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), + 0); + + /* Complete handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* create a first record in the buffer */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(ssl_c, "test0", 5), 5); + rec0_len = test_ctx.s_msg_sizes[0]; + + /* create a second record in the buffer */ + ExpectIntEQ(wolfSSL_write(ssl_c, "test1", 5), 5); + rec1_len = test_ctx.s_msg_sizes[1]; + + ExpectIntLE(rec0_len + rec1_len, sizeof(readBuf)); + XMEMCPY(readBuf, test_ctx.s_buff, rec0_len + rec1_len); + + /* clear buffer */ + test_memio_clear_buffer(&test_ctx, 0); + + /* inject first record + 1 bytes of second record */ + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, (const char*)readBuf, + rec0_len + 1), + 0); + + /* inject second record */ + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, + (const char*)readBuf + rec0_len + 1, rec1_len - 1), + 0); + ExpectIntEQ(test_ctx.s_len, rec0_len + rec1_len); + + /* reading the record should return just the first message*/ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), 5); + ExpectBufEQ(readBuf, "test0", 5); + + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), + WOLFSSL_FATAL_ERROR); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + + /* cleanup */ + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); + + return EXPECT_RESULT(); +} +#else +int test_dtls12_record_length_mismatch(void) +{ + return TEST_SKIPPED; +} +int test_dtls_record_cross_boundaries(void) +{ + return TEST_SKIPPED; +} +#endif /* !defined(WOLFSSL_DTLS_RECORDS_CAN_SPAN_DATAGRAMS) */ + +int test_dtls_short_ciphertext(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Setup DTLS contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), + 0); + + /* Complete handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* Create a message, that looks encrypted but shorter than minimum ciphertext length */ + /* create the data in the buffer */ + ExpectIntEQ(wolfSSL_write(ssl_c, "bad", 3), 3); + + /* check client wrote the record */ + ExpectIntGT(test_ctx.s_len, 14); + + /* modify the length field to be smaller than the content */ + test_ctx.s_buff[11] = 0x00; + test_ctx.s_buff[12] = 0x02; + /* modify the amount of data to send */ + ExpectIntEQ(test_memio_modify_message_len(&test_ctx, 0, 0, 15), 0); + + /* Try to read the malformed record */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ); + ExpectIntEQ(test_ctx.s_len, 0); + + ExpectIntEQ(test_dtls_communication(ssl_s, ssl_c), TEST_SUCCESS); + + ExpectIntEQ(test_dtls_shutdown(ssl_s, ssl_c, ctx_c, ctx_s), TEST_SUCCESS); + + return EXPECT_RESULT(); +} +#else +int test_dtls_short_ciphertext(void) +{ + return TEST_SKIPPED; +} +int test_dtls12_record_length_mismatch(void) +{ + return TEST_SKIPPED; +} +int test_dtls12_short_read(void) +{ + return TEST_SKIPPED; +} +int test_dtls13_short_read(void) +{ + return TEST_SKIPPED; +} +int test_dtls13_longer_length(void) +{ + return TEST_SKIPPED; +} +int test_dtls_record_cross_boundaries(void) +{ + return TEST_SKIPPED; +} +#endif /* defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) */ + +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(WOLFSSL_NO_TLS12) +/* This test that the DTLS record boundary check doesn't interfere with TLS + * records processing */ +int test_records_span_network_boundaries(void) +{ + EXPECT_DECLS; + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + unsigned char readBuf[50]; + int record_len; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* Setup DTLS contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), + 0); + + /* Complete handshake */ + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + + /* create a good record in the buffer */ + wolfSSL_SetLoggingPrefix("client"); + ExpectIntEQ(wolfSSL_write(ssl_c, "test", 4), 4); + ExpectIntLE(test_ctx.s_len, 50); + ExpectIntGT(test_ctx.s_len, 10); + record_len = test_ctx.s_len; + XMEMCPY(readBuf, test_ctx.s_buff, record_len); + + /* drop record and simulate a split write */ + ExpectIntEQ(test_memio_drop_message(&test_ctx, 0, 0), 0); + ExpectIntEQ(test_ctx.s_msg_count, 0); + + /* inject first record header */ + ExpectIntEQ( + test_memio_inject_message(&test_ctx, 0, (const char*)readBuf, 5), 0); + ExpectIntEQ(test_ctx.s_msg_count, 1); + ExpectIntEQ(test_ctx.s_msg_sizes[0], 5); + + /* inject another 5 bytes of the record */ + ExpectIntEQ( + test_memio_inject_message(&test_ctx, 0, (const char*)readBuf + 5, 5), + 0); + ExpectIntEQ(test_ctx.s_msg_count, 2); + ExpectIntEQ(test_ctx.s_msg_sizes[1], 5); + + /* inject the rest of the record */ + ExpectIntEQ(test_memio_inject_message(&test_ctx, 0, + (const char*)readBuf + 10, record_len - 10), + 0); + ExpectIntEQ(test_ctx.s_msg_count, 3); + ExpectIntEQ(test_ctx.s_msg_sizes[2], record_len - 10); + + /* read the record */ + wolfSSL_SetLoggingPrefix("server"); + ExpectIntEQ(wolfSSL_read(ssl_s, readBuf, sizeof(readBuf)), 4); + ExpectIntEQ(test_ctx.s_len, 0); + + ExpectBufEQ(readBuf, "test", 4); + + wolfSSL_free(ssl_s); + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_s); + wolfSSL_CTX_free(ctx_c); + + return EXPECT_RESULT(); +} +#else +int test_records_span_network_boundaries(void) +{ + return TEST_SKIPPED; +} +#endif /* defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) */ diff --git a/tests/api/test_dtls.h b/tests/api/test_dtls.h index 25f9ab263..7f8f0457f 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -28,5 +28,11 @@ int test_wolfSSL_dtls_cid_parse(void); int test_dtls13_epochs(void); int test_dtls13_ack_order(void); int test_dtls_version_checking(void); - +int test_dtls_short_ciphertext(void); +int test_dtls12_record_length_mismatch(void); +int test_dtls12_short_read(void); +int test_dtls13_longer_length(void); +int test_dtls13_short_read(void); +int test_records_span_network_boundaries(void); +int test_dtls_record_cross_boundaries(void); #endif /* TESTS_API_DTLS_H */ diff --git a/tests/unit.h b/tests/unit.h index 4edd20a22..67c555558 100644 --- a/tests/unit.h +++ b/tests/unit.h @@ -385,6 +385,8 @@ typedef struct test_ssl_cbf { } test_ssl_cbf; #define TEST_SSL_MEMIO_BUF_SZ (64 * 1024) +#define TEST_MEMIO_MAX_MSGS 32 + typedef struct test_ssl_memio_ctx { WOLFSSL_CTX* s_ctx; WOLFSSL_CTX* c_ctx; @@ -406,6 +408,16 @@ typedef struct test_ssl_memio_ctx { int c_len; byte s_buff[TEST_SSL_MEMIO_BUF_SZ]; int s_len; + + int c_msg_sizes[TEST_MEMIO_MAX_MSGS]; + int c_msg_count; + int c_msg_pos; + int c_msg_offset; + + int s_msg_sizes[TEST_MEMIO_MAX_MSGS]; + int s_msg_count; + int s_msg_pos; + int s_msg_offset; } test_ssl_memio_ctx; int test_ssl_memio_setup(test_ssl_memio_ctx *ctx); diff --git a/tests/utils.c b/tests/utils.c index 2b78b3a67..e0af4c923 100644 --- a/tests/utils.c +++ b/tests/utils.c @@ -43,21 +43,30 @@ int test_memio_write_cb(WOLFSSL *ssl, char *data, int sz, void *ctx) struct test_memio_ctx *test_ctx; byte *buf; int *len; + int *msg_sizes; + int *msg_count; test_ctx = (struct test_memio_ctx*)ctx; if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { buf = test_ctx->c_buff; len = &test_ctx->c_len; + msg_sizes = test_ctx->c_msg_sizes; + msg_count = &test_ctx->c_msg_count; } else { buf = test_ctx->s_buff; len = &test_ctx->s_len; + msg_sizes = test_ctx->s_msg_sizes; + msg_count = &test_ctx->s_msg_count; } if ((unsigned)(*len + sz) > TEST_MEMIO_BUF_SZ) return WOLFSSL_CBIO_ERR_WANT_WRITE; + if (*msg_count >= TEST_MEMIO_MAX_MSGS) + return WOLFSSL_CBIO_ERR_WANT_WRITE; + #ifdef WOLFSSL_DUMP_MEMIO_STREAM { char dump_file_name[64]; @@ -71,6 +80,8 @@ int test_memio_write_cb(WOLFSSL *ssl, char *data, int sz, void *ctx) } #endif XMEMCPY(buf + *len, data, (size_t)sz); + msg_sizes[*msg_count] = sz; + (*msg_count)++; *len += sz; return sz; @@ -82,27 +93,64 @@ int test_memio_read_cb(WOLFSSL *ssl, char *data, int sz, void *ctx) int read_sz; byte *buf; int *len; + int *msg_sizes; + int *msg_count; + int *msg_pos; + int is_dtls; test_ctx = (struct test_memio_ctx*)ctx; + is_dtls = wolfSSL_dtls(ssl); if (wolfSSL_GetSide(ssl) == WOLFSSL_SERVER_END) { buf = test_ctx->s_buff; len = &test_ctx->s_len; + msg_sizes = test_ctx->s_msg_sizes; + msg_count = &test_ctx->s_msg_count; + msg_pos = &test_ctx->s_msg_pos; } else { buf = test_ctx->c_buff; len = &test_ctx->c_len; + msg_sizes = test_ctx->c_msg_sizes; + msg_count = &test_ctx->c_msg_count; + msg_pos = &test_ctx->c_msg_pos; } - if (*len == 0) + if (*len == 0 || *msg_pos >= *msg_count) return WOLFSSL_CBIO_ERR_WANT_READ; - read_sz = sz < *len ? sz : *len; + /* Calculate how much we can read from current message */ + read_sz = msg_sizes[*msg_pos]; + if (read_sz > sz) + read_sz = sz; + if (read_sz > *len) { + return WOLFSSL_CBIO_ERR_GENERAL; + } + + /* Copy data from current message */ XMEMCPY(data, buf, (size_t)read_sz); - XMEMMOVE(buf, buf + read_sz,(size_t) (*len - read_sz)); - + /* remove the read data from the buffer */ + XMEMMOVE(buf, buf + read_sz, (size_t)(*len - read_sz)); *len -= read_sz; + msg_sizes[*msg_pos] -= read_sz; + + /* if we are on dtls, discard the rest of the message */ + if (is_dtls && msg_sizes[*msg_pos] > 0) { + XMEMMOVE(buf, buf + msg_sizes[*msg_pos], (size_t)(*len - msg_sizes[*msg_pos])); + *len -= msg_sizes[*msg_pos]; + msg_sizes[*msg_pos] = 0; + } + + /* If we've read the entire message */ + if (msg_sizes[*msg_pos] == 0) { + /* Move to next message */ + (*msg_pos)++; + if (*msg_pos >= *msg_count) { + *msg_pos = 0; + *msg_count = 0; + } + } return read_sz; } @@ -251,6 +299,190 @@ int test_memio_setup_ex(struct test_memio_ctx *ctx, return 0; } +void test_memio_clear_buffer(struct test_memio_ctx *ctx, int is_client) +{ + if (is_client) { + ctx->c_len = 0; + ctx->c_msg_pos = 0; + ctx->c_msg_count = 0; + } else { + ctx->s_len = 0; + ctx->s_msg_pos = 0; + ctx->s_msg_count = 0; + } +} + +int test_memio_inject_message(struct test_memio_ctx* ctx, int client, + const char* data, int sz) +{ + int* len; + int* msg_count; + int* msg_sizes; + byte* buff; + + if (client) { + buff = ctx->c_buff; + len = &ctx->c_len; + msg_count = &ctx->c_msg_count; + msg_sizes = ctx->c_msg_sizes; + } + else { + buff = ctx->s_buff; + len = &ctx->s_len; + msg_count = &ctx->s_msg_count; + msg_sizes = ctx->s_msg_sizes; + } + if (*len + sz > TEST_MEMIO_BUF_SZ) { + return -1; + } + if (*msg_count >= TEST_MEMIO_MAX_MSGS) { + return -1; + } + XMEMCPY(buff + *len, data, (size_t)sz); + msg_sizes[*msg_count] = sz; + (*msg_count)++; + *len += sz; + return 0; +} + +int test_memio_drop_message(struct test_memio_ctx *ctx, int client, int msg_pos) +{ + int *len; + int *msg_count; + int *msg_sizes; + int msg_off, msg_sz; + int i; + byte *buff; + if (client) { + buff = ctx->c_buff; + len = &ctx->c_len; + msg_count = &ctx->c_msg_count; + msg_sizes = ctx->c_msg_sizes; + } else { + buff = ctx->s_buff; + len = &ctx->s_len; + msg_count = &ctx->s_msg_count; + msg_sizes = ctx->s_msg_sizes; + } + if (*msg_count == 0) { + return -1; + } + msg_off = 0; + if (msg_pos >= *msg_count) { + return -1; + } + msg_sz = msg_sizes[msg_pos]; + for (i = 0; i < msg_pos; i++) { + msg_off += msg_sizes[i]; + } + XMEMMOVE(buff + msg_off, buff + msg_off + msg_sz, *len - msg_off - msg_sz); + for (i = msg_pos; i < *msg_count - 1; i++) { + msg_sizes[i] = msg_sizes[i + 1]; + } + *len -= msg_sz; + (*msg_count)--; + return 0; +} + +int test_memio_remove_from_buffer(struct test_memio_ctx* ctx, int client, + int off, int sz) +{ + int* len; + int* msg_count; + int* msg_sizes; + int msg_off; + int i; + byte* buff; + + if (client) { + buff = ctx->c_buff; + len = &ctx->c_len; + msg_count = &ctx->c_msg_count; + msg_sizes = ctx->c_msg_sizes; + } + else { + buff = ctx->s_buff; + len = &ctx->s_len; + msg_count = &ctx->s_msg_count; + msg_sizes = ctx->s_msg_sizes; + } + if (*len == 0) { + return -1; + } + if (off >= *len) { + return -1; + } + if (off + sz > *len) { + return -1; + } + /* find which message the offset is in */ + msg_off = 0; + for (i = 0; i < *msg_count; i++) { + if (off >= msg_off && off < msg_off + msg_sizes[i]) { + break; + } + msg_off += msg_sizes[i]; + } + /* don't support records that are split across messages */ + if (off + sz > msg_off + msg_sizes[i]) { + return -1; + } + if (i == *msg_count) { + return -1; + } + if (sz == msg_sizes[i]) { + return test_memio_drop_message(ctx, client, i); + } + XMEMMOVE(buff + off, buff + off + sz, *len - off - sz); + msg_sizes[i] -= sz; + *len -= sz; + return 0; +} + +int test_memio_modify_message_len(struct test_memio_ctx* ctx, int client, + int msg_pos, int new_len) +{ + int* len; + int* msg_count; + int* msg_sizes; + int msg_off, msg_sz; + int i; + byte* buff; + if (client) { + buff = ctx->c_buff; + len = &ctx->c_len; + msg_count = &ctx->c_msg_count; + msg_sizes = ctx->c_msg_sizes; + } + else { + buff = ctx->s_buff; + len = &ctx->s_len; + msg_count = &ctx->s_msg_count; + msg_sizes = ctx->s_msg_sizes; + } + if (*msg_count == 0) { + return -1; + } + if (msg_pos >= *msg_count) { + return -1; + } + msg_off = 0; + for (i = 0; i < msg_pos; i++) { + msg_off += msg_sizes[i]; + } + msg_sz = msg_sizes[msg_pos]; + if (new_len > msg_sz) { + if (*len + (new_len - msg_sz) > TEST_MEMIO_BUF_SZ) { + return -1; + } + } + XMEMMOVE(buff + msg_off + new_len, buff + msg_off + msg_sz, + *len - msg_off - msg_sz); + msg_sizes[msg_pos] = new_len; + *len = *len - msg_sz + new_len; + return 0; +} + int test_memio_setup(struct test_memio_ctx *ctx, WOLFSSL_CTX **ctx_c, WOLFSSL_CTX **ctx_s, WOLFSSL **ssl_c, WOLFSSL **ssl_s, method_provider method_c, method_provider method_s) @@ -260,4 +492,3 @@ int test_memio_setup(struct test_memio_ctx *ctx, } #endif /* HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES */ - diff --git a/tests/utils.h b/tests/utils.h index 75bae2cb0..ce410f86f 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -32,6 +32,8 @@ (!defined(WOLFSSL_NO_TLS12) || defined(WOLFSSL_TLS13)) #define HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES #define TEST_MEMIO_BUF_SZ (64 * 1024) +#define TEST_MEMIO_MAX_MSGS 32 + struct test_memio_ctx { byte c_buff[TEST_MEMIO_BUF_SZ]; @@ -40,6 +42,14 @@ struct test_memio_ctx byte s_buff[TEST_MEMIO_BUF_SZ]; int s_len; const char* s_ciphers; + + int c_msg_sizes[TEST_MEMIO_MAX_MSGS]; + int c_msg_count; + int c_msg_pos; + + int s_msg_sizes[TEST_MEMIO_MAX_MSGS]; + int s_msg_count; + int s_msg_pos; }; int test_memio_write_cb(WOLFSSL *ssl, char *data, int sz, void *ctx); int test_memio_read_cb(WOLFSSL *ssl, char *data, int sz, void *ctx); @@ -53,6 +63,11 @@ int test_memio_setup_ex(struct test_memio_ctx *ctx, method_provider method_c, method_provider method_s, byte *caCert, int caCertSz, byte *serverCert, int serverCertSz, byte *serverKey, int serverKeySz); +void test_memio_clear_buffer(struct test_memio_ctx *ctx, int is_client); +int test_memio_inject_message(struct test_memio_ctx *ctx, int client, const char *data, int sz); +int test_memio_drop_message(struct test_memio_ctx *ctx, int client, int msg_pos); +int test_memio_modify_message_len(struct test_memio_ctx *ctx, int client, int msg_pos, int new_len); +int test_memio_remove_from_buffer(struct test_memio_ctx *ctx, int client, int off, int sz); #endif #endif /* TESTS_UTILS_H */ diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index bc3e64100..63f8d35c5 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -220,6 +220,7 @@ enum wolfSSL_ErrorCodes { POST_HAND_AUTH_ERROR = -504, /* client won't do post-hand auth */ HRR_COOKIE_ERROR = -505, /* HRR msg cookie mismatch */ UNSUPPORTED_CERTIFICATE = -506, /* unsupported certificate type */ + DTLS_PARTIAL_RECORD_READ = -455, /* received a partial record in a datagram */ /* PEM and EVP errors */ WOLFSSL_PEM_R_NO_START_LINE_E = -507,