Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions tests/api/test_tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,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;
Expand Down
4 changes: 4 additions & 0 deletions tests/api/test_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,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);
Expand All @@ -57,6 +59,8 @@ int test_wolfSSL_alert_desc_string(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), \
Expand Down
Loading