diff --git a/src/ssl_sess.c b/src/ssl_sess.c index 1a6a6b5f35..647851ac17 100644 --- a/src/ssl_sess.c +++ b/src/ssl_sess.c @@ -1610,6 +1610,23 @@ int wolfSSL_SetSession(WOLFSSL* ssl, WOLFSSL_SESSION* session) ssl->options.haveEMS = (ssl->session->haveEMS) ? 1 : 0; if (ssl->session->version.major != 0) { + /* Reject sessions whose protocol version is below the configured + * minimum so a stale cached session cannot make the client send a + * ClientHello advertising a version it isn't allowed to negotiate. + * DTLS minor versions are inverted: a higher minor means an older + * protocol, so the comparison flips. */ + byte belowMinDowngrade; + if (ssl->options.dtls) + belowMinDowngrade = ssl->session->version.minor > + ssl->options.minDowngrade; + else + belowMinDowngrade = ssl->session->version.minor < + ssl->options.minDowngrade; + if (belowMinDowngrade) { + WOLFSSL_MSG("Session version below configured minDowngrade"); + ssl->options.resuming = 0; + return WOLFSSL_FAILURE; + } ssl->version = ssl->session->version; if (IsAtLeastTLSv1_3(ssl->version)) ssl->options.tls1_3 = 1; diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c index f3c65fc0d4..7453357ba2 100644 --- a/tests/api/test_dtls.c +++ b/tests/api/test_dtls.c @@ -3129,3 +3129,45 @@ int test_dtls13_oversized_cert_chain(void) #endif return EXPECT_RESULT(); } + +/* DTLS counterpart to test_tls_set_session_min_downgrade. Exercises the + * inverted DTLS minor-version comparison (DTLS 1.2 minor 0xFD is "below" + * floor 0xFC = DTLS 1.3). */ +int test_dtls_set_session_min_downgrade(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS) && \ + defined(WOLFSSL_DTLS13) && defined(HAVE_SESSION_TICKET) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLSv1_2_client_method, wolfDTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfDTLS_client_method, wolfDTLS_server_method), 0); + ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, WOLFSSL_DTLSV1_3), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_FAILURE); + if (ssl_c != NULL) + ExpectIntEQ(ssl_c->options.resuming, 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} diff --git a/tests/api/test_dtls.h b/tests/api/test_dtls.h index 062033f572..ee399fbe98 100644 --- a/tests/api/test_dtls.h +++ b/tests/api/test_dtls.h @@ -56,6 +56,7 @@ int test_dtls_mtu_split_messages(void); int test_dtls13_min_rtx_interval(void); int test_dtls13_no_session_id_echo(void); int test_dtls13_oversized_cert_chain(void); +int test_dtls_set_session_min_downgrade(void); #define TEST_DTLS_DECLS \ TEST_DECL_GROUP("dtls", test_dtls12_basic_connection_id), \ @@ -91,5 +92,6 @@ int test_dtls13_oversized_cert_chain(void); TEST_DECL_GROUP("dtls", test_dtls_memio_wolfio_stateless), \ TEST_DECL_GROUP("dtls", test_dtls13_min_rtx_interval), \ TEST_DECL_GROUP("dtls", test_dtls13_no_session_id_echo), \ - TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain) + TEST_DECL_GROUP("dtls", test_dtls13_oversized_cert_chain), \ + TEST_DECL_GROUP("dtls", test_dtls_set_session_min_downgrade) #endif /* TESTS_API_DTLS_H */ diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c index aedae4f703..2de15544b0 100644 --- a/tests/api/test_tls.c +++ b/tests/api/test_tls.c @@ -861,6 +861,48 @@ int test_tls12_etm_failed_resumption(void) return EXPECT_RESULT(); } +/* wolfSSL_set_session() must reject a TLS 1.2 session when minDowngrade is + * set to TLS 1.3. */ +int test_tls_set_session_min_downgrade(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \ + !defined(WOLFSSL_NO_TLS12) && defined(WOLFSSL_TLS13) && \ + defined(HAVE_SESSION_TICKET) + WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL; + WOLFSSL *ssl_c = NULL, *ssl_s = NULL; + WOLFSSL_SESSION *sess = NULL; + struct test_memio_ctx test_ctx; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + ExpectNotNull(sess = wolfSSL_get1_session(ssl_c)); + + wolfSSL_free(ssl_c); ssl_c = NULL; + wolfSSL_free(ssl_s); ssl_s = NULL; + wolfSSL_CTX_free(ctx_c); ctx_c = NULL; + wolfSSL_CTX_free(ctx_s); ctx_s = NULL; + + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLS_client_method, wolfTLS_server_method), 0); + ExpectIntEQ(wolfSSL_SetMinVersion(ssl_c, WOLFSSL_TLSV1_3), + WOLFSSL_SUCCESS); + ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_FAILURE); + if (ssl_c != NULL) + ExpectIntEQ(ssl_c->options.resuming, 0); + + wolfSSL_SESSION_free(sess); + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + int test_tls_set_curves_list_ecc_fallback(void) { EXPECT_DECLS; diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h index c0f74f2150..3ca34689e3 100644 --- a/tests/api/test_tls.h +++ b/tests/api/test_tls.h @@ -32,6 +32,7 @@ int test_tls_certreq_order(void); int test_tls12_bad_cv_sig_alg(void); int test_tls12_no_null_compression(void); int test_tls12_etm_failed_resumption(void); +int test_tls_set_session_min_downgrade(void); int test_tls_set_curves_list_ecc_fallback(void); int test_tls12_corrupted_finished(void); int test_tls12_peerauth_failsafe(void); @@ -47,6 +48,7 @@ int test_tls12_peerauth_failsafe(void); TEST_DECL_GROUP("tls", test_tls12_bad_cv_sig_alg), \ TEST_DECL_GROUP("tls", test_tls12_no_null_compression), \ TEST_DECL_GROUP("tls", test_tls12_etm_failed_resumption), \ + TEST_DECL_GROUP("tls", test_tls_set_session_min_downgrade), \ TEST_DECL_GROUP("tls", test_tls_set_curves_list_ecc_fallback), \ TEST_DECL_GROUP("tls", test_tls12_corrupted_finished), \ TEST_DECL_GROUP("tls", test_tls12_peerauth_failsafe)