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 ../templates
  34  * @modules java.base/sun.misc
  35  * @build SSLCapabilities SSLExplorer
  36  * @run main/othervm SSLSocketExplorerFailure SSLv2Hello,SSLv3
  37  * @run main/othervm SSLSocketExplorerFailure SSLv3
  38  * @run main/othervm SSLSocketExplorerFailure TLSv1
  39  * @run main/othervm SSLSocketExplorerFailure TLSv1.1
  40  * @run main/othervm SSLSocketExplorerFailure TLSv1.2
  41  */
  42 
  43 import java.io.*;
  44 import java.nio.*;
  45 import java.nio.channels.*;
  46 import java.util.*;
  47 import java.net.*;
  48 import javax.net.ssl.*;
  49 
  50 public class SSLSocketExplorerFailure {
  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     /*
  66      * Where do we find the keystores?
  67      */
  68     static String pathToStores = "../etc";
  69     static String keyStoreFile = "keystore";
  70     static String trustStoreFile = "truststore";
  71     static String passwd = "passphrase";
  72 
  73     /*
  74      * Is the server ready to serve?
  75      */
  76     volatile static boolean serverReady = false;
  77 
  78     /*
  79      * Turn on SSL debugging?
  80      */
  81     static boolean debug = false;
  82 
  83     /*
  84      * If the client or server is doing some kind of object creation
  85      * that the other side depends on, and that thread prematurely
  86      * exits, you may experience a hang.  The test harness will
  87      * terminate all hung threads after its timeout has expired,
  88      * currently 3 minutes by default, but you might try to be
  89      * smart about it....
  90      */
  91 
  92     /*
  93      * Define the server side of the test.
  94      *
  95      * If the server prematurely exits, serverReady will be set to true
  96      * to avoid infinite hangs.
  97      */
  98     void doServerSide() throws Exception {
  99 
 100         ServerSocket serverSocket = new ServerSocket(serverPort);
 101 
 102         // Signal Client, we're ready for his connect.
 103         serverPort = serverSocket.getLocalPort();
 104         serverReady = true;
 105 
 106         Socket socket = serverSocket.accept();
 107         InputStream ins = socket.getInputStream();
 108 
 109         byte[] buffer = new byte[0xFF];
 110         int position = 0;
 111         SSLCapabilities capabilities = null;
 112         boolean failed = false;
 113         try {
 114             // Read the header of TLS record
 115             while (position < SSLExplorer.RECORD_HEADER_SIZE) {
 116                 int count = SSLExplorer.RECORD_HEADER_SIZE - position;
 117                 int n = ins.read(buffer, position, count);
 118                 if (n < 0) {
 119                     throw new Exception("unexpected end of stream!");
 120                 }
 121                 position += n;
 122             }
 123 
 124             int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position);
 125             if (buffer.length < recordLength) {
 126                 buffer = Arrays.copyOf(buffer, recordLength);
 127             }
 128 
 129             while (position < recordLength) {
 130                 int count = recordLength - position;
 131                 int n = ins.read(buffer, position, count);
 132                 if (n < 0) {
 133                     throw new Exception("unexpected end of stream!");
 134                 }
 135                 position += n;
 136             }
 137 
 138             capabilities = SSLExplorer.explore(buffer, 0, recordLength);;
 139             if (capabilities != null) {
 140                 System.out.println("Record version: " +
 141                         capabilities.getRecordVersion());
 142                 System.out.println("Hello version: " +
 143                         capabilities.getHelloVersion());
 144             }
 145 
 146             // want an I/O exception
 147             throw new IOException("We just want a I/O exception");
 148         } catch (Exception e) {
 149             failed =  true;
 150         }
 151 
 152         // off course, the above explore failed. Faile to failure handler
 153         SSLContext context = SSLContext.getInstance("TLS");
 154         context.init(null, null, null);
 155         SSLSocketFactory sslsf = context.getSocketFactory();
 156         ByteArrayInputStream bais =
 157             new ByteArrayInputStream(buffer, 0, position);
 158         SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(socket, bais, true);
 159 
 160         try {
 161             InputStream sslIS = sslSocket.getInputStream();
 162             OutputStream sslOS = sslSocket.getOutputStream();
 163 
 164             sslIS.read();
 165             if (!failed) {
 166                 sslOS.write(85);
 167                 sslOS.flush();
 168             } else {
 169                 sslSocket.close();
 170             }
 171         } catch (Exception e) {
 172             System.out.println("server exception " + e);
 173         } finally {
 174             sslSocket.close();
 175             serverSocket.close();
 176         }
 177     }
 178 
 179 
 180     /*
 181      * Define the client side of the test.
 182      *
 183      * If the server prematurely exits, serverReady will be set to true
 184      * to avoid infinite hangs.
 185      */
 186     void doClientSide() throws Exception {
 187 
 188         /*
 189          * Wait for server to get started.
 190          */
 191         while (!serverReady) {
 192             Thread.sleep(50);
 193         }
 194 
 195         SSLSocketFactory sslsf =
 196             (SSLSocketFactory) SSLSocketFactory.getDefault();
 197         SSLSocket sslSocket = (SSLSocket)
 198             sslsf.createSocket("localhost", serverPort);
 199 
 200         // enable the specified TLS protocol
 201         sslSocket.setEnabledProtocols(supportedProtocols);
 202 
 203         try {
 204             InputStream sslIS = sslSocket.getInputStream();
 205             OutputStream sslOS = sslSocket.getOutputStream();
 206 
 207             sslOS.write(280);
 208             sslOS.flush();
 209             sslIS.read();
 210         } catch (Exception e) {
 211             System.out.println("client exception " + e);
 212         } finally {
 213             sslSocket.close();
 214         }
 215     }
 216 
 217     private static String[] supportedProtocols;    // supported protocols
 218 
 219     private static void parseArguments(String[] args) {
 220         supportedProtocols = args[0].split(",");
 221     }
 222 
 223 
 224     /*
 225      * =============================================================
 226      * The remainder is just support stuff
 227      */
 228 
 229     // use any free port by default
 230     volatile int serverPort = 0;
 231 
 232     volatile Exception serverException = null;
 233     volatile Exception clientException = null;
 234 
 235     public static void main(String[] args) throws Exception {
 236         String keyFilename =
 237             System.getProperty("test.src", ".") + "/" + pathToStores +
 238                 "/" + keyStoreFile;
 239         String trustFilename =
 240             System.getProperty("test.src", ".") + "/" + pathToStores +
 241                 "/" + trustStoreFile;
 242 
 243         System.setProperty("javax.net.ssl.keyStore", keyFilename);
 244         System.setProperty("javax.net.ssl.keyStorePassword", passwd);
 245         System.setProperty("javax.net.ssl.trustStore", trustFilename);
 246         System.setProperty("javax.net.ssl.trustStorePassword", passwd);
 247 
 248         if (debug)
 249             System.setProperty("javax.net.debug", "all");
 250 
 251         /*
 252          * Get the customized arguments.
 253          */
 254         parseArguments(args);
 255 
 256         /*
 257          * Start the tests.
 258          */
 259         new SSLSocketExplorerFailure();
 260     }
 261 
 262     Thread clientThread = null;
 263     Thread serverThread = null;
 264 
 265     /*
 266      * Primary constructor, used to drive remainder of the test.
 267      *
 268      * Fork off the other side, then do your work.
 269      */
 270     SSLSocketExplorerFailure() throws Exception {
 271         try {
 272             if (separateServerThread) {
 273                 startServer(true);
 274                 startClient(false);
 275             } else {
 276                 startClient(true);
 277                 startServer(false);
 278             }
 279         } catch (Exception e) {
 280             // swallow for now.  Show later
 281         }
 282 
 283         /*
 284          * Wait for other side to close down.
 285          */
 286         if (separateServerThread) {
 287             serverThread.join();
 288         } else {
 289             clientThread.join();
 290         }
 291 
 292         /*
 293          * When we get here, the test is pretty much over.
 294          * Which side threw the error?
 295          */
 296         Exception local;
 297         Exception remote;
 298         String whichRemote;
 299 
 300         if (separateServerThread) {
 301             remote = serverException;
 302             local = clientException;
 303             whichRemote = "server";
 304         } else {
 305             remote = clientException;
 306             local = serverException;
 307             whichRemote = "client";
 308         }
 309 
 310         /*
 311          * If both failed, return the curthread's exception, but also
 312          * print the remote side Exception
 313          */
 314         if ((local != null) && (remote != null)) {
 315             System.out.println(whichRemote + " also threw:");
 316             remote.printStackTrace();
 317             System.out.println();
 318             throw local;
 319         }
 320 
 321         if (remote != null) {
 322             throw remote;
 323         }
 324 
 325         if (local != null) {
 326             throw local;
 327         }
 328     }
 329 
 330     void startServer(boolean newThread) throws Exception {
 331         if (newThread) {
 332             serverThread = new Thread() {
 333                 public void run() {
 334                     try {
 335                         doServerSide();
 336                     } catch (Exception e) {
 337                         /*
 338                          * Our server thread just died.
 339                          *
 340                          * Release the client, if not active already...
 341                          */
 342                         System.err.println("Server died...");
 343                         serverReady = true;
 344                         serverException = e;
 345                     }
 346                 }
 347             };
 348             serverThread.start();
 349         } else {
 350             try {
 351                 doServerSide();
 352             } catch (Exception e) {
 353                 serverException = e;
 354             } finally {
 355                 serverReady = true;
 356             }
 357         }
 358     }
 359 
 360     void startClient(boolean newThread) throws Exception {
 361         if (newThread) {
 362             clientThread = new Thread() {
 363                 public void run() {
 364                     try {
 365                         doClientSide();
 366                     } catch (Exception e) {
 367                         /*
 368                          * Our client thread just died.
 369                          */
 370                         System.err.println("Client died...");
 371                         clientException = e;
 372                     }
 373                 }
 374             };
 375             clientThread.start();
 376         } else {
 377             try {
 378                 doClientSide();
 379             } catch (Exception e) {
 380                 clientException = e;
 381             }
 382         }
 383     }
 384 }