Path: blob/master/test/jdk/javax/net/ssl/ServerName/SSLEngineExplorerUnmatchedSNI.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 ../SSLEngine ../templates33* @build SSLEngineService SSLCapabilities SSLExplorer34* @run main/othervm SSLEngineExplorerUnmatchedSNI www.example.com35* www\.example\.org36*/3738import javax.net.ssl.*;39import java.io.*;40import java.nio.*;41import java.net.*;42import java.util.*;43import java.nio.channels.*;4445public class SSLEngineExplorerUnmatchedSNI extends SSLEngineService {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// Is the server ready to serve?61volatile static boolean serverReady = false;6263/*64* Turn on SSL debugging?65*/66static boolean debug = false;6768/*69* Define the server side of the test.70*71* If the server prematurely exits, serverReady will be set to true72* to avoid infinite hangs.73*/74void doServerSide() throws Exception {7576// create SSLEngine.77SSLEngine ssle = createSSLEngine(false);7879// Create a server socket channel.80InetSocketAddress isa =81new InetSocketAddress(InetAddress.getLocalHost(), serverPort);82ServerSocketChannel ssc = ServerSocketChannel.open();83ssc.socket().bind(isa);84serverPort = ssc.socket().getLocalPort();8586// Signal Client, we're ready for his connect.87serverReady = true;8889// Accept a socket channel.90SocketChannel sc = ssc.accept();9192// Complete connection.93while (!sc.finishConnect()) {94Thread.sleep(50);95// waiting for the connection completed.96}9798ByteBuffer buffer = ByteBuffer.allocate(0xFF);99int position = 0;100SSLCapabilities capabilities = null;101102// Read the header of TLS record103buffer.limit(SSLExplorer.RECORD_HEADER_SIZE);104while (position < SSLExplorer.RECORD_HEADER_SIZE) {105int n = sc.read(buffer);106if (n < 0) {107throw new Exception("unexpected end of stream!");108}109position += n;110}111buffer.flip();112113int recordLength = SSLExplorer.getRequiredSize(buffer);114if (buffer.capacity() < recordLength) {115ByteBuffer oldBuffer = buffer;116buffer = ByteBuffer.allocate(recordLength);117buffer.put(oldBuffer);118}119120buffer.position(SSLExplorer.RECORD_HEADER_SIZE);121buffer.limit(buffer.capacity());122while (position < recordLength) {123int n = sc.read(buffer);124if (n < 0) {125throw new Exception("unexpected end of stream!");126}127position += n;128}129buffer.flip();130131capabilities = SSLExplorer.explore(buffer);132if (capabilities != null) {133System.out.println("Record version: " +134capabilities.getRecordVersion());135System.out.println("Hello version: " +136capabilities.getHelloVersion());137}138139// enable server name indication checking140SNIMatcher matcher = SNIHostName.createSNIMatcher(141serverAcceptableHostname);142Collection<SNIMatcher> matchers = new ArrayList<>(1);143matchers.add(matcher);144SSLParameters params = ssle.getSSLParameters();145params.setSNIMatchers(matchers);146ssle.setSSLParameters(params);147148try {149// handshaking150handshaking(ssle, sc, buffer);151152// receive application data153receive(ssle, sc);154155// send out application data156deliver(ssle, sc);157158// check server name indication159ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();160checkCapabilities(capabilities, session);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 {170// close the socket channel.171sc.close();172ssc.close();173}174}175176/*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 {183// create SSLEngine.184SSLEngine ssle = createSSLEngine(true);185186/*187* Wait for server to get started.188*/189while (!serverReady) {190Thread.sleep(50);191}192193// Create a non-blocking socket channel.194SocketChannel sc = SocketChannel.open();195sc.configureBlocking(false);196InetSocketAddress isa =197new InetSocketAddress(InetAddress.getLocalHost(), serverPort);198sc.connect(isa);199200// Complete connection.201while (!sc.finishConnect() ) {202Thread.sleep(50);203// waiting for the connection completed.204}205206SNIHostName serverName = new SNIHostName(clientRequestedHostname);207List<SNIServerName> serverNames = new ArrayList<>(1);208serverNames.add(serverName);209SSLParameters params = ssle.getSSLParameters();210params.setServerNames(serverNames);211ssle.setSSLParameters(params);212213try {214// handshaking215handshaking(ssle, sc, null);216217// send out application data218deliver(ssle, sc);219220// receive application data221receive(ssle, sc);222223// check server name indication224ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();225checkSNIInSession(session);226227throw new Exception(228"Mismatched server name indication was accepted");229} catch (SSLHandshakeException sslhe) {230// the expected unrecognized server name indication exception231} catch (IOException ioe) {232// the peer may have closed the socket because of the unmatched233// server name indication.234} finally {235// close the socket channel.236sc.close();237}238}239240void checkCapabilities(SSLCapabilities capabilities,241ExtendedSSLSession session) throws Exception {242List<SNIServerName> sessionSNI = session.getRequestedServerNames();243if (!sessionSNI.equals(capabilities.getServerNames())) {244for (SNIServerName sni : sessionSNI) {245System.out.println("SNI in session is " + sni);246}247248List<SNIServerName> capaSNI = capabilities.getServerNames();249for (SNIServerName sni : capaSNI) {250System.out.println("SNI in session is " + sni);251}252253throw new Exception(254"server name indication does not match capabilities");255}256257checkSNIInSession(session);258}259260void checkSNIInSession(ExtendedSSLSession session) throws Exception {261List<SNIServerName> sessionSNI = session.getRequestedServerNames();262if (sessionSNI.isEmpty()) {263throw new Exception(264"unexpected empty request server name indication");265}266267if (sessionSNI.size() != 1) {268throw new Exception(269"unexpected request server name indication");270}271272SNIServerName serverName = sessionSNI.get(0);273if (!(serverName instanceof SNIHostName)) {274throw new Exception(275"unexpected instance of request server name indication");276}277278String hostname = ((SNIHostName)serverName).getAsciiName();279if (!clientRequestedHostname.equalsIgnoreCase(hostname)) {280throw new Exception(281"unexpected request server name indication value");282}283}284285private static String clientRequestedHostname;286private static String serverAcceptableHostname;287288private static void parseArguments(String[] args) {289clientRequestedHostname = args[0];290serverAcceptableHostname = args[1];291}292293/*294* =============================================================295* The remainder is just support stuff296*/297volatile Exception serverException = null;298volatile Exception clientException = null;299300// use any free port by default301volatile int serverPort = 0;302303public static void main(String args[]) throws Exception {304if (debug)305System.setProperty("javax.net.debug", "all");306307/*308* Get the customized arguments.309*/310parseArguments(args);311312new SSLEngineExplorerUnmatchedSNI();313}314315Thread clientThread = null;316Thread serverThread = null;317318/*319* Primary constructor, used to drive remainder of the test.320*321* Fork off the other side, then do your work.322*/323SSLEngineExplorerUnmatchedSNI() throws Exception {324super("../etc");325326if (separateServerThread) {327startServer(true);328startClient(false);329} else {330startClient(true);331startServer(false);332}333334/*335* Wait for other side to close down.336*/337if (separateServerThread) {338serverThread.join();339} else {340clientThread.join();341}342343/*344* When we get here, the test is pretty much over.345*346* If the main thread excepted, that propagates back347* immediately. If the other thread threw an exception, we348* should report back.349*/350if (serverException != null) {351System.out.print("Server Exception:");352throw serverException;353}354if (clientException != null) {355System.out.print("Client Exception:");356throw clientException;357}358}359360void startServer(boolean newThread) throws Exception {361if (newThread) {362serverThread = new Thread() {363public void run() {364try {365doServerSide();366} catch (Exception e) {367/*368* Our server thread just died.369*370* Release the client, if not active already...371*/372System.err.println("Server died...");373System.err.println(e);374serverReady = true;375serverException = e;376}377}378};379serverThread.start();380} else {381doServerSide();382}383}384385void startClient(boolean newThread) throws Exception {386if (newThread) {387clientThread = new Thread() {388public void run() {389try {390doClientSide();391} catch (Exception e) {392/*393* Our client thread just died.394*/395System.err.println("Client died...");396clientException = e;397}398}399};400clientThread.start();401} else {402doClientSide();403}404}405}406407408