Path: blob/master/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerMatchedSNI.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 SSLSocketExplorerMatchedSNI www.example.com35* www\.example\.com36* @run main/othervm SSLSocketExplorerMatchedSNI www.example.com37* www\.example\.(com|org)38* @run main/othervm SSLSocketExplorerMatchedSNI example.com39* (.*\.)*example\.(com|org)40* @run main/othervm SSLSocketExplorerMatchedSNI www.example.com41* (.*\.)*example\.(com|org)42* @run main/othervm SSLSocketExplorerMatchedSNI www.us.example.com43* (.*\.)*example\.(com|org)44*/4546import java.io.*;47import java.nio.*;48import java.nio.channels.*;49import java.util.*;50import java.net.*;51import javax.net.ssl.*;5253public class SSLSocketExplorerMatchedSNI {5455/*56* =============================================================57* Set the various variables needed for the tests, then58* specify what tests to run on each side.59*/6061/*62* Should we run the client or server in a separate thread?63* Both sides can throw exceptions, but do you have a preference64* as to which side should be the main thread.65*/66static boolean separateServerThread = false;6768/*69* Where do we find the keystores?70*/71static String pathToStores = "../etc";72static String keyStoreFile = "keystore";73static String trustStoreFile = "truststore";74static String passwd = "passphrase";7576/*77* Is the server ready to serve?78*/79volatile static boolean serverReady = false;8081/*82* Turn on SSL debugging?83*/84static boolean debug = false;8586/*87* If the client or server is doing some kind of object creation88* that the other side depends on, and that thread prematurely89* exits, you may experience a hang. The test harness will90* terminate all hung threads after its timeout has expired,91* currently 3 minutes by default, but you might try to be92* smart about it....93*/9495/*96* Define the server side of the test.97*98* If the server prematurely exits, serverReady will be set to true99* to avoid infinite hangs.100*/101void doServerSide() throws Exception {102103ServerSocket serverSocket = new ServerSocket(serverPort);104105// Signal Client, we're ready for his connect.106serverPort = serverSocket.getLocalPort();107serverReady = true;108109Socket socket = serverSocket.accept();110InputStream ins = socket.getInputStream();111112byte[] buffer = new byte[0xFF];113int position = 0;114SSLCapabilities capabilities = null;115116// Read the header of TLS record117while (position < SSLExplorer.RECORD_HEADER_SIZE) {118int count = SSLExplorer.RECORD_HEADER_SIZE - position;119int n = ins.read(buffer, position, count);120if (n < 0) {121throw new Exception("unexpected end of stream!");122}123position += n;124}125126int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position);127if (buffer.length < recordLength) {128buffer = Arrays.copyOf(buffer, recordLength);129}130131while (position < recordLength) {132int count = recordLength - position;133int n = ins.read(buffer, position, count);134if (n < 0) {135throw new Exception("unexpected end of stream!");136}137position += n;138}139140capabilities = SSLExplorer.explore(buffer, 0, recordLength);;141if (capabilities != null) {142System.out.println("Record version: " +143capabilities.getRecordVersion());144System.out.println("Hello version: " +145capabilities.getHelloVersion());146}147148SSLSocketFactory sslsf =149(SSLSocketFactory) SSLSocketFactory.getDefault();150ByteArrayInputStream bais =151new ByteArrayInputStream(buffer, 0, position);152SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(socket, bais, true);153154SNIMatcher matcher = SNIHostName.createSNIMatcher(155serverAcceptableHostname);156Collection<SNIMatcher> matchers = new ArrayList<>(1);157matchers.add(matcher);158SSLParameters params = sslSocket.getSSLParameters();159params.setSNIMatchers(matchers);160sslSocket.setSSLParameters(params);161162InputStream sslIS = sslSocket.getInputStream();163OutputStream sslOS = sslSocket.getOutputStream();164165sslIS.read();166sslOS.write(85);167sslOS.flush();168169ExtendedSSLSession session = (ExtendedSSLSession)sslSocket.getSession();170checkCapabilities(capabilities, session);171172sslSocket.close();173serverSocket.close();174}175176177/*178* Define the client side of the test.179*180* If the server prematurely exits, serverReady will be set to true181* to avoid infinite hangs.182*/183void doClientSide() throws Exception {184185/*186* Wait for server to get started.187*/188while (!serverReady) {189Thread.sleep(50);190}191192SSLSocketFactory sslsf =193(SSLSocketFactory) SSLSocketFactory.getDefault();194SSLSocket sslSocket = (SSLSocket)195sslsf.createSocket("localhost", serverPort);196197SNIHostName serverName = new SNIHostName(clientRequestedHostname);198List<SNIServerName> serverNames = new ArrayList<>(1);199serverNames.add(serverName);200SSLParameters params = sslSocket.getSSLParameters();201params.setServerNames(serverNames);202sslSocket.setSSLParameters(params);203204InputStream sslIS = sslSocket.getInputStream();205OutputStream sslOS = sslSocket.getOutputStream();206207sslOS.write(280);208sslOS.flush();209sslIS.read();210211ExtendedSSLSession session = (ExtendedSSLSession)sslSocket.getSession();212checkSNIInSession(session);213214sslSocket.close();215}216217218void checkCapabilities(SSLCapabilities capabilities,219ExtendedSSLSession session) throws Exception {220221List<SNIServerName> sessionSNI = session.getRequestedServerNames();222if (!sessionSNI.equals(capabilities.getServerNames())) {223for (SNIServerName sni : sessionSNI) {224System.out.println("SNI in session is " + sni);225}226227List<SNIServerName> capaSNI = capabilities.getServerNames();228for (SNIServerName sni : capaSNI) {229System.out.println("SNI in session is " + sni);230}231232throw new Exception(233"server name indication does not match capabilities");234}235236checkSNIInSession(session);237}238239void checkSNIInSession(ExtendedSSLSession session) throws Exception {240List<SNIServerName> sessionSNI = session.getRequestedServerNames();241if (sessionSNI.isEmpty()) {242throw new Exception(243"unexpected empty request server name indication");244}245246if (sessionSNI.size() != 1) {247throw new Exception(248"unexpected request server name indication");249}250251SNIServerName serverName = sessionSNI.get(0);252if (!(serverName instanceof SNIHostName)) {253throw new Exception(254"unexpected instance of request server name indication");255}256257String hostname = ((SNIHostName)serverName).getAsciiName();258if (!clientRequestedHostname.equalsIgnoreCase(hostname)) {259throw new Exception(260"unexpected request server name indication value");261}262}263264private static String clientRequestedHostname;265private static String serverAcceptableHostname;266267private static void parseArguments(String[] args) {268clientRequestedHostname = args[0];269serverAcceptableHostname = args[1];270}271272273/*274* =============================================================275* The remainder is just support stuff276*/277278// use any free port by default279volatile int serverPort = 0;280281volatile Exception serverException = null;282volatile Exception clientException = null;283284285public static void main(String[] args) throws Exception {286String keyFilename =287System.getProperty("test.src", ".") + "/" + pathToStores +288"/" + keyStoreFile;289String trustFilename =290System.getProperty("test.src", ".") + "/" + pathToStores +291"/" + trustStoreFile;292293System.setProperty("javax.net.ssl.keyStore", keyFilename);294System.setProperty("javax.net.ssl.keyStorePassword", passwd);295System.setProperty("javax.net.ssl.trustStore", trustFilename);296System.setProperty("javax.net.ssl.trustStorePassword", passwd);297298if (debug)299System.setProperty("javax.net.debug", "all");300301/*302* Get the customized arguments.303*/304parseArguments(args);305306/*307* Start the tests.308*/309new SSLSocketExplorerMatchedSNI();310}311312Thread clientThread = null;313Thread serverThread = null;314315/*316* Primary constructor, used to drive remainder of the test.317*318* Fork off the other side, then do your work.319*/320SSLSocketExplorerMatchedSNI() throws Exception {321try {322if (separateServerThread) {323startServer(true);324startClient(false);325} else {326startClient(true);327startServer(false);328}329} catch (Exception e) {330// swallow for now. Show later331}332333/*334* Wait for other side to close down.335*/336if (separateServerThread) {337serverThread.join();338} else {339clientThread.join();340}341342/*343* When we get here, the test is pretty much over.344* Which side threw the error?345*/346Exception local;347Exception remote;348String whichRemote;349350if (separateServerThread) {351remote = serverException;352local = clientException;353whichRemote = "server";354} else {355remote = clientException;356local = serverException;357whichRemote = "client";358}359360/*361* If both failed, return the curthread's exception, but also362* print the remote side Exception363*/364if ((local != null) && (remote != null)) {365System.out.println(whichRemote + " also threw:");366remote.printStackTrace();367System.out.println();368throw local;369}370371if (remote != null) {372throw remote;373}374375if (local != null) {376throw local;377}378}379380void startServer(boolean newThread) throws Exception {381if (newThread) {382serverThread = new Thread() {383public void run() {384try {385doServerSide();386} catch (Exception e) {387/*388* Our server thread just died.389*390* Release the client, if not active already...391*/392System.err.println("Server died...");393serverReady = true;394serverException = e;395}396}397};398serverThread.start();399} else {400try {401doServerSide();402} catch (Exception e) {403serverException = e;404} finally {405serverReady = true;406}407}408}409410void startClient(boolean newThread) throws Exception {411if (newThread) {412clientThread = new Thread() {413public void run() {414try {415doClientSide();416} catch (Exception e) {417/*418* Our client thread just died.419*/420System.err.println("Client died...");421clientException = e;422}423}424};425clientThread.start();426} else {427try {428doClientSide();429} catch (Exception e) {430clientException = e;431}432}433}434}435436437