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