jdk/test/javax/net/ssl/ServerName/SSLEngineExplorerWithCli.java
changeset 23052 241885315119
parent 14194 971f46db533d
child 30820 0d4717a011d3
equal deleted inserted replaced
23051:501d8479f798 23052:241885315119
       
     1 /*
       
     2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 //
       
    25 // SunJSSE does not support dynamic system properties, no way to re-use
       
    26 // system properties in samevm/agentvm mode.
       
    27 //
       
    28 
       
    29 /*
       
    30  * @test
       
    31  * @bug 7068321
       
    32  * @summary Support TLS Server Name Indication (SNI) Extension in JSSE Server
       
    33  * @library ../SSLEngine ../templates
       
    34  * @build SSLEngineService SSLCapabilities SSLExplorer
       
    35  * @run main/othervm SSLEngineExplorerWithCli
       
    36  */
       
    37 
       
    38 import javax.net.ssl.*;
       
    39 import java.nio.*;
       
    40 import java.net.*;
       
    41 import java.util.*;
       
    42 import java.nio.channels.*;
       
    43 
       
    44 public class SSLEngineExplorerWithCli extends SSLEngineService {
       
    45 
       
    46     /*
       
    47      * =============================================================
       
    48      * Set the various variables needed for the tests, then
       
    49      * specify what tests to run on each side.
       
    50      */
       
    51 
       
    52     /*
       
    53      * Should we run the client or server in a separate thread?
       
    54      * Both sides can throw exceptions, but do you have a preference
       
    55      * as to which side should be the main thread.
       
    56      */
       
    57     static boolean separateServerThread = true;
       
    58 
       
    59     // Is the server ready to serve?
       
    60     volatile static boolean serverReady = false;
       
    61 
       
    62     /*
       
    63      * Turn on SSL debugging?
       
    64      */
       
    65     static boolean debug = false;
       
    66 
       
    67     /*
       
    68      * Define the server side of the test.
       
    69      *
       
    70      * If the server prematurely exits, serverReady will be set to true
       
    71      * to avoid infinite hangs.
       
    72      */
       
    73     void doServerSide() throws Exception {
       
    74 
       
    75         // create SSLEngine.
       
    76         SSLEngine ssle = createSSLEngine(false);
       
    77 
       
    78         // Create a server socket channel.
       
    79         InetSocketAddress isa =
       
    80                 new InetSocketAddress(InetAddress.getLocalHost(), serverPort);
       
    81         ServerSocketChannel ssc = ServerSocketChannel.open();
       
    82         ssc.socket().bind(isa);
       
    83         serverPort = ssc.socket().getLocalPort();
       
    84 
       
    85         // Signal Client, we're ready for his connect.
       
    86         serverReady = true;
       
    87 
       
    88         // Accept a socket channel.
       
    89         SocketChannel sc = ssc.accept();
       
    90 
       
    91         // Complete connection.
       
    92         while (!sc.finishConnect()) {
       
    93             Thread.sleep(50);
       
    94             // waiting for the connection completed.
       
    95         }
       
    96 
       
    97         ByteBuffer buffer = ByteBuffer.allocate(0xFF);
       
    98         int position = 0;
       
    99         SSLCapabilities capabilities = null;
       
   100 
       
   101         // Read the header of TLS record
       
   102         buffer.limit(SSLExplorer.RECORD_HEADER_SIZE);
       
   103         while (position < SSLExplorer.RECORD_HEADER_SIZE) {
       
   104             int n = sc.read(buffer);
       
   105             if (n < 0) {
       
   106                 throw new Exception("unexpected end of stream!");
       
   107             }
       
   108             position += n;
       
   109         }
       
   110         buffer.flip();
       
   111 
       
   112         int recordLength = SSLExplorer.getRequiredSize(buffer);
       
   113         if (buffer.capacity() < recordLength) {
       
   114             ByteBuffer oldBuffer = buffer;
       
   115             buffer = ByteBuffer.allocate(recordLength);
       
   116             buffer.put(oldBuffer);
       
   117         }
       
   118 
       
   119         buffer.position(SSLExplorer.RECORD_HEADER_SIZE);
       
   120         buffer.limit(buffer.capacity());
       
   121         while (position < recordLength) {
       
   122             int n = sc.read(buffer);
       
   123             if (n < 0) {
       
   124                 throw new Exception("unexpected end of stream!");
       
   125             }
       
   126             position += n;
       
   127         }
       
   128         buffer.flip();
       
   129 
       
   130         capabilities = SSLExplorer.explore(buffer);
       
   131         if (capabilities != null) {
       
   132             System.out.println("Record version: " +
       
   133                     capabilities.getRecordVersion());
       
   134             System.out.println("Hello version: " +
       
   135                     capabilities.getHelloVersion());
       
   136         }
       
   137 
       
   138         // handshaking
       
   139         handshaking(ssle, sc, buffer);
       
   140 
       
   141         // receive application data
       
   142         receive(ssle, sc);
       
   143 
       
   144         // send out application data
       
   145         deliver(ssle, sc);
       
   146 
       
   147         ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();
       
   148         checkCapabilities(capabilities, session);
       
   149 
       
   150         // close the socket channel.
       
   151         sc.close();
       
   152         ssc.close();
       
   153     }
       
   154 
       
   155     /*
       
   156      * Define the client side of the test.
       
   157      *
       
   158      * If the server prematurely exits, serverReady will be set to true
       
   159      * to avoid infinite hangs.
       
   160      */
       
   161     void doClientSide() throws Exception {
       
   162         // create SSLEngine.
       
   163         SSLEngine ssle = createSSLEngine(true);
       
   164 
       
   165         /*
       
   166          * Wait for server to get started.
       
   167          */
       
   168         while (!serverReady) {
       
   169             Thread.sleep(50);
       
   170         }
       
   171 
       
   172         // Create a non-blocking socket channel.
       
   173         SocketChannel sc = SocketChannel.open();
       
   174         sc.configureBlocking(false);
       
   175         InetSocketAddress isa =
       
   176                 new InetSocketAddress(InetAddress.getLocalHost(), serverPort);
       
   177         sc.connect(isa);
       
   178 
       
   179         // Complete connection.
       
   180         while (!sc.finishConnect() ) {
       
   181             Thread.sleep(50);
       
   182             // waiting for the connection completed.
       
   183         }
       
   184 
       
   185         SNIHostName serverName = new SNIHostName(clientRequestedHostname);
       
   186         List<SNIServerName> serverNames = new ArrayList<>(1);
       
   187         serverNames.add(serverName);
       
   188         SSLParameters params = ssle.getSSLParameters();
       
   189         params.setServerNames(serverNames);
       
   190         ssle.setSSLParameters(params);
       
   191 
       
   192         // handshaking
       
   193         handshaking(ssle, sc, null);
       
   194 
       
   195         // send out application data
       
   196         deliver(ssle, sc);
       
   197 
       
   198         // receive application data
       
   199         receive(ssle, sc);
       
   200 
       
   201         // check server name indication
       
   202         ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();
       
   203         checkSNIInSession(session);
       
   204 
       
   205         // close the socket channel.
       
   206         sc.close();
       
   207     }
       
   208 
       
   209     private static String clientRequestedHostname = "www.example.com";
       
   210     private static String serverAcceptableHostname =
       
   211                                                 "www\\.example\\.(com|org)";
       
   212 
       
   213     void checkCapabilities(SSLCapabilities capabilities,
       
   214             ExtendedSSLSession session) throws Exception {
       
   215         List<SNIServerName> sessionSNI = session.getRequestedServerNames();
       
   216         if (!sessionSNI.equals(capabilities.getServerNames())) {
       
   217             for (SNIServerName sni : sessionSNI) {
       
   218                 System.out.println("SNI in session is " + sni);
       
   219             }
       
   220 
       
   221             List<SNIServerName> capaSNI = capabilities.getServerNames();
       
   222             for (SNIServerName sni : capaSNI) {
       
   223                 System.out.println("SNI in session is " + sni);
       
   224             }
       
   225 
       
   226             throw new Exception(
       
   227                     "server name indication does not match capabilities");
       
   228         }
       
   229 
       
   230         checkSNIInSession(session);
       
   231     }
       
   232 
       
   233     void checkSNIInSession(ExtendedSSLSession session) throws Exception {
       
   234         List<SNIServerName> sessionSNI = session.getRequestedServerNames();
       
   235         if (sessionSNI.isEmpty()) {
       
   236             throw new Exception(
       
   237                     "unexpected empty request server name indication");
       
   238         }
       
   239 
       
   240         if (sessionSNI.size() != 1) {
       
   241             throw new Exception(
       
   242                     "unexpected request server name indication");
       
   243         }
       
   244 
       
   245         SNIServerName serverName = sessionSNI.get(0);
       
   246         if (!(serverName instanceof SNIHostName)) {
       
   247             throw new Exception(
       
   248                     "unexpected instance of request server name indication");
       
   249         }
       
   250 
       
   251         String hostname = ((SNIHostName)serverName).getAsciiName();
       
   252         if (!clientRequestedHostname.equalsIgnoreCase(hostname)) {
       
   253             throw new Exception(
       
   254                     "unexpected request server name indication value");
       
   255         }
       
   256     }
       
   257 
       
   258     /*
       
   259      * =============================================================
       
   260      * The remainder is just support stuff
       
   261      */
       
   262     volatile Exception serverException = null;
       
   263     volatile Exception clientException = null;
       
   264 
       
   265     // use any free port by default
       
   266     volatile int serverPort = 0;
       
   267 
       
   268     public static void main(String args[]) throws Exception {
       
   269         if (debug)
       
   270             System.setProperty("javax.net.debug", "all");
       
   271 
       
   272         new SSLEngineExplorerWithCli();
       
   273     }
       
   274 
       
   275     Thread clientThread = null;
       
   276     Thread serverThread = null;
       
   277 
       
   278     /*
       
   279      * Primary constructor, used to drive remainder of the test.
       
   280      *
       
   281      * Fork off the other side, then do your work.
       
   282      */
       
   283     SSLEngineExplorerWithCli() throws Exception {
       
   284         super("../etc");
       
   285 
       
   286         if (separateServerThread) {
       
   287             startServer(true);
       
   288             startClient(false);
       
   289         } else {
       
   290             startClient(true);
       
   291             startServer(false);
       
   292         }
       
   293 
       
   294         /*
       
   295          * Wait for other side to close down.
       
   296          */
       
   297         if (separateServerThread) {
       
   298             serverThread.join();
       
   299         } else {
       
   300             clientThread.join();
       
   301         }
       
   302 
       
   303         /*
       
   304          * When we get here, the test is pretty much over.
       
   305          *
       
   306          * If the main thread excepted, that propagates back
       
   307          * immediately.  If the other thread threw an exception, we
       
   308          * should report back.
       
   309          */
       
   310         if (serverException != null) {
       
   311             System.out.print("Server Exception:");
       
   312             throw serverException;
       
   313         }
       
   314         if (clientException != null) {
       
   315             System.out.print("Client Exception:");
       
   316             throw clientException;
       
   317         }
       
   318     }
       
   319 
       
   320     void startServer(boolean newThread) throws Exception {
       
   321         if (newThread) {
       
   322             serverThread = new Thread() {
       
   323                 public void run() {
       
   324                     try {
       
   325                         doServerSide();
       
   326                     } catch (Exception e) {
       
   327                         /*
       
   328                          * Our server thread just died.
       
   329                          *
       
   330                          * Release the client, if not active already...
       
   331                          */
       
   332                         System.err.println("Server died...");
       
   333                         System.err.println(e);
       
   334                         serverReady = true;
       
   335                         serverException = e;
       
   336                     }
       
   337                 }
       
   338             };
       
   339             serverThread.start();
       
   340         } else {
       
   341             doServerSide();
       
   342         }
       
   343     }
       
   344 
       
   345     void startClient(boolean newThread) throws Exception {
       
   346         if (newThread) {
       
   347             clientThread = new Thread() {
       
   348                 public void run() {
       
   349                     try {
       
   350                         doClientSide();
       
   351                     } catch (Exception e) {
       
   352                         /*
       
   353                          * Our client thread just died.
       
   354                          */
       
   355                         System.err.println("Client died...");
       
   356                         clientException = e;
       
   357                     }
       
   358                 }
       
   359             };
       
   360             clientThread.start();
       
   361         } else {
       
   362             doClientSide();
       
   363         }
       
   364     }
       
   365 }