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 }