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