mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-09 06:10:52 +02:00
Validate minDowngrade in wolfSSL_SetSession before reusing version
When resuming a session wolfSSL_SetSession unconditionally overwrote ssl->version with the version stored in the cached session, even if that version was below the WOLFSSL's configured minDowngrade. The overwritten version then fed straight into SendClientHello, so a client configured to require TLS 1.2 or higher could still emit a ClientHello advertising e.g. TLS 1.0 when resuming an old cached session. The ServerHello path catches the actual downgrade, but the ClientHello version is already a protocol-conformance issue and can confuse middleboxes. Reject the session if its stored minor version is below ssl->options.minDowngrade. The check is DTLS-aware: DTLS minor versions decrease as the protocol version increases, so the direction of the comparison is flipped for DTLS. F-2105
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user