1 /*
   2  * Copyright (c) 2015, 2020, 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  * @test
  26  * @bug 8044860
  27  * @summary Vectors and fixed length fields should be verified
  28  *          for allowed sizes.
  29  * @library /lib/security
  30  * @run main/othervm LengthCheckTest
  31  * @key randomness
  32  */
  33 
  34 /**
  35  * A SSLEngine usage example which simplifies the presentation
  36  * by removing the I/O and multi-threading concerns.
  37  *
  38  * The test creates two SSLEngines, simulating a client and server.
  39  * The "transport" layer consists two byte buffers:  think of them
  40  * as directly connected pipes.
  41  *
  42  * Note, this is a *very* simple example: real code will be much more
  43  * involved.  For example, different threading and I/O models could be
  44  * used, transport mechanisms could close unexpectedly, and so on.
  45  *
  46  * When this application runs, notice that several messages
  47  * (wrap/unwrap) pass before any application data is consumed or
  48  * produced.  (For more information, please see the SSL/TLS
  49  * specifications.)  There may several steps for a successful handshake,
  50  * so it's typical to see the following series of operations:
  51  *
  52  *      client          server          message
  53  *      ======          ======          =======
  54  *      wrap()          ...             ClientHello
  55  *      ...             unwrap()        ClientHello
  56  *      ...             wrap()          ServerHello/Certificate
  57  *      unwrap()        ...             ServerHello/Certificate
  58  *      wrap()          ...             ClientKeyExchange
  59  *      wrap()          ...             ChangeCipherSpec
  60  *      wrap()          ...             Finished
  61  *      ...             unwrap()        ClientKeyExchange
  62  *      ...             unwrap()        ChangeCipherSpec
  63  *      ...             unwrap()        Finished
  64  *      ...             wrap()          ChangeCipherSpec
  65  *      ...             wrap()          Finished
  66  *      unwrap()        ...             ChangeCipherSpec
  67  *      unwrap()        ...             Finished
  68  */
  69 
  70 import javax.net.ssl.*;
  71 import javax.net.ssl.SSLEngineResult.*;
  72 import java.io.*;
  73 import java.security.*;
  74 import java.nio.*;
  75 import java.util.List;
  76 import java.util.ArrayList;
  77 import java.util.Iterator;
  78 
  79 public class LengthCheckTest {
  80 
  81     /*
  82      * Enables logging of the SSLEngine operations.
  83      */
  84     private static final boolean logging = true;
  85 
  86     /*
  87      * Enables the JSSE system debugging system property:
  88      *
  89      *     -Djavax.net.debug=all
  90      *
  91      * This gives a lot of low-level information about operations underway,
  92      * including specific handshake messages, and might be best examined
  93      * after gaining some familiarity with this application.
  94      */
  95     private static final boolean debug = false;
  96     private static final boolean dumpBufs = true;
  97 
  98     private final SSLContext sslc;
  99 
 100     private SSLEngine clientEngine;     // client Engine
 101     private ByteBuffer clientOut;       // write side of clientEngine
 102     private ByteBuffer clientIn;        // read side of clientEngine
 103 
 104     private SSLEngine serverEngine;     // server Engine
 105     private ByteBuffer serverOut;       // write side of serverEngine
 106     private ByteBuffer serverIn;        // read side of serverEngine
 107 
 108     private HandshakeTest handshakeTest;
 109 
 110     /*
 111      * For data transport, this example uses local ByteBuffers.  This
 112      * isn't really useful, but the purpose of this example is to show
 113      * SSLEngine concepts, not how to do network transport.
 114      */
 115     private ByteBuffer cTOs;            // "reliable" transport client->server
 116     private ByteBuffer sTOc;            // "reliable" transport server->client
 117 
 118     /*
 119      * The following is to set up the keystores.
 120      */
 121     private static final String pathToStores = "../../../../javax/net/ssl/etc";
 122     private static final String keyStoreFile = "keystore";
 123     private static final String trustStoreFile = "truststore";
 124     private static final String passwd = "passphrase";
 125 
 126     private static final String keyFilename =
 127             System.getProperty("test.src", ".") + "/" + pathToStores +
 128                 "/" + keyStoreFile;
 129     private static final String trustFilename =
 130             System.getProperty("test.src", ".") + "/" + pathToStores +
 131                 "/" + trustStoreFile;
 132 
 133     // Define a few basic TLS record and message types we might need
 134     private static final int TLS_RECTYPE_CCS = 0x14;
 135     private static final int TLS_RECTYPE_ALERT = 0x15;
 136     private static final int TLS_RECTYPE_HANDSHAKE = 0x16;
 137     private static final int TLS_RECTYPE_APPDATA = 0x17;
 138 
 139     private static final int TLS_HS_HELLO_REQUEST = 0x00;
 140     private static final int TLS_HS_CLIENT_HELLO = 0x01;
 141     private static final int TLS_HS_SERVER_HELLO = 0x02;
 142     private static final int TLS_HS_CERTIFICATE = 0x0B;
 143     private static final int TLS_HS_SERVER_KEY_EXCHG = 0x0C;
 144     private static final int TLS_HS_CERT_REQUEST = 0x0D;
 145     private static final int TLS_HS_SERVER_HELLO_DONE = 0x0E;
 146     private static final int TLS_HS_CERT_VERIFY = 0x0F;
 147     private static final int TLS_HS_CLIENT_KEY_EXCHG = 0x10;
 148     private static final int TLS_HS_FINISHED = 0x14;
 149 
 150     // We're not going to define all the alert types in TLS, just
 151     // the ones we think we'll need to reference by name.
 152     private static final int TLS_ALERT_LVL_WARNING = 0x01;
 153     private static final int TLS_ALERT_LVL_FATAL = 0x02;
 154 
 155     private static final int TLS_ALERT_UNEXPECTED_MSG = 0x0A;
 156     private static final int TLS_ALERT_HANDSHAKE_FAILURE = 0x28;
 157     private static final int TLS_ALERT_INTERNAL_ERROR = 0x50;
 158     private static final int TLS_ALERT_ILLEGAL_PARAMETER = 0x2F;
 159 
 160     public interface HandshakeTest {
 161         void execTest() throws Exception;
 162     }
 163 
 164     public final HandshakeTest servSendLongID = new HandshakeTest() {
 165         @Override
 166         public void execTest() throws Exception {
 167             boolean gotException = false;
 168             SSLEngineResult clientResult;   // results from client's last op
 169             SSLEngineResult serverResult;   // results from server's last op
 170 
 171             log("\n==== Test: Client receives 64-byte session ID ====");
 172 
 173             // Send Client Hello
 174             clientResult = clientEngine.wrap(clientOut, cTOs);
 175             log("client wrap: ", clientResult);
 176             runDelegatedTasks(clientResult, clientEngine);
 177             cTOs.flip();
 178             dumpByteBuffer("CLIENT-TO-SERVER", cTOs);
 179 
 180             // Server consumes Client Hello
 181             serverResult = serverEngine.unwrap(cTOs, serverIn);
 182             log("server unwrap: ", serverResult);
 183             runDelegatedTasks(serverResult, serverEngine);
 184             cTOs.compact();
 185 
 186             // Server generates ServerHello/Cert/Done record
 187             serverResult = serverEngine.wrap(serverOut, sTOc);
 188             log("server wrap: ", serverResult);
 189             runDelegatedTasks(serverResult, serverEngine);
 190             sTOc.flip();
 191 
 192             // Intercept the ServerHello messages and instead send
 193             // one that has a 64-byte session ID.
 194             if (isTlsMessage(sTOc, TLS_RECTYPE_HANDSHAKE,
 195                         TLS_HS_SERVER_HELLO)) {
 196                 ArrayList<ByteBuffer> recList = splitRecord(sTOc);
 197 
 198                 // Use the original ServerHello as a template to craft one
 199                 // with a longer-than-allowed session ID.
 200                 ByteBuffer servHelloBuf =
 201                         createEvilServerHello(recList.get(0), 64);
 202 
 203                 recList.set(0, servHelloBuf);
 204 
 205                 // Now send each ByteBuffer (each being a complete
 206                 // TLS record) into the client-side unwrap.
 207                 // for (ByteBuffer bBuf : recList) {
 208 
 209                 Iterator<ByteBuffer> iter = recList.iterator();
 210                 while (!gotException && (iter.hasNext())) {
 211                     ByteBuffer bBuf = iter.next();
 212                     dumpByteBuffer("SERVER-TO-CLIENT", bBuf);
 213                     try {
 214                         clientResult = clientEngine.unwrap(bBuf, clientIn);
 215                     } catch (SSLProtocolException e) {
 216                         log("Received expected SSLProtocolException: " + e);
 217                         gotException = true;
 218                     }
 219                     log("client unwrap: ", clientResult);
 220                     runDelegatedTasks(clientResult, clientEngine);
 221                 }
 222             } else {
 223                 dumpByteBuffer("SERVER-TO-CLIENT", sTOc);
 224                 log("client unwrap: ", clientResult);
 225                 runDelegatedTasks(clientResult, clientEngine);
 226             }
 227             sTOc.compact();
 228 
 229             // The Client should now send a TLS Alert
 230             clientResult = clientEngine.wrap(clientOut, cTOs);
 231             log("client wrap: ", clientResult);
 232             runDelegatedTasks(clientResult, clientEngine);
 233             cTOs.flip();
 234             dumpByteBuffer("CLIENT-TO-SERVER", cTOs);
 235 
 236             // At this point we can verify that both an exception
 237             // was thrown and the proper action (a TLS alert) was
 238             // sent back to the server.
 239             if (gotException == false ||
 240                     !isTlsMessage(cTOs, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
 241                             TLS_ALERT_ILLEGAL_PARAMETER)) {
 242                 throw new SSLException(
 243                     "Client failed to throw Alert:fatal:internal_error");
 244             }
 245         }
 246     };
 247 
 248     public final HandshakeTest clientSendLongID = new HandshakeTest() {
 249         @Override
 250         public void execTest() throws Exception {
 251             boolean gotException = false;
 252             SSLEngineResult clientResult;   // results from client's last op
 253             SSLEngineResult serverResult;   // results from server's last op
 254 
 255             log("\n==== Test: Server receives 64-byte session ID ====");
 256 
 257             // Send Client Hello
 258             ByteBuffer evilClientHello = createEvilClientHello(64);
 259             dumpByteBuffer("CLIENT-TO-SERVER", evilClientHello);
 260 
 261             // Server consumes Client Hello
 262             serverResult = serverEngine.unwrap(evilClientHello, serverIn);
 263             log("server unwrap: ", serverResult);
 264             runDelegatedTasks(serverResult, serverEngine);
 265             evilClientHello.compact();
 266 
 267             // Under normal circumstances this should be a ServerHello
 268             // But should throw an exception instead due to the invalid
 269             // session ID.
 270             try {
 271                 serverResult = serverEngine.wrap(serverOut, sTOc);
 272                 log("server wrap: ", serverResult);
 273                 runDelegatedTasks(serverResult, serverEngine);
 274             } catch (SSLProtocolException ssle) {
 275                 log("Received expected SSLProtocolException: " + ssle);
 276                 gotException = true;
 277             }
 278 
 279             // We expect to see the server generate an alert here
 280             serverResult = serverEngine.wrap(serverOut, sTOc);
 281             log("server wrap: ", serverResult);
 282             runDelegatedTasks(serverResult, serverEngine);
 283             sTOc.flip();
 284             dumpByteBuffer("SERVER-TO-CLIENT", sTOc);
 285 
 286             // At this point we can verify that both an exception
 287             // was thrown and the proper action (a TLS alert) was
 288             // sent back to the client.
 289             if (gotException == false ||
 290                     !isTlsMessage(sTOc, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
 291                         TLS_ALERT_ILLEGAL_PARAMETER)) {
 292                 throw new SSLException(
 293                     "Server failed to throw Alert:fatal:internal_error");
 294             }
 295         }
 296     };
 297 
 298 
 299     /*
 300      * Main entry point for this test.
 301      */
 302     public static void main(String args[]) throws Exception {
 303         // Re-enable TLSv1 since test depends on it.
 304         SecurityUtils.removeFromDisabledTlsAlgs("TLSv1");
 305 
 306         List<LengthCheckTest> ccsTests = new ArrayList<>();
 307 
 308         if (debug) {
 309             System.setProperty("javax.net.debug", "ssl");
 310         }
 311 
 312         ccsTests.add(new LengthCheckTest("ServSendLongID"));
 313         ccsTests.add(new LengthCheckTest("ClientSendLongID"));
 314 
 315         for (LengthCheckTest test : ccsTests) {
 316             test.runTest();
 317         }
 318 
 319         System.out.println("Test Passed.");
 320     }
 321 
 322     /*
 323      * Create an initialized SSLContext to use for these tests.
 324      */
 325     public LengthCheckTest(String testName) throws Exception {
 326 
 327         KeyStore ks = KeyStore.getInstance("JKS");
 328         KeyStore ts = KeyStore.getInstance("JKS");
 329 
 330         char[] passphrase = "passphrase".toCharArray();
 331 
 332         ks.load(new FileInputStream(keyFilename), passphrase);
 333         ts.load(new FileInputStream(trustFilename), passphrase);
 334 
 335         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 336         kmf.init(ks, passphrase);
 337 
 338         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
 339         tmf.init(ts);
 340 
 341         SSLContext sslCtx = SSLContext.getInstance("TLS");
 342 
 343         sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 344 
 345         sslc = sslCtx;
 346 
 347         switch (testName) {
 348             case "ServSendLongID":
 349                 handshakeTest = servSendLongID;
 350                 break;
 351             case "ClientSendLongID":
 352                 handshakeTest = clientSendLongID;
 353                 break;
 354             default:
 355                 throw new IllegalArgumentException("Unknown test name: " +
 356                         testName);
 357         }
 358     }
 359 
 360     /*
 361      * Run the test.
 362      *
 363      * Sit in a tight loop, both engines calling wrap/unwrap regardless
 364      * of whether data is available or not.  We do this until both engines
 365      * report back they are closed.
 366      *
 367      * The main loop handles all of the I/O phases of the SSLEngine's
 368      * lifetime:
 369      *
 370      *     initial handshaking
 371      *     application data transfer
 372      *     engine closing
 373      *
 374      * One could easily separate these phases into separate
 375      * sections of code.
 376      */
 377     private void runTest() throws Exception {
 378         boolean dataDone = false;
 379 
 380         createSSLEngines();
 381         createBuffers();
 382 
 383         handshakeTest.execTest();
 384     }
 385 
 386     /*
 387      * Using the SSLContext created during object creation,
 388      * create/configure the SSLEngines we'll use for this test.
 389      */
 390     private void createSSLEngines() throws Exception {
 391         /*
 392          * Configure the serverEngine to act as a server in the SSL/TLS
 393          * handshake.  Also, require SSL client authentication.
 394          */
 395         serverEngine = sslc.createSSLEngine();
 396         serverEngine.setUseClientMode(false);
 397         serverEngine.setNeedClientAuth(false);
 398 
 399         /*
 400          * Similar to above, but using client mode instead.
 401          */
 402         clientEngine = sslc.createSSLEngine("client", 80);
 403         clientEngine.setUseClientMode(true);
 404 
 405         // In order to make a test that will be backwards compatible
 406         // going back to JDK 5, force the handshake to be TLS 1.0 and
 407         // use one of the older cipher suites.
 408         clientEngine.setEnabledProtocols(new String[]{"TLSv1"});
 409         clientEngine.setEnabledCipherSuites(
 410                 new String[]{"TLS_RSA_WITH_AES_128_CBC_SHA"});
 411     }
 412 
 413     /*
 414      * Create and size the buffers appropriately.
 415      */
 416     private void createBuffers() {
 417 
 418         /*
 419          * We'll assume the buffer sizes are the same
 420          * between client and server.
 421          */
 422         SSLSession session = clientEngine.getSession();
 423         int appBufferMax = session.getApplicationBufferSize();
 424         int netBufferMax = session.getPacketBufferSize();
 425 
 426         /*
 427          * We'll make the input buffers a bit bigger than the max needed
 428          * size, so that unwrap()s following a successful data transfer
 429          * won't generate BUFFER_OVERFLOWS.
 430          *
 431          * We'll use a mix of direct and indirect ByteBuffers for
 432          * tutorial purposes only.  In reality, only use direct
 433          * ByteBuffers when they give a clear performance enhancement.
 434          */
 435         clientIn = ByteBuffer.allocate(appBufferMax + 50);
 436         serverIn = ByteBuffer.allocate(appBufferMax + 50);
 437 
 438         cTOs = ByteBuffer.allocateDirect(netBufferMax);
 439         sTOc = ByteBuffer.allocateDirect(netBufferMax);
 440 
 441         clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
 442         serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
 443     }
 444 
 445     /*
 446      * If the result indicates that we have outstanding tasks to do,
 447      * go ahead and run them in this thread.
 448      */
 449     private static void runDelegatedTasks(SSLEngineResult result,
 450             SSLEngine engine) throws Exception {
 451 
 452         if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
 453             Runnable runnable;
 454             while ((runnable = engine.getDelegatedTask()) != null) {
 455                 log("\trunning delegated task...");
 456                 runnable.run();
 457             }
 458             HandshakeStatus hsStatus = engine.getHandshakeStatus();
 459             if (hsStatus == HandshakeStatus.NEED_TASK) {
 460                 throw new Exception(
 461                     "handshake shouldn't need additional tasks");
 462             }
 463             log("\tnew HandshakeStatus: " + hsStatus);
 464         }
 465     }
 466 
 467     private static boolean isEngineClosed(SSLEngine engine) {
 468         return (engine.isOutboundDone() && engine.isInboundDone());
 469     }
 470 
 471     /*
 472      * Simple check to make sure everything came across as expected.
 473      */
 474     private static void checkTransfer(ByteBuffer a, ByteBuffer b)
 475             throws Exception {
 476         a.flip();
 477         b.flip();
 478 
 479         if (!a.equals(b)) {
 480             throw new Exception("Data didn't transfer cleanly");
 481         } else {
 482             log("\tData transferred cleanly");
 483         }
 484 
 485         a.position(a.limit());
 486         b.position(b.limit());
 487         a.limit(a.capacity());
 488         b.limit(b.capacity());
 489     }
 490 
 491     /*
 492      * Logging code
 493      */
 494     private static boolean resultOnce = true;
 495 
 496     private static void log(String str, SSLEngineResult result) {
 497         if (!logging) {
 498             return;
 499         }
 500         if (resultOnce) {
 501             resultOnce = false;
 502             System.out.println("The format of the SSLEngineResult is: \n" +
 503                 "\t\"getStatus() / getHandshakeStatus()\" +\n" +
 504                 "\t\"bytesConsumed() / bytesProduced()\"\n");
 505         }
 506         HandshakeStatus hsStatus = result.getHandshakeStatus();
 507         log(str +
 508             result.getStatus() + "/" + hsStatus + ", " +
 509             result.bytesConsumed() + "/" + result.bytesProduced() +
 510             " bytes");
 511         if (hsStatus == HandshakeStatus.FINISHED) {
 512             log("\t...ready for application data");
 513         }
 514     }
 515 
 516     private static void log(String str) {
 517         if (logging) {
 518             System.out.println(str);
 519         }
 520     }
 521 
 522     /**
 523      * Split a record consisting of multiple TLS handshake messages
 524      * into individual TLS records, each one in a ByteBuffer of its own.
 525      *
 526      * @param tlsRecord A ByteBuffer containing the tls record data.
 527      *        The position of the buffer should be at the first byte
 528      *        in the TLS record data.
 529      *
 530      * @return An ArrayList consisting of one or more ByteBuffers.  Each
 531      *         ByteBuffer will contain a single TLS record with one message.
 532      *         That message will be taken from the input record.  The order
 533      *         of the messages in the ArrayList will be the same as they
 534      *         were in the input record.
 535      */
 536     private ArrayList<ByteBuffer> splitRecord(ByteBuffer tlsRecord) {
 537         SSLSession session = clientEngine.getSession();
 538         int netBufferMax = session.getPacketBufferSize();
 539         ArrayList<ByteBuffer> recordList = new ArrayList<>();
 540 
 541         if (tlsRecord.hasRemaining()) {
 542             int type = Byte.toUnsignedInt(tlsRecord.get());
 543             byte ver_major = tlsRecord.get();
 544             byte ver_minor = tlsRecord.get();
 545             int recLen = Short.toUnsignedInt(tlsRecord.getShort());
 546             byte[] newMsgData = null;
 547             while (tlsRecord.hasRemaining()) {
 548                 ByteBuffer newRecord = ByteBuffer.allocateDirect(netBufferMax);
 549                 switch (type) {
 550                     case TLS_RECTYPE_CCS:
 551                     case TLS_RECTYPE_ALERT:
 552                     case TLS_RECTYPE_APPDATA:
 553                         // None of our tests have multiple non-handshake
 554                         // messages coalesced into a single record.
 555                         break;
 556                     case TLS_RECTYPE_HANDSHAKE:
 557                         newMsgData = getHandshakeMessage(tlsRecord);
 558                         break;
 559                 }
 560 
 561                 // Put a new TLS record on the destination ByteBuffer
 562                 newRecord.put((byte)type);
 563                 newRecord.put(ver_major);
 564                 newRecord.put(ver_minor);
 565                 newRecord.putShort((short)newMsgData.length);
 566 
 567                 // Now add the message content itself and attach to the
 568                 // returned ArrayList
 569                 newRecord.put(newMsgData);
 570                 newRecord.flip();
 571                 recordList.add(newRecord);
 572             }
 573         }
 574 
 575         return recordList;
 576     }
 577 
 578     private static ByteBuffer createEvilClientHello(int sessIdLen) {
 579         ByteBuffer newRecord = ByteBuffer.allocateDirect(4096);
 580 
 581         // Lengths will initially be place holders until we determine the
 582         // finished length of the ByteBuffer.  Then we'll go back and scribble
 583         // in the correct lengths.
 584 
 585         newRecord.put((byte)TLS_RECTYPE_HANDSHAKE);     // Record type
 586         newRecord.putShort((short)0x0301);              // Protocol (TLS 1.0)
 587         newRecord.putShort((short)0);                   // Length place holder
 588 
 589         newRecord.putInt(TLS_HS_CLIENT_HELLO << 24);    // HS type and length
 590         newRecord.putShort((short)0x0301);
 591         newRecord.putInt((int)(System.currentTimeMillis() / 1000));
 592         SecureRandom sr = new SecureRandom();
 593         byte[] randBuf = new byte[28];
 594         sr.nextBytes(randBuf);
 595         newRecord.put(randBuf);                         // Client Random
 596         newRecord.put((byte)sessIdLen);                 // Session ID length
 597         if (sessIdLen > 0) {
 598             byte[] sessId = new byte[sessIdLen];
 599             sr.nextBytes(sessId);
 600             newRecord.put(sessId);                      // Session ID
 601         }
 602         newRecord.putShort((short)2);                   // 2 bytes of ciphers
 603         newRecord.putShort((short)0x002F);              // TLS_RSA_AES_CBC_SHA
 604         newRecord.putShort((short)0x0100);              // only null compression
 605         newRecord.putShort((short)5);                   // 5 bytes of extensions
 606         newRecord.putShort((short)0xFF01);              // Renegotiation info
 607         newRecord.putShort((short)1);
 608         newRecord.put((byte)0);                         // No reneg info exts
 609 
 610         // Go back and fill in the correct length values for the record
 611         // and handshake message headers.
 612         int recordLength = newRecord.position();
 613         newRecord.putShort(3, (short)(recordLength - 5));
 614         int newTypeAndLen = (newRecord.getInt(5) & 0xFF000000) |
 615                 ((recordLength - 9) & 0x00FFFFFF);
 616         newRecord.putInt(5, newTypeAndLen);
 617 
 618         newRecord.flip();
 619         return newRecord;
 620     }
 621 
 622     private static ByteBuffer createEvilServerHello(ByteBuffer origHello,
 623             int newSessIdLen) {
 624         if (newSessIdLen < 0 || newSessIdLen > Byte.MAX_VALUE) {
 625             throw new RuntimeException("Length must be 0 <= X <= 127");
 626         }
 627 
 628         ByteBuffer newRecord = ByteBuffer.allocateDirect(4096);
 629         // Copy the bytes from the old hello to the new up to the session ID
 630         // field.  We will go back later and fill in a new length field in
 631         // the record header.  This includes the record header (5 bytes), the
 632         // Handshake message header (4 bytes), protocol version (2 bytes),
 633         // and the random (32 bytes).
 634         ByteBuffer scratchBuffer = origHello.slice();
 635         scratchBuffer.limit(43);
 636         newRecord.put(scratchBuffer);
 637 
 638         // Advance the position in the originial hello buffer past the
 639         // session ID.
 640         origHello.position(43);
 641         int origIDLen = Byte.toUnsignedInt(origHello.get());
 642         if (origIDLen > 0) {
 643             // Skip over the session ID
 644             origHello.position(origHello.position() + origIDLen);
 645         }
 646 
 647         // Now add our own sessionID to the new record
 648         SecureRandom sr = new SecureRandom();
 649         byte[] sessId = new byte[newSessIdLen];
 650         sr.nextBytes(sessId);
 651         newRecord.put((byte)newSessIdLen);
 652         newRecord.put(sessId);
 653 
 654         // Create another slice in the original buffer, based on the position
 655         // past the session ID.  Copy the remaining bytes into the new
 656         // hello buffer.  Then go back and fix up the length
 657         newRecord.put(origHello.slice());
 658 
 659         // Go back and fill in the correct length values for the record
 660         // and handshake message headers.
 661         int recordLength = newRecord.position();
 662         newRecord.putShort(3, (short)(recordLength - 5));
 663         int newTypeAndLen = (newRecord.getInt(5) & 0xFF000000) |
 664                 ((recordLength - 9) & 0x00FFFFFF);
 665         newRecord.putInt(5, newTypeAndLen);
 666 
 667         newRecord.flip();
 668         return newRecord;
 669     }
 670 
 671     /**
 672      * Look at an incoming TLS record and see if it is the desired
 673      * record type, and where appropriate the correct subtype.
 674      *
 675      * @param srcRecord The input TLS record to be evaluated.  This
 676      *        method will only look at the leading message if multiple
 677      *        TLS handshake messages are coalesced into a single record.
 678      * @param reqRecType The requested TLS record type
 679      * @param recParams Zero or more integer sub type fields.  For CCS
 680      *        and ApplicationData, no params are used.  For handshake records,
 681      *        one value corresponding to the HandshakeType is required.
 682      *        For Alerts, two values corresponding to AlertLevel and
 683      *        AlertDescription are necessary.
 684      *
 685      * @return true if the proper handshake message is the first one
 686      *         in the input record, false otherwise.
 687      */
 688     private boolean isTlsMessage(ByteBuffer srcRecord, int reqRecType,
 689             int... recParams) {
 690         boolean foundMsg = false;
 691 
 692         if (srcRecord.hasRemaining()) {
 693             srcRecord.mark();
 694 
 695             // Grab the fields from the TLS Record
 696             int recordType = Byte.toUnsignedInt(srcRecord.get());
 697             byte ver_major = srcRecord.get();
 698             byte ver_minor = srcRecord.get();
 699             int recLen = Short.toUnsignedInt(srcRecord.getShort());
 700 
 701             if (recordType == reqRecType) {
 702                 // For any zero-length recParams, making sure the requested
 703                 // type is sufficient.
 704                 if (recParams.length == 0) {
 705                     foundMsg = true;
 706                 } else {
 707                     switch (recordType) {
 708                         case TLS_RECTYPE_CCS:
 709                         case TLS_RECTYPE_APPDATA:
 710                             // We really shouldn't find ourselves here, but
 711                             // if someone asked for these types and had more
 712                             // recParams we can ignore them.
 713                             foundMsg = true;
 714                             break;
 715                         case TLS_RECTYPE_ALERT:
 716                             // Needs two params, AlertLevel and AlertDescription
 717                             if (recParams.length != 2) {
 718                                 throw new RuntimeException(
 719                                     "Test for Alert requires level and desc.");
 720                             } else {
 721                                 int level = Byte.toUnsignedInt(srcRecord.get());
 722                                 int desc = Byte.toUnsignedInt(srcRecord.get());
 723                                 if (level == recParams[0] &&
 724                                         desc == recParams[1]) {
 725                                     foundMsg = true;
 726                                 }
 727                             }
 728                             break;
 729                         case TLS_RECTYPE_HANDSHAKE:
 730                             // Needs one parameter, HandshakeType
 731                             if (recParams.length != 1) {
 732                                 throw new RuntimeException(
 733                                     "Test for Handshake requires only HS type");
 734                             } else {
 735                                 // Go into the first handhshake message in the
 736                                 // record and grab the handshake message header.
 737                                 // All we need to do is parse out the leading
 738                                 // byte.
 739                                 int msgHdr = srcRecord.getInt();
 740                                 int msgType = (msgHdr >> 24) & 0x000000FF;
 741                                 if (msgType == recParams[0]) {
 742                                 foundMsg = true;
 743                             }
 744                         }
 745                         break;
 746                     }
 747                 }
 748             }
 749 
 750             srcRecord.reset();
 751         }
 752 
 753         return foundMsg;
 754     }
 755 
 756     private byte[] getHandshakeMessage(ByteBuffer srcRecord) {
 757         // At the start of this routine, the position should be lined up
 758         // at the first byte of a handshake message.  Mark this location
 759         // so we can return to it after reading the type and length.
 760         srcRecord.mark();
 761         int msgHdr = srcRecord.getInt();
 762         int type = (msgHdr >> 24) & 0x000000FF;
 763         int length = msgHdr & 0x00FFFFFF;
 764 
 765         // Create a byte array that has enough space for the handshake
 766         // message header and body.
 767         byte[] data = new byte[length + 4];
 768         srcRecord.reset();
 769         srcRecord.get(data, 0, length + 4);
 770 
 771         return (data);
 772     }
 773 
 774     /**
 775      * Hex-dumps a ByteBuffer to stdout.
 776      */
 777     private static void dumpByteBuffer(String header, ByteBuffer bBuf) {
 778         if (dumpBufs == false) {
 779             return;
 780         }
 781 
 782         int bufLen = bBuf.remaining();
 783         if (bufLen > 0) {
 784             bBuf.mark();
 785 
 786             // We expect the position of the buffer to be at the
 787             // beginning of a TLS record.  Get the type, version and length.
 788             int type = Byte.toUnsignedInt(bBuf.get());
 789             int ver_major = Byte.toUnsignedInt(bBuf.get());
 790             int ver_minor = Byte.toUnsignedInt(bBuf.get());
 791             int recLen = Short.toUnsignedInt(bBuf.getShort());
 792 
 793             log("===== " + header + " (" + tlsRecType(type) + " / " +
 794                 ver_major + "." + ver_minor + " / " + bufLen + " bytes) =====");
 795             bBuf.reset();
 796             for (int i = 0; i < bufLen; i++) {
 797                 if (i != 0 && i % 16 == 0) {
 798                     System.out.print("\n");
 799                 }
 800                 System.out.format("%02X ", bBuf.get(i));
 801             }
 802             log("\n===============================================");
 803             bBuf.reset();
 804         }
 805     }
 806 
 807     private static String tlsRecType(int type) {
 808         switch (type) {
 809             case 20:
 810                 return "Change Cipher Spec";
 811             case 21:
 812                 return "Alert";
 813             case 22:
 814                 return "Handshake";
 815             case 23:
 816                 return "Application Data";
 817             default:
 818                 return ("Unknown (" + type + ")");
 819         }
 820     }
 821 }