Path: blob/master/test/jdk/javax/net/ssl/ServerName/SSLEngineExplorerWithSrv.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 SSLEngineExplorerWithSrv35*/3637import javax.net.ssl.*;38import java.nio.*;39import java.net.*;40import java.util.*;41import java.nio.channels.*;4243public class SSLEngineExplorerWithSrv 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// enable server name indication checking138SNIMatcher matcher = SNIHostName.createSNIMatcher(139serverAcceptableHostname);140Collection<SNIMatcher> matchers = new ArrayList<>(1);141matchers.add(matcher);142SSLParameters params = ssle.getSSLParameters();143params.setSNIMatchers(matchers);144ssle.setSSLParameters(params);145146// handshaking147handshaking(ssle, sc, buffer);148149// receive application data150receive(ssle, sc);151152// send out application data153deliver(ssle, sc);154155// check server name indication156ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();157checkCapabilities(capabilities, session);158159// close the socket channel.160sc.close();161ssc.close();162}163164/*165* Define the client side of the test.166*167* If the server prematurely exits, serverReady will be set to true168* to avoid infinite hangs.169*/170void doClientSide() throws Exception {171// create SSLEngine.172SSLEngine ssle = createSSLEngine(true);173174/*175* Wait for server to get started.176*/177while (!serverReady) {178Thread.sleep(50);179}180181// Create a non-blocking socket channel.182SocketChannel sc = SocketChannel.open();183sc.configureBlocking(false);184InetSocketAddress isa =185new InetSocketAddress(InetAddress.getLocalHost(), serverPort);186sc.connect(isa);187188// Complete connection.189while (!sc.finishConnect() ) {190Thread.sleep(50);191// waiting for the connection completed.192}193194// handshaking195handshaking(ssle, sc, null);196197// send out application data198deliver(ssle, sc);199200// receive application data201receive(ssle, sc);202203// check server name indication204ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();205checkSNIInSession(session);206207// close the socket channel.208sc.close();209}210211private static String clientRequestedHostname = "www.example.com";212private static String serverAcceptableHostname =213"www\\.example\\.(com|org)";214215void checkCapabilities(SSLCapabilities capabilities,216ExtendedSSLSession session) throws Exception {217List<SNIServerName> sessionSNI = session.getRequestedServerNames();218if (!sessionSNI.equals(capabilities.getServerNames())) {219for (SNIServerName sni : sessionSNI) {220System.out.println("SNI in session is " + sni);221}222223List<SNIServerName> capaSNI = capabilities.getServerNames();224for (SNIServerName sni : capaSNI) {225System.out.println("SNI in session is " + sni);226}227228throw new Exception(229"server name indication does not match capabilities");230}231232checkSNIInSession(session);233}234235void checkSNIInSession(ExtendedSSLSession session) throws Exception {236List<SNIServerName> sessionSNI = session.getRequestedServerNames();237if (!sessionSNI.isEmpty()) {238throw new Exception(239"should be empty request server name indication");240}241}242243/*244* =============================================================245* The remainder is just support stuff246*/247volatile Exception serverException = null;248volatile Exception clientException = null;249250// use any free port by default251volatile int serverPort = 0;252253public static void main(String args[]) throws Exception {254if (debug)255System.setProperty("javax.net.debug", "all");256257new SSLEngineExplorerWithSrv();258}259260Thread clientThread = null;261Thread serverThread = null;262263/*264* Primary constructor, used to drive remainder of the test.265*266* Fork off the other side, then do your work.267*/268SSLEngineExplorerWithSrv() throws Exception {269super("../etc");270271if (separateServerThread) {272startServer(true);273startClient(false);274} else {275startClient(true);276startServer(false);277}278279/*280* Wait for other side to close down.281*/282if (separateServerThread) {283serverThread.join();284} else {285clientThread.join();286}287288/*289* When we get here, the test is pretty much over.290*291* If the main thread excepted, that propagates back292* immediately. If the other thread threw an exception, we293* should report back.294*/295if (serverException != null) {296System.out.print("Server Exception:");297throw serverException;298}299if (clientException != null) {300System.out.print("Client Exception:");301throw clientException;302}303}304305void startServer(boolean newThread) throws Exception {306if (newThread) {307serverThread = new Thread() {308public void run() {309try {310doServerSide();311} catch (Exception e) {312/*313* Our server thread just died.314*315* Release the client, if not active already...316*/317System.err.println("Server died...");318System.err.println(e);319serverReady = true;320serverException = e;321}322}323};324serverThread.start();325} else {326doServerSide();327}328}329330void startClient(boolean newThread) throws Exception {331if (newThread) {332clientThread = new Thread() {333public void run() {334try {335doClientSide();336} catch (Exception e) {337/*338* Our client thread just died.339*/340System.err.println("Client died...");341clientException = e;342}343}344};345clientThread.start();346} else {347doClientSide();348}349}350}351352353