@@ -1244,6 +1244,159 @@ int test_tls13_resumption_with_alpn(void)
12441244 return EXPECT_RESULT ();
12451245}
12461246
1247+ /* TLS 1.2 stateful (session-ID) resumption must fall back to a full
1248+ * handshake if the ALPN protocol negotiated for the resumed connection
1249+ * does not match the ALPN bound to the original session. Mirrors
1250+ * test_tls12_session_id_resumption_sni_mismatch but varies ALPN instead
1251+ * of SNI. */
1252+ int test_tls12_session_id_resumption_alpn_mismatch (void )
1253+ {
1254+ EXPECT_DECLS ;
1255+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
1256+ !defined(WOLFSSL_NO_TLS12 ) && defined(HAVE_ALPN ) && \
1257+ defined(HAVE_SESSION_TICKET ) && !defined(NO_SESSION_CACHE )
1258+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
1259+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
1260+ WOLFSSL_SESSION * sess = NULL ;
1261+ struct test_memio_ctx test_ctx ;
1262+ const char alpnA [] = "h2" ;
1263+ const char alpnB [] = "http/1.1" ;
1264+
1265+ /* Step 1: full TLS 1.2 handshake negotiating ALPN=h2, with the
1266+ * session ticket path disabled so resumption can only happen via the
1267+ * server's session-ID cache. The negotiated ALPN is retained on
1268+ * ssl->extensions by ALPN_Select, so SetupSession binds its hash to
1269+ * the cached session. */
1270+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1271+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
1272+ wolfTLSv1_2_client_method , wolfTLSv1_2_server_method ), 0 );
1273+ ExpectIntEQ (wolfSSL_NoTicketTLSv12 (ssl_c ), WOLFSSL_SUCCESS );
1274+ ExpectIntEQ (wolfSSL_NoTicketTLSv12 (ssl_s ), WOLFSSL_SUCCESS );
1275+ ExpectIntEQ (wolfSSL_UseALPN (ssl_c , (char * )alpnA , (word32 )XSTRLEN (alpnA ),
1276+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1277+ ExpectIntEQ (wolfSSL_UseALPN (ssl_s , (char * )alpnA , (word32 )XSTRLEN (alpnA ),
1278+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1279+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1280+ /* Sanity: the first handshake was not a resumption. */
1281+ ExpectIntEQ (wolfSSL_session_reused (ssl_s ), 0 );
1282+ ExpectNotNull (sess = wolfSSL_get1_session (ssl_c ));
1283+
1284+ wolfSSL_free (ssl_c ); ssl_c = NULL ;
1285+ wolfSSL_free (ssl_s ); ssl_s = NULL ;
1286+
1287+ /* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's
1288+ * session cache still holds the entry from step 1). The client offers
1289+ * the saved session but both sides now advertise a *different* ALPN
1290+ * (http/1.1), so the handshake negotiates http/1.1. The server's cache
1291+ * lookup matches by session ID, but the server MUST NOT resume because
1292+ * the negotiated ALPN differs from the one bound to the original
1293+ * session. */
1294+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1295+ ExpectNotNull (ssl_c = wolfSSL_new (ctx_c ));
1296+ wolfSSL_SetIOReadCtx (ssl_c , & test_ctx );
1297+ wolfSSL_SetIOWriteCtx (ssl_c , & test_ctx );
1298+ ExpectNotNull (ssl_s = wolfSSL_new (ctx_s ));
1299+ wolfSSL_SetIOReadCtx (ssl_s , & test_ctx );
1300+ wolfSSL_SetIOWriteCtx (ssl_s , & test_ctx );
1301+ ExpectIntEQ (wolfSSL_NoTicketTLSv12 (ssl_c ), WOLFSSL_SUCCESS );
1302+ ExpectIntEQ (wolfSSL_NoTicketTLSv12 (ssl_s ), WOLFSSL_SUCCESS );
1303+ ExpectIntEQ (wolfSSL_UseALPN (ssl_c , (char * )alpnB , (word32 )XSTRLEN (alpnB ),
1304+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1305+ ExpectIntEQ (wolfSSL_UseALPN (ssl_s , (char * )alpnB , (word32 )XSTRLEN (alpnB ),
1306+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1307+ ExpectIntEQ (wolfSSL_set_session (ssl_c , sess ), WOLFSSL_SUCCESS );
1308+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1309+
1310+ /* Expected behavior: server falls back to a full handshake because the
1311+ * negotiated ALPN does not match the ALPN bound to the cached session.
1312+ * Both sides should report no resumption. */
1313+ ExpectIntEQ (wolfSSL_session_reused (ssl_s ), 0 );
1314+ ExpectIntEQ (wolfSSL_session_reused (ssl_c ), 0 );
1315+
1316+ wolfSSL_SESSION_free (sess );
1317+ wolfSSL_free (ssl_c );
1318+ wolfSSL_free (ssl_s );
1319+ wolfSSL_CTX_free (ctx_c );
1320+ wolfSSL_CTX_free (ctx_s );
1321+ #endif
1322+ return EXPECT_RESULT ();
1323+ }
1324+
1325+ /* TLS 1.3 PSK resumption must fall back to a full handshake if the ALPN
1326+ * protocol negotiated for the resumed connection does not match the ALPN
1327+ * bound to the original session. Mirrors
1328+ * test_tls13_session_resumption_sni_mismatch but varies ALPN instead of
1329+ * SNI. */
1330+ int test_tls13_session_resumption_alpn_mismatch (void )
1331+ {
1332+ EXPECT_DECLS ;
1333+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_TLS13 ) && \
1334+ defined(HAVE_ALPN ) && defined(HAVE_SESSION_TICKET ) && \
1335+ !defined(NO_SESSION_CACHE )
1336+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
1337+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
1338+ WOLFSSL_SESSION * sess = NULL ;
1339+ struct test_memio_ctx test_ctx ;
1340+ const char alpnA [] = "h2" ;
1341+ const char alpnB [] = "http/1.1" ;
1342+ byte readBuf [16 ];
1343+
1344+ /* Step 1: full TLS 1.3 handshake negotiating ALPN=h2 to obtain a
1345+ * session ticket. The negotiated ALPN is retained on ssl->extensions
1346+ * by ALPN_Select and bound to the ticket. */
1347+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1348+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
1349+ wolfTLSv1_3_client_method , wolfTLSv1_3_server_method ), 0 );
1350+ ExpectIntEQ (wolfSSL_UseALPN (ssl_c , (char * )alpnA , (word32 )XSTRLEN (alpnA ),
1351+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1352+ ExpectIntEQ (wolfSSL_UseALPN (ssl_s , (char * )alpnA , (word32 )XSTRLEN (alpnA ),
1353+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1354+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1355+ /* Sanity: the first handshake was not a resumption. */
1356+ ExpectIntEQ (wolfSSL_session_reused (ssl_s ), 0 );
1357+ /* Drive the post-handshake NewSessionTicket through to the client so
1358+ * the saved session is a real resumption ticket. */
1359+ ExpectIntEQ (wolfSSL_read (ssl_c , readBuf , sizeof (readBuf )), -1 );
1360+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
1361+ ExpectNotNull (sess = wolfSSL_get1_session (ssl_c ));
1362+
1363+ wolfSSL_free (ssl_c ); ssl_c = NULL ;
1364+ wolfSSL_free (ssl_s ); ssl_s = NULL ;
1365+
1366+ /* Step 2: new SSL objects on the SAME WOLFSSL_CTX (so the server's
1367+ * ticket key still matches). The client offers the saved session but
1368+ * both sides now advertise a *different* ALPN (http/1.1). The server
1369+ * MUST NOT resume because the negotiated ALPN differs from the one
1370+ * bound to the original ticket. */
1371+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1372+ ExpectNotNull (ssl_c = wolfSSL_new (ctx_c ));
1373+ wolfSSL_SetIOReadCtx (ssl_c , & test_ctx );
1374+ wolfSSL_SetIOWriteCtx (ssl_c , & test_ctx );
1375+ ExpectNotNull (ssl_s = wolfSSL_new (ctx_s ));
1376+ wolfSSL_SetIOReadCtx (ssl_s , & test_ctx );
1377+ wolfSSL_SetIOWriteCtx (ssl_s , & test_ctx );
1378+ ExpectIntEQ (wolfSSL_UseALPN (ssl_c , (char * )alpnB , (word32 )XSTRLEN (alpnB ),
1379+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1380+ ExpectIntEQ (wolfSSL_UseALPN (ssl_s , (char * )alpnB , (word32 )XSTRLEN (alpnB ),
1381+ WOLFSSL_ALPN_FAILED_ON_MISMATCH ), WOLFSSL_SUCCESS );
1382+ ExpectIntEQ (wolfSSL_set_session (ssl_c , sess ), WOLFSSL_SUCCESS );
1383+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
1384+
1385+ /* Expected behavior: server falls back to a full handshake because the
1386+ * negotiated ALPN does not match the ALPN bound to the cached ticket.
1387+ * Both sides should report no resumption. */
1388+ ExpectIntEQ (wolfSSL_session_reused (ssl_s ), 0 );
1389+ ExpectIntEQ (wolfSSL_session_reused (ssl_c ), 0 );
1390+
1391+ wolfSSL_SESSION_free (sess );
1392+ wolfSSL_free (ssl_c );
1393+ wolfSSL_free (ssl_s );
1394+ wolfSSL_CTX_free (ctx_c );
1395+ wolfSSL_CTX_free (ctx_s );
1396+ #endif
1397+ return EXPECT_RESULT ();
1398+ }
1399+
12471400int test_tls_set_curves_list_ecc_fallback (void )
12481401{
12491402 EXPECT_DECLS ;
0 commit comments