Path: blob/master/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerWithSrvSNI.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 SSLSocketExplorerWithSrvSNI35*/3637import java.io.*;38import java.nio.*;39import java.nio.channels.*;40import java.util.*;41import java.net.*;42import javax.net.ssl.*;4344public class SSLSocketExplorerWithSrvSNI {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);144145SNIMatcher matcher = SNIHostName.createSNIMatcher(146serverAcceptableHostname);147Collection<SNIMatcher> matchers = new ArrayList<>(1);148matchers.add(matcher);149SSLParameters params = sslSocket.getSSLParameters();150params.setSNIMatchers(matchers);151sslSocket.setSSLParameters(params);152153InputStream sslIS = sslSocket.getInputStream();154OutputStream sslOS = sslSocket.getOutputStream();155156sslIS.read();157sslOS.write(85);158sslOS.flush();159160ExtendedSSLSession session = (ExtendedSSLSession)sslSocket.getSession();161checkCapabilities(capabilities, session);162163sslSocket.close();164serverSocket.close();165}166167168/*169* Define the client side of the test.170*171* If the server prematurely exits, serverReady will be set to true172* to avoid infinite hangs.173*/174void doClientSide() throws Exception {175176/*177* Wait for server to get started.178*/179while (!serverReady) {180Thread.sleep(50);181}182183SSLSocketFactory sslsf =184(SSLSocketFactory) SSLSocketFactory.getDefault();185SSLSocket sslSocket = (SSLSocket)186sslsf.createSocket("localhost", serverPort);187188InputStream sslIS = sslSocket.getInputStream();189OutputStream sslOS = sslSocket.getOutputStream();190191sslOS.write(280);192sslOS.flush();193sslIS.read();194195ExtendedSSLSession session = (ExtendedSSLSession)sslSocket.getSession();196checkSNIInSession(session);197198sslSocket.close();199}200201private static String clientRequestedHostname = "www.example.com";202private static String serverAcceptableHostname =203"www\\.example\\.(com|org)";204205void checkCapabilities(SSLCapabilities capabilities,206ExtendedSSLSession session) throws Exception {207208List<SNIServerName> sessionSNI = session.getRequestedServerNames();209if (!sessionSNI.equals(capabilities.getServerNames())) {210for (SNIServerName sni : sessionSNI) {211System.out.println("SNI in session is " + sni);212}213214List<SNIServerName> capaSNI = capabilities.getServerNames();215for (SNIServerName sni : capaSNI) {216System.out.println("SNI in session is " + sni);217}218219throw new Exception(220"server name indication does not match capabilities");221}222223checkSNIInSession(session);224}225226void checkSNIInSession(ExtendedSSLSession session) throws Exception {227List<SNIServerName> sessionSNI = session.getRequestedServerNames();228if (!sessionSNI.isEmpty()) {229throw new Exception(230"should be empty request server name indication");231}232}233234/*235* =============================================================236* The remainder is just support stuff237*/238239// use any free port by default240volatile int serverPort = 0;241242volatile Exception serverException = null;243volatile Exception clientException = null;244245public static void main(String[] args) throws Exception {246String keyFilename =247System.getProperty("test.src", ".") + "/" + pathToStores +248"/" + keyStoreFile;249String trustFilename =250System.getProperty("test.src", ".") + "/" + pathToStores +251"/" + trustStoreFile;252253System.setProperty("javax.net.ssl.keyStore", keyFilename);254System.setProperty("javax.net.ssl.keyStorePassword", passwd);255System.setProperty("javax.net.ssl.trustStore", trustFilename);256System.setProperty("javax.net.ssl.trustStorePassword", passwd);257258if (debug)259System.setProperty("javax.net.debug", "all");260261/*262* Start the tests.263*/264new SSLSocketExplorerWithSrvSNI();265}266267Thread clientThread = null;268Thread serverThread = null;269270/*271* Primary constructor, used to drive remainder of the test.272*273* Fork off the other side, then do your work.274*/275SSLSocketExplorerWithSrvSNI() throws Exception {276try {277if (separateServerThread) {278startServer(true);279startClient(false);280} else {281startClient(true);282startServer(false);283}284} catch (Exception e) {285// swallow for now. Show later286}287288/*289* Wait for other side to close down.290*/291if (separateServerThread) {292serverThread.join();293} else {294clientThread.join();295}296297/*298* When we get here, the test is pretty much over.299* Which side threw the error?300*/301Exception local;302Exception remote;303String whichRemote;304305if (separateServerThread) {306remote = serverException;307local = clientException;308whichRemote = "server";309} else {310remote = clientException;311local = serverException;312whichRemote = "client";313}314315/*316* If both failed, return the curthread's exception, but also317* print the remote side Exception318*/319if ((local != null) && (remote != null)) {320System.out.println(whichRemote + " also threw:");321remote.printStackTrace();322System.out.println();323throw local;324}325326if (remote != null) {327throw remote;328}329330if (local != null) {331throw local;332}333}334335void startServer(boolean newThread) throws Exception {336if (newThread) {337serverThread = new Thread() {338public void run() {339try {340doServerSide();341} catch (Exception e) {342/*343* Our server thread just died.344*345* Release the client, if not active already...346*/347System.err.println("Server died...");348serverReady = true;349serverException = e;350}351}352};353serverThread.start();354} else {355try {356doServerSide();357} catch (Exception e) {358serverException = e;359} finally {360serverReady = true;361}362}363}364365void startClient(boolean newThread) throws Exception {366if (newThread) {367clientThread = new Thread() {368public void run() {369try {370doClientSide();371} catch (Exception e) {372/*373* Our client thread just died.374*/375System.err.println("Client died...");376clientException = e;377}378}379};380clientThread.start();381} else {382try {383doClientSide();384} catch (Exception e) {385clientException = e;386}387}388}389}390391392