@@ -1128,6 +1128,159 @@ int test_tls13_resumption_with_alpn(void)
11281128 return EXPECT_RESULT ();
11291129}
11301130
1131+ /* TLS 1.2 stateful (session-ID) resumption must fall back to a full
1132+ * handshake if the ALPN protocol negotiated for the resumed connection
1133+ * does not match the ALPN bound to the original session. Mirrors
1134+ * test_tls12_session_id_resumption_sni_mismatch but varies ALPN instead
1135+ * of SNI. */
1136+ int test_tls12_session_id_resumption_alpn_mismatch (void )
1137+ {
1138+ EXPECT_DECLS ;
1139+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
1140+ !defined(WOLFSSL_NO_TLS12 ) && defined(HAVE_ALPN ) && \
1141+ defined(HAVE_SESSION_TICKET ) && !defined(NO_SESSION_CACHE )
1142+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
1143+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
1144+ WOLFSSL_SESSION * sess = NULL ;
1145+ struct test_memio_ctx test_ctx ;
1146+ const char alpnA [] = "h2" ;
1147+ const char alpnB [] = "http/1.1" ;
1148+
1149+ /* Step 1: full TLS 1.2 handshake negotiating ALPN=h2, with the
1150+ * session ticket path disabled so resumption can only happen via the
1151+ * server's session-ID cache. The negotiated ALPN is retained on
1152+ * ssl->extensions by ALPN_Select, so SetupSession binds its hash to
1153+ * the cached session. */
1154+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1155+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
1156+ wolfTLSv1_2_client_method , wolfTLSv1_2_server_method ), 0 );
1157+ ExpectIntEQ (wolfSSL_NoTicketTLSv12 (ssl_c ), WOLFSSL_SUCCESS );
1158+ ExpectIntEQ (wolfSSL_NoTicketTLSv12 (ssl_s ), WOLFSSL_SUCCESS );
1159+ ExpectIntEQ (wolfSSL_UseALPN (ssl_c , (char * )alpnA , (word32 )XSTRLEN (alpnA ),
1160+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1161+ ExpectIntEQ (wolfSSL_UseALPN (ssl_s , (char * )alpnA , (word32 )XSTRLEN (alpnA ),
1162+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1163+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1164+ /* Sanity: the first handshake was not a resumption. */
1165+ ExpectIntEQ (wolfSSL_session_reused (ssl_s ), 0 );
1166+ ExpectNotNull (sess = wolfSSL_get1_session (ssl_c ));
1167+
1168+ wolfSSL_free (ssl_c ); ssl_c = NULL ;
1169+ wolfSSL_free (ssl_s ); ssl_s = NULL ;
1170+
1171+ /* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's
1172+ * session cache still holds the entry from step 1). The client offers
1173+ * the saved session but both sides now advertise a *different* ALPN
1174+ * (http/1.1), so the handshake negotiates http/1.1. The server's cache
1175+ * lookup matches by session ID, but the server MUST NOT resume because
1176+ * the negotiated ALPN differs from the one bound to the original
1177+ * session. */
1178+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1179+ ExpectNotNull (ssl_c = wolfSSL_new (ctx_c ));
1180+ wolfSSL_SetIOReadCtx (ssl_c , & test_ctx );
1181+ wolfSSL_SetIOWriteCtx (ssl_c , & test_ctx );
1182+ ExpectNotNull (ssl_s = wolfSSL_new (ctx_s ));
1183+ wolfSSL_SetIOReadCtx (ssl_s , & test_ctx );
1184+ wolfSSL_SetIOWriteCtx (ssl_s , & test_ctx );
1185+ ExpectIntEQ (wolfSSL_NoTicketTLSv12 (ssl_c ), WOLFSSL_SUCCESS );
1186+ ExpectIntEQ (wolfSSL_NoTicketTLSv12 (ssl_s ), WOLFSSL_SUCCESS );
1187+ ExpectIntEQ (wolfSSL_UseALPN (ssl_c , (char * )alpnB , (word32 )XSTRLEN (alpnB ),
1188+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1189+ ExpectIntEQ (wolfSSL_UseALPN (ssl_s , (char * )alpnB , (word32 )XSTRLEN (alpnB ),
1190+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1191+ ExpectIntEQ (wolfSSL_set_session (ssl_c , sess ), WOLFSSL_SUCCESS );
1192+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1193+
1194+ /* Expected behavior: server falls back to a full handshake because the
1195+ * negotiated ALPN does not match the ALPN bound to the cached session.
1196+ * Both sides should report no resumption. */
1197+ ExpectIntEQ (wolfSSL_session_reused (ssl_s ), 0 );
1198+ ExpectIntEQ (wolfSSL_session_reused (ssl_c ), 0 );
1199+
1200+ wolfSSL_SESSION_free (sess );
1201+ wolfSSL_free (ssl_c );
1202+ wolfSSL_free (ssl_s );
1203+ wolfSSL_CTX_free (ctx_c );
1204+ wolfSSL_CTX_free (ctx_s );
1205+ #endif
1206+ return EXPECT_RESULT ();
1207+ }
1208+
1209+ /* TLS 1.3 PSK resumption must fall back to a full handshake if the ALPN
1210+ * protocol negotiated for the resumed connection does not match the ALPN
1211+ * bound to the original session. Mirrors
1212+ * test_tls13_session_resumption_sni_mismatch but varies ALPN instead of
1213+ * SNI. */
1214+ int test_tls13_session_resumption_alpn_mismatch (void )
1215+ {
1216+ EXPECT_DECLS ;
1217+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_TLS13 ) && \
1218+ defined(HAVE_ALPN ) && defined(HAVE_SESSION_TICKET ) && \
1219+ !defined(NO_SESSION_CACHE )
1220+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
1221+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
1222+ WOLFSSL_SESSION * sess = NULL ;
1223+ struct test_memio_ctx test_ctx ;
1224+ const char alpnA [] = "h2" ;
1225+ const char alpnB [] = "http/1.1" ;
1226+ byte readBuf [16 ];
1227+
1228+ /* Step 1: full TLS 1.3 handshake negotiating ALPN=h2 to obtain a
1229+ * session ticket. The negotiated ALPN is retained on ssl->extensions
1230+ * by ALPN_Select and bound to the ticket. */
1231+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1232+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
1233+ wolfTLSv1_3_client_method , wolfTLSv1_3_server_method ), 0 );
1234+ ExpectIntEQ (wolfSSL_UseALPN (ssl_c , (char * )alpnA , (word32 )XSTRLEN (alpnA ),
1235+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1236+ ExpectIntEQ (wolfSSL_UseALPN (ssl_s , (char * )alpnA , (word32 )XSTRLEN (alpnA ),
1237+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1238+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1239+ /* Sanity: the first handshake was not a resumption. */
1240+ ExpectIntEQ (wolfSSL_session_reused (ssl_s ), 0 );
1241+ /* Drive the post-handshake NewSessionTicket through to the client so
1242+ * the saved session is a real resumption ticket. */
1243+ ExpectIntEQ (wolfSSL_read (ssl_c , readBuf , sizeof (readBuf )), -1 );
1244+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
1245+ ExpectNotNull (sess = wolfSSL_get1_session (ssl_c ));
1246+
1247+ wolfSSL_free (ssl_c ); ssl_c = NULL ;
1248+ wolfSSL_free (ssl_s ); ssl_s = NULL ;
1249+
1250+ /* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's
1251+ * ticket key still matches). The client offers the saved session but
1252+ * both sides now advertise a *different* ALPN (http/1.1). The server
1253+ * MUST NOT resume because the negotiated ALPN differs from the one
1254+ * bound to the original ticket. */
1255+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1256+ ExpectNotNull (ssl_c = wolfSSL_new (ctx_c ));
1257+ wolfSSL_SetIOReadCtx (ssl_c , & test_ctx );
1258+ wolfSSL_SetIOWriteCtx (ssl_c , & test_ctx );
1259+ ExpectNotNull (ssl_s = wolfSSL_new (ctx_s ));
1260+ wolfSSL_SetIOReadCtx (ssl_s , & test_ctx );
1261+ wolfSSL_SetIOWriteCtx (ssl_s , & test_ctx );
1262+ ExpectIntEQ (wolfSSL_UseALPN (ssl_c , (char * )alpnB , (word32 )XSTRLEN (alpnB ),
1263+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1264+ ExpectIntEQ (wolfSSL_UseALPN (ssl_s , (char * )alpnB , (word32 )XSTRLEN (alpnB ),
1265+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1266+ ExpectIntEQ (wolfSSL_set_session (ssl_c , sess ), WOLFSSL_SUCCESS );
1267+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1268+
1269+ /* Expected behavior: server falls back to a full handshake because the
1270+ * negotiated ALPN does not match the ALPN bound to the cached ticket.
1271+ * Both sides should report no resumption. */
1272+ ExpectIntEQ (wolfSSL_session_reused (ssl_s ), 0 );
1273+ ExpectIntEQ (wolfSSL_session_reused (ssl_c ), 0 );
1274+
1275+ wolfSSL_SESSION_free (sess );
1276+ wolfSSL_free (ssl_c );
1277+ wolfSSL_free (ssl_s );
1278+ wolfSSL_CTX_free (ctx_c );
1279+ wolfSSL_CTX_free (ctx_s );
1280+ #endif
1281+ return EXPECT_RESULT ();
1282+ }
1283+
11311284int test_tls_set_curves_list_ecc_fallback (void )
11321285{
11331286 EXPECT_DECLS ;
0 commit comments