Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/security/ssl/ClientHandshaker/LengthCheckTest.java
38853 views
/*1* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 804486026* @summary Vectors and fixed length fields should be verified27* for allowed sizes.28* @library /lib/security29* @run main/othervm LengthCheckTest30* @key randomness31*/3233/**34* A SSLEngine usage example which simplifies the presentation35* 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 them39* as directly connected pipes.40*41* Note, this is a *very* simple example: real code will be much more42* involved. For example, different threading and I/O models could be43* used, transport mechanisms could close unexpectedly, and so on.44*45* When this application runs, notice that several messages46* (wrap/unwrap) pass before any application data is consumed or47* produced. (For more information, please see the SSL/TLS48* 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 message52* ====== ====== =======53* wrap() ... ClientHello54* ... unwrap() ClientHello55* ... wrap() ServerHello/Certificate56* unwrap() ... ServerHello/Certificate57* wrap() ... ClientKeyExchange58* wrap() ... ChangeCipherSpec59* wrap() ... Finished60* ... unwrap() ClientKeyExchange61* ... unwrap() ChangeCipherSpec62* ... unwrap() Finished63* ... wrap() ChangeCipherSpec64* ... wrap() Finished65* unwrap() ... ChangeCipherSpec66* unwrap() ... Finished67*/6869import javax.net.ssl.*;70import javax.net.ssl.SSLEngineResult.*;71import java.io.*;72import java.security.*;73import java.nio.*;74import java.util.List;75import java.util.ArrayList;76import java.util.Iterator;7778public class LengthCheckTest {7980/*81* Enables logging of the SSLEngine operations.82*/83private static final boolean logging = true;8485/*86* Enables the JSSE system debugging system property:87*88* -Djavax.net.debug=all89*90* This gives a lot of low-level information about operations underway,91* including specific handshake messages, and might be best examined92* after gaining some familiarity with this application.93*/94private static final boolean debug = false;95private static final boolean dumpBufs = true;9697private final SSLContext sslc;9899private SSLEngine clientEngine; // client Engine100private ByteBuffer clientOut; // write side of clientEngine101private ByteBuffer clientIn; // read side of clientEngine102103private SSLEngine serverEngine; // server Engine104private ByteBuffer serverOut; // write side of serverEngine105private ByteBuffer serverIn; // read side of serverEngine106107private HandshakeTest handshakeTest;108109/*110* For data transport, this example uses local ByteBuffers. This111* isn't really useful, but the purpose of this example is to show112* SSLEngine concepts, not how to do network transport.113*/114private ByteBuffer cTOs; // "reliable" transport client->server115private ByteBuffer sTOc; // "reliable" transport server->client116117/*118* The following is to set up the keystores.119*/120private static final String pathToStores = "../../../../javax/net/ssl/etc";121private static final String keyStoreFile = "keystore";122private static final String trustStoreFile = "truststore";123private static final String passwd = "passphrase";124125private static final String keyFilename =126System.getProperty("test.src", ".") + "/" + pathToStores +127"/" + keyStoreFile;128private static final String trustFilename =129System.getProperty("test.src", ".") + "/" + pathToStores +130"/" + trustStoreFile;131132// Define a few basic TLS record and message types we might need133private static final int TLS_RECTYPE_CCS = 0x14;134private static final int TLS_RECTYPE_ALERT = 0x15;135private static final int TLS_RECTYPE_HANDSHAKE = 0x16;136private static final int TLS_RECTYPE_APPDATA = 0x17;137138private static final int TLS_HS_HELLO_REQUEST = 0x00;139private static final int TLS_HS_CLIENT_HELLO = 0x01;140private static final int TLS_HS_SERVER_HELLO = 0x02;141private static final int TLS_HS_CERTIFICATE = 0x0B;142private static final int TLS_HS_SERVER_KEY_EXCHG = 0x0C;143private static final int TLS_HS_CERT_REQUEST = 0x0D;144private static final int TLS_HS_SERVER_HELLO_DONE = 0x0E;145private static final int TLS_HS_CERT_VERIFY = 0x0F;146private static final int TLS_HS_CLIENT_KEY_EXCHG = 0x10;147private static final int TLS_HS_FINISHED = 0x14;148149// We're not going to define all the alert types in TLS, just150// the ones we think we'll need to reference by name.151private static final int TLS_ALERT_LVL_WARNING = 0x01;152private static final int TLS_ALERT_LVL_FATAL = 0x02;153154private static final int TLS_ALERT_UNEXPECTED_MSG = 0x0A;155private static final int TLS_ALERT_HANDSHAKE_FAILURE = 0x28;156private static final int TLS_ALERT_INTERNAL_ERROR = 0x50;157private static final int TLS_ALERT_ILLEGAL_PARAMETER = 0x2F;158159public interface HandshakeTest {160void execTest() throws Exception;161}162163public final HandshakeTest servSendLongID = new HandshakeTest() {164@Override165public void execTest() throws Exception {166boolean gotException = false;167SSLEngineResult clientResult; // results from client's last op168SSLEngineResult serverResult; // results from server's last op169170log("\n==== Test: Client receives 64-byte session ID ====");171172// Send Client Hello173clientResult = clientEngine.wrap(clientOut, cTOs);174log("client wrap: ", clientResult);175runDelegatedTasks(clientResult, clientEngine);176cTOs.flip();177dumpByteBuffer("CLIENT-TO-SERVER", cTOs);178179// Server consumes Client Hello180serverResult = serverEngine.unwrap(cTOs, serverIn);181log("server unwrap: ", serverResult);182runDelegatedTasks(serverResult, serverEngine);183cTOs.compact();184185// Server generates ServerHello/Cert/Done record186serverResult = serverEngine.wrap(serverOut, sTOc);187log("server wrap: ", serverResult);188runDelegatedTasks(serverResult, serverEngine);189sTOc.flip();190191// Intercept the ServerHello messages and instead send192// one that has a 64-byte session ID.193if (isTlsMessage(sTOc, TLS_RECTYPE_HANDSHAKE,194TLS_HS_SERVER_HELLO)) {195ArrayList<ByteBuffer> recList = splitRecord(sTOc);196197// Use the original ServerHello as a template to craft one198// with a longer-than-allowed session ID.199ByteBuffer servHelloBuf =200createEvilServerHello(recList.get(0), 64);201202recList.set(0, servHelloBuf);203204// Now send each ByteBuffer (each being a complete205// TLS record) into the client-side unwrap.206// for (ByteBuffer bBuf : recList) {207208Iterator<ByteBuffer> iter = recList.iterator();209while (!gotException && (iter.hasNext())) {210ByteBuffer bBuf = iter.next();211dumpByteBuffer("SERVER-TO-CLIENT", bBuf);212try {213clientResult = clientEngine.unwrap(bBuf, clientIn);214} catch (SSLProtocolException e) {215log("Received expected SSLProtocolException: " + e);216gotException = true;217}218log("client unwrap: ", clientResult);219runDelegatedTasks(clientResult, clientEngine);220}221} else {222dumpByteBuffer("SERVER-TO-CLIENT", sTOc);223log("client unwrap: ", clientResult);224runDelegatedTasks(clientResult, clientEngine);225}226sTOc.compact();227228// The Client should now send a TLS Alert229clientResult = clientEngine.wrap(clientOut, cTOs);230log("client wrap: ", clientResult);231runDelegatedTasks(clientResult, clientEngine);232cTOs.flip();233dumpByteBuffer("CLIENT-TO-SERVER", cTOs);234235// At this point we can verify that both an exception236// was thrown and the proper action (a TLS alert) was237// sent back to the server.238if (gotException == false ||239!isTlsMessage(cTOs, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,240TLS_ALERT_ILLEGAL_PARAMETER)) {241throw new SSLException(242"Client failed to throw Alert:fatal:internal_error");243}244}245};246247public final HandshakeTest clientSendLongID = new HandshakeTest() {248@Override249public void execTest() throws Exception {250boolean gotException = false;251SSLEngineResult clientResult; // results from client's last op252SSLEngineResult serverResult; // results from server's last op253254log("\n==== Test: Server receives 64-byte session ID ====");255256// Send Client Hello257ByteBuffer evilClientHello = createEvilClientHello(64);258dumpByteBuffer("CLIENT-TO-SERVER", evilClientHello);259260// Server consumes Client Hello261serverResult = serverEngine.unwrap(evilClientHello, serverIn);262log("server unwrap: ", serverResult);263runDelegatedTasks(serverResult, serverEngine);264evilClientHello.compact();265266// Under normal circumstances this should be a ServerHello267// But should throw an exception instead due to the invalid268// session ID.269try {270serverResult = serverEngine.wrap(serverOut, sTOc);271log("server wrap: ", serverResult);272runDelegatedTasks(serverResult, serverEngine);273} catch (SSLProtocolException ssle) {274log("Received expected SSLProtocolException: " + ssle);275gotException = true;276}277278// We expect to see the server generate an alert here279serverResult = serverEngine.wrap(serverOut, sTOc);280log("server wrap: ", serverResult);281runDelegatedTasks(serverResult, serverEngine);282sTOc.flip();283dumpByteBuffer("SERVER-TO-CLIENT", sTOc);284285// At this point we can verify that both an exception286// was thrown and the proper action (a TLS alert) was287// sent back to the client.288if (gotException == false ||289!isTlsMessage(sTOc, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,290TLS_ALERT_ILLEGAL_PARAMETER)) {291throw new SSLException(292"Server failed to throw Alert:fatal:internal_error");293}294}295};296297298/*299* Main entry point for this test.300*/301public static void main(String args[]) throws Exception {302// Re-enable TLSv1 since test depends on it.303SecurityUtils.removeFromDisabledTlsAlgs("TLSv1");304305List<LengthCheckTest> ccsTests = new ArrayList<>();306307if (debug) {308System.setProperty("javax.net.debug", "ssl");309}310311ccsTests.add(new LengthCheckTest("ServSendLongID"));312ccsTests.add(new LengthCheckTest("ClientSendLongID"));313314for (LengthCheckTest test : ccsTests) {315test.runTest();316}317318System.out.println("Test Passed.");319}320321/*322* Create an initialized SSLContext to use for these tests.323*/324public LengthCheckTest(String testName) throws Exception {325326KeyStore ks = KeyStore.getInstance("JKS");327KeyStore ts = KeyStore.getInstance("JKS");328329char[] passphrase = "passphrase".toCharArray();330331ks.load(new FileInputStream(keyFilename), passphrase);332ts.load(new FileInputStream(trustFilename), passphrase);333334KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");335kmf.init(ks, passphrase);336337TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");338tmf.init(ts);339340SSLContext sslCtx = SSLContext.getInstance("TLS");341342sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);343344sslc = sslCtx;345346switch (testName) {347case "ServSendLongID":348handshakeTest = servSendLongID;349break;350case "ClientSendLongID":351handshakeTest = clientSendLongID;352break;353default:354throw new IllegalArgumentException("Unknown test name: " +355testName);356}357}358359/*360* Run the test.361*362* Sit in a tight loop, both engines calling wrap/unwrap regardless363* of whether data is available or not. We do this until both engines364* report back they are closed.365*366* The main loop handles all of the I/O phases of the SSLEngine's367* lifetime:368*369* initial handshaking370* application data transfer371* engine closing372*373* One could easily separate these phases into separate374* sections of code.375*/376private void runTest() throws Exception {377boolean dataDone = false;378379createSSLEngines();380createBuffers();381382handshakeTest.execTest();383}384385/*386* Using the SSLContext created during object creation,387* create/configure the SSLEngines we'll use for this test.388*/389private void createSSLEngines() throws Exception {390/*391* Configure the serverEngine to act as a server in the SSL/TLS392* handshake. Also, require SSL client authentication.393*/394serverEngine = sslc.createSSLEngine();395serverEngine.setUseClientMode(false);396serverEngine.setNeedClientAuth(false);397398/*399* Similar to above, but using client mode instead.400*/401clientEngine = sslc.createSSLEngine("client", 80);402clientEngine.setUseClientMode(true);403404// In order to make a test that will be backwards compatible405// going back to JDK 5, force the handshake to be TLS 1.0 and406// use one of the older cipher suites.407clientEngine.setEnabledProtocols(new String[]{"TLSv1"});408clientEngine.setEnabledCipherSuites(409new String[]{"TLS_RSA_WITH_AES_128_CBC_SHA"});410}411412/*413* Create and size the buffers appropriately.414*/415private void createBuffers() {416417/*418* We'll assume the buffer sizes are the same419* between client and server.420*/421SSLSession session = clientEngine.getSession();422int appBufferMax = session.getApplicationBufferSize();423int netBufferMax = session.getPacketBufferSize();424425/*426* We'll make the input buffers a bit bigger than the max needed427* size, so that unwrap()s following a successful data transfer428* won't generate BUFFER_OVERFLOWS.429*430* We'll use a mix of direct and indirect ByteBuffers for431* tutorial purposes only. In reality, only use direct432* ByteBuffers when they give a clear performance enhancement.433*/434clientIn = ByteBuffer.allocate(appBufferMax + 50);435serverIn = ByteBuffer.allocate(appBufferMax + 50);436437cTOs = ByteBuffer.allocateDirect(netBufferMax);438sTOc = ByteBuffer.allocateDirect(netBufferMax);439440clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());441serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());442}443444/*445* If the result indicates that we have outstanding tasks to do,446* go ahead and run them in this thread.447*/448private static void runDelegatedTasks(SSLEngineResult result,449SSLEngine engine) throws Exception {450451if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {452Runnable runnable;453while ((runnable = engine.getDelegatedTask()) != null) {454log("\trunning delegated task...");455runnable.run();456}457HandshakeStatus hsStatus = engine.getHandshakeStatus();458if (hsStatus == HandshakeStatus.NEED_TASK) {459throw new Exception(460"handshake shouldn't need additional tasks");461}462log("\tnew HandshakeStatus: " + hsStatus);463}464}465466private static boolean isEngineClosed(SSLEngine engine) {467return (engine.isOutboundDone() && engine.isInboundDone());468}469470/*471* Simple check to make sure everything came across as expected.472*/473private static void checkTransfer(ByteBuffer a, ByteBuffer b)474throws Exception {475a.flip();476b.flip();477478if (!a.equals(b)) {479throw new Exception("Data didn't transfer cleanly");480} else {481log("\tData transferred cleanly");482}483484a.position(a.limit());485b.position(b.limit());486a.limit(a.capacity());487b.limit(b.capacity());488}489490/*491* Logging code492*/493private static boolean resultOnce = true;494495private static void log(String str, SSLEngineResult result) {496if (!logging) {497return;498}499if (resultOnce) {500resultOnce = false;501System.out.println("The format of the SSLEngineResult is: \n" +502"\t\"getStatus() / getHandshakeStatus()\" +\n" +503"\t\"bytesConsumed() / bytesProduced()\"\n");504}505HandshakeStatus hsStatus = result.getHandshakeStatus();506log(str +507result.getStatus() + "/" + hsStatus + ", " +508result.bytesConsumed() + "/" + result.bytesProduced() +509" bytes");510if (hsStatus == HandshakeStatus.FINISHED) {511log("\t...ready for application data");512}513}514515private static void log(String str) {516if (logging) {517System.out.println(str);518}519}520521/**522* Split a record consisting of multiple TLS handshake messages523* into individual TLS records, each one in a ByteBuffer of its own.524*525* @param tlsRecord A ByteBuffer containing the tls record data.526* The position of the buffer should be at the first byte527* in the TLS record data.528*529* @return An ArrayList consisting of one or more ByteBuffers. Each530* ByteBuffer will contain a single TLS record with one message.531* That message will be taken from the input record. The order532* of the messages in the ArrayList will be the same as they533* were in the input record.534*/535private ArrayList<ByteBuffer> splitRecord(ByteBuffer tlsRecord) {536SSLSession session = clientEngine.getSession();537int netBufferMax = session.getPacketBufferSize();538ArrayList<ByteBuffer> recordList = new ArrayList<>();539540if (tlsRecord.hasRemaining()) {541int type = Byte.toUnsignedInt(tlsRecord.get());542byte ver_major = tlsRecord.get();543byte ver_minor = tlsRecord.get();544int recLen = Short.toUnsignedInt(tlsRecord.getShort());545byte[] newMsgData = null;546while (tlsRecord.hasRemaining()) {547ByteBuffer newRecord = ByteBuffer.allocateDirect(netBufferMax);548switch (type) {549case TLS_RECTYPE_CCS:550case TLS_RECTYPE_ALERT:551case TLS_RECTYPE_APPDATA:552// None of our tests have multiple non-handshake553// messages coalesced into a single record.554break;555case TLS_RECTYPE_HANDSHAKE:556newMsgData = getHandshakeMessage(tlsRecord);557break;558}559560// Put a new TLS record on the destination ByteBuffer561newRecord.put((byte)type);562newRecord.put(ver_major);563newRecord.put(ver_minor);564newRecord.putShort((short)newMsgData.length);565566// Now add the message content itself and attach to the567// returned ArrayList568newRecord.put(newMsgData);569newRecord.flip();570recordList.add(newRecord);571}572}573574return recordList;575}576577private static ByteBuffer createEvilClientHello(int sessIdLen) {578ByteBuffer newRecord = ByteBuffer.allocateDirect(4096);579580// Lengths will initially be place holders until we determine the581// finished length of the ByteBuffer. Then we'll go back and scribble582// in the correct lengths.583584newRecord.put((byte)TLS_RECTYPE_HANDSHAKE); // Record type585newRecord.putShort((short)0x0301); // Protocol (TLS 1.0)586newRecord.putShort((short)0); // Length place holder587588newRecord.putInt(TLS_HS_CLIENT_HELLO << 24); // HS type and length589newRecord.putShort((short)0x0301);590newRecord.putInt((int)(System.currentTimeMillis() / 1000));591SecureRandom sr = new SecureRandom();592byte[] randBuf = new byte[28];593sr.nextBytes(randBuf);594newRecord.put(randBuf); // Client Random595newRecord.put((byte)sessIdLen); // Session ID length596if (sessIdLen > 0) {597byte[] sessId = new byte[sessIdLen];598sr.nextBytes(sessId);599newRecord.put(sessId); // Session ID600}601newRecord.putShort((short)2); // 2 bytes of ciphers602newRecord.putShort((short)0x002F); // TLS_RSA_AES_CBC_SHA603newRecord.putShort((short)0x0100); // only null compression604newRecord.putShort((short)5); // 5 bytes of extensions605newRecord.putShort((short)0xFF01); // Renegotiation info606newRecord.putShort((short)1);607newRecord.put((byte)0); // No reneg info exts608609// Go back and fill in the correct length values for the record610// and handshake message headers.611int recordLength = newRecord.position();612newRecord.putShort(3, (short)(recordLength - 5));613int newTypeAndLen = (newRecord.getInt(5) & 0xFF000000) |614((recordLength - 9) & 0x00FFFFFF);615newRecord.putInt(5, newTypeAndLen);616617newRecord.flip();618return newRecord;619}620621private static ByteBuffer createEvilServerHello(ByteBuffer origHello,622int newSessIdLen) {623if (newSessIdLen < 0 || newSessIdLen > Byte.MAX_VALUE) {624throw new RuntimeException("Length must be 0 <= X <= 127");625}626627ByteBuffer newRecord = ByteBuffer.allocateDirect(4096);628// Copy the bytes from the old hello to the new up to the session ID629// field. We will go back later and fill in a new length field in630// the record header. This includes the record header (5 bytes), the631// Handshake message header (4 bytes), protocol version (2 bytes),632// and the random (32 bytes).633ByteBuffer scratchBuffer = origHello.slice();634scratchBuffer.limit(43);635newRecord.put(scratchBuffer);636637// Advance the position in the originial hello buffer past the638// session ID.639origHello.position(43);640int origIDLen = Byte.toUnsignedInt(origHello.get());641if (origIDLen > 0) {642// Skip over the session ID643origHello.position(origHello.position() + origIDLen);644}645646// Now add our own sessionID to the new record647SecureRandom sr = new SecureRandom();648byte[] sessId = new byte[newSessIdLen];649sr.nextBytes(sessId);650newRecord.put((byte)newSessIdLen);651newRecord.put(sessId);652653// Create another slice in the original buffer, based on the position654// past the session ID. Copy the remaining bytes into the new655// hello buffer. Then go back and fix up the length656newRecord.put(origHello.slice());657658// Go back and fill in the correct length values for the record659// and handshake message headers.660int recordLength = newRecord.position();661newRecord.putShort(3, (short)(recordLength - 5));662int newTypeAndLen = (newRecord.getInt(5) & 0xFF000000) |663((recordLength - 9) & 0x00FFFFFF);664newRecord.putInt(5, newTypeAndLen);665666newRecord.flip();667return newRecord;668}669670/**671* Look at an incoming TLS record and see if it is the desired672* record type, and where appropriate the correct subtype.673*674* @param srcRecord The input TLS record to be evaluated. This675* method will only look at the leading message if multiple676* TLS handshake messages are coalesced into a single record.677* @param reqRecType The requested TLS record type678* @param recParams Zero or more integer sub type fields. For CCS679* and ApplicationData, no params are used. For handshake records,680* one value corresponding to the HandshakeType is required.681* For Alerts, two values corresponding to AlertLevel and682* AlertDescription are necessary.683*684* @return true if the proper handshake message is the first one685* in the input record, false otherwise.686*/687private boolean isTlsMessage(ByteBuffer srcRecord, int reqRecType,688int... recParams) {689boolean foundMsg = false;690691if (srcRecord.hasRemaining()) {692srcRecord.mark();693694// Grab the fields from the TLS Record695int recordType = Byte.toUnsignedInt(srcRecord.get());696byte ver_major = srcRecord.get();697byte ver_minor = srcRecord.get();698int recLen = Short.toUnsignedInt(srcRecord.getShort());699700if (recordType == reqRecType) {701// For any zero-length recParams, making sure the requested702// type is sufficient.703if (recParams.length == 0) {704foundMsg = true;705} else {706switch (recordType) {707case TLS_RECTYPE_CCS:708case TLS_RECTYPE_APPDATA:709// We really shouldn't find ourselves here, but710// if someone asked for these types and had more711// recParams we can ignore them.712foundMsg = true;713break;714case TLS_RECTYPE_ALERT:715// Needs two params, AlertLevel and AlertDescription716if (recParams.length != 2) {717throw new RuntimeException(718"Test for Alert requires level and desc.");719} else {720int level = Byte.toUnsignedInt(srcRecord.get());721int desc = Byte.toUnsignedInt(srcRecord.get());722if (level == recParams[0] &&723desc == recParams[1]) {724foundMsg = true;725}726}727break;728case TLS_RECTYPE_HANDSHAKE:729// Needs one parameter, HandshakeType730if (recParams.length != 1) {731throw new RuntimeException(732"Test for Handshake requires only HS type");733} else {734// Go into the first handhshake message in the735// record and grab the handshake message header.736// All we need to do is parse out the leading737// byte.738int msgHdr = srcRecord.getInt();739int msgType = (msgHdr >> 24) & 0x000000FF;740if (msgType == recParams[0]) {741foundMsg = true;742}743}744break;745}746}747}748749srcRecord.reset();750}751752return foundMsg;753}754755private byte[] getHandshakeMessage(ByteBuffer srcRecord) {756// At the start of this routine, the position should be lined up757// at the first byte of a handshake message. Mark this location758// so we can return to it after reading the type and length.759srcRecord.mark();760int msgHdr = srcRecord.getInt();761int type = (msgHdr >> 24) & 0x000000FF;762int length = msgHdr & 0x00FFFFFF;763764// Create a byte array that has enough space for the handshake765// message header and body.766byte[] data = new byte[length + 4];767srcRecord.reset();768srcRecord.get(data, 0, length + 4);769770return (data);771}772773/**774* Hex-dumps a ByteBuffer to stdout.775*/776private static void dumpByteBuffer(String header, ByteBuffer bBuf) {777if (dumpBufs == false) {778return;779}780781int bufLen = bBuf.remaining();782if (bufLen > 0) {783bBuf.mark();784785// We expect the position of the buffer to be at the786// beginning of a TLS record. Get the type, version and length.787int type = Byte.toUnsignedInt(bBuf.get());788int ver_major = Byte.toUnsignedInt(bBuf.get());789int ver_minor = Byte.toUnsignedInt(bBuf.get());790int recLen = Short.toUnsignedInt(bBuf.getShort());791792log("===== " + header + " (" + tlsRecType(type) + " / " +793ver_major + "." + ver_minor + " / " + bufLen + " bytes) =====");794bBuf.reset();795for (int i = 0; i < bufLen; i++) {796if (i != 0 && i % 16 == 0) {797System.out.print("\n");798}799System.out.format("%02X ", bBuf.get(i));800}801log("\n===============================================");802bBuf.reset();803}804}805806private static String tlsRecType(int type) {807switch (type) {808case 20:809return "Change Cipher Spec";810case 21:811return "Alert";812case 22:813return "Handshake";814case 23:815return "Application Data";816default:817return ("Unknown (" + type + ")");818}819}820}821822823