From fc26d3e5770ca3440105d3904a6e4af9af4860fa Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Thu, 26 Jan 2023 18:36:29 +0000 Subject: [PATCH] 8298873: Update IllegalRecordVersion.java for changes to TLS implementation Reviewed-by: rhalade --- test/jdk/ProblemList.txt | 1 - .../HandshakeWithInvalidRecordVersion.java | 236 ++++++++++++++++++ .../ssl/SSLEngine/IllegalRecordVersion.java | 77 ------ 3 files changed, 236 insertions(+), 78 deletions(-) create mode 100644 test/jdk/javax/net/ssl/SSLEngine/HandshakeWithInvalidRecordVersion.java delete mode 100644 test/jdk/javax/net/ssl/SSLEngine/IllegalRecordVersion.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1180063120a..b445f4d738a 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -586,7 +586,6 @@ sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8161536 generic- sun/security/tools/keytool/ListKeychainStore.sh 8156889 macosx-all javax/net/ssl/SSLEngine/TestAllSuites.java 8298874 generic-all -javax/net/ssl/SSLEngine/IllegalRecordVersion.java 8298873 generic-all javax/net/ssl/SSLEngine/EngineCloseOnAlert.java 8298868 generic-all javax/net/ssl/SSLEngine/ConnectionTest.java 8298869 generic-all javax/net/ssl/SSLEngine/CheckStatus.java 8298872 generic-all diff --git a/test/jdk/javax/net/ssl/SSLEngine/HandshakeWithInvalidRecordVersion.java b/test/jdk/javax/net/ssl/SSLEngine/HandshakeWithInvalidRecordVersion.java new file mode 100644 index 00000000000..4c6949d10c2 --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLEngine/HandshakeWithInvalidRecordVersion.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2014, 2023 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8042449 8299870 + * @library /javax/net/ssl/templates + * @summary Verify successful handshake ignores invalid record version + * + * @run main/timeout=300 HandshakeWithInvalidRecordVersion + */ + +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.*; +import java.io.*; +import java.security.*; +import java.nio.*; +import java.util.Arrays; + +public class HandshakeWithInvalidRecordVersion implements SSLContextTemplate { + private static final boolean DEBUG = Boolean.getBoolean("test.debug"); + + private static final String PATH_TO_STORES = "../etc"; + private static final String KEYSTORE_FILE = "keystore"; + private static final String TRUSTSTORE_FILE = "truststore"; + + private static final String KEYSTORE_PATH = + System.getProperty("test.src", "./") + "/" + PATH_TO_STORES + + "/" + KEYSTORE_FILE; + private static final String TRUSTSTORE_PATH = + System.getProperty("test.src", "./") + "/" + PATH_TO_STORES + + "/" + TRUSTSTORE_FILE; + + public static void main(String [] args) throws Exception { + var runner = new HandshakeWithInvalidRecordVersion(); + runner.executeTest("TLSv1.2", + new String[]{"TLSv1.2"}, new String[]{"TLSv1.3", "TLSv1.2"}); + + runner.executeTest("TLSv1.2", + new String[]{"TLSv1.3", "TLSv1.2"}, new String[]{"TLSv1.2"}); + + runner.executeTest("TLSv1.3", + new String[]{"TLSv1.2", "TLSv1.3"}, new String[]{"TLSv1.3"}); + + runner.executeTest("TLSv1.3", + new String[]{"TLSv1.3"}, new String[]{"TLSv1.2", "TLSv1.3"}); + } + + + private void executeTest(String expectedProtocol, String[] clientProtocols, + String[] serverProtocols) throws Exception { + System.out.printf("Executing test%n" + + "Client protocols: %s%nServer protocols: %s%nExpected negotiated: %s%n", + Arrays.toString(clientProtocols), Arrays.toString(serverProtocols), + expectedProtocol); + + SSLEngine cliEngine = createClientSSLContext().createSSLEngine(); + cliEngine.setUseClientMode(true); + cliEngine.setEnabledProtocols(clientProtocols); + SSLEngine srvEngine = createServerSSLContext().createSSLEngine(); + srvEngine.setUseClientMode(false); + srvEngine.setEnabledProtocols(serverProtocols); + + SSLSession session = cliEngine.getSession(); + int netBufferMax = session.getPacketBufferSize(); + int appBufferMax = session.getApplicationBufferSize(); + + ByteBuffer cliToSrv = ByteBuffer.allocateDirect(netBufferMax); + ByteBuffer srvIBuff = ByteBuffer.allocateDirect(appBufferMax + 50); + ByteBuffer cliOBuff = ByteBuffer.wrap("I'm client".getBytes()); + + + System.out.println("Generating ClientHello"); + SSLEngineResult cliRes = cliEngine.wrap(cliOBuff, cliToSrv); + checkResult(cliRes, HandshakeStatus.NEED_UNWRAP); + log("Client wrap result: " + cliRes); + cliToSrv.flip(); + if (cliToSrv.limit() > 5) { + System.out.println("Setting record version to (0xa9, 0xa2)"); + cliToSrv.put(1, (byte)0xa9); + cliToSrv.put(2, (byte)0xa2); + } else { + throw new RuntimeException("ClientHello message is only " + + cliToSrv.limit() + "bytes. Expecting at least 6 bytes. "); + } + + System.out.println("Processing ClientHello"); + SSLEngineResult srv = srvEngine.unwrap(cliToSrv, srvIBuff); + checkResult(srv, HandshakeStatus.NEED_TASK); + runDelegatedTasks(srvEngine); + + finishHandshake(cliEngine, srvEngine); + + if (!cliEngine.getSession().getProtocol() + .equals(srvEngine.getSession().getProtocol()) + || !cliEngine.getSession().getProtocol().equals(expectedProtocol)) { + throw new RuntimeException("Client and server did not negotiate protocol. " + + "Expected: " + expectedProtocol + ". Negotiated: " + + cliEngine.getSession().getProtocol()); + } + } + private boolean isHandshaking(SSLEngine e) { + return (e.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING); + } + + private void finishHandshake(SSLEngine client, SSLEngine server) throws Exception { + boolean clientDone = false; + boolean serverDone = false; + SSLEngineResult serverResult; + SSLEngineResult clientResult; + int capacity = client.getSession().getPacketBufferSize(); + ByteBuffer emptyBuffer = ByteBuffer.allocate(capacity); + ByteBuffer serverToClient = ByteBuffer.allocate(capacity); + ByteBuffer clientToServer = ByteBuffer.allocate(capacity); + + System.out.println("Finishing handshake..."); + while (isHandshaking(client) || + isHandshaking(server)) { + + log("================"); + + clientResult = client.wrap(emptyBuffer, clientToServer); + serverResult = server.wrap(emptyBuffer, serverToClient); + + if (clientResult.getHandshakeStatus() == HandshakeStatus.FINISHED) { + clientDone = true; + } + + if (serverResult.getHandshakeStatus() == HandshakeStatus.FINISHED) { + serverDone = true; + } + + log("wrap1 = " + clientResult); + log("wrap2 = " + serverResult); + + if (clientResult.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = client.getDelegatedTask()) != null) { + runnable.run(); + } + } + + if (serverResult.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = server.getDelegatedTask()) != null) { + runnable.run(); + } + } + + clientToServer.flip(); + serverToClient.flip(); + + log("----"); + + clientResult = client.unwrap(serverToClient, emptyBuffer); + serverResult = server.unwrap(clientToServer, emptyBuffer); + + if (clientResult.getHandshakeStatus() == HandshakeStatus.FINISHED) { + clientDone = true; + } + + if (serverResult.getHandshakeStatus() == HandshakeStatus.FINISHED) { + serverDone = true; + } + + log("unwrap1 = " + clientResult); + log("unwrap2 = " + serverResult); + + if (clientResult.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = client.getDelegatedTask()) != null) { + runnable.run(); + } + } + + if (serverResult.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = server.getDelegatedTask()) != null) { + runnable.run(); + } + } + + clientToServer.clear(); + serverToClient.clear(); + } + + System.out.println("Handshake complete"); + + if (!clientDone || !serverDone) { + throw new RuntimeException("Both should be true:\n" + + " clientDone = " + clientDone + " serverDone = " + serverDone); + } + } + + private static void runDelegatedTasks(SSLEngine engine) { + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + log("\trunning delegated task..."); + runnable.run(); + } + } + + private static void checkResult(SSLEngineResult result, HandshakeStatus expectedStatus) { + if(result.getHandshakeStatus() != expectedStatus) { + throw new RuntimeException(String.format( + "Handshake status %s does not match expected status of %s", + result.getHandshakeStatus(), expectedStatus)); + } + } + + private static void log(Object msg) { + if (DEBUG) { + System.out.println(msg); + } + } +} \ No newline at end of file diff --git a/test/jdk/javax/net/ssl/SSLEngine/IllegalRecordVersion.java b/test/jdk/javax/net/ssl/SSLEngine/IllegalRecordVersion.java deleted file mode 100644 index cab26528790..00000000000 --- a/test/jdk/javax/net/ssl/SSLEngine/IllegalRecordVersion.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -// This test case relies on updated static security property, no way to re-use -// security property in samevm/agentvm mode. - -/* - * @test - * @bug 8042449 - * @summary Issue for negative byte major record version - * - * @run main/othervm IllegalRecordVersion - */ - -import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.*; -import java.io.*; -import java.security.*; -import java.nio.*; - -public class IllegalRecordVersion { - - public static void main(String args[]) throws Exception { - SSLContext context = SSLContext.getDefault(); - - SSLEngine cliEngine = context.createSSLEngine(); - cliEngine.setUseClientMode(true); - SSLEngine srvEngine = context.createSSLEngine(); - srvEngine.setUseClientMode(false); - - SSLSession session = cliEngine.getSession(); - int netBufferMax = session.getPacketBufferSize(); - int appBufferMax = session.getApplicationBufferSize(); - - ByteBuffer cliToSrv = ByteBuffer.allocateDirect(netBufferMax); - ByteBuffer srvIBuff = ByteBuffer.allocateDirect(appBufferMax + 50); - ByteBuffer cliOBuff = ByteBuffer.wrap("I'm client".getBytes()); - - - System.out.println("client hello (record version(0xa9, 0xa2))"); - SSLEngineResult cliRes = cliEngine.wrap(cliOBuff, cliToSrv); - System.out.println("Client wrap result: " + cliRes); - cliToSrv.flip(); - if (cliToSrv.limit() > 5) { - cliToSrv.put(1, (byte)0xa9); - cliToSrv.put(2, (byte)0xa2); - } - - try { - srvEngine.unwrap(cliToSrv, srvIBuff); - throw new Exception( - "Cannot catch the unsupported record version issue"); - } catch (SSLException e) { - // get the expected exception - } - } -}