1 /*
   2  * Copyright (c) 2012, 2014, 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  * @modules java.base/sun.misc
  35  * @build SSLEngineService SSLCapabilities SSLExplorer
  36  * @run main/othervm SSLEngineExplorer SSLv2Hello,SSLv3
  37  * @run main/othervm SSLEngineExplorer SSLv3
  38  * @run main/othervm SSLEngineExplorer TLSv1
  39  * @run main/othervm SSLEngineExplorer TLSv1.1
  40  * @run main/othervm SSLEngineExplorer TLSv1.2
  41  */
  42 
  43 import javax.net.ssl.*;
  44 import java.nio.*;
  45 import java.net.*;
  46 import java.util.*;
  47 import java.nio.channels.*;
  48 import java.security.Security;
  49 
  50 public class SSLEngineExplorer extends SSLEngineService {
  51 
  52     /*
  53      * =============================================================
  54      * Set the various variables needed for the tests, then
  55      * specify what tests to run on each side.
  56      */
  57 
  58     /*
  59      * Should we run the client or server in a separate thread?
  60      * Both sides can throw exceptions, but do you have a preference
  61      * as to which side should be the main thread.
  62      */
  63     static boolean separateServerThread = true;
  64 
  65     // Is the server ready to serve?
  66     volatile static boolean serverReady = false;
  67 
  68     /*
  69      * Turn on SSL debugging?
  70      */
  71     static boolean debug = false;
  72 
  73     /*
  74      * Define the server side of the test.
  75      *
  76      * If the server prematurely exits, serverReady will be set to true
  77      * to avoid infinite hangs.
  78      */
  79     void doServerSide() throws Exception {
  80 
  81         // create SSLEngine.
  82         SSLEngine ssle = createSSLEngine(false);
  83 
  84         // Create a server socket channel.
  85         InetSocketAddress isa =
  86                 new InetSocketAddress(InetAddress.getLocalHost(), serverPort);
  87         ServerSocketChannel ssc = ServerSocketChannel.open();
  88         ssc.socket().bind(isa);
  89         serverPort = ssc.socket().getLocalPort();
  90 
  91         // Signal Client, we're ready for his connect.
  92         serverReady = true;
  93 
  94         // Accept a socket channel.
  95         SocketChannel sc = ssc.accept();
  96         sc.configureBlocking(false);
  97 
  98         // Complete connection.
  99         while (!sc.finishConnect()) {
 100             Thread.sleep(50);
 101             // waiting for the connection completed.
 102         }
 103 
 104         ByteBuffer buffer = ByteBuffer.allocate(0xFF);
 105         int position = 0;
 106         SSLCapabilities capabilities = null;
 107 
 108         // Read the header of TLS record
 109         buffer.limit(SSLExplorer.RECORD_HEADER_SIZE);
 110         while (position < SSLExplorer.RECORD_HEADER_SIZE) {
 111             int n = sc.read(buffer);
 112             if (n < 0) {
 113                 throw new Exception("unexpected end of stream!");
 114             }
 115             position += n;
 116         }
 117         buffer.flip();
 118 
 119         int recordLength = SSLExplorer.getRequiredSize(buffer);
 120         if (buffer.capacity() < recordLength) {
 121             ByteBuffer oldBuffer = buffer;
 122             buffer = ByteBuffer.allocate(recordLength);
 123             buffer.put(oldBuffer);
 124         }
 125 
 126         buffer.position(SSLExplorer.RECORD_HEADER_SIZE);
 127         buffer.limit(buffer.capacity());
 128         while (position < recordLength) {
 129             int n = sc.read(buffer);
 130             if (n < 0) {
 131                 throw new Exception("unexpected end of stream!");
 132             }
 133             position += n;
 134         }
 135         buffer.flip();
 136 
 137         capabilities = SSLExplorer.explore(buffer);
 138         if (capabilities != null) {
 139             System.out.println("Record version: " +
 140                     capabilities.getRecordVersion());
 141             System.out.println("Hello version: " +
 142                     capabilities.getHelloVersion());
 143         }
 144 
 145         // handshaking
 146         handshaking(ssle, sc, buffer);
 147 
 148         // receive application data
 149         receive(ssle, sc);
 150 
 151         // send out application data
 152         deliver(ssle, sc);
 153 
 154         ExtendedSSLSession session = (ExtendedSSLSession)ssle.getSession();
 155         checkCapabilities(capabilities, session);
 156 
 157         // close the socket channel.
 158         sc.close();
 159         ssc.close();
 160     }
 161 
 162     /*
 163      * Define the client side of the test.
 164      *
 165      * If the server prematurely exits, serverReady will be set to true
 166      * to avoid infinite hangs.
 167      */
 168     void doClientSide() throws Exception {
 169         // create SSLEngine.
 170         SSLEngine ssle = createSSLEngine(true);
 171 
 172         /*
 173          * Wait for server to get started.
 174          */
 175         while (!serverReady) {
 176             Thread.sleep(50);
 177         }
 178 
 179         // Create a non-blocking socket channel.
 180         SocketChannel sc = SocketChannel.open();
 181         sc.configureBlocking(false);
 182         InetSocketAddress isa =
 183                 new InetSocketAddress(InetAddress.getLocalHost(), serverPort);
 184         sc.connect(isa);
 185 
 186         // Complete connection.
 187         while (!sc.finishConnect() ) {
 188             Thread.sleep(50);
 189             // waiting for the connection completed.
 190         }
 191 
 192         // enable the specified TLS protocol
 193         ssle.setEnabledProtocols(supportedProtocols);
 194 
 195         // handshaking
 196         handshaking(ssle, sc, null);
 197 
 198         // send out application data
 199         deliver(ssle, sc);
 200 
 201         // receive application data
 202         receive(ssle, sc);
 203 
 204         // close the socket channel.
 205         sc.close();
 206     }
 207 
 208     void checkCapabilities(SSLCapabilities capabilities,
 209             ExtendedSSLSession session) throws Exception {
 210 
 211         List<SNIServerName> sessionSNI = session.getRequestedServerNames();
 212         if (!sessionSNI.equals(capabilities.getServerNames())) {
 213             throw new Exception(
 214                     "server name indication does not match capabilities");
 215         }
 216     }
 217 
 218     private static String[] supportedProtocols;    // supported protocols
 219 
 220     private static void parseArguments(String[] args) {
 221         supportedProtocols = args[0].split(",");
 222     }
 223 
 224 
 225     /*
 226      * =============================================================
 227      * The remainder is just support stuff
 228      */
 229     volatile Exception serverException = null;
 230     volatile Exception clientException = null;
 231 
 232     // use any free port by default
 233     volatile int serverPort = 0;
 234 
 235     public static void main(String args[]) throws Exception {
 236         // reset the security property to make sure that the algorithms
 237         // and keys used in this test are not disabled.
 238         Security.setProperty("jdk.tls.disabledAlgorithms", "");
 239 
 240         if (debug)
 241             System.setProperty("javax.net.debug", "all");
 242 
 243         /*
 244          * Get the customized arguments.
 245          */
 246         parseArguments(args);
 247 
 248         new SSLEngineExplorer();
 249     }
 250 
 251     Thread clientThread = null;
 252     Thread serverThread = null;
 253 
 254     /*
 255      * Primary constructor, used to drive remainder of the test.
 256      *
 257      * Fork off the other side, then do your work.
 258      */
 259     SSLEngineExplorer() throws Exception {
 260         super("../etc");
 261 
 262         if (separateServerThread) {
 263             startServer(true);
 264             startClient(false);
 265         } else {
 266             startClient(true);
 267             startServer(false);
 268         }
 269 
 270         /*
 271          * Wait for other side to close down.
 272          */
 273         if (separateServerThread) {
 274             serverThread.join();
 275         } else {
 276             clientThread.join();
 277         }
 278 
 279         /*
 280          * When we get here, the test is pretty much over.
 281          *
 282          * If the main thread excepted, that propagates back
 283          * immediately.  If the other thread threw an exception, we
 284          * should report back.
 285          */
 286         if (serverException != null) {
 287             System.out.print("Server Exception:");
 288             throw serverException;
 289         }
 290         if (clientException != null) {
 291             System.out.print("Client Exception:");
 292             throw clientException;
 293         }
 294     }
 295 
 296     void startServer(boolean newThread) throws Exception {
 297         if (newThread) {
 298             serverThread = new Thread() {
 299                 public void run() {
 300                     try {
 301                         doServerSide();
 302                     } catch (Exception e) {
 303                         /*
 304                          * Our server thread just died.
 305                          *
 306                          * Release the client, if not active already...
 307                          */
 308                         System.err.println("Server died...");
 309                         System.err.println(e);
 310                         serverReady = true;
 311                         serverException = e;
 312                     }
 313                 }
 314             };
 315             serverThread.start();
 316         } else {
 317             doServerSide();
 318         }
 319     }
 320 
 321     void startClient(boolean newThread) throws Exception {
 322         if (newThread) {
 323             clientThread = new Thread() {
 324                 public void run() {
 325                     try {
 326                         doClientSide();
 327                     } catch (Exception e) {
 328                         /*
 329                          * Our client thread just died.
 330                          */
 331                         System.err.println("Client died...");
 332                         clientException = e;
 333                     }
 334                 }
 335             };
 336             clientThread.start();
 337         } else {
 338             doClientSide();
 339         }
 340     }
 341 }