Path: blob/master/test/jdk/javax/net/ssl/ServerName/SSLSocketExplorerUnmatchedSNI.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 SSLSocketExplorerUnmatchedSNI www.example.com35* www\.example\.org36*/3738import java.io.*;39import java.nio.*;40import java.nio.channels.*;41import java.util.*;42import java.net.*;43import javax.net.ssl.*;4445public class SSLSocketExplorerUnmatchedSNI {4647/*48* =============================================================49* Set the various variables needed for the tests, then50* specify what tests to run on each side.51*/5253/*54* Should we run the client or server in a separate thread?55* Both sides can throw exceptions, but do you have a preference56* as to which side should be the main thread.57*/58static boolean separateServerThread = false;5960/*61* Where do we find the keystores?62*/63static String pathToStores = "../etc";64static String keyStoreFile = "keystore";65static String trustStoreFile = "truststore";66static String passwd = "passphrase";6768/*69* Is the server ready to serve?70*/71volatile static boolean serverReady = false;7273/*74* Turn on SSL debugging?75*/76static boolean debug = false;7778/*79* If the client or server is doing some kind of object creation80* that the other side depends on, and that thread prematurely81* exits, you may experience a hang. The test harness will82* terminate all hung threads after its timeout has expired,83* currently 3 minutes by default, but you might try to be84* smart about it....85*/8687/*88* Define the server side of the test.89*90* If the server prematurely exits, serverReady will be set to true91* to avoid infinite hangs.92*/93void doServerSide() throws Exception {9495ServerSocket serverSocket = new ServerSocket(serverPort);9697// Signal Client, we're ready for his connect.98serverPort = serverSocket.getLocalPort();99serverReady = true;100101Socket socket = serverSocket.accept();102InputStream ins = socket.getInputStream();103104byte[] buffer = new byte[0xFF];105int position = 0;106SSLCapabilities capabilities = null;107108// Read the header of TLS record109while (position < SSLExplorer.RECORD_HEADER_SIZE) {110int count = SSLExplorer.RECORD_HEADER_SIZE - position;111int n = ins.read(buffer, position, count);112if (n < 0) {113throw new Exception("unexpected end of stream!");114}115position += n;116}117118int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position);119if (buffer.length < recordLength) {120buffer = Arrays.copyOf(buffer, recordLength);121}122123while (position < recordLength) {124int count = recordLength - position;125int n = ins.read(buffer, position, count);126if (n < 0) {127throw new Exception("unexpected end of stream!");128}129position += n;130}131132capabilities = SSLExplorer.explore(buffer, 0, recordLength);;133if (capabilities != null) {134System.out.println("Record version: " +135capabilities.getRecordVersion());136System.out.println("Hello version: " +137capabilities.getHelloVersion());138}139140SSLSocketFactory sslsf =141(SSLSocketFactory) SSLSocketFactory.getDefault();142ByteArrayInputStream bais =143new ByteArrayInputStream(buffer, 0, position);144SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(socket, bais, true);145146SNIMatcher matcher = SNIHostName.createSNIMatcher(147serverAcceptableHostname);148Collection<SNIMatcher> matchers = new ArrayList<>(1);149matchers.add(matcher);150SSLParameters params = sslSocket.getSSLParameters();151params.setSNIMatchers(matchers);152sslSocket.setSSLParameters(params);153154InputStream sslIS = sslSocket.getInputStream();155OutputStream sslOS = sslSocket.getOutputStream();156157try {158sslIS.read();159sslOS.write(85);160sslOS.flush();161162throw new Exception(163"Mismatched server name indication was accepted");164} catch (SSLHandshakeException sslhe) {165// the expected unrecognized server name indication exception166} catch (IOException ioe) {167// the peer may have closed the socket because of the unmatched168// server name indication.169} finally {170sslSocket.close();171serverSocket.close();172}173}174175176/*177* Define the client side of the test.178*179* If the server prematurely exits, serverReady will be set to true180* to avoid infinite hangs.181*/182void doClientSide() throws Exception {183184/*185* Wait for server to get started.186*/187while (!serverReady) {188Thread.sleep(50);189}190191SSLSocketFactory sslsf =192(SSLSocketFactory) SSLSocketFactory.getDefault();193SSLSocket sslSocket = (SSLSocket)194sslsf.createSocket("localhost", serverPort);195196SNIHostName serverName = new SNIHostName(clientRequestedHostname);197List<SNIServerName> serverNames = new ArrayList<>(1);198serverNames.add(serverName);199SSLParameters params = sslSocket.getSSLParameters();200params.setServerNames(serverNames);201sslSocket.setSSLParameters(params);202203InputStream sslIS = sslSocket.getInputStream();204OutputStream sslOS = sslSocket.getOutputStream();205206try {207sslOS.write(280);208sslOS.flush();209sslIS.read();210211throw new Exception(212"Mismatched server name indication was accepted");213} catch (SSLHandshakeException sslhe) {214// the expected unrecognized server name indication exception215} catch (IOException ioe) {216// the peer may have closed the socket because of the unmatched217// server name indication.218} finally {219sslSocket.close();220}221}222223private static String clientRequestedHostname;224private static String serverAcceptableHostname;225226private static void parseArguments(String[] args) {227clientRequestedHostname = args[0];228serverAcceptableHostname = args[1];229}230231/*232* =============================================================233* The remainder is just support stuff234*/235236// use any free port by default237volatile int serverPort = 0;238239volatile Exception serverException = null;240volatile Exception clientException = null;241242public static void main(String[] args) throws Exception {243String keyFilename =244System.getProperty("test.src", ".") + "/" + pathToStores +245"/" + keyStoreFile;246String trustFilename =247System.getProperty("test.src", ".") + "/" + pathToStores +248"/" + trustStoreFile;249250System.setProperty("javax.net.ssl.keyStore", keyFilename);251System.setProperty("javax.net.ssl.keyStorePassword", passwd);252System.setProperty("javax.net.ssl.trustStore", trustFilename);253System.setProperty("javax.net.ssl.trustStorePassword", passwd);254255if (debug)256System.setProperty("javax.net.debug", "all");257258/*259* Get the customized arguments.260*/261parseArguments(args);262263/*264* Start the tests.265*/266new SSLSocketExplorerUnmatchedSNI();267}268269Thread clientThread = null;270Thread serverThread = null;271272/*273* Primary constructor, used to drive remainder of the test.274*275* Fork off the other side, then do your work.276*/277SSLSocketExplorerUnmatchedSNI() throws Exception {278try {279if (separateServerThread) {280startServer(true);281startClient(false);282} else {283startClient(true);284startServer(false);285}286} catch (Exception e) {287// swallow for now. Show later288}289290/*291* Wait for other side to close down.292*/293if (separateServerThread) {294serverThread.join();295} else {296clientThread.join();297}298299/*300* When we get here, the test is pretty much over.301* Which side threw the error?302*/303Exception local;304Exception remote;305String whichRemote;306307if (separateServerThread) {308remote = serverException;309local = clientException;310whichRemote = "server";311} else {312remote = clientException;313local = serverException;314whichRemote = "client";315}316317/*318* If both failed, return the curthread's exception, but also319* print the remote side Exception320*/321if ((local != null) && (remote != null)) {322System.out.println(whichRemote + " also threw:");323remote.printStackTrace();324System.out.println();325throw local;326}327328if (remote != null) {329throw remote;330}331332if (local != null) {333throw local;334}335}336337void startServer(boolean newThread) throws Exception {338if (newThread) {339serverThread = new Thread() {340public void run() {341try {342doServerSide();343} catch (Exception e) {344/*345* Our server thread just died.346*347* Release the client, if not active already...348*/349System.err.println("Server died...");350serverReady = true;351serverException = e;352}353}354};355serverThread.start();356} else {357try {358doServerSide();359} catch (Exception e) {360serverException = e;361} finally {362serverReady = true;363}364}365}366367void startClient(boolean newThread) throws Exception {368if (newThread) {369clientThread = new Thread() {370public void run() {371try {372doClientSide();373} catch (Exception e) {374/*375* Our client thread just died.376*/377System.err.println("Client died...");378clientException = e;379}380}381};382clientThread.start();383} else {384try {385doClientSide();386} catch (Exception e) {387clientException = e;388}389}390}391}392393394