Path: blob/master/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.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 8158978 817028229* @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension30* @compile MyX509ExtendedKeyManager.java31*32* @run main/othervm SSLServerSocketAlpnTest h2 UNUSED h2 h233* @run main/othervm SSLServerSocketAlpnTest h2 UNUSED h2,http/1.1 h234* @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 UNUSED h2,http/1.1 h235* @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 UNUSED h2,http/1.1 http/1.136* @run main/othervm SSLServerSocketAlpnTest h4,h3,h2 UNUSED h1,h2 h237* @run main/othervm SSLServerSocketAlpnTest EMPTY UNUSED h2,http/1.1 NONE38* @run main/othervm SSLServerSocketAlpnTest h2 UNUSED EMPTY NONE39* @run main/othervm SSLServerSocketAlpnTest H2 UNUSED h2 ERROR40* @run main/othervm SSLServerSocketAlpnTest h2 UNUSED http/1.1 ERROR41*42* @run main/othervm SSLServerSocketAlpnTest UNUSED h2 h2 h243* @run main/othervm SSLServerSocketAlpnTest UNUSED h2 h2,http/1.1 h244* @run main/othervm SSLServerSocketAlpnTest UNUSED h2 http/1.1,h2 h245* @run main/othervm SSLServerSocketAlpnTest UNUSED http/1.1 h2,http/1.1 http/1.146* @run main/othervm SSLServerSocketAlpnTest UNUSED EMPTY h2,http/1.1 NONE47* @run main/othervm SSLServerSocketAlpnTest UNUSED h2 EMPTY NONE48* @run main/othervm SSLServerSocketAlpnTest UNUSED H2 h2 ERROR49* @run main/othervm SSLServerSocketAlpnTest UNUSED h2 http/1.1 ERROR50*51* @run main/othervm SSLServerSocketAlpnTest h2 h2 h2 h252* @run main/othervm SSLServerSocketAlpnTest H2 h2 h2,http/1.1 h253* @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.154* @run main/othervm SSLServerSocketAlpnTest http/1.1,h2 h2 h2,http/1.1 h255* @run main/othervm SSLServerSocketAlpnTest EMPTY h2 h2 h256* @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 EMPTY http/1.1 NONE57* @run main/othervm SSLServerSocketAlpnTest h2,http/1.1 h2 EMPTY NONE58* @run main/othervm SSLServerSocketAlpnTest UNUSED UNUSED http/1.1,h2 NONE59* @run main/othervm SSLServerSocketAlpnTest h2 h2 http/1.1 ERROR60* @run main/othervm SSLServerSocketAlpnTest 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 SSLServerSocketAlpnTest70* <server-APs> <callback-AP> <client-APs> <result>71*72* where:73* EMPTY indicates that ALPN is disabled74* UNUSED indicates that no ALPN values are supplied (server-side only)75* ERROR indicates that an exception is expected76* NONE indicates that no ALPN is expected77*78* This example is based on our standard SSLSocketTemplate.79*/80import java.io.*;81import java.security.KeyStore;82import java.util.Arrays;8384import javax.net.ssl.*;8586public class SSLServerSocketAlpnTest {8788/*89* =============================================================90* Set the various variables needed for the tests, then91* specify what tests to run on each side.92*/9394/*95* Should we run the client or server in a separate thread?96* Both sides can throw exceptions, but do you have a preference97* as to which side should be the main thread.98*/99static boolean separateServerThread = false;100101/*102* Where do we find the keystores?103*/104static String pathToStores = "../etc";105static String keyStoreFile = "keystore";106static String trustStoreFile = "truststore";107static String passwd = "passphrase";108109static String keyFilename = System.getProperty("test.src", ".") + "/"110+ pathToStores + "/" + keyStoreFile;111static String trustFilename = System.getProperty("test.src", ".") + "/"112+ pathToStores + "/" + trustStoreFile;113114private static boolean hasServerAPs; // whether server APs are present115private static boolean hasCallback; // whether a callback is present116117/*118* SSLContext119*/120SSLContext mySSLContext = null;121122/*123* Is the server ready to serve?124*/125volatile static boolean serverReady = false;126127/*128* Turn on SSL debugging?129*/130static boolean debug = false;131132static String[] serverAPs;133static String callbackAP;134static String[] clientAPs;135static String expectedAP;136137/*138* If the client or server is doing some kind of object creation139* that the other side depends on, and that thread prematurely140* exits, you may experience a hang. The test harness will141* terminate all hung threads after its timeout has expired,142* currently 3 minutes by default, but you might try to be143* smart about it....144*/145146/*147* Define the server side of the test.148*149* If the server prematurely exits, serverReady will be set to true150* to avoid infinite hangs.151*/152void doServerSide() throws Exception {153SSLServerSocketFactory sslssf = mySSLContext.getServerSocketFactory();154SSLServerSocket sslServerSocket155= (SSLServerSocket) sslssf.createServerSocket(serverPort);156sslServerSocket.setNeedClientAuth(true);157158SSLParameters sslp = sslServerSocket.getSSLParameters();159160// for both client/server to call into X509KM161sslp.setNeedClientAuth(true);162163/*164* The default ciphersuite ordering from the SSLContext may not165* reflect "h2" ciphersuites as being preferred, additionally the166* client may not send them in an appropriate order. We could resort167* the suite list if so desired.168*/169String[] suites = sslp.getCipherSuites();170sslp.setCipherSuites(suites);171sslp.setUseCipherSuitesOrder(true); // Set server side order172173// Set the ALPN selection.174if (serverAPs != null) {175sslp.setApplicationProtocols(serverAPs);176}177sslServerSocket.setSSLParameters(sslp);178179serverPort = sslServerSocket.getLocalPort();180181/*182* Signal Client, we're ready for his connect.183*/184serverReady = true;185186SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();187188if (sslSocket.getHandshakeApplicationProtocol() != null) {189throw new Exception ("getHandshakeApplicationProtocol() should "190+ "return null before the handshake starts");191}192193// check that no callback has been registered194if (sslSocket.getHandshakeApplicationProtocolSelector() != null) {195throw new Exception("getHandshakeApplicationProtocolSelector() " +196"should return null");197}198199if (hasCallback) {200sslSocket.setHandshakeApplicationProtocolSelector(201(serverSocket, clientProtocols) -> {202return callbackAP.equals("EMPTY") ? "" : callbackAP;203});204205// check that the callback can be retrieved206if (sslSocket.getHandshakeApplicationProtocolSelector() == null) {207throw new Exception("getHandshakeApplicationProtocolSelector()"208+ " should return non-null");209}210}211212sslSocket.startHandshake();213214if (sslSocket.getHandshakeApplicationProtocol() != null) {215throw new Exception ("getHandshakeApplicationProtocol() should "216+ "return null after the handshake is completed");217}218219String ap = sslSocket.getApplicationProtocol();220System.out.println("Application Protocol: \"" + ap + "\"");221222if (ap == null) {223throw new Exception(224"Handshake was completed but null was received");225}226if (expectedAP.equals("NONE")) {227if (!ap.isEmpty()) {228throw new Exception("Expected no ALPN value");229} else {230System.out.println("No ALPN value negotiated, as expected");231}232} else if (!expectedAP.equals(ap)) {233throw new Exception(expectedAP234+ " ALPN value not available on negotiated connection");235}236237InputStream sslIS = sslSocket.getInputStream();238OutputStream sslOS = sslSocket.getOutputStream();239240sslIS.read();241sslOS.write(85);242sslOS.flush();243244sslSocket.close();245}246247/*248* Define the client side of the test.249*250* If the server prematurely exits, serverReady will be set to true251* to avoid infinite hangs.252*/253void doClientSide() throws Exception {254255/*256* Wait for server to get started.257*/258while (!serverReady) {259Thread.sleep(50);260}261262SSLSocketFactory sslsf = mySSLContext.getSocketFactory();263SSLSocket sslSocket264= (SSLSocket) sslsf.createSocket("localhost", serverPort);265266SSLParameters sslp = sslSocket.getSSLParameters();267268/*269* The default ciphersuite ordering from the SSLContext may not270* reflect "h2" ciphersuites as being preferred, additionally the271* client may not send them in an appropriate order. We could resort272* the suite list if so desired.273*/274String[] suites = sslp.getCipherSuites();275sslp.setCipherSuites(suites);276sslp.setUseCipherSuitesOrder(true); // Set server side order277278// Set the ALPN selection.279sslp.setApplicationProtocols(clientAPs);280sslSocket.setSSLParameters(sslp);281282if (sslSocket.getHandshakeApplicationProtocol() != null) {283throw new Exception ("getHandshakeApplicationProtocol() should "284+ "return null before the handshake starts");285}286287sslSocket.startHandshake();288289if (sslSocket.getHandshakeApplicationProtocol() != null) {290throw new Exception ("getHandshakeApplicationProtocol() should "291+ "return null after the handshake is completed");292}293294/*295* Check that the resulting connection meets our defined ALPN296* criteria. If we were connecting to a non-JSSE implementation,297* the server might have negotiated something we shouldn't accept.298*/299String ap = sslSocket.getApplicationProtocol();300System.out.println("Application Protocol: \"" + ap + "\"");301302if (ap == null) {303throw new Exception(304"Handshake was completed but null was received");305}306if (expectedAP.equals("NONE")) {307if (!ap.isEmpty()) {308throw new Exception("Expected no ALPN value");309} else {310System.out.println("No ALPN value negotiated, as expected");311}312} else if (!expectedAP.equals(ap)) {313throw new Exception(expectedAP314+ " ALPN value not available on negotiated connection");315}316317InputStream sslIS = sslSocket.getInputStream();318OutputStream sslOS = sslSocket.getOutputStream();319320sslOS.write(280);321sslOS.flush();322sslIS.read();323324sslSocket.close();325}326327/*328* =============================================================329* The remainder is just support stuff330*/331// use any free port by default332volatile int serverPort = 0;333334volatile Exception serverException = null;335volatile Exception clientException = null;336337public static void main(String[] args) throws Exception {338339if (debug) {340System.setProperty("javax.net.debug", "all");341}342System.out.println("Test args: " + Arrays.toString(args));343344// Validate parameters345if (args.length != 4) {346throw new Exception("Invalid number of test parameters");347}348serverAPs = convert(args[0]);349callbackAP = args[1];350clientAPs = convert(args[2]);351expectedAP = args[3];352353hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?354hasCallback = !callbackAP.equals("UNUSED"); // is callback being used?355356/*357* Start the tests.358*/359try {360new SSLServerSocketAlpnTest();361} catch (SSLHandshakeException she) {362if (args[3].equals("ERROR")) {363System.out.println("Caught the expected exception: " + she);364} else {365throw she;366}367}368369System.out.println("Test Passed.");370}371372SSLContext getSSLContext(String keyFilename, String trustFilename)373throws Exception {374SSLContext ctx = SSLContext.getInstance("TLS");375376// Keystores377KeyStore keyKS = KeyStore.getInstance("JKS");378keyKS.load(new FileInputStream(keyFilename), passwd.toCharArray());379380KeyStore trustKS = KeyStore.getInstance("JKS");381trustKS.load(new FileInputStream(trustFilename), passwd.toCharArray());382383// Generate KeyManager and TrustManager384KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");385kmf.init(keyKS, passwd.toCharArray());386387KeyManager[] kms = kmf.getKeyManagers();388if (!(kms[0] instanceof X509ExtendedKeyManager)) {389throw new Exception("kms[0] not X509ExtendedKeyManager");390}391392kms = new KeyManager[] { new MyX509ExtendedKeyManager(393(X509ExtendedKeyManager) kms[0], expectedAP,394!hasCallback && hasServerAPs) };395396TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");397tmf.init(trustKS);398TrustManager[] tms = tmf.getTrustManagers();399400// initial SSLContext401ctx.init(kms, tms, null);402403return ctx;404}405406/*407* Convert a comma-separated list into an array of strings.408*/409private static String[] convert(String list) {410if (list.equals("UNUSED")) {411return null;412}413414if (list.equals("EMPTY")) {415return new String[0];416}417418String[] strings;419if (list.indexOf(',') > 0) {420strings = list.split(",");421} else {422strings = new String[]{ list };423}424425return strings;426}427428Thread clientThread = null;429Thread serverThread = null;430431/*432* Primary constructor, used to drive remainder of the test.433*434* Fork off the other side, then do your work.435*/436SSLServerSocketAlpnTest() throws Exception {437Exception startException = null;438mySSLContext = getSSLContext(keyFilename, trustFilename);439try {440if (separateServerThread) {441startServer(true);442startClient(false);443} else {444startClient(true);445startServer(false);446}447} catch (Exception e) {448startException = e;449}450451/*452* Wait for other side to close down.453*/454if (separateServerThread) {455if (serverThread != null) {456serverThread.join();457}458} else {459if (clientThread != null) {460clientThread.join();461}462}463464/*465* When we get here, the test is pretty much over.466* Which side threw the error?467*/468Exception local;469Exception remote;470471if (separateServerThread) {472remote = serverException;473local = clientException;474} else {475remote = clientException;476local = serverException;477}478479Exception exception = null;480481/*482* Check various exception conditions.483*/484if ((local != null) && (remote != null)) {485// If both failed, return the curthread's exception.486local.initCause(remote);487exception = local;488} else if (local != null) {489exception = local;490} else if (remote != null) {491exception = remote;492} else if (startException != null) {493exception = startException;494}495496/*497* If there was an exception *AND* a startException,498* output it.499*/500if (exception != null) {501if (exception != startException && startException != null) {502exception.addSuppressed(startException);503}504throw exception;505}506507// Fall-through: no exception to throw!508}509510void startServer(boolean newThread) throws Exception {511if (newThread) {512serverThread = new Thread() {513@Override514public void run() {515try {516doServerSide();517} catch (Exception e) {518/*519* Our server thread just died.520*521* Release the client, if not active already...522*/523System.err.println("Server died...");524serverReady = true;525serverException = e;526}527}528};529serverThread.start();530} else {531try {532doServerSide();533} catch (Exception e) {534serverException = e;535} finally {536serverReady = true;537}538}539}540541void startClient(boolean newThread) throws Exception {542if (newThread) {543clientThread = new Thread() {544@Override545public void run() {546try {547doClientSide();548} catch (Exception e) {549/*550* Our client thread just died.551*/552System.err.println("Client died...");553clientException = e;554}555}556};557clientThread.start();558} else {559try {560doClientSide();561} catch (Exception e) {562clientException = e;563}564}565}566}567568569