/* * Copyright (c) 2001, 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. */ // SunJSSE does not support dynamic system properties, no way to re-use // system properties in samevm/agentvm mode. /* * @test * @bug 8051498 8145849 8170282 * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension * @library /javax/net/ssl/templates * * @run main/othervm SSLSocketAlpnTest h2 UNUSED h2 h2 * @run main/othervm SSLSocketAlpnTest h2 UNUSED h2,http/1.1 h2 * @run main/othervm SSLSocketAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h2 * @run main/othervm SSLSocketAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.1 * @run main/othervm SSLSocketAlpnTest h4,h3,h2 UNUSED h1,h2 h2 * @run main/othervm SSLSocketAlpnTest EMPTY UNUSED h2,http/1.1 NONE * @run main/othervm SSLSocketAlpnTest h2 UNUSED EMPTY NONE * @run main/othervm SSLSocketAlpnTest H2 UNUSED h2 ERROR * @run main/othervm SSLSocketAlpnTest h2 UNUSED http/1.1 ERROR * * @run main/othervm SSLSocketAlpnTest UNUSED h2 h2 h2 * @run main/othervm SSLSocketAlpnTest UNUSED h2 h2,http/1.1 h2 * @run main/othervm SSLSocketAlpnTest UNUSED h2 http/1.1,h2 h2 * @run main/othervm SSLSocketAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.1 * @run main/othervm SSLSocketAlpnTest UNUSED EMPTY h2,http/1.1 NONE * @run main/othervm SSLSocketAlpnTest UNUSED h2 EMPTY NONE * @run main/othervm SSLSocketAlpnTest UNUSED H2 h2 ERROR * @run main/othervm SSLSocketAlpnTest UNUSED h2 http/1.1 ERROR * * @run main/othervm SSLSocketAlpnTest h2 h2 h2 h2 * @run main/othervm SSLSocketAlpnTest H2 h2 h2,http/1.1 h2 * @run main/othervm SSLSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1 * @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2 h2,http/1.1 h2 * @run main/othervm SSLSocketAlpnTest EMPTY h2 h2 h2 * @run main/othervm SSLSocketAlpnTest h2,http/1.1 EMPTY http/1.1 NONE * @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2 EMPTY NONE * @run main/othervm SSLSocketAlpnTest UNUSED UNUSED http/1.1,h2 NONE * @run main/othervm SSLSocketAlpnTest h2 h2 http/1.1 ERROR * @run main/othervm SSLSocketAlpnTest h2,http/1.1 H2 http/1.1 ERROR * * @author Brad Wetmore */ /** * A simple SSLSocket-based client/server that demonstrates the proposed API * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301). * * Usage: * java SSLSocketAlpnTest * * where: * EMPTY indicates that ALPN is disabled * UNUSED indicates that no ALPN values are supplied (server-side only) * ERROR indicates that an exception is expected * NONE indicates that no ALPN is expected * * This example is based on our standard SSLSocketTemplate. */ import java.io.*; import java.util.Arrays; import javax.net.ssl.*; public class SSLSocketAlpnTest extends SSLSocketTemplate { private static boolean hasCallback; // whether a callback is present /* * Turn on SSL debugging? */ static boolean debug = Boolean.getBoolean("test.debug"); static String[] serverAPs; static String callbackAP; static String[] clientAPs; static String expectedAP; /* * If the client or server is doing some kind of object creation * that the other side depends on, and that thread prematurely * exits, you may experience a hang. The test harness will * terminate all hung threads after its timeout has expired, * currently 3 minutes by default, but you might try to be * smart about it.... */ @Override protected void configureServerSocket(SSLServerSocket socket) { socket.setNeedClientAuth(true); } /* * Define the server side of the test. * * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ @Override protected void runServerApplication(SSLSocket sslSocket) throws Exception { System.out.println("in runServerApplication(SSLSocket)"); SSLParameters sslp = sslSocket.getSSLParameters(); /* * The default ciphersuite ordering from the SSLContext may not * reflect "h2" ciphersuites as being preferred, additionally the * client may not send them in an appropriate order. We could resort * the suite list if so desired. */ String[] suites = sslp.getCipherSuites(); sslp.setCipherSuites(suites); sslp.setUseCipherSuitesOrder(true); // Set server side order // Set the ALPN selection. if (serverAPs != null) { sslp.setApplicationProtocols(serverAPs); } sslSocket.setSSLParameters(sslp); if (sslSocket.getHandshakeApplicationProtocol() != null) { throw new Exception ("getHandshakeApplicationProtocol() should " + "return null before the handshake starts"); } // check that no callback has been registered if (sslSocket.getHandshakeApplicationProtocolSelector() != null) { throw new Exception("getHandshakeApplicationProtocolSelector() " + "should return null"); } if (hasCallback) { sslSocket.setHandshakeApplicationProtocolSelector( (serverSocket, clientProtocols) -> { return callbackAP.equals("EMPTY") ? "" : callbackAP; }); // check that the callback can be retrieved if (sslSocket.getHandshakeApplicationProtocolSelector() == null) { throw new Exception("getHandshakeApplicationProtocolSelector()" + " should return non-null"); } } System.out.println("server starting handshake"); sslSocket.startHandshake(); if (sslSocket.getHandshakeApplicationProtocol() != null) { throw new Exception ("getHandshakeApplicationProtocol() should " + "return null after the handshake is completed"); } String ap = sslSocket.getApplicationProtocol(); System.out.println("Application Protocol: \"" + ap + "\""); if (ap == null) { throw new Exception( "Handshake was completed but null was received"); } if (expectedAP.equals("NONE")) { if (!ap.isEmpty()) { throw new Exception("Expected no ALPN value"); } else { System.out.println("No ALPN value negotiated, as expected"); } } else if (!expectedAP.equals(ap)) { throw new Exception(expectedAP + " ALPN value not available on negotiated connection"); } InputStream sslIS = sslSocket.getInputStream(); OutputStream sslOS = sslSocket.getOutputStream(); sslIS.read(); sslOS.write(85); sslOS.flush(); sslSocket.close(); } /* * Define the client side of the test. * * If the server prematurely exits, serverReady will be set to true * to avoid infinite hangs. */ @Override protected void runClientApplication(SSLSocket sslSocket) throws Exception { System.out.println("in runClientApplication(SSLSocket)"); SSLParameters sslp = sslSocket.getSSLParameters(); /* * The default ciphersuite ordering from the SSLContext may not * reflect "h2" ciphersuites as being preferred, additionally the * client may not send them in an appropriate order. We could resort * the suite list if so desired. */ String[] suites = sslp.getCipherSuites(); sslp.setCipherSuites(suites); sslp.setUseCipherSuitesOrder(true); // Set server side order // Set the ALPN selection. sslp.setApplicationProtocols(clientAPs); sslSocket.setSSLParameters(sslp); if (sslSocket.getHandshakeApplicationProtocol() != null) { throw new Exception ("getHandshakeApplicationProtocol() should " + "return null before the handshake starts"); } System.out.println("Client starting handshake"); sslSocket.startHandshake(); if (sslSocket.getHandshakeApplicationProtocol() != null) { throw new Exception ("getHandshakeApplicationProtocol() should " + "return null after the handshake is completed"); } /* * Check that the resulting connection meets our defined ALPN * criteria. If we were connecting to a non-JSSE implementation, * the server might have negotiated something we shouldn't accept. */ String ap = sslSocket.getApplicationProtocol(); System.out.println("Application Protocol: \"" + ap + "\""); if (ap == null) { throw new Exception( "Handshake was completed but null was received"); } if (expectedAP.equals("NONE")) { if (!ap.isEmpty()) { throw new Exception("Expected no ALPN value"); } else { System.out.println("No ALPN value negotiated, as expected"); } } else if (!expectedAP.equals(ap)) { throw new Exception(expectedAP + " ALPN value not available on negotiated connection"); } InputStream sslIS = sslSocket.getInputStream(); OutputStream sslOS = sslSocket.getOutputStream(); sslOS.write(280); sslOS.flush(); sslIS.read(); sslSocket.close(); } public static void main(String[] args) throws Exception { if (debug) { System.setProperty("javax.net.debug", "all"); } System.out.println("Test args: " + Arrays.toString(args)); // Validate parameters if (args.length != 4) { throw new Exception("Invalid number of test parameters"); } serverAPs = convert(args[0]); callbackAP = args[1]; clientAPs = convert(args[2]); expectedAP = args[3]; hasCallback = !callbackAP.equals("UNUSED"); // is callback being used? /* * Start the tests. */ try { new SSLSocketAlpnTest().run(); } catch (SSLHandshakeException she) { if (args[3].equals("ERROR")) { System.out.println("Caught the expected exception: " + she); } else { throw she; } } System.out.println("Test Passed."); } /* * Convert a comma-separated list into an array of strings. */ private static String[] convert(String list) { if (list.equals("UNUSED")) { return null; } if (list.equals("EMPTY")) { return new String[0]; } String[] strings; if (list.indexOf(',') > 0) { strings = list.split(","); } else { strings = new String[]{ list }; } return strings; } }