Path: blob/master/test/jdk/javax/net/ssl/ServerName/SSLEngineExplorerWithCli.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 SSLEngineExplorerWithCli35*/3637import javax.net.ssl.*;38import java.nio.*;39import java.net.*;40import java.util.*;41import java.nio.channels.*;4243public class SSLEngineExplorerWithCli extends SSLEngineService {4445/*46* =============================================================47* Set the various variables needed for the tests, then48* specify what tests to run on each side.49*/5051/*52* Should we run the client or server in a separate thread?53* Both sides can throw exceptions, but do you have a preference54* as to which side should be the main thread.55*/56static boolean separateServerThread = true;5758// Is the server ready to serve?59volatile static boolean serverReady = false;6061/*62* Turn on SSL debugging?63*/64static boolean debug = false;6566/*67* Define the server side of the test.68*69* If the server prematurely exits, serverReady will be set to true70* to avoid infinite hangs.71*/72void doServerSide() throws Exception {7374// create SSLEngine.75SSLEngine ssle = createSSLEngine(false);7677// Create a server socket channel.78InetSocketAddress isa =79new InetSocketAddress(InetAddress.getLocalHost(), serverPort);80ServerSocketChannel ssc = ServerSocketChannel.open();81ssc.socket().bind(isa);82serverPort = ssc.socket().getLocalPort();8384// Signal Client, we're ready for his connect.85serverReady = true;8687// Accept a socket channel.88SocketChannel sc = ssc.accept();8990// Complete connection.91while (!sc.finishConnect()) {92Thread.sleep(50);93// waiting for the connection completed.94}9596ByteBuffer buffer = ByteBuffer.allocate(0xFF);97int position = 0;98SSLCapabilities capabilities = null;99100// Read the header of TLS record101buffer.limit(SSLExplorer.RECORD_HEADER_SIZE);102while (position < SSLExplorer.RECORD_HEADER_SIZE) {103int n = sc.read(buffer);104if (n < 0) {105throw new Exception("unexpected end of stream!");106}107position += n;108}109buffer.flip();110111int recordLength = SSLExplorer.getRequiredSize(buffer);112if (buffer.capacity() < recordLength) {113ByteBuffer oldBuffer = buffer;114buffer = ByteBuffer.allocate(recordLength);115buffer.put(oldBuffer);116}117118buffer.position(SSLExplorer.RECORD_HEADER_SIZE);119buffer.limit(buffer.capacity());120while (position < recordLength) {121int n = sc.read(buffer);122if (n < 0) {123throw new Exception("unexpected end of stream!");124}125position += n;126}127buffer.flip();128129capabilities = SSLExplorer.explore(buffer);130if (capabilities != null) {131System.out.println("Record version: " +132capabilities.getRecordVersion());133System.out.println("Hello version: " +134capabilities.getHelloVersion());135}136137// handshaking138handshaking(ssle, sc, buffer);139140// receive application data141receive(ssle, sc);142143// send out application data144deliver(ssle, sc);145146ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();147checkCapabilities(capabilities, session);148149// close the socket channel.150sc.close();151ssc.close();152}153154/*155* Define the client side of the test.156*157* If the server prematurely exits, serverReady will be set to true158* to avoid infinite hangs.159*/160void doClientSide() throws Exception {161// create SSLEngine.162SSLEngine ssle = createSSLEngine(true);163164/*165* Wait for server to get started.166*/167while (!serverReady) {168Thread.sleep(50);169}170171// Create a non-blocking socket channel.172SocketChannel sc = SocketChannel.open();173sc.configureBlocking(false);174InetSocketAddress isa =175new InetSocketAddress(InetAddress.getLocalHost(), serverPort);176sc.connect(isa);177178// Complete connection.179while (!sc.finishConnect() ) {180Thread.sleep(50);181// waiting for the connection completed.182}183184SNIHostName serverName = new SNIHostName(clientRequestedHostname);185List<SNIServerName> serverNames = new ArrayList<>(1);186serverNames.add(serverName);187SSLParameters params = ssle.getSSLParameters();188params.setServerNames(serverNames);189ssle.setSSLParameters(params);190191// handshaking192handshaking(ssle, sc, null);193194// send out application data195deliver(ssle, sc);196197// receive application data198receive(ssle, sc);199200// check server name indication201ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();202checkSNIInSession(session);203204// close the socket channel.205sc.close();206}207208private static String clientRequestedHostname = "www.example.com";209private static String serverAcceptableHostname =210"www\\.example\\.(com|org)";211212void checkCapabilities(SSLCapabilities capabilities,213ExtendedSSLSession session) throws Exception {214List<SNIServerName> sessionSNI = session.getRequestedServerNames();215if (!sessionSNI.equals(capabilities.getServerNames())) {216for (SNIServerName sni : sessionSNI) {217System.out.println("SNI in session is " + sni);218}219220List<SNIServerName> capaSNI = capabilities.getServerNames();221for (SNIServerName sni : capaSNI) {222System.out.println("SNI in session is " + sni);223}224225throw new Exception(226"server name indication does not match capabilities");227}228229checkSNIInSession(session);230}231232void checkSNIInSession(ExtendedSSLSession session) throws Exception {233List<SNIServerName> sessionSNI = session.getRequestedServerNames();234if (sessionSNI.isEmpty()) {235throw new Exception(236"unexpected empty request server name indication");237}238239if (sessionSNI.size() != 1) {240throw new Exception(241"unexpected request server name indication");242}243244SNIServerName serverName = sessionSNI.get(0);245if (!(serverName instanceof SNIHostName)) {246throw new Exception(247"unexpected instance of request server name indication");248}249250String hostname = ((SNIHostName)serverName).getAsciiName();251if (!clientRequestedHostname.equalsIgnoreCase(hostname)) {252throw new Exception(253"unexpected request server name indication value");254}255}256257/*258* =============================================================259* The remainder is just support stuff260*/261volatile Exception serverException = null;262volatile Exception clientException = null;263264// use any free port by default265volatile int serverPort = 0;266267public static void main(String args[]) throws Exception {268if (debug)269System.setProperty("javax.net.debug", "all");270271new SSLEngineExplorerWithCli();272}273274Thread clientThread = null;275Thread serverThread = null;276277/*278* Primary constructor, used to drive remainder of the test.279*280* Fork off the other side, then do your work.281*/282SSLEngineExplorerWithCli() throws Exception {283super("../etc");284285if (separateServerThread) {286startServer(true);287startClient(false);288} else {289startClient(true);290startServer(false);291}292293/*294* Wait for other side to close down.295*/296if (separateServerThread) {297serverThread.join();298} else {299clientThread.join();300}301302/*303* When we get here, the test is pretty much over.304*305* If the main thread excepted, that propagates back306* immediately. If the other thread threw an exception, we307* should report back.308*/309if (serverException != null) {310System.out.print("Server Exception:");311throw serverException;312}313if (clientException != null) {314System.out.print("Client Exception:");315throw clientException;316}317}318319void startServer(boolean newThread) throws Exception {320if (newThread) {321serverThread = new Thread() {322public void run() {323try {324doServerSide();325} catch (Exception e) {326/*327* Our server thread just died.328*329* Release the client, if not active already...330*/331System.err.println("Server died...");332System.err.println(e);333serverReady = true;334serverException = e;335}336}337};338serverThread.start();339} else {340doServerSide();341}342}343344void startClient(boolean newThread) throws Exception {345if (newThread) {346clientThread = new Thread() {347public void run() {348try {349doClientSide();350} catch (Exception e) {351/*352* Our client thread just died.353*/354System.err.println("Client died...");355clientException = e;356}357}358};359clientThread.start();360} else {361doClientSide();362}363}364}365366367