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