Path: blob/master/test/jdk/javax/net/ssl/ServerName/SSLEngineExplorerMatchedSNI.java
41152 views
/*1* Copyright (c) 2012, 2021, 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 SSLEngineExplorerMatchedSNI www.example.com35* www\.example\.com36* @run main/othervm SSLEngineExplorerMatchedSNI www.example.com37* www\.example\.(com|org)38* @run main/othervm SSLEngineExplorerMatchedSNI example.com39* (.*\.)*example\.(com|org)40* @run main/othervm SSLEngineExplorerMatchedSNI www.example.com41* (.*\.)*example\.(com|org)42* @run main/othervm SSLEngineExplorerMatchedSNI www.us.example.com43* (.*\.)*example\.(com|org)44*/4546import javax.net.ssl.*;47import java.nio.*;48import java.net.*;49import java.util.*;50import java.nio.channels.*;5152public class SSLEngineExplorerMatchedSNI extends SSLEngineService {5354/*55* =============================================================56* Set the various variables needed for the tests, then57* specify what tests to run on each side.58*/5960/*61* Should we run the client or server in a separate thread?62* Both sides can throw exceptions, but do you have a preference63* as to which side should be the main thread.64*/65static boolean separateServerThread = false;6667// Is the server ready to serve?68volatile static boolean serverReady = false;6970/*71* Turn on SSL debugging?72*/73static boolean debug = true;7475/*76* Define the server side of the test.77*78* If the server prematurely exits, serverReady will be set to true79* to avoid infinite hangs.80*/81void doServerSide() throws Exception {8283// create SSLEngine.84SSLEngine ssle = createSSLEngine(false);8586// Create a server socket channel.87InetSocketAddress isa =88new InetSocketAddress(InetAddress.getLocalHost(), serverPort);89ServerSocketChannel ssc = ServerSocketChannel.open();90ssc.socket().bind(isa);91serverPort = ssc.socket().getLocalPort();9293// Signal Client, we're ready for his connect.94serverReady = true;9596// Accept a socket channel.97SocketChannel sc = ssc.accept();9899// Complete connection.100while (!sc.finishConnect()) {101Thread.sleep(50);102// waiting for the connection completed.103}104105ByteBuffer buffer = ByteBuffer.allocate(0xFF);106int position = 0;107SSLCapabilities capabilities = null;108109// Read the header of TLS record110buffer.limit(SSLExplorer.RECORD_HEADER_SIZE);111while (position < SSLExplorer.RECORD_HEADER_SIZE) {112int n = sc.read(buffer);113if (n < 0) {114throw new Exception("unexpected end of stream!");115}116position += n;117}118buffer.flip();119120int recordLength = SSLExplorer.getRequiredSize(buffer);121if (buffer.capacity() < recordLength) {122ByteBuffer oldBuffer = buffer;123buffer = ByteBuffer.allocate(recordLength);124buffer.put(oldBuffer);125}126127buffer.position(SSLExplorer.RECORD_HEADER_SIZE);128buffer.limit(buffer.capacity());129while (position < recordLength) {130int n = sc.read(buffer);131if (n < 0) {132throw new Exception("unexpected end of stream!");133}134position += n;135}136buffer.flip();137138capabilities = SSLExplorer.explore(buffer);139if (capabilities != null) {140System.out.println("Record version: " +141capabilities.getRecordVersion());142System.out.println("Hello version: " +143capabilities.getHelloVersion());144}145146// enable server name indication checking147SNIMatcher matcher = SNIHostName.createSNIMatcher(148serverAcceptableHostname);149Collection<SNIMatcher> matchers = new ArrayList<>(1);150matchers.add(matcher);151SSLParameters params = ssle.getSSLParameters();152params.setSNIMatchers(matchers);153ssle.setSSLParameters(params);154155// handshaking156handshaking(ssle, sc, buffer);157158// receive application data159receive(ssle, sc);160161// send out application data162deliver(ssle, sc);163164// check server name indication165ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();166checkCapabilities(capabilities, session);167168// close the socket channel.169sc.close();170ssc.close();171}172173/*174* Define the client side of the test.175*176* If the server prematurely exits, serverReady will be set to true177* to avoid infinite hangs.178*/179void doClientSide() throws Exception {180// create SSLEngine.181SSLEngine ssle = createSSLEngine(true);182183/*184* Wait for server to get started.185*/186while (!serverReady) {187Thread.sleep(50);188}189190// Create a non-blocking socket channel.191SocketChannel sc = SocketChannel.open();192sc.configureBlocking(false);193InetSocketAddress isa =194new InetSocketAddress(InetAddress.getLocalHost(), serverPort);195sc.connect(isa);196197// Complete connection.198while (!sc.finishConnect() ) {199Thread.sleep(50);200// waiting for the connection completed.201}202203SNIHostName serverName = new SNIHostName(clientRequestedHostname);204List<SNIServerName> serverNames = new ArrayList<>(1);205serverNames.add(serverName);206SSLParameters params = ssle.getSSLParameters();207params.setServerNames(serverNames);208ssle.setSSLParameters(params);209210// handshaking211handshaking(ssle, sc, null);212213// send out application data214deliver(ssle, sc);215216// receive application data217receive(ssle, sc);218219// check server name indication220ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();221checkSNIInSession(session);222223// close the socket channel.224sc.close();225}226227void checkCapabilities(SSLCapabilities capabilities,228ExtendedSSLSession session) throws Exception {229List<SNIServerName> sessionSNI = session.getRequestedServerNames();230if (!sessionSNI.equals(capabilities.getServerNames())) {231for (SNIServerName sni : sessionSNI) {232System.out.println("SNI in session is " + sni);233}234235List<SNIServerName> capaSNI = capabilities.getServerNames();236for (SNIServerName sni : capaSNI) {237System.out.println("SNI in session is " + sni);238}239240throw new Exception(241"server name indication does not match capabilities");242}243244checkSNIInSession(session);245}246247void checkSNIInSession(ExtendedSSLSession session) throws Exception {248List<SNIServerName> sessionSNI = session.getRequestedServerNames();249if (sessionSNI.isEmpty()) {250throw new Exception(251"unexpected empty request server name indication");252}253254if (sessionSNI.size() != 1) {255throw new Exception(256"unexpected request server name indication");257}258259SNIServerName serverName = sessionSNI.get(0);260if (!(serverName instanceof SNIHostName)) {261throw new Exception(262"unexpected instance of request server name indication");263}264265String hostname = ((SNIHostName)serverName).getAsciiName();266if (!clientRequestedHostname.equalsIgnoreCase(hostname)) {267throw new Exception(268"unexpected request server name indication value");269}270}271272private static String clientRequestedHostname;273private static String serverAcceptableHostname;274275private static void parseArguments(String[] args) {276clientRequestedHostname = args[0];277serverAcceptableHostname = args[1];278}279280/*281* =============================================================282* The remainder is just support stuff283*/284volatile Exception serverException = null;285volatile Exception clientException = null;286287// use any free port by default288volatile int serverPort = 0;289290public static void main(String args[]) throws Exception {291if (debug)292System.setProperty("javax.net.debug", "all");293294/*295* Get the customized arguments.296*/297parseArguments(args);298299new SSLEngineExplorerMatchedSNI();300}301302Thread clientThread = null;303Thread serverThread = null;304305/*306* Primary constructor, used to drive remainder of the test.307*308* Fork off the other side, then do your work.309*/310SSLEngineExplorerMatchedSNI() throws Exception {311super("../etc");312313if (separateServerThread) {314startServer(true);315startClient(false);316} else {317startClient(true);318startServer(false);319}320321/*322* Wait for other side to close down.323*/324if (separateServerThread) {325serverThread.join();326} else {327clientThread.join();328}329330/*331* When we get here, the test is pretty much over.332*333* If the main thread excepted, that propagates back334* immediately. If the other thread threw an exception, we335* should report back.336*/337if (serverException != null) {338System.out.print("Server Exception:");339throw serverException;340}341if (clientException != null) {342System.out.print("Client Exception:");343throw clientException;344}345}346347void startServer(boolean newThread) throws Exception {348if (newThread) {349serverThread = new Thread() {350public void run() {351try {352doServerSide();353} catch (Exception e) {354/*355* Our server thread just died.356*357* Release the client, if not active already...358*/359System.err.println("Server died...");360System.err.println(e);361serverReady = true;362serverException = e;363}364}365};366serverThread.start();367} else {368doServerSide();369}370}371372void startClient(boolean newThread) throws Exception {373if (newThread) {374clientThread = new Thread() {375public void run() {376try {377doClientSide();378} catch (Exception e) {379/*380* Our client thread just died.381*/382System.err.println("Client died...");383clientException = e;384}385}386};387clientThread.start();388} else {389doClientSide();390}391}392}393394395