/**
* TLS-Attacker - A Modular Penetration Testing Framework for TLS
*
* Copyright 2014-2016 Ruhr University Bochum / Hackmanit GmbH
*
* Licensed under Apache License 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*/
package de.rub.nds.tlsattacker.dtls.protocol.handshake;
import de.rub.nds.tlsattacker.dtls.protocol.handshake.HandshakeFragmentHandler;
import de.rub.nds.tlsattacker.tls.record.Record;
import de.rub.nds.tlsattacker.util.ArrayConverter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.List;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
/**
* @author Florian Pfützenreuter <florian.pfuetzenreuter@rub.de>
*/
public class HandshakeFragmentHandlerTest {
static byte[] serverHelloMessageHeader = ArrayConverter.hexStringToByteArray("030000170000000000000017");
static byte[] serverHelloMessage = ArrayConverter
.hexStringToByteArray("feff149c5cc753b1e17b2652f33f9fb4f357eeaec8fce5");
static byte[] certificateMessageHeader = ArrayConverter.hexStringToByteArray("0b00030e000000000000030e");
static byte[] certificateMessage = ArrayConverter
.hexStringToByteArray("00030b00030830820304308201ec020900d0f4245a0e4132f5300d06092a"
+ "864886f70d01010b05003044310b3009060355040613024445310c300a06035504080c036e7277310c300a060355040a0c03626c61310c300a"
+ "060355040b0c03626c61310b300906035504030c02626c301e170d3135303732323137333434325a170d3235303731393137333434325a3044"
+ "310b3009060355040613024445310c300a06035504080c036e7277310c300a060355040a0c03626c61310c300a060355040b0c03626c61310b"
+ "300906035504030c02626c30820122300d06092a864886f70d01010105000382010f003082010a0282010100b5b35dcf8034fd6f0d2220de29"
+ "7a1c7b9de644d37d0e536fece3fc741bd181e0f7ccd3d224fbb813ed941e52bd943060fc4c51174bf50eef96b71c453d275072ad45ddba68c9"
+ "909dd2692673048f9eeb1485ea9d3ecd33f7d1e91cf2e7ff3e50e62c4543ee5bbbdb9f3ec5763bb5a2ff2a45ccee9828f708cc17db60abba9d"
+ "f571afe62f5064ecd96470514ed2ac214cebfe624893ff5f62fdecd5969b8915eb0fba8fe5d2355833f1000dfcbafc0842b71943636c127a94"
+ "88f7056da18213889f91d63c7baaddc9c032581bcd4b37f58f93b550b0ccbc2026460a12af537dc812e84bf89d362ff737046ed6c5b0507efd"
+ "d751cbb7c03211e287da9f7ea5aa730203010001300d06092a864886f70d01010b0500038201010065728672ed0f02abaf84945ea13aa66c5b"
+ "90b8bb8d9cfeda47dffc80b8125f5fd76867920dfd7138679f03bf801d0640e473618a6ecb6a16bbf2fac13d8a621a09ed4e823658777d6c4f"
+ "68ddbb549acb67ed547aac153c85a707da0eeae53210196bbdcb2463f6ded663345d7e0fb780f29e03301100e6028ad520feebedab74aa8dd6"
+ "26c3d5b4412c07e844618e6f7ccd731303277e028a24543da4a226c3d128162e7edfcfb1d45daff0e73fd3ba984836f68b746b18403afcd06a"
+ "bd99c967a684de7df75abf8783ba5148d02aa156a334f8bec4f37debedf9ee16c9222a15f66fee055baaf40cbfed9f95f2e00019eeb67d72d9"
+ "0afed2d8f3abafdff409b8");
static byte[] serverDoneMessageHeader = ArrayConverter.hexStringToByteArray("0e00000004FF000000000000");
static Record message1Record, message2Variant1Record, message2Variant2Record1, message2Variant2Record2,
message2Variant2Record3, message2Variant3Record1, message2Variant3Record2, message2Variant3Record3,
message2Variant3Record4, message2Variant3Record5, message2Variant3Record6, message2Variant3Record7,
message3Record;
HandshakeFragmentHandler hfh = new HandshakeFragmentHandler();
@BeforeClass
public static void prepareRecords() {
message1Record = new Record();
message1Record.setContentType((byte) 22);
message2Variant1Record = new Record();
message2Variant1Record.setContentType((byte) 22);
message2Variant2Record1 = new Record();
message2Variant2Record1.setContentType((byte) 22);
message2Variant2Record2 = new Record();
message2Variant2Record2.setContentType((byte) 22);
message2Variant2Record3 = new Record();
message2Variant2Record3.setContentType((byte) 22);
message2Variant3Record1 = new Record();
message2Variant3Record1.setContentType((byte) 22);
message2Variant3Record2 = new Record();
message2Variant3Record2.setContentType((byte) 22);
message2Variant3Record3 = new Record();
message2Variant3Record3.setContentType((byte) 22);
message2Variant3Record4 = new Record();
message2Variant3Record4.setContentType((byte) 22);
message2Variant3Record5 = new Record();
message2Variant3Record5.setContentType((byte) 22);
message2Variant3Record6 = new Record();
message2Variant3Record6.setContentType((byte) 22);
message2Variant3Record7 = new Record();
message2Variant3Record7.setContentType((byte) 22);
message3Record = new Record();
message3Record.setContentType((byte) 22);
message1Record
.setProtocolMessageBytes(ArrayConverter.concatenate(serverHelloMessageHeader, serverHelloMessage));
message2Variant1Record.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e000000000000012C"),
Arrays.copyOfRange(certificateMessage, 0, 300),
ArrayConverter.hexStringToByteArray("0b00030e000000012C00012C"),
Arrays.copyOfRange(certificateMessage, 300, 600),
ArrayConverter.hexStringToByteArray("0b00030e00000002580000B6"),
Arrays.copyOfRange(certificateMessage, 600, 782)));
message2Variant2Record1.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e000000000000012C"),
Arrays.copyOfRange(certificateMessage, 0, 300)));
message2Variant2Record2.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e000000012C00012C"),
Arrays.copyOfRange(certificateMessage, 300, 600)));
message2Variant2Record3.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e00000002580000B6"),
Arrays.copyOfRange(certificateMessage, 600, 782)));
message2Variant3Record1.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e0000000000000080"),
Arrays.copyOfRange(certificateMessage, 0, 128)));
message2Variant3Record2.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e000000006400009C"),
Arrays.copyOfRange(certificateMessage, 100, 256)));
message2Variant3Record3.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e0000000100000080"),
Arrays.copyOfRange(certificateMessage, 256, 384)));
message2Variant3Record4.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e000000012C0000D4"),
Arrays.copyOfRange(certificateMessage, 300, 512)));
message2Variant3Record5.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e0000000200000080"),
Arrays.copyOfRange(certificateMessage, 512, 640)));
message2Variant3Record6.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e0000000280000080"),
Arrays.copyOfRange(certificateMessage, 640, 768)));
message2Variant3Record7.setProtocolMessageBytes(ArrayConverter.concatenate(
ArrayConverter.hexStringToByteArray("0b00030e000000030000000E"),
Arrays.copyOfRange(certificateMessage, 768, 782)));
message3Record.setProtocolMessageBytes(serverDoneMessageHeader);
}
@Test
public void testProcessHandshakeRecord() {
byte[] result;
byte[] expectedResult;
hfh.processHandshakeRecord(message1Record);
result = hfh.getHandshakeMessage();
expectedResult = ArrayConverter.concatenate(serverHelloMessageHeader, serverHelloMessage);
assertArrayEquals("Check unfragmentened message", expectedResult, result);
hfh.flush();
hfh.processHandshakeRecord(message2Variant1Record);
result = hfh.getHandshakeMessage();
expectedResult = ArrayConverter.concatenate(certificateMessageHeader, certificateMessage);
assertArrayEquals("Check fragmented message in single record", expectedResult, result);
hfh.flush();
hfh.processHandshakeRecord(message2Variant2Record1);
result = hfh.getHandshakeMessage();
assertNull("One of three fragment parsed, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant2Record3);
result = hfh.getHandshakeMessage();
assertNull("Two of three fragment parsed, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant2Record2);
result = hfh.getHandshakeMessage();
expectedResult = ArrayConverter.concatenate(certificateMessageHeader, certificateMessage);
assertArrayEquals("Check fragmented message (3 fragments)", expectedResult, result);
hfh.flush();
hfh.processHandshakeRecord(message2Variant3Record6);
result = hfh.getHandshakeMessage();
assertNull("One of seven fragments parsed, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant3Record5);
result = hfh.getHandshakeMessage();
assertNull("Two of seven fragments parsed, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant3Record3);
result = hfh.getHandshakeMessage();
assertNull("Three of seven fragments parsed, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant3Record2);
result = hfh.getHandshakeMessage();
assertNull("Four of seven fragments parsed, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant3Record2);
result = hfh.getHandshakeMessage();
assertNull("Duplicate fragment, no new information, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant3Record7);
result = hfh.getHandshakeMessage();
assertNull("Five of seven fragments parsed, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant3Record1);
result = hfh.getHandshakeMessage();
assertNull("Six of seven fragments parsed, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant3Record2);
result = hfh.getHandshakeMessage();
assertNull("Duplicate fragment, no new information, no bytes should be returned", result);
hfh.processHandshakeRecord(message2Variant3Record4);
result = hfh.getHandshakeMessage();
assertArrayEquals("Check fragmented message (7 fragments, partly overlapping, differen fragment sizes)",
expectedResult, result);
hfh.processHandshakeRecord(message2Variant3Record6);
result = hfh.getHandshakeMessage();
assertArrayEquals("Duplicate fragment, but message already complete, check correct message return",
expectedResult, result);
hfh.flush();
hfh.processHandshakeRecord(message3Record);
hfh.setExpectedHandshakeMessageSeq(1279);
result = hfh.getHandshakeMessage();
expectedResult = serverDoneMessageHeader;
assertArrayEquals(
"Check message consisting just of handshake message header, no content and check message with sequence "
+ "number different from zero.", expectedResult, result);
}
@Test
public void testCreateCompleteHandshakeMessageHeader() {
byte[] result = hfh.createCompleteHandshakeMessageHeader((byte) 0x00, 0, 0);
byte[] expectedResult = ArrayConverter.hexStringToByteArray("000000000000000000000000");
assertArrayEquals("Check 'all zero' input", expectedResult, result);
result = hfh.createCompleteHandshakeMessageHeader((byte) 0x9B, 5316, 897461);
expectedResult = ArrayConverter.hexStringToByteArray("9B0DB1B514C40000000DB1B5");
assertArrayEquals("Check some input", expectedResult, result);
result = hfh.createCompleteHandshakeMessageHeader((byte) 0xFF, 65535, 16777215);
expectedResult = ArrayConverter.hexStringToByteArray("FFFFFFFFFFFF000000FFFFFF");
assertArrayEquals("Check max input", expectedResult, result);
}
@Test
public void testGetHandshakeMessage() {
loadServerHelloMessasge();
byte[] result = hfh.getHandshakeMessage();
byte[] expectedResult = ArrayConverter.concatenate(serverHelloMessageHeader, serverHelloMessage);
assertArrayEquals("Check correct return of loaded message", expectedResult, result);
hfh.flush();
loadServerHelloMessageIncomplete();
result = hfh.getHandshakeMessage();
assertNull("Check null return when message incomplete", result);
}
@Test
public void testCheckHandshakeMessageAvailable() {
loadServerHelloMessasge();
boolean result = hfh.checkHandshakeMessageAvailable(0);
assertTrue("Check availability of loaded message", result);
hfh.flush();
loadServerHelloMessageIncomplete();
result = hfh.checkHandshakeMessageAvailable(0);
assertFalse("Check if uncompletely loaded message is not available", result);
}
@Test
public void testFragmentHandshakeMessage() {
byte[] result = hfh.fragmentHandshakeMessage(
ArrayConverter.concatenate(certificateMessageHeader, certificateMessage), 10000);
byte[] expectedResult = ArrayConverter.concatenate(certificateMessageHeader, certificateMessage);
assertArrayEquals("Check unfragmented message:", expectedResult, result);
result = hfh.fragmentHandshakeMessage(ArrayConverter.concatenate(certificateMessageHeader, certificateMessage),
403);
expectedResult = ArrayConverter.concatenate(ArrayConverter.hexStringToByteArray("0b00030e0000000000000187"),
Arrays.copyOf(certificateMessage, 391),
ArrayConverter.hexStringToByteArray("0b00030e0000000187000187"),
Arrays.copyOfRange(certificateMessage, 391, 782));
assertArrayEquals("Check fragmented message (two fragments):", expectedResult, result);
result = hfh.fragmentHandshakeMessage(ArrayConverter.concatenate(certificateMessageHeader, certificateMessage),
362);
expectedResult = ArrayConverter.concatenate(ArrayConverter.hexStringToByteArray("0b00030e000000000000015E"),
Arrays.copyOf(certificateMessage, 350),
ArrayConverter.hexStringToByteArray("0b00030e000000015E00015E"),
Arrays.copyOfRange(certificateMessage, 350, 700),
ArrayConverter.hexStringToByteArray("0b00030e00000002BC000052"),
Arrays.copyOfRange(certificateMessage, 700, 782));
assertArrayEquals("Check fragmented message (three fragments):", expectedResult, result);
result = hfh.fragmentHandshakeMessage(ArrayConverter.concatenate(certificateMessageHeader, certificateMessage),
112);
expectedResult = ArrayConverter.concatenate(ArrayConverter.hexStringToByteArray("0b00030e0000000000000064"),
Arrays.copyOf(certificateMessage, 100),
ArrayConverter.hexStringToByteArray("0b00030e0000000064000064"),
Arrays.copyOfRange(certificateMessage, 100, 200),
ArrayConverter.hexStringToByteArray("0b00030e00000000C8000064"),
Arrays.copyOfRange(certificateMessage, 200, 300),
ArrayConverter.hexStringToByteArray("0b00030e000000012c000064"),
Arrays.copyOfRange(certificateMessage, 300, 400),
ArrayConverter.hexStringToByteArray("0b00030e0000000190000064"),
Arrays.copyOfRange(certificateMessage, 400, 500),
ArrayConverter.hexStringToByteArray("0b00030e00000001F4000064"),
Arrays.copyOfRange(certificateMessage, 500, 600),
ArrayConverter.hexStringToByteArray("0b00030e0000000258000064"),
Arrays.copyOfRange(certificateMessage, 600, 700),
ArrayConverter.hexStringToByteArray("0b00030e00000002BC000052"),
Arrays.copyOfRange(certificateMessage, 700, 782));
assertArrayEquals("Check fragmented message (eight fragments):", expectedResult, result);
}
private void loadServerHelloMessasge() {
List<Record> recordList = new ArrayList<>();
BitSet messageBitmask = new BitSet();
messageBitmask.set(0, message1Record.getProtocolMessageBytes().getValue().length, true);
recordList.add(message1Record);
hfh.handshakeMessageRecordMap.put(0, recordList);
hfh.handshakeMessageReassembleBitmaskMap.put(0, messageBitmask);
hfh.reassembledHandshakeMessageMap.put(0, message1Record.getProtocolMessageBytes().getValue());
}
private void loadServerHelloMessageIncomplete() {
List<Record> recordList = new ArrayList<>();
BitSet messageBitmask = new BitSet(12);
hfh.handshakeMessageRecordMap.put(0, recordList);
hfh.handshakeMessageReassembleBitmaskMap.put(0, messageBitmask);
hfh.reassembledHandshakeMessageMap.put(0, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
}
}