diff --git a/src/internal.c b/src/internal.c index 4608839eb84..67b8f922646 100644 --- a/src/internal.c +++ b/src/internal.c @@ -18922,8 +18922,9 @@ static int DoDtlsHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, if (type == finished && ssl->keys.dtls_peer_handshake_number >= ssl->keys.dtls_expected_peer_handshake_number && - ssl->keys.curEpoch == ssl->keys.dtls_epoch) { - /* finished msg should be ignore from the current epoch + ssl->keys.curEpoch == ssl->keys.dtls_epoch && + ssl->keys.curEpoch != 0) { + /* finished msg should be ignored from the current epoch * if it comes from a previous handshake */ if (ssl->options.side == WOLFSSL_CLIENT_END) { ignoreFinished = ssl->options.connectState < FINISHED_DONE; diff --git a/tests/api.c b/tests/api.c index 1ae524f780d..6f2a05c6852 100644 --- a/tests/api.c +++ b/tests/api.c @@ -51225,6 +51225,7 @@ TEST_DECL(test_wc_RsaPSS_DigitalSignVerify), TEST_DECL(test_dtls13_epochs), TEST_DECL(test_dtls_rtx_across_epoch_change), TEST_DECL(test_dtls_drop_client_ack), + TEST_DECL(test_dtls_bogus_finished_epoch_zero), TEST_DECL(test_dtls_replay), TEST_DECL(test_dtls13_ack_order), TEST_DECL(test_dtls_version_checking), diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c index 9458874dc77..52e1bd34144 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -1474,6 +1474,80 @@ int test_dtls_drop_client_ack(void) return EXPECT_RESULT(); } +int test_dtls_bogus_finished_epoch_zero(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + !defined(WOLFSSL_NO_TLS12) && defined(HAVE_AES_CBC) && \ + defined(WOLFSSL_AES_128) && !defined(NO_SHA256) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + struct test_memio_ctx test_ctx; + int error; + + /* bogus Finished message bytes from the original bug report (epoch 0) + * https://github.com/wolfSSL/wolfssl/issues/9188 */ + static const unsigned char bogus_finished[] = { + 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x14, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0xd9, 0xc6, 0xe3, 0x01, 0x59, 0xf2, 0xc2, 0x4f, 0xfa, 0xfd, 0x20, + 0xd7 + }; + + /* serverHelloDone message bytes */ + static const unsigned char server_hello_done_message[] = { + 0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + }; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + + /* setting up dtls 1.2 contexts */ + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + + /* start handshake, send first ClientHelloDone */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ); + + /* clearing server buffer to inject the wrong Finished packet */ + test_memio_clear_buffer(&test_ctx, 1); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, + (const char*)bogus_finished, sizeof(bogus_finished)), 0); + + /* continue client handshake to process it */ + ExpectIntEQ(wolfSSL_connect(ssl_c), -1); + + /* client should terminate with dtls sequence error */ + error = wolfSSL_get_error(ssl_c, -1); + + /* check if the error is SEQUENCE_ERROR, handshake should not + * expect a finished packet in that moment, in particular should not + * be in epoch = 0 (should be epoch = 1) */ + ExpectTrue(error == WC_NO_ERR_TRACE(SEQUENCE_ERROR) || + error == WC_NO_ERR_TRACE(WOLFSSL_ERROR_WANT_READ)); + + /* forcing injection ServerHelloDone to test if client would replay + * ClientHello */ + test_memio_clear_buffer(&test_ctx, 0); + ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, + (const char*)server_hello_done_message, sizeof(server_hello_done_message)), 0); + wolfSSL_connect(ssl_c); + + /* verifying no ClientHello replay occurred, + * buffer should empty since we exit early on + * because of the bogus finished packet */ + ExpectIntLE(test_ctx.s_len, 0); + + wolfSSL_free(ssl_c); + wolfSSL_CTX_free(ctx_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + int test_dtls_replay(void) { EXPECT_DECLS; diff --git a/tests/api/test_dtls.h b/tests/api/test_dtls.h index 9c717826a1e..fe159a73d9a 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -38,5 +38,6 @@ int test_records_span_network_boundaries(void); int test_dtls_record_cross_boundaries(void); int test_dtls_rtx_across_epoch_change(void); int test_dtls_drop_client_ack(void); +int test_dtls_bogus_finished_epoch_zero(void); int test_dtls_replay(void); #endif /* TESTS_API_DTLS_H */