Path: blob/master/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java
41152 views
/*1* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223// SunJSSE does not support dynamic system properties, no way to re-use24// system properties in samevm/agentvm mode.2526/*27* @test28* @bug 8051498 8145849 817028229* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension30* @compile MyX509ExtendedKeyManager.java31*32* @run main/othervm SSLSocketAlpnTest h2 UNUSED h2 h233* @run main/othervm SSLSocketAlpnTest h2 UNUSED h2,http/1.1 h234* @run main/othervm SSLSocketAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h235* @run main/othervm SSLSocketAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.136* @run main/othervm SSLSocketAlpnTest h4,h3,h2 UNUSED h1,h2 h237* @run main/othervm SSLSocketAlpnTest EMPTY UNUSED h2,http/1.1 NONE38* @run main/othervm SSLSocketAlpnTest h2 UNUSED EMPTY NONE39* @run main/othervm SSLSocketAlpnTest H2 UNUSED h2 ERROR40* @run main/othervm SSLSocketAlpnTest h2 UNUSED http/1.1 ERROR41*42* @run main/othervm SSLSocketAlpnTest UNUSED h2 h2 h243* @run main/othervm SSLSocketAlpnTest UNUSED h2 h2,http/1.1 h244* @run main/othervm SSLSocketAlpnTest UNUSED h2 http/1.1,h2 h245* @run main/othervm SSLSocketAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.146* @run main/othervm SSLSocketAlpnTest UNUSED EMPTY h2,http/1.1 NONE47* @run main/othervm SSLSocketAlpnTest UNUSED h2 EMPTY NONE48* @run main/othervm SSLSocketAlpnTest UNUSED H2 h2 ERROR49* @run main/othervm SSLSocketAlpnTest UNUSED h2 http/1.1 ERROR50*51* @run main/othervm SSLSocketAlpnTest h2 h2 h2 h252* @run main/othervm SSLSocketAlpnTest H2 h2 h2,http/1.1 h253* @run main/othervm SSLSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.154* @run main/othervm SSLSocketAlpnTest http/1.1,h2 h2 h2,http/1.1 h255* @run main/othervm SSLSocketAlpnTest EMPTY h2 h2 h256* @run main/othervm SSLSocketAlpnTest h2,http/1.1 EMPTY http/1.1 NONE57* @run main/othervm SSLSocketAlpnTest h2,http/1.1 h2 EMPTY NONE58* @run main/othervm SSLSocketAlpnTest UNUSED UNUSED http/1.1,h2 NONE59* @run main/othervm SSLSocketAlpnTest h2 h2 http/1.1 ERROR60* @run main/othervm SSLSocketAlpnTest h2,http/1.1 H2 http/1.1 ERROR61*62* @author Brad Wetmore63*/64/**65* A simple SSLSocket-based client/server that demonstrates the proposed API66* changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).67*68* Usage:69* java SSLSocketAlpnTest <server-APs> <callback-AP> <client-APs> <result>70*71* where:72* EMPTY indicates that ALPN is disabled73* UNUSED indicates that no ALPN values are supplied (server-side only)74* ERROR indicates that an exception is expected75* NONE indicates that no ALPN is expected76*77* This example is based on our standard SSLSocketTemplate.78*/79import java.io.*;80import java.security.KeyStore;81import java.util.Arrays;8283import javax.net.ssl.*;8485public class SSLSocketAlpnTest {8687/*88* =============================================================89* Set the various variables needed for the tests, then90* specify what tests to run on each side.91*/9293/*94* Should we run the client or server in a separate thread?95* Both sides can throw exceptions, but do you have a preference96* as to which side should be the main thread.97*/98static boolean separateServerThread = false;99100/*101* Where do we find the keystores?102*/103static String pathToStores = "../etc";104static String keyStoreFile = "keystore";105static String trustStoreFile = "truststore";106static String passwd = "passphrase";107108static String keyFilename = System.getProperty("test.src", ".") + "/"109+ pathToStores + "/" + keyStoreFile;110static String trustFilename = System.getProperty("test.src", ".") + "/"111+ pathToStores + "/" + trustStoreFile;112113private static boolean hasServerAPs; // whether server APs are present114private static boolean hasCallback; // whether a callback is present115116/*117* SSLContext118*/119SSLContext mySSLContext = null;120121/*122* Is the server ready to serve?123*/124volatile static boolean serverReady = false;125126/*127* Turn on SSL debugging?128*/129static boolean debug = false;130131static String[] serverAPs;132static String callbackAP;133static String[] clientAPs;134static String expectedAP;135136/*137* If the client or server is doing some kind of object creation138* that the other side depends on, and that thread prematurely139* exits, you may experience a hang. The test harness will140* terminate all hung threads after its timeout has expired,141* currently 3 minutes by default, but you might try to be142* smart about it....143*/144145/*146* Define the server side of the test.147*148* If the server prematurely exits, serverReady will be set to true149* to avoid infinite hangs.150*/151void doServerSide() throws Exception {152SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory();153SSLServerSocket sslServerSocket154= (SSLServerSocket) sslssf.createServerSocket(serverPort);155// for both client/server to call into X509KM156sslServerSocket.setNeedClientAuth(true);157158serverPort = sslServerSocket.getLocalPort();159160/*161* Signal Client, we're ready for his connect.162*/163serverReady = true;164165SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();166167SSLParameters sslp = sslSocket.getSSLParameters();168169/*170* The default ciphersuite ordering from the SSLContext may not171* reflect "h2" ciphersuites as being preferred, additionally the172* client may not send them in an appropriate order. We could resort173* the suite list if so desired.174*/175String[] suites = sslp.getCipherSuites();176sslp.setCipherSuites(suites);177sslp.setUseCipherSuitesOrder(true); // Set server side order178179// Set the ALPN selection.180if (serverAPs != null) {181sslp.setApplicationProtocols(serverAPs);182}183sslSocket.setSSLParameters(sslp);184185if (sslSocket.getHandshakeApplicationProtocol() != null) {186throw new Exception ("getHandshakeApplicationProtocol() should "187+ "return null before the handshake starts");188}189190// check that no callback has been registered191if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {192throw new Exception("getHandshakeApplicationProtocolSelector() " +193"should return null");194}195196if (hasCallback) {197sslSocket.setHandshakeApplicationProtocolSelector(198(serverSocket, clientProtocols) -> {199return callbackAP.equals("EMPTY") ? "" : callbackAP;200});201202// check that the callback can be retrieved203if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {204throw new Exception("getHandshakeApplicationProtocolSelector()" + " should return non-null");205}206}207208sslSocket.startHandshake();209210if (sslSocket.getHandshakeApplicationProtocol() != null) {211throw new Exception ("getHandshakeApplicationProtocol() should "212+ "return null after the handshake is completed");213}214215String ap = sslSocket.getApplicationProtocol();216System.out.println("Application Protocol: \"" + ap + "\"");217218if (ap == null) {219throw new Exception(220"Handshake was completed but null was received");221}222if (expectedAP.equals("NONE")) {223if (!ap.isEmpty()) {224throw new Exception("Expected no ALPN value");225} else {226System.out.println("No ALPN value negotiated, as expected");227}228} else if (!expectedAP.equals(ap)) {229throw new Exception(expectedAP230+ " ALPN value not available on negotiated connection");231}232233InputStream sslIS = sslSocket.getInputStream();234OutputStream sslOS = sslSocket.getOutputStream();235236sslIS.read();237sslOS.write(85);238sslOS.flush();239240sslSocket.close();241}242243/*244* Define the client side of the test.245*246* If the server prematurely exits, serverReady will be set to true247* to avoid infinite hangs.248*/249void doClientSide() throws Exception {250251/*252* Wait for server to get started.253*/254while (!serverReady) {255Thread.sleep(50);256}257258SSLSocketFactory sslsf = mySSLContext.getSocketFactory();259SSLSocket sslSocket260= (SSLSocket) sslsf.createSocket("localhost", serverPort);261262SSLParameters sslp = sslSocket.getSSLParameters();263264/*265* The default ciphersuite ordering from the SSLContext may not266* reflect "h2" ciphersuites as being preferred, additionally the267* client may not send them in an appropriate order. We could resort268* the suite list if so desired.269*/270String[] suites = sslp.getCipherSuites();271sslp.setCipherSuites(suites);272sslp.setUseCipherSuitesOrder(true); // Set server side order273274// Set the ALPN selection.275sslp.setApplicationProtocols(clientAPs);276sslSocket.setSSLParameters(sslp);277278if (sslSocket.getHandshakeApplicationProtocol() != null) {279throw new Exception ("getHandshakeApplicationProtocol() should "280+ "return null before the handshake starts");281}282283sslSocket.startHandshake();284285if (sslSocket.getHandshakeApplicationProtocol() != null) {286throw new Exception ("getHandshakeApplicationProtocol() should "287+ "return null after the handshake is completed");288}289290/*291* Check that the resulting connection meets our defined ALPN292* criteria. If we were connecting to a non-JSSE implementation,293* the server might have negotiated something we shouldn't accept.294*/295String ap = sslSocket.getApplicationProtocol();296System.out.println("Application Protocol: \"" + ap + "\"");297298if (ap == null) {299throw new Exception(300"Handshake was completed but null was received");301}302if (expectedAP.equals("NONE")) {303if (!ap.isEmpty()) {304throw new Exception("Expected no ALPN value");305} else {306System.out.println("No ALPN value negotiated, as expected");307}308} else if (!expectedAP.equals(ap)) {309throw new Exception(expectedAP310+ " ALPN value not available on negotiated connection");311}312313InputStream sslIS = sslSocket.getInputStream();314OutputStream sslOS = sslSocket.getOutputStream();315316sslOS.write(280);317sslOS.flush();318sslIS.read();319320sslSocket.close();321}322323/*324* =============================================================325* The remainder is just support stuff326*/327// use any free port by default328volatile int serverPort = 0;329330volatile Exception serverException = null;331volatile Exception clientException = null;332333public static void main(String[] args) throws Exception {334335if (debug) {336System.setProperty("javax.net.debug", "all");337}338System.out.println("Test args: " + Arrays.toString(args));339340// Validate parameters341if (args.length != 4) {342throw new Exception("Invalid number of test parameters");343}344serverAPs = convert(args[0]);345callbackAP = args[1];346clientAPs = convert(args[2]);347expectedAP = args[3];348349hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?350hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?351352/*353* Start the tests.354*/355try {356new SSLSocketAlpnTest();357} catch (SSLHandshakeException she) {358if (args[3].equals("ERROR")) {359System.out.println("Caught the expected exception: " + she);360} else {361throw she;362}363}364365System.out.println("Test Passed.");366}367368SSLContext getSSLContext(String keyFilename, String trustFilename)369throws Exception {370SSLContext ctx = SSLContext.getInstance("TLS");371372// Keystores373KeyStore keyKS = KeyStore.getInstance("JKS");374keyKS.load(new FileInputStream(keyFilename), passwd.toCharArray());375376KeyStore trustKS = KeyStore.getInstance("JKS");377trustKS.load(new FileInputStream(trustFilename), passwd.toCharArray());378379// Generate KeyManager and TrustManager380KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");381kmf.init(keyKS, passwd.toCharArray());382383KeyManager[] kms = kmf.getKeyManagers();384if (!(kms[0] instanceof X509ExtendedKeyManager)) {385throw new Exception("kms[0] not X509ExtendedKeyManager");386}387388kms = new KeyManager[] { new MyX509ExtendedKeyManager(389(X509ExtendedKeyManager) kms[0], expectedAP,390!hasCallback && hasServerAPs) };391392TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");393tmf.init(trustKS);394TrustManager[] tms = tmf.getTrustManagers();395396// initial SSLContext397ctx.init(kms, tms, null);398399return ctx;400}401402/*403* Convert a comma-separated list into an array of strings.404*/405private static String[] convert(String list) {406if (list.equals("UNUSED")) {407return null;408}409410if (list.equals("EMPTY")) {411return new String[0];412}413414String[] strings;415if (list.indexOf(',') > 0) {416strings = list.split(",");417} else {418strings = new String[]{ list };419}420421return strings;422}423424Thread clientThread = null;425Thread serverThread = null;426427/*428* Primary constructor, used to drive remainder of the test.429*430* Fork off the other side, then do your work.431*/432SSLSocketAlpnTest() throws Exception {433Exception startException = null;434mySSLContext = getSSLContext(keyFilename, trustFilename);435try {436if (separateServerThread) {437startServer(true);438startClient(false);439} else {440startClient(true);441startServer(false);442}443} catch (Exception e) {444startException = e;445}446447/*448* Wait for other side to close down.449*/450if (separateServerThread) {451if (serverThread != null) {452serverThread.join();453}454} else {455if (clientThread != null) {456clientThread.join();457}458}459460/*461* When we get here, the test is pretty much over.462* Which side threw the error?463*/464Exception local;465Exception remote;466467if (separateServerThread) {468remote = serverException;469local = clientException;470} else {471remote = clientException;472local = serverException;473}474475Exception exception = null;476477/*478* Check various exception conditions.479*/480if ((local != null) && (remote != null)) {481// If both failed, return the curthread's exception.482local.initCause(remote);483exception = local;484} else if (local != null) {485exception = local;486} else if (remote != null) {487exception = remote;488} else if (startException != null) {489exception = startException;490}491492/*493* If there was an exception *AND* a startException,494* output it.495*/496if (exception != null) {497if (exception != startException && startException != null) {498exception.addSuppressed(startException);499}500throw exception;501}502503// Fall-through: no exception to throw!504}505506void startServer(boolean newThread) throws Exception {507if (newThread) {508serverThread = new Thread() {509@Override510public void run() {511try {512doServerSide();513} catch (Exception e) {514/*515* Our server thread just died.516*517* Release the client, if not active already...518*/519System.err.println("Server died...");520serverReady = true;521serverException = e;522}523}524};525serverThread.start();526} else {527try {528doServerSide();529} catch (Exception e) {530serverException = e;531} finally {532serverReady = true;533}534}535}536537void startClient(boolean newThread) throws Exception {538if (newThread) {539clientThread = new Thread() {540@Override541public void run() {542try {543doClientSide();544} catch (Exception e) {545/*546* Our client thread just died.547*/548System.err.println("Client died...");549clientException = e;550}551}552};553clientThread.start();554} else {555try {556doClientSide();557} catch (Exception e) {558clientException = e;559}560}561}562}563564565