Path: blob/master/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithCliSNI.java
41152 views
/*1* Copyright (c) 2012, 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//24// SunJSSE does not support dynamic system properties, no way to re-use25// system properties in samevm/agentvm mode.26//2728/**29* @test30* @bug 706832131* @summary Support TLS Server Name Indication (SNI) Extension in JSSE Server32* @library ../templates33* @build SSLCapabilities SSLExplorer34* @run main/othervm SSLSocketExplorerWithCliSNI35*/3637import java.io.*;38import java.nio.*;39import java.nio.channels.*;40import java.util.*;41import java.net.*;42import javax.net.ssl.*;4344public class SSLSocketExplorerWithCliSNI {4546/*47* =============================================================48* Set the various variables needed for the tests, then49* specify what tests to run on each side.50*/5152/*53* Should we run the client or server in a separate thread?54* Both sides can throw exceptions, but do you have a preference55* as to which side should be the main thread.56*/57static boolean separateServerThread = true;5859/*60* Where do we find the keystores?61*/62static String pathToStores = "../etc";63static String keyStoreFile = "keystore";64static String trustStoreFile = "truststore";65static String passwd = "passphrase";6667/*68* Is the server ready to serve?69*/70volatile static boolean serverReady = false;7172/*73* Turn on SSL debugging?74*/75static boolean debug = false;7677/*78* If the client or server is doing some kind of object creation79* that the other side depends on, and that thread prematurely80* exits, you may experience a hang. The test harness will81* terminate all hung threads after its timeout has expired,82* currently 3 minutes by default, but you might try to be83* smart about it....84*/8586/*87* Define the server side of the test.88*89* If the server prematurely exits, serverReady will be set to true90* to avoid infinite hangs.91*/92void doServerSide() throws Exception {9394ServerSocket serverSocket = new ServerSocket(serverPort);9596// Signal Client, we're ready for his connect.97serverPort = serverSocket.getLocalPort();98serverReady = true;99100Socket socket = serverSocket.accept();101InputStream ins = socket.getInputStream();102103byte[] buffer = new byte[0xFF];104int position = 0;105SSLCapabilities capabilities = null;106107// Read the header of TLS record108while (position < SSLExplorer.RECORD_HEADER_SIZE) {109int count = SSLExplorer.RECORD_HEADER_SIZE - position;110int n = ins.read(buffer, position, count);111if (n < 0) {112throw new Exception("unexpected end of stream!");113}114position += n;115}116117int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position);118if (buffer.length < recordLength) {119buffer = Arrays.copyOf(buffer, recordLength);120}121122while (position < recordLength) {123int count = recordLength - position;124int n = ins.read(buffer, position, count);125if (n < 0) {126throw new Exception("unexpected end of stream!");127}128position += n;129}130131capabilities = SSLExplorer.explore(buffer, 0, recordLength);;132if (capabilities != null) {133System.out.println("Record version: " +134capabilities.getRecordVersion());135System.out.println("Hello version: " +136capabilities.getHelloVersion());137}138139SSLSocketFactory sslsf =140(SSLSocketFactory) SSLSocketFactory.getDefault();141ByteArrayInputStream bais =142new ByteArrayInputStream(buffer, 0, position);143SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(socket, bais, true);144145InputStream sslIS = sslSocket.getInputStream();146OutputStream sslOS = sslSocket.getOutputStream();147148sslIS.read();149sslOS.write(85);150sslOS.flush();151152ExtendedSSLSession session = (ExtendedSSLSession)sslSocket.getSession();153checkCapabilities(capabilities, session);154155sslSocket.close();156serverSocket.close();157}158159160/*161* Define the client side of the test.162*163* If the server prematurely exits, serverReady will be set to true164* to avoid infinite hangs.165*/166void doClientSide() throws Exception {167168/*169* Wait for server to get started.170*/171while (!serverReady) {172Thread.sleep(50);173}174175SSLSocketFactory sslsf =176(SSLSocketFactory) SSLSocketFactory.getDefault();177SSLSocket sslSocket = (SSLSocket)178sslsf.createSocket("localhost", serverPort);179180SNIHostName serverName = new SNIHostName(clientRequestedHostname);181List<SNIServerName> serverNames = new ArrayList<>(1);182serverNames.add(serverName);183SSLParameters params = sslSocket.getSSLParameters();184params.setServerNames(serverNames);185sslSocket.setSSLParameters(params);186187InputStream sslIS = sslSocket.getInputStream();188OutputStream sslOS = sslSocket.getOutputStream();189190sslOS.write(280);191sslOS.flush();192sslIS.read();193194ExtendedSSLSession session = (ExtendedSSLSession)sslSocket.getSession();195checkSNIInSession(session);196197sslSocket.close();198}199200private static String clientRequestedHostname = "www.example.com";201private static String serverAcceptableHostname =202"www\\.example\\.(com|org)";203204void checkCapabilities(SSLCapabilities capabilities,205ExtendedSSLSession session) throws Exception {206207List<SNIServerName> sessionSNI = session.getRequestedServerNames();208if (!sessionSNI.equals(capabilities.getServerNames())) {209for (SNIServerName sni : sessionSNI) {210System.out.println("SNI in session is " + sni);211}212213List<SNIServerName> capaSNI = capabilities.getServerNames();214for (SNIServerName sni : capaSNI) {215System.out.println("SNI in session is " + sni);216}217218throw new Exception(219"server name indication does not match capabilities");220}221222checkSNIInSession(session);223}224225void checkSNIInSession(ExtendedSSLSession session) throws Exception {226List<SNIServerName> sessionSNI = session.getRequestedServerNames();227if (sessionSNI.isEmpty()) {228throw new Exception(229"unexpected empty request server name indication");230}231232if (sessionSNI.size() != 1) {233throw new Exception(234"unexpected request server name indication");235}236237SNIServerName serverName = sessionSNI.get(0);238if (!(serverName instanceof SNIHostName)) {239throw new Exception(240"unexpected instance of request server name indication");241}242243String hostname = ((SNIHostName)serverName).getAsciiName();244if (!clientRequestedHostname.equalsIgnoreCase(hostname)) {245throw new Exception(246"unexpected request server name indication value");247}248}249250251/*252* =============================================================253* The remainder is just support stuff254*/255256// use any free port by default257volatile int serverPort = 0;258259volatile Exception serverException = null;260volatile Exception clientException = null;261262public static void main(String[] args) throws Exception {263String keyFilename =264System.getProperty("test.src", ".") + "/" + pathToStores +265"/" + keyStoreFile;266String trustFilename =267System.getProperty("test.src", ".") + "/" + pathToStores +268"/" + trustStoreFile;269270System.setProperty("javax.net.ssl.keyStore", keyFilename);271System.setProperty("javax.net.ssl.keyStorePassword", passwd);272System.setProperty("javax.net.ssl.trustStore", trustFilename);273System.setProperty("javax.net.ssl.trustStorePassword", passwd);274275if (debug)276System.setProperty("javax.net.debug", "all");277278/*279* Start the tests.280*/281new SSLSocketExplorerWithCliSNI();282}283284Thread clientThread = null;285Thread serverThread = null;286287/*288* Primary constructor, used to drive remainder of the test.289*290* Fork off the other side, then do your work.291*/292SSLSocketExplorerWithCliSNI() throws Exception {293try {294if (separateServerThread) {295startServer(true);296startClient(false);297} else {298startClient(true);299startServer(false);300}301} catch (Exception e) {302// swallow for now. Show later303}304305/*306* Wait for other side to close down.307*/308if (separateServerThread) {309serverThread.join();310} else {311clientThread.join();312}313314/*315* When we get here, the test is pretty much over.316* Which side threw the error?317*/318Exception local;319Exception remote;320String whichRemote;321322if (separateServerThread) {323remote = serverException;324local = clientException;325whichRemote = "server";326} else {327remote = clientException;328local = serverException;329whichRemote = "client";330}331332/*333* If both failed, return the curthread's exception, but also334* print the remote side Exception335*/336if ((local != null) && (remote != null)) {337System.out.println(whichRemote + " also threw:");338remote.printStackTrace();339System.out.println();340throw local;341}342343if (remote != null) {344throw remote;345}346347if (local != null) {348throw local;349}350}351352void startServer(boolean newThread) throws Exception {353if (newThread) {354serverThread = new Thread() {355public void run() {356try {357doServerSide();358} catch (Exception e) {359/*360* Our server thread just died.361*362* Release the client, if not active already...363*/364System.err.println("Server died...");365serverReady = true;366serverException = e;367}368}369};370serverThread.start();371} else {372try {373doServerSide();374} catch (Exception e) {375serverException = e;376} finally {377serverReady = true;378}379}380}381382void startClient(boolean newThread) throws Exception {383if (newThread) {384clientThread = new Thread() {385public void run() {386try {387doClientSide();388} catch (Exception e) {389/*390* Our client thread just died.391*/392System.err.println("Client died...");393clientException = e;394}395}396};397clientThread.start();398} else {399try {400doClientSide();401} catch (Exception e) {402clientException = e;403}404}405}406}407408409