|
52 | 52 | import javax.net.ssl.SSLSocket; |
53 | 53 | import javax.net.ssl.SSLServerSocket; |
54 | 54 | import javax.net.ssl.TrustManager; |
| 55 | +import javax.net.ssl.SNIHostName; |
| 56 | +import javax.net.ssl.SNIMatcher; |
| 57 | +import javax.net.ssl.SSLParameters; |
55 | 58 | import javax.net.ssl.X509TrustManager; |
56 | 59 | import javax.net.ssl.X509ExtendedTrustManager; |
57 | 60 | import javax.net.ssl.SSLEngineResult; |
@@ -1212,6 +1215,123 @@ public void testReuseSession() |
1212 | 1215 | } |
1213 | 1216 | } |
1214 | 1217 |
|
| 1218 | + /** |
| 1219 | + * Test that SNI is correctly preserved across TLS session resumption |
| 1220 | + * when using SSLEngine. Regression test for the bug where |
| 1221 | + * setLocalServerNames() would overwrite session-cached SNI with the |
| 1222 | + * autoSNI hostname on resumption. |
| 1223 | + */ |
| 1224 | + @Test |
| 1225 | + public void testEngineSessionResumptionSNI() |
| 1226 | + throws NoSuchProviderException, NoSuchAlgorithmException, |
| 1227 | + KeyManagementException, KeyStoreException, IOException, |
| 1228 | + CertificateException, UnrecoverableKeyException { |
| 1229 | + |
| 1230 | + System.out.print("\tEngine session resumption SNI"); |
| 1231 | + |
| 1232 | + /* Requires WOLFSSL_ALWAYS_KEEP_SNI, enabled by default with |
| 1233 | + * --enable-jni in wolfSSL 5.7.6+ (PR 8283) */ |
| 1234 | + if (WolfSSL.getLibVersionHex() < 0x05007006L) { |
| 1235 | + System.out.println("\t... skipped"); |
| 1236 | + return; |
| 1237 | + } |
| 1238 | + |
| 1239 | + if (!enabledProtocols.contains("TLSv1.3")) { |
| 1240 | + System.out.println("\t... skipped"); |
| 1241 | + return; |
| 1242 | + } |
| 1243 | + |
| 1244 | + /* wolfjsse.clientSessionCache.disabled could be set in users |
| 1245 | + * java.security file which would cause this test to not work |
| 1246 | + * properly. Save their setting here, and re-enable session |
| 1247 | + * cache for this test */ |
| 1248 | + String originalProp = Security.getProperty( |
| 1249 | + "wolfjsse.clientSessionCache.disabled"); |
| 1250 | + Security.setProperty("wolfjsse.clientSessionCache.disabled", "false"); |
| 1251 | + |
| 1252 | + /* SNI hostname intentionally differs from peer hostname. |
| 1253 | + * autoSNI would send "localhost"; the fix sends "www.example.com" |
| 1254 | + * from the session cache instead. The server SNI matcher only |
| 1255 | + * accepts "www.example.com", so the outcome distinguishes the two. */ |
| 1256 | + final String sniHostname = "www.example.com"; |
| 1257 | + final String peerHostname = "localhost"; |
| 1258 | + final SNIMatcher matcher = |
| 1259 | + SNIHostName.createSNIMatcher("www\\.example\\.com"); |
| 1260 | + |
| 1261 | + try { |
| 1262 | + int ret; |
| 1263 | + SSLEngine client1 = null, client2 = null; |
| 1264 | + SSLEngine server1 = null, server2 = null; |
| 1265 | + SSLContext ctx13 = tf.createSSLContext("TLSv1.3", engineProvider); |
| 1266 | + |
| 1267 | + /* --- Connection #1: explicit SNI, caches it in the session --- */ |
| 1268 | + try { |
| 1269 | + client1 = ctx13.createSSLEngine(peerHostname, 8443); |
| 1270 | + client1.setUseClientMode(true); |
| 1271 | + SSLParameters cliParams1 = client1.getSSLParameters(); |
| 1272 | + cliParams1.setServerNames( |
| 1273 | + Arrays.asList(new SNIHostName(sniHostname))); |
| 1274 | + client1.setSSLParameters(cliParams1); |
| 1275 | + |
| 1276 | + server1 = ctx13.createSSLEngine(); |
| 1277 | + server1.setUseClientMode(false); |
| 1278 | + SSLParameters srvParams1 = server1.getSSLParameters(); |
| 1279 | + srvParams1.setSNIMatchers(Arrays.asList(matcher)); |
| 1280 | + server1.setSSLParameters(srvParams1); |
| 1281 | + |
| 1282 | + ret = tf.testConnection(server1, client1, null, null, "Hello"); |
| 1283 | + if (ret != 0) { |
| 1284 | + error("\t... failed"); |
| 1285 | + fail("Initial connection with explicit SNI failed"); |
| 1286 | + } |
| 1287 | + } finally { |
| 1288 | + if (server1 != null && client1 != null) { |
| 1289 | + tf.CloseConnection(server1, client1, false); |
| 1290 | + } |
| 1291 | + } |
| 1292 | + |
| 1293 | + /* Connection #2: SNI must come from session cache */ |
| 1294 | + try { |
| 1295 | + client2 = ctx13.createSSLEngine(peerHostname, 8443); |
| 1296 | + client2.setUseClientMode(true); |
| 1297 | + /* Intentionally no setSSLParameters() with server names. |
| 1298 | + * peerHostname ("localhost") makes |
| 1299 | + * isEngineConnectionWithHost=true and autoSNI=true. Without |
| 1300 | + * the fix, autoSNI would send "localhost" and the server |
| 1301 | + * would reject it. With the fix, the session-cached |
| 1302 | + * "www.example.com" is used instead. */ |
| 1303 | + |
| 1304 | + server2 = ctx13.createSSLEngine(); |
| 1305 | + server2.setUseClientMode(false); |
| 1306 | + SSLParameters srvParams2 = server2.getSSLParameters(); |
| 1307 | + srvParams2.setSNIMatchers(Arrays.asList(matcher)); |
| 1308 | + server2.setSSLParameters(srvParams2); |
| 1309 | + |
| 1310 | + ret = tf.testConnection(server2, client2, null, null, "Hello"); |
| 1311 | + } finally { |
| 1312 | + if (server2 != null && client2 != null) { |
| 1313 | + tf.CloseConnection(server2, client2, false); |
| 1314 | + } |
| 1315 | + } |
| 1316 | + if (ret != 0) { |
| 1317 | + error("\t... failed"); |
| 1318 | + fail("Resumed connection did not carry session-cached SNI"); |
| 1319 | + } |
| 1320 | + |
| 1321 | + pass("\t... passed"); |
| 1322 | + |
| 1323 | + } catch (Exception e) { |
| 1324 | + error("\t... failed"); |
| 1325 | + e.printStackTrace(); |
| 1326 | + fail("testEngineSessionResumptionSNI failed with exception: " + e); |
| 1327 | + } finally { |
| 1328 | + if (originalProp != null && !originalProp.isEmpty()) { |
| 1329 | + Security.setProperty( |
| 1330 | + "wolfjsse.clientSessionCache.disabled", originalProp); |
| 1331 | + } |
| 1332 | + } |
| 1333 | + } |
| 1334 | + |
1215 | 1335 | /** |
1216 | 1336 | * More extended threading test of SSLEngine class. |
1217 | 1337 | * Launches a simple multi-threaded SSLSocket-based server, which |
|
0 commit comments