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 ../templates 34 * @build SSLCapabilities SSLExplorer 35 * @run main/othervm SSLSocketExplorer SSLv2Hello,SSLv3 36 * @run main/othervm SSLSocketExplorer SSLv3 37 * @run main/othervm SSLSocketExplorer TLSv1 38 * @run main/othervm SSLSocketExplorer TLSv1.1 39 * @run main/othervm SSLSocketExplorer TLSv1.2 40 */ 41 42 import java.io.*; 43 import java.nio.*; 44 import java.nio.channels.*; 45 import java.util.*; 46 import java.net.*; 47 import javax.net.ssl.*; 48 import java.security.Security; 49 50 public class SSLSocketExplorer { 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 113 // Read the header of TLS record 114 while (position < SSLExplorer.RECORD_HEADER_SIZE) { 115 int count = SSLExplorer.RECORD_HEADER_SIZE - position; 116 int n = ins.read(buffer, position, count); 117 if (n < 0) { 118 throw new Exception("unexpected end of stream!"); 119 } 120 position += n; 121 } 122 123 int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position); 124 if (buffer.length < recordLength) { 125 buffer = Arrays.copyOf(buffer, recordLength); 126 } 127 128 while (position < recordLength) { 129 int count = recordLength - position; 130 int n = ins.read(buffer, position, count); 131 if (n < 0) { 132 throw new Exception("unexpected end of stream!"); 133 } 134 position += n; 135 } 136 137 capabilities = SSLExplorer.explore(buffer, 0, recordLength);; 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 SSLSocketFactory sslsf = 146 (SSLSocketFactory) SSLSocketFactory.getDefault(); 147 ByteArrayInputStream bais = 148 new ByteArrayInputStream(buffer, 0, position); 149 SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(socket, bais, true); 150 151 InputStream sslIS = sslSocket.getInputStream(); 152 OutputStream sslOS = sslSocket.getOutputStream(); 153 154 sslIS.read(); 155 sslOS.write(85); 156 sslOS.flush(); 157 158 ExtendedSSLSession session = (ExtendedSSLSession)sslSocket.getSession(); 159 checkCapabilities(capabilities, session); 160 161 sslSocket.close(); 162 serverSocket.close(); 163 } 164 165 166 /* 167 * Define the client side of the test. 168 * 169 * If the server prematurely exits, serverReady will be set to true 170 * to avoid infinite hangs. 171 */ 172 void doClientSide() throws Exception { 173 174 /* 175 * Wait for server to get started. 176 */ 177 while (!serverReady) { 178 Thread.sleep(50); 179 } 180 181 SSLSocketFactory sslsf = 182 (SSLSocketFactory) SSLSocketFactory.getDefault(); 183 SSLSocket sslSocket = (SSLSocket) 184 sslsf.createSocket("localhost", serverPort); 185 186 // enable the specified TLS protocol 187 sslSocket.setEnabledProtocols(supportedProtocols); 188 189 InputStream sslIS = sslSocket.getInputStream(); 190 OutputStream sslOS = sslSocket.getOutputStream(); 191 192 sslOS.write(280); 193 sslOS.flush(); 194 sslIS.read(); 195 196 sslSocket.close(); 197 } 198 199 void checkCapabilities(SSLCapabilities capabilities, 200 ExtendedSSLSession session) throws Exception { 201 202 List<SNIServerName> sessionSNI = session.getRequestedServerNames(); 203 if (!sessionSNI.equals(capabilities.getServerNames())) { 204 throw new Exception( 205 "server name indication does not match capabilities"); 206 } 207 } 208 209 private static String[] supportedProtocols; // supported protocols 210 211 private static void parseArguments(String[] args) { 212 supportedProtocols = args[0].split(","); 213 } 214 215 216 /* 217 * ============================================================= 218 * The remainder is just support stuff 219 */ 220 221 // use any free port by default 222 volatile int serverPort = 0; 223 224 volatile Exception serverException = null; 225 volatile Exception clientException = null; 226 227 public static void main(String[] args) throws Exception { 228 // reset the security property to make sure that the algorithms 229 // and keys used in this test are not disabled. 230 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 231 232 String keyFilename = 233 System.getProperty("test.src", ".") + "/" + pathToStores + 234 "/" + keyStoreFile; 235 String trustFilename = 236 System.getProperty("test.src", ".") + "/" + pathToStores + 237 "/" + trustStoreFile; 238 239 System.setProperty("javax.net.ssl.keyStore", keyFilename); 240 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 241 System.setProperty("javax.net.ssl.trustStore", trustFilename); 242 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 243 244 if (debug) 245 System.setProperty("javax.net.debug", "all"); 246 247 /* 248 * Get the customized arguments. 249 */ 250 parseArguments(args); 251 252 /* 253 * Start the tests. 254 */ 255 new SSLSocketExplorer(); 256 } 257 258 Thread clientThread = null; 259 Thread serverThread = null; 260 261 /* 262 * Primary constructor, used to drive remainder of the test. 263 * 264 * Fork off the other side, then do your work. 265 */ 266 SSLSocketExplorer() throws Exception { 267 try { 268 if (separateServerThread) { 269 startServer(true); 270 startClient(false); 271 } else { 272 startClient(true); 273 startServer(false); 274 } 275 } catch (Exception e) { 276 // swallow for now. Show later 277 } 278 279 /* 280 * Wait for other side to close down. 281 */ 282 if (separateServerThread) { 283 serverThread.join(); 284 } else { 285 clientThread.join(); 286 } 287 288 /* 289 * When we get here, the test is pretty much over. 290 * Which side threw the error? 291 */ 292 Exception local; 293 Exception remote; 294 String whichRemote; 295 296 if (separateServerThread) { 297 remote = serverException; 298 local = clientException; 299 whichRemote = "server"; 300 } else { 301 remote = clientException; 302 local = serverException; 303 whichRemote = "client"; 304 } 305 306 /* 307 * If both failed, return the curthread's exception, but also 308 * print the remote side Exception 309 */ 310 if ((local != null) && (remote != null)) { 311 System.out.println(whichRemote + " also threw:"); 312 remote.printStackTrace(); 313 System.out.println(); 314 throw local; 315 } 316 317 if (remote != null) { 318 throw remote; 319 } 320 321 if (local != null) { 322 throw local; 323 } 324 } 325 326 void startServer(boolean newThread) throws Exception { 327 if (newThread) { 328 serverThread = new Thread() { 329 public void run() { 330 try { 331 doServerSide(); 332 } catch (Exception e) { 333 /* 334 * Our server thread just died. 335 * 336 * Release the client, if not active already... 337 */ 338 System.err.println("Server died..."); 339 serverReady = true; 340 serverException = e; 341 } 342 } 343 }; 344 serverThread.start(); 345 } else { 346 try { 347 doServerSide(); 348 } catch (Exception e) { 349 serverException = e; 350 } finally { 351 serverReady = true; 352 } 353 } 354 } 355 356 void startClient(boolean newThread) throws Exception { 357 if (newThread) { 358 clientThread = new Thread() { 359 public void run() { 360 try { 361 doClientSide(); 362 } catch (Exception e) { 363 /* 364 * Our client thread just died. 365 */ 366 System.err.println("Client died..."); 367 clientException = e; 368 } 369 } 370 }; 371 clientThread.start(); 372 } else { 373 try { 374 doClientSide(); 375 } catch (Exception e) { 376 clientException = e; 377 } 378 } 379 } 380 }