1/* 2 * Copyright (c) 2004, 2013, 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 6207322 32 * @summary SSLEngine is returning a premature FINISHED message when doing 33 * an abbreviated handshake. 34 * @run main/othervm RehandshakeFinished 35 * @author Brad Wetmore 36 */ 37 38/* 39 * This test may need some updating if the messages change order. 40 * Currently I'm expecting that there is a simple renegotiation, with 41 * each message being contained in a single SSL packet. 42 * 43 * ClientHello 44 * Server Hello 45 * CCS 46 * FINISHED 47 * CCS 48 * FINISHED 49 */ 50 51/** 52 * A SSLEngine usage example which simplifies the presentation 53 * by removing the I/O and multi-threading concerns. 54 * 55 * The test creates two SSLEngines, simulating a client and server. 56 * The "transport" layer consists two byte buffers: think of them 57 * as directly connected pipes. 58 * 59 * Note, this is a *very* simple example: real code will be much more 60 * involved. For example, different threading and I/O models could be 61 * used, transport mechanisms could close unexpectedly, and so on. 62 * 63 * When this application runs, notice that several messages 64 * (wrap/unwrap) pass before any application data is consumed or 65 * produced. (For more information, please see the SSL/TLS 66 * specifications.) There may several steps for a successful handshake, 67 * so it's typical to see the following series of operations: 68 * 69 * client server message 70 * ====== ====== ======= 71 * wrap() ... ClientHello 72 * ... unwrap() ClientHello 73 * ... wrap() ServerHello/Certificate 74 * unwrap() ... ServerHello/Certificate 75 * wrap() ... ClientKeyExchange 76 * wrap() ... ChangeCipherSpec 77 * wrap() ... Finished 78 * ... unwrap() ClientKeyExchange 79 * ... unwrap() ChangeCipherSpec 80 * ... unwrap() Finished 81 * ... wrap() ChangeCipherSpec 82 * ... wrap() Finished 83 * unwrap() ... ChangeCipherSpec 84 * unwrap() ... Finished 85 */ 86 87import javax.net.ssl.*; 88import javax.net.ssl.SSLEngineResult.*; 89import java.io.*; 90import java.security.*; 91import java.nio.*; 92 93public class RehandshakeFinished { 94 95 /* 96 * Enables logging of the SSLEngine operations. 97 */ 98 private static boolean logging = true; 99 100 /* 101 * Enables the JSSE system debugging system property: 102 * 103 * -Djavax.net.debug=all 104 * 105 * This gives a lot of low-level information about operations underway, 106 * including specific handshake messages, and might be best examined 107 * after gaining some familiarity with this application. 108 */ 109 private static boolean debug = false; 110 111 static private SSLContext sslc; 112 113 private SSLEngine clientEngine; // client Engine 114 private ByteBuffer clientOut; // write side of clientEngine 115 private ByteBuffer clientIn; // read side of clientEngine 116 117 private SSLEngine serverEngine; // server Engine 118 private ByteBuffer serverOut; // write side of serverEngine 119 private ByteBuffer serverIn; // read side of serverEngine 120 121 /* 122 * For data transport, this example uses local ByteBuffers. This 123 * isn't really useful, but the purpose of this example is to show 124 * SSLEngine concepts, not how to do network transport. 125 */ 126 private ByteBuffer cTOs; // "reliable" transport client->server 127 private ByteBuffer sTOc; // "reliable" transport server->client 128 129 /* 130 * The following is to set up the keystores. 131 */ 132 private static String pathToStores = "../../../../javax/net/ssl/etc"; 133 private static String keyStoreFile = "keystore"; 134 private static String trustStoreFile = "truststore"; 135 private static String passwd = "passphrase"; 136 137 private static String keyFilename = 138 System.getProperty("test.src", "./") + "/" + pathToStores + 139 "/" + keyStoreFile; 140 private static String trustFilename = 141 System.getProperty("test.src", "./") + "/" + pathToStores + 142 "/" + trustStoreFile; 143 144 private static Exception loadException = null; 145 146 static { 147 try { 148 KeyStore ks = KeyStore.getInstance("JKS"); 149 KeyStore ts = KeyStore.getInstance("JKS"); 150 151 char[] passphrase = "passphrase".toCharArray(); 152 153 ks.load(new FileInputStream(keyFilename), passphrase); 154 ts.load(new FileInputStream(trustFilename), passphrase); 155 156 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 157 kmf.init(ks, passphrase); 158 159 TrustManagerFactory tmf = 160 TrustManagerFactory.getInstance("SunX509"); 161 tmf.init(ts); 162 163 SSLContext sslCtx = SSLContext.getInstance("TLS"); 164 sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 165 sslc = sslCtx; 166 } catch (Exception e) { 167 loadException = e; 168 } 169 } 170 171 /* 172 * Main entry point for this test. 173 */ 174 public static void main(String args[]) throws Exception { 175 if (debug) { 176 System.setProperty("javax.net.debug", "all"); 177 } 178 179 if (loadException != null) { 180 throw loadException; 181 } 182 183 // Prime the session cache with a good session 184 // Second connection should be a simple session resumption. 185 if ((new RehandshakeFinished().runTest()) != 186 new RehandshakeFinished().runRehandshake()) { 187 throw new Exception("Sessions not equivalent"); 188 } 189 190 System.out.println("Test Passed."); 191 } 192 193 private void checkResult(SSLEngine engine, SSLEngineResult result, 194 HandshakeStatus rqdHsStatus, 195 boolean consumed, boolean produced) throws Exception { 196 197 HandshakeStatus hsStatus = result.getHandshakeStatus(); 198 199 if (hsStatus == HandshakeStatus.NEED_TASK) { 200 Runnable runnable; 201 while ((runnable = engine.getDelegatedTask()) != null) { 202 runnable.run(); 203 } 204 hsStatus = engine.getHandshakeStatus(); 205 } 206 207 if (hsStatus != rqdHsStatus) { 208 throw new Exception("Required " + rqdHsStatus + 209 ", got " + hsStatus); 210 } 211 212 int bc = result.bytesConsumed(); 213 int bp = result.bytesProduced(); 214 215 if (consumed) { 216 if (bc <= 0) { 217 throw new Exception("Should have consumed bytes"); 218 } 219 } else { 220 if (bc > 0) { 221 throw new Exception("Should not have consumed bytes"); 222 } 223 } 224 225 if (produced) { 226 if (bp <= 0) { 227 throw new Exception("Should have produced bytes"); 228 } 229 } else { 230 if (bp > 0) { 231 throw new Exception("Should not have produced bytes"); 232 } 233 } 234 } 235 236 private SSLSession runRehandshake() throws Exception { 237 238 log("\n\n=============================================="); 239 log("Staring actual test."); 240 241 createSSLEngines(); 242 createBuffers(); 243 SSLEngineResult result; 244 245 log("Client's ClientHello"); 246 checkResult(clientEngine, 247 clientEngine.wrap(clientOut, cTOs), HandshakeStatus.NEED_UNWRAP, 248 false, true); 249 cTOs.flip(); 250 checkResult(serverEngine, 251 serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.NEED_WRAP, 252 true, false); 253 cTOs.compact(); 254 255 log("Server's ServerHello/ServerHelloDone"); 256 checkResult(serverEngine, 257 serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_WRAP, 258 false, true); 259 sTOc.flip(); 260 checkResult(clientEngine, 261 clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_UNWRAP, 262 true, false); 263 sTOc.compact(); 264 265 log("Server's CCS"); 266 checkResult(serverEngine, 267 serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_WRAP, 268 false, true); 269 sTOc.flip(); 270 checkResult(clientEngine, 271 clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_UNWRAP, 272 true, false); 273 sTOc.compact(); 274 275 log("Server's FINISHED"); 276 checkResult(serverEngine, 277 serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_UNWRAP, 278 false, true); 279 sTOc.flip(); 280 checkResult(clientEngine, 281 clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_WRAP, 282 true, false); 283 sTOc.compact(); 284 285 log("Client's CCS"); 286 checkResult(clientEngine, 287 clientEngine.wrap(clientOut, cTOs), HandshakeStatus.NEED_WRAP, 288 false, true); 289 cTOs.flip(); 290 checkResult(serverEngine, 291 serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.NEED_UNWRAP, 292 true, false); 293 cTOs.compact(); 294 295 log("Client's FINISHED should trigger FINISHED messages all around."); 296 checkResult(clientEngine, 297 clientEngine.wrap(clientOut, cTOs), HandshakeStatus.FINISHED, 298 false, true); 299 cTOs.flip(); 300 checkResult(serverEngine, 301 serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.FINISHED, 302 true, false); 303 cTOs.compact(); 304 305 return clientEngine.getSession(); 306 } 307 308 /* 309 * Run the test. 310 * 311 * Sit in a tight loop, both engines calling wrap/unwrap regardless 312 * of whether data is available or not. We do this until both engines 313 * report back they are closed. 314 * 315 * The main loop handles all of the I/O phases of the SSLEngine's 316 * lifetime: 317 * 318 * initial handshaking 319 * application data transfer 320 * engine closing 321 * 322 * One could easily separate these phases into separate 323 * sections of code. 324 */ 325 private SSLSession runTest() throws Exception { 326 boolean dataDone = false; 327 328 createSSLEngines(); 329 createBuffers(); 330 331 SSLEngineResult clientResult; // results from client's last operation 332 SSLEngineResult serverResult; // results from server's last operation 333 334 /* 335 * Examining the SSLEngineResults could be much more involved, 336 * and may alter the overall flow of the application. 337 * 338 * For example, if we received a BUFFER_OVERFLOW when trying 339 * to write to the output pipe, we could reallocate a larger 340 * pipe, but instead we wait for the peer to drain it. 341 */ 342 while (!isEngineClosed(clientEngine) || 343 !isEngineClosed(serverEngine)) { 344 345 log("================"); 346 347 clientResult = clientEngine.wrap(clientOut, cTOs); 348 log("client wrap: ", clientResult); 349 runDelegatedTasks(clientResult, clientEngine); 350 351 serverResult = serverEngine.wrap(serverOut, sTOc); 352 log("server wrap: ", serverResult); 353 runDelegatedTasks(serverResult, serverEngine); 354 355 cTOs.flip(); 356 sTOc.flip(); 357 358 log("----"); 359 360 clientResult = clientEngine.unwrap(sTOc, clientIn); 361 log("client unwrap: ", clientResult); 362 runDelegatedTasks(clientResult, clientEngine); 363 364 serverResult = serverEngine.unwrap(cTOs, serverIn); 365 log("server unwrap: ", serverResult); 366 runDelegatedTasks(serverResult, serverEngine); 367 368 cTOs.compact(); 369 sTOc.compact(); 370 371 /* 372 * After we've transfered all application data between the client 373 * and server, we close the clientEngine's outbound stream. 374 * This generates a close_notify handshake message, which the 375 * server engine receives and responds by closing itself. 376 */ 377 if (!dataDone && (clientOut.limit() == serverIn.position()) && 378 (serverOut.limit() == clientIn.position())) { 379 380 /* 381 * A sanity check to ensure we got what was sent. 382 */ 383 checkTransfer(serverOut, clientIn); 384 checkTransfer(clientOut, serverIn); 385 386 log("\tClosing clientEngine's *OUTBOUND*..."); 387 clientEngine.closeOutbound(); 388 dataDone = true; 389 } 390 } 391 392 return clientEngine.getSession(); 393 } 394 395 /* 396 * Using the SSLContext created during object creation, 397 * create/configure the SSLEngines we'll use for this test. 398 */ 399 private void createSSLEngines() throws Exception { 400 /* 401 * Configure the serverEngine to act as a server in the SSL/TLS 402 * handshake. Also, require SSL client authentication. 403 */ 404 serverEngine = sslc.createSSLEngine(); 405 serverEngine.setUseClientMode(false); 406 serverEngine.setNeedClientAuth(true); 407 408 /* 409 * Similar to above, but using client mode instead. 410 */ 411 clientEngine = sslc.createSSLEngine("client", 80); 412 clientEngine.setUseClientMode(true); 413 } 414 415 /* 416 * Create and size the buffers appropriately. 417 */ 418 private void createBuffers() { 419 420 /* 421 * We'll assume the buffer sizes are the same 422 * between client and server. 423 */ 424 SSLSession session = clientEngine.getSession(); 425 int appBufferMax = session.getApplicationBufferSize(); 426 int netBufferMax = session.getPacketBufferSize(); 427 428 /* 429 * We'll make the input buffers a bit bigger than the max needed 430 * size, so that unwrap()s following a successful data transfer 431 * won't generate BUFFER_OVERFLOWS. 432 * 433 * We'll use a mix of direct and indirect ByteBuffers for 434 * tutorial purposes only. In reality, only use direct 435 * ByteBuffers when they give a clear performance enhancement. 436 */ 437 clientIn = ByteBuffer.allocate(appBufferMax + 50); 438 serverIn = ByteBuffer.allocate(appBufferMax + 50); 439 440 cTOs = ByteBuffer.allocateDirect(netBufferMax); 441 sTOc = ByteBuffer.allocateDirect(netBufferMax); 442 443 clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes()); 444 serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes()); 445 } 446 447 /* 448 * If the result indicates that we have outstanding tasks to do, 449 * go ahead and run them in this thread. 450 */ 451 private static void runDelegatedTasks(SSLEngineResult result, 452 SSLEngine engine) throws Exception { 453 454 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 455 Runnable runnable; 456 while ((runnable = engine.getDelegatedTask()) != null) { 457 log("\trunning delegated task..."); 458 runnable.run(); 459 } 460 HandshakeStatus hsStatus = engine.getHandshakeStatus(); 461 if (hsStatus == HandshakeStatus.NEED_TASK) { 462 throw new Exception( 463 "handshake shouldn't need additional tasks"); 464 } 465 log("\tnew HandshakeStatus: " + hsStatus); 466 } 467 } 468 469 private static boolean isEngineClosed(SSLEngine engine) { 470 return (engine.isOutboundDone() && engine.isInboundDone()); 471 } 472 473 /* 474 * Simple check to make sure everything came across as expected. 475 */ 476 private static void checkTransfer(ByteBuffer a, ByteBuffer b) 477 throws Exception { 478 a.flip(); 479 b.flip(); 480 481 if (!a.equals(b)) { 482 throw new Exception("Data didn't transfer cleanly"); 483 } else { 484 log("\tData transferred cleanly"); 485 } 486 487 a.position(a.limit()); 488 b.position(b.limit()); 489 a.limit(a.capacity()); 490 b.limit(b.capacity()); 491 } 492 493 /* 494 * Logging code 495 */ 496 private static boolean resultOnce = true; 497 498 private static void log(String str, SSLEngineResult result) { 499 if (!logging) { 500 return; 501 } 502 if (resultOnce) { 503 resultOnce = false; 504 System.out.println("The format of the SSLEngineResult is: \n" + 505 "\t\"getStatus() / getHandshakeStatus()\" +\n" + 506 "\t\"bytesConsumed() / bytesProduced()\"\n"); 507 } 508 HandshakeStatus hsStatus = result.getHandshakeStatus(); 509 log(str + 510 result.getStatus() + "/" + hsStatus + ", " + 511 result.bytesConsumed() + "/" + result.bytesProduced() + 512 " bytes"); 513 if (hsStatus == HandshakeStatus.FINISHED) { 514 log("\t...ready for application data"); 515 } 516 } 517 518 private static void log(String str) { 519 if (logging) { 520 System.out.println(str); 521 } 522 } 523} 524