1 /* 2 * Copyright (c) 2011, 2016, 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 7031830 32 * @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine 33 * @run main/othervm SSLEngineBadBufferArrayAccess 34 */ 35 36 /** 37 * A SSLSocket/SSLEngine interop test case. This is not the way to 38 * code SSLEngine-based servers, but works for what we need to do here, 39 * which is to make sure that SSLEngine/SSLSockets can talk to each other. 40 * SSLEngines can use direct or indirect buffers, and different code 41 * is used to get at the buffer contents internally, so we test that here. 42 * 43 * The test creates one SSLSocket (client) and one SSLEngine (server). 44 * The SSLSocket talks to a raw ServerSocket, and the server code 45 * does the translation between byte [] and ByteBuffers that the SSLEngine 46 * can use. The "transport" layer consists of a Socket Input/OutputStream 47 * and two byte buffers for the SSLEngines: think of them 48 * as directly connected pipes. 49 * 50 * Again, this is a *very* simple example: real code will be much more 51 * involved. For example, different threading and I/O models could be 52 * used, transport mechanisms could close unexpectedly, and so on. 53 * 54 * When this application runs, notice that several messages 55 * (wrap/unwrap) pass before any application data is consumed or 56 * produced. (For more information, please see the SSL/TLS 57 * specifications.) There may several steps for a successful handshake, 58 * so it's typical to see the following series of operations: 59 * 60 * client server message 61 * ====== ====== ======= 62 * write() ... ClientHello 63 * ... unwrap() ClientHello 64 * ... wrap() ServerHello/Certificate 65 * read() ... ServerHello/Certificate 66 * write() ... ClientKeyExchange 67 * write() ... ChangeCipherSpec 68 * write() ... Finished 69 * ... unwrap() ClientKeyExchange 70 * ... unwrap() ChangeCipherSpec 71 * ... unwrap() Finished 72 * ... wrap() ChangeCipherSpec 73 * ... wrap() Finished 74 * read() ... ChangeCipherSpec 75 * read() ... Finished 76 * 77 * This particular bug had a problem where byte buffers backed by an 78 * array didn't offset correctly, and we got bad MAC errors. 79 */ 80 import javax.net.ssl.*; 81 import javax.net.ssl.SSLEngineResult.*; 82 import java.io.*; 83 import java.net.*; 84 import java.security.*; 85 import java.nio.*; 86 import java.util.concurrent.CountDownLatch; 87 import java.util.concurrent.TimeUnit; 88 89 public class SSLEngineBadBufferArrayAccess { 90 91 /* 92 * Enables logging of the SSL/TLS operations. 93 */ 94 private static boolean logging = true; 95 96 /* 97 * Enables the JSSE system debugging system property: 98 * 99 * -Djavax.net.debug=all 100 * 101 * This gives a lot of low-level information about operations underway, 102 * including specific handshake messages, and might be best examined 103 * after gaining some familiarity with this application. 104 */ 105 private static boolean debug = false; 106 private SSLContext sslc; 107 private SSLEngine serverEngine; // server-side SSLEngine 108 109 private final byte[] serverMsg = "Hi there Client, I'm a Server".getBytes(); 110 private final byte[] clientMsg = "Hello Server, I'm a Client".getBytes(); 111 112 private ByteBuffer serverOut; // write side of serverEngine 113 private ByteBuffer serverIn; // read side of serverEngine 114 115 private volatile Exception clientException; 116 private volatile Exception serverException; 117 118 /* 119 * For data transport, this example uses local ByteBuffers. 120 */ 121 private ByteBuffer cTOs; // "reliable" transport client->server 122 private ByteBuffer sTOc; // "reliable" transport server->client 123 124 /* 125 * The following is to set up the keystores/trust material. 126 */ 127 private static final String pathToStores = "../../../../javax/net/ssl/etc"; 128 private static final String keyStoreFile = "keystore"; 129 private static final String trustStoreFile = "truststore"; 130 private static final String passwd = "passphrase"; 131 private static String keyFilename = 132 System.getProperty("test.src", ".") + "/" + pathToStores 133 + "/" + keyStoreFile; 134 private static String trustFilename = 135 System.getProperty("test.src", ".") + "/" + pathToStores 136 + "/" + trustStoreFile; 137 138 /* 139 * Is the server ready to serve? 140 */ 141 private static final CountDownLatch serverCondition = new CountDownLatch(1); 142 143 /* 144 * Is the client ready to handshake? 145 */ 146 private static final CountDownLatch clientCondition = new CountDownLatch(1); 147 148 /* 149 * What's the server port? Use any free port by default 150 */ 151 private volatile int serverPort = 0; 152 153 /* 154 * Main entry point for this test. 155 */ 156 public static void main(String args[]) throws Exception { 157 if (debug) { 158 System.setProperty("javax.net.debug", "all"); 159 } 160 161 String [] protocols = new String [] { 162 "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" }; 163 164 for (String protocol : protocols) { 165 /* 166 * Run the tests with direct and indirect buffers. 167 */ 168 log("Testing " + protocol + ":true"); 169 new SSLEngineBadBufferArrayAccess(protocol).runTest(true); 170 171 log("Testing " + protocol + ":false"); 172 new SSLEngineBadBufferArrayAccess(protocol).runTest(false); 173 } 174 175 System.out.println("Test Passed."); 176 } 177 178 /* 179 * Create an initialized SSLContext to use for these tests. 180 */ 181 public SSLEngineBadBufferArrayAccess(String protocol) throws Exception { 182 183 KeyStore ks = KeyStore.getInstance("JKS"); 184 KeyStore ts = KeyStore.getInstance("JKS"); 185 186 char[] passphrase = "passphrase".toCharArray(); 187 188 try (FileInputStream fis = new FileInputStream(keyFilename)) { 189 ks.load(fis, passphrase); 190 } 191 192 try (FileInputStream fis = new FileInputStream(trustFilename)) { 193 ts.load(fis, passphrase); 194 } 195 196 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 197 kmf.init(ks, passphrase); 198 199 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 200 tmf.init(ts); 201 202 SSLContext sslCtx = SSLContext.getInstance(protocol); 203 204 sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 205 206 sslc = sslCtx; 207 } 208 209 /* 210 * Run the test. 211 * 212 * Sit in a tight loop, with the server engine calling wrap/unwrap 213 * regardless of whether data is available or not. We do this until 214 * we get the application data. Then we shutdown and go to the next one. 215 * 216 * The main loop handles all of the I/O phases of the SSLEngine's 217 * lifetime: 218 * 219 * initial handshaking 220 * application data transfer 221 * engine closing 222 * 223 * One could easily separate these phases into separate 224 * sections of code. 225 */ 226 private void runTest(boolean direct) throws Exception { 227 boolean serverClose = direct; 228 229 ServerSocket serverSocket = new ServerSocket(0); 230 serverPort = serverSocket.getLocalPort(); 231 232 // Signal the client, the server is ready to accept connection. 233 serverCondition.countDown(); 234 235 Thread clientThread = runClient(serverClose); 236 237 // Try to accept a connection in 30 seconds. 238 Socket socket; 239 try { 240 serverSocket.setSoTimeout(30000); 241 socket = (Socket) serverSocket.accept(); 242 } catch (SocketTimeoutException ste) { 243 serverSocket.close(); 244 245 // Ignore the test case if no connection within 30 seconds. 246 System.out.println( 247 "No incoming client connection in 30 seconds. " + 248 "Ignore in server side."); 249 return; 250 } 251 252 // handle the connection 253 try { 254 // Is it the expected client connection? 255 // 256 // Naughty test cases or third party routines may try to 257 // connection to this server port unintentionally. In 258 // order to mitigate the impact of unexpected client 259 // connections and avoid intermittent failure, it should 260 // be checked that the accepted connection is really linked 261 // to the expected client. 262 boolean clientIsReady = 263 clientCondition.await(30L, TimeUnit.SECONDS); 264 265 if (clientIsReady) { 266 // Run the application in server side. 267 runServerApplication(socket, direct, serverClose); 268 } else { // Otherwise, ignore 269 // We don't actually care about plain socket connections 270 // for TLS communication testing generally. Just ignore 271 // the test if the accepted connection is not linked to 272 // the expected client or the client connection timeout 273 // in 30 seconds. 274 System.out.println( 275 "The client is not the expected one or timeout. " + 276 "Ignore in server side."); 277 } 278 } catch (Exception e) { 279 System.out.println("Server died ..."); 280 e.printStackTrace(System.out); 281 serverException = e; 282 } finally { 283 socket.close(); 284 serverSocket.close(); 285 } 286 287 clientThread.join(); 288 289 if (clientException != null || serverException != null) { 290 throw new RuntimeException("Test failed"); 291 } 292 } 293 294 /* 295 * Define the server side application of the test for the specified socket. 296 */ 297 void runServerApplication(Socket socket, boolean direct, 298 boolean serverClose) throws Exception { 299 300 socket.setSoTimeout(500); 301 302 createSSLEngine(); 303 createBuffers(direct); 304 305 boolean closed = false; 306 307 InputStream is = socket.getInputStream(); 308 OutputStream os = socket.getOutputStream(); 309 310 SSLEngineResult serverResult; // results from last operation 311 312 /* 313 * Examining the SSLEngineResults could be much more involved, 314 * and may alter the overall flow of the application. 315 * 316 * For example, if we received a BUFFER_OVERFLOW when trying 317 * to write to the output pipe, we could reallocate a larger 318 * pipe, but instead we wait for the peer to drain it. 319 */ 320 byte[] inbound = new byte[8192]; 321 byte[] outbound = new byte[8192]; 322 323 while (!isEngineClosed(serverEngine)) { 324 int len = 0; 325 326 // Inbound data 327 log("================"); 328 329 // Read from the Client side. 330 try { 331 len = is.read(inbound); 332 if (len == -1) { 333 throw new Exception("Unexpected EOF"); 334 } 335 cTOs.put(inbound, 0, len); 336 } catch (SocketTimeoutException ste) { 337 // swallow. Nothing yet, probably waiting on us. 338 System.out.println("Warning: " + ste); 339 } 340 341 cTOs.flip(); 342 343 serverResult = serverEngine.unwrap(cTOs, serverIn); 344 log("server unwrap: ", serverResult); 345 runDelegatedTasks(serverResult, serverEngine); 346 cTOs.compact(); 347 348 // Outbound data 349 log("----"); 350 351 serverResult = serverEngine.wrap(serverOut, sTOc); 352 log("server wrap: ", serverResult); 353 runDelegatedTasks(serverResult, serverEngine); 354 355 sTOc.flip(); 356 357 if ((len = sTOc.remaining()) != 0) { 358 sTOc.get(outbound, 0, len); 359 os.write(outbound, 0, len); 360 // Give the other side a chance to process 361 } 362 363 sTOc.compact(); 364 365 if (!closed && (serverOut.remaining() == 0)) { 366 closed = true; 367 368 /* 369 * We'll alternate initiatating the shutdown. 370 * When the server initiates, it will take one more 371 * loop, but tests the orderly shutdown. 372 */ 373 if (serverClose) { 374 serverEngine.closeOutbound(); 375 } 376 } 377 378 if (closed && isEngineClosed(serverEngine)) { 379 serverIn.flip(); 380 381 /* 382 * A sanity check to ensure we got what was sent. 383 */ 384 if (serverIn.remaining() != clientMsg.length) { 385 throw new Exception("Client: Data length error -" + 386 " IF THIS FAILS, PLEASE REPORT THIS TO THE" + 387 " SECURITY TEAM. WE HAVE BEEN UNABLE TO" + 388 " RELIABLY DUPLICATE."); 389 } 390 391 for (int i = 0; i < clientMsg.length; i++) { 392 if (clientMsg[i] != serverIn.get()) { 393 throw new Exception("Client: Data content error -" + 394 " IF THIS FAILS, PLEASE REPORT THIS TO THE" + 395 " SECURITY TEAM. WE HAVE BEEN UNABLE TO" + 396 " RELIABLY DUPLICATE."); 397 } 398 } 399 serverIn.compact(); 400 } 401 } 402 } 403 404 /* 405 * Create a client thread which does simple SSLSocket operations. 406 * We'll write and read one data packet. 407 */ 408 private Thread runClient(final boolean serverClose) 409 throws Exception { 410 411 Thread t = new Thread("ClientThread") { 412 413 @Override 414 public void run() { 415 try { 416 doClientSide(serverClose); 417 } catch (Exception e) { 418 System.out.println("Client died ..."); 419 e.printStackTrace(System.out); 420 clientException = e; 421 } 422 } 423 }; 424 425 t.start(); 426 return t; 427 } 428 429 /* 430 * Define the client side of the test. 431 */ 432 void doClientSide(boolean serverClose) throws Exception { 433 // Wait for server to get started. 434 // 435 // The server side takes care of the issue if the server cannot 436 // get started in 90 seconds. The client side would just ignore 437 // the test case if the serer is not ready. 438 boolean serverIsReady = 439 serverCondition.await(90L, TimeUnit.SECONDS); 440 if (!serverIsReady) { 441 System.out.println( 442 "The server is not ready yet in 90 seconds. " + 443 "Ignore in client side."); 444 return; 445 } 446 447 SSLSocketFactory sslsf = sslc.getSocketFactory(); 448 try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) { 449 try { 450 sslSocket.connect( 451 new InetSocketAddress("localhost", serverPort), 15000); 452 } catch (IOException ioe) { 453 // The server side may be impacted by naughty test cases or 454 // third party routines, and cannot accept connections. 455 // 456 // Just ignore the test if the connection cannot be 457 // established. 458 System.out.println( 459 "Cannot make a connection in 15 seconds. " + 460 "Ignore in client side."); 461 return; 462 } 463 464 // OK, here the client and server get connected. 465 466 // Signal the server, the client is ready to communicate. 467 clientCondition.countDown(); 468 469 // There is still a chance in theory that the server thread may 470 // wait client-ready timeout and then quit. The chance should 471 // be really rare so we don't consider it until it becomes a 472 // real problem. 473 474 // Run the application in client side. 475 runClientApplication(sslSocket, serverClose); 476 } 477 } 478 479 /* 480 * Define the server side application of the test for the specified socket. 481 */ 482 void runClientApplication(SSLSocket sslSocket, boolean serverClose) 483 throws Exception { 484 485 OutputStream os = sslSocket.getOutputStream(); 486 InputStream is = sslSocket.getInputStream(); 487 488 // write(byte[]) goes in one shot. 489 os.write(clientMsg); 490 491 byte[] inbound = new byte[2048]; 492 int pos = 0; 493 494 int len; 495 while ((len = is.read(inbound, pos, 2048 - pos)) != -1) { 496 pos += len; 497 // Let the client do the closing. 498 if ((pos == serverMsg.length) && !serverClose) { 499 sslSocket.close(); 500 break; 501 } 502 } 503 504 if (pos != serverMsg.length) { 505 throw new Exception("Client: Data length error"); 506 } 507 508 for (int i = 0; i < serverMsg.length; i++) { 509 if (inbound[i] != serverMsg[i]) { 510 throw new Exception("Client: Data content error"); 511 } 512 } 513 } 514 515 /* 516 * Using the SSLContext created during object creation, 517 * create/configure the SSLEngines we'll use for this test. 518 */ 519 private void createSSLEngine() throws Exception { 520 /* 521 * Configure the serverEngine to act as a server in the SSL/TLS 522 * handshake. 523 */ 524 serverEngine = sslc.createSSLEngine(); 525 serverEngine.setUseClientMode(false); 526 serverEngine.getNeedClientAuth(); 527 } 528 529 /* 530 * Create and size the buffers appropriately. 531 */ 532 private void createBuffers(boolean direct) { 533 534 SSLSession session = serverEngine.getSession(); 535 int appBufferMax = session.getApplicationBufferSize(); 536 int netBufferMax = session.getPacketBufferSize(); 537 538 /* 539 * We'll make the input buffers a bit bigger than the max needed 540 * size, so that unwrap()s following a successful data transfer 541 * won't generate BUFFER_OVERFLOWS. 542 * 543 * We'll use a mix of direct and indirect ByteBuffers for 544 * tutorial purposes only. In reality, only use direct 545 * ByteBuffers when they give a clear performance enhancement. 546 */ 547 if (direct) { 548 serverIn = ByteBuffer.allocateDirect(appBufferMax + 50); 549 cTOs = ByteBuffer.allocateDirect(netBufferMax); 550 sTOc = ByteBuffer.allocateDirect(netBufferMax); 551 } else { 552 serverIn = ByteBuffer.allocate(appBufferMax + 50); 553 cTOs = ByteBuffer.allocate(netBufferMax); 554 sTOc = ByteBuffer.allocate(netBufferMax); 555 } 556 557 serverOut = ByteBuffer.wrap(serverMsg); 558 } 559 560 /* 561 * If the result indicates that we have outstanding tasks to do, 562 * go ahead and run them in this thread. 563 */ 564 private static void runDelegatedTasks(SSLEngineResult result, 565 SSLEngine engine) throws Exception { 566 567 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { 568 Runnable runnable; 569 while ((runnable = engine.getDelegatedTask()) != null) { 570 log("\trunning delegated task..."); 571 runnable.run(); 572 } 573 HandshakeStatus hsStatus = engine.getHandshakeStatus(); 574 if (hsStatus == HandshakeStatus.NEED_TASK) { 575 throw new Exception( 576 "handshake shouldn't need additional tasks"); 577 } 578 log("\tnew HandshakeStatus: " + hsStatus); 579 } 580 } 581 582 private static boolean isEngineClosed(SSLEngine engine) { 583 return (engine.isOutboundDone() && engine.isInboundDone()); 584 } 585 586 /* 587 * Logging code 588 */ 589 private static boolean resultOnce = true; 590 591 private static void log(String str, SSLEngineResult result) { 592 if (!logging) { 593 return; 594 } 595 if (resultOnce) { 596 resultOnce = false; 597 System.out.println("The format of the SSLEngineResult is: \n" 598 + "\t\"getStatus() / getHandshakeStatus()\" +\n" 599 + "\t\"bytesConsumed() / bytesProduced()\"\n"); 600 } 601 HandshakeStatus hsStatus = result.getHandshakeStatus(); 602 log(str 603 + result.getStatus() + "/" + hsStatus + ", " 604 + result.bytesConsumed() + "/" + result.bytesProduced() 605 + " bytes"); 606 if (hsStatus == HandshakeStatus.FINISHED) { 607 log("\t...ready for application data"); 608 } 609 } 610 611 private static void log(String str) { 612 if (logging) { 613 System.out.println(str); 614 } 615 } 616 }