mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 13:20:52 +02:00
Merge pull request #10633 from holtrop-wolfssl/f-4141
Add unit tests that TLS resumption fails due to ALPN mismatch
This commit is contained in:
@@ -1244,6 +1244,159 @@ int test_tls13_resumption_with_alpn(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* TLS 1.2 stateful (session-ID) resumption must fall back to a full
|
||||
* handshake if the ALPN protocol negotiated for the resumed connection
|
||||
* does not match the ALPN bound to the original session. Mirrors
|
||||
* test_tls12_session_id_resumption_sni_mismatch but varies ALPN instead
|
||||
* of SNI. */
|
||||
int test_tls12_session_id_resumption_alpn_mismatch(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
|
||||
!defined(WOLFSSL_NO_TLS12) && defined(HAVE_ALPN) && \
|
||||
defined(HAVE_SESSION_TICKET) && !defined(NO_SESSION_CACHE)
|
||||
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;
|
||||
const char alpnA[] = "h2";
|
||||
const char alpnB[] = "http/1.1";
|
||||
|
||||
/* Step 1: full TLS 1.2 handshake negotiating ALPN=h2, with the
|
||||
* session ticket path disabled so resumption can only happen via the
|
||||
* server's session-ID cache. The negotiated ALPN is retained on
|
||||
* ssl->extensions by ALPN_Select, so SetupSession binds its hash to
|
||||
* the cached session. */
|
||||
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(wolfSSL_NoTicketTLSv12(ssl_c), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_s), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpnA, (word32)XSTRLEN(alpnA),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpnA, (word32)XSTRLEN(alpnA),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
/* Sanity: the first handshake was not a resumption. */
|
||||
ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0);
|
||||
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
|
||||
|
||||
wolfSSL_free(ssl_c); ssl_c = NULL;
|
||||
wolfSSL_free(ssl_s); ssl_s = NULL;
|
||||
|
||||
/* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's
|
||||
* session cache still holds the entry from step 1). The client offers
|
||||
* the saved session but both sides now advertise a *different* ALPN
|
||||
* (http/1.1), so the handshake negotiates http/1.1. The server's cache
|
||||
* lookup matches by session ID, but the server MUST NOT resume because
|
||||
* the negotiated ALPN differs from the one bound to the original
|
||||
* session. */
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
|
||||
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
|
||||
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
|
||||
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
|
||||
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
|
||||
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
|
||||
ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_c), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_s), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpnB, (word32)XSTRLEN(alpnB),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpnB, (word32)XSTRLEN(alpnB),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
|
||||
/* Expected behavior: server falls back to a full handshake because the
|
||||
* negotiated ALPN does not match the ALPN bound to the cached session.
|
||||
* Both sides should report no resumption. */
|
||||
ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0);
|
||||
ExpectIntEQ(wolfSSL_session_reused(ssl_c), 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();
|
||||
}
|
||||
|
||||
/* TLS 1.3 PSK resumption must fall back to a full handshake if the ALPN
|
||||
* protocol negotiated for the resumed connection does not match the ALPN
|
||||
* bound to the original session. Mirrors
|
||||
* test_tls13_session_resumption_sni_mismatch but varies ALPN instead of
|
||||
* SNI. */
|
||||
int test_tls13_session_resumption_alpn_mismatch(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
|
||||
defined(HAVE_ALPN) && defined(HAVE_SESSION_TICKET) && \
|
||||
!defined(NO_SESSION_CACHE)
|
||||
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;
|
||||
const char alpnA[] = "h2";
|
||||
const char alpnB[] = "http/1.1";
|
||||
byte readBuf[16];
|
||||
|
||||
/* Step 1: full TLS 1.3 handshake negotiating ALPN=h2 to obtain a
|
||||
* session ticket. The negotiated ALPN is retained on ssl->extensions
|
||||
* by ALPN_Select and bound to the ticket. */
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
||||
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
|
||||
ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpnA, (word32)XSTRLEN(alpnA),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpnA, (word32)XSTRLEN(alpnA),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
/* Sanity: the first handshake was not a resumption. */
|
||||
ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0);
|
||||
/* Drive the post-handshake NewSessionTicket through to the client so
|
||||
* the saved session is a real resumption ticket. */
|
||||
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, sizeof(readBuf)), -1);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||
ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
|
||||
|
||||
wolfSSL_free(ssl_c); ssl_c = NULL;
|
||||
wolfSSL_free(ssl_s); ssl_s = NULL;
|
||||
|
||||
/* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's
|
||||
* ticket key still matches). The client offers the saved session but
|
||||
* both sides now advertise a *different* ALPN (http/1.1). The server
|
||||
* MUST NOT resume because the negotiated ALPN differs from the one
|
||||
* bound to the original ticket. */
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
ExpectNotNull(ssl_c = wolfSSL_new(ctx_c));
|
||||
wolfSSL_SetIOReadCtx(ssl_c, &test_ctx);
|
||||
wolfSSL_SetIOWriteCtx(ssl_c, &test_ctx);
|
||||
ExpectNotNull(ssl_s = wolfSSL_new(ctx_s));
|
||||
wolfSSL_SetIOReadCtx(ssl_s, &test_ctx);
|
||||
wolfSSL_SetIOWriteCtx(ssl_s, &test_ctx);
|
||||
ExpectIntEQ(wolfSSL_UseALPN(ssl_c, (char*)alpnB, (word32)XSTRLEN(alpnB),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_UseALPN(ssl_s, (char*)alpnB, (word32)XSTRLEN(alpnB),
|
||||
WOLFSSL_ALPN_FAILED_ON_MISMATCH), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
|
||||
/* Expected behavior: server falls back to a full handshake because the
|
||||
* negotiated ALPN does not match the ALPN bound to the cached ticket.
|
||||
* Both sides should report no resumption. */
|
||||
ExpectIntEQ(wolfSSL_session_reused(ssl_s), 0);
|
||||
ExpectIntEQ(wolfSSL_session_reused(ssl_c), 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;
|
||||
|
||||
@@ -37,6 +37,8 @@ int test_tls_set_session_min_downgrade(void);
|
||||
int test_tls12_session_id_resumption_sni_mismatch(void);
|
||||
int test_tls13_session_resumption_sni_mismatch(void);
|
||||
int test_tls13_resumption_with_alpn(void);
|
||||
int test_tls12_session_id_resumption_alpn_mismatch(void);
|
||||
int test_tls13_session_resumption_alpn_mismatch(void);
|
||||
int test_tls_set_curves_list_ecc_fallback(void);
|
||||
int test_tls12_corrupted_finished(void);
|
||||
int test_tls12_peerauth_failsafe(void);
|
||||
@@ -63,6 +65,8 @@ int test_record_size_cache_invalidated_on_renegotiation(void);
|
||||
TEST_DECL_GROUP("tls", test_tls12_session_id_resumption_sni_mismatch), \
|
||||
TEST_DECL_GROUP("tls", test_tls13_session_resumption_sni_mismatch), \
|
||||
TEST_DECL_GROUP("tls", test_tls13_resumption_with_alpn), \
|
||||
TEST_DECL_GROUP("tls", test_tls12_session_id_resumption_alpn_mismatch),\
|
||||
TEST_DECL_GROUP("tls", test_tls13_session_resumption_alpn_mismatch), \
|
||||
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