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 } --- EOF ---