/** * 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.tls.protocol.handshake; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; import org.junit.Test; import de.rub.nds.tlsattacker.dtls.protocol.handshake.ClientHelloDtlsMessage; import de.rub.nds.tlsattacker.tls.constants.CipherSuite; import de.rub.nds.tlsattacker.tls.constants.CompressionMethod; import de.rub.nds.tlsattacker.tls.constants.ExtensionType; import de.rub.nds.tlsattacker.tls.constants.HandshakeMessageType; import de.rub.nds.tlsattacker.tls.constants.HeartbeatMode; import de.rub.nds.tlsattacker.tls.constants.NamedCurve; import de.rub.nds.tlsattacker.tls.constants.ProtocolVersion; import de.rub.nds.tlsattacker.tls.protocol.extension.EllipticCurvesExtensionMessage; import de.rub.nds.tlsattacker.tls.protocol.extension.ExtensionMessage; import de.rub.nds.tlsattacker.tls.protocol.extension.HeartbeatExtensionMessage; import de.rub.nds.tlsattacker.tls.workflow.TlsContext; import de.rub.nds.tlsattacker.util.ArrayConverter; import static org.junit.Assert.*; /** * * @author Juraj Somorovsky <juraj.somorovsky@rub.de> * @author Florian Pfützenreuter <florian.pfuetzenreuter@rub.de> * @author Philip Riese <philip.riese@rub.de> */ public class ClientHelloHandlerTest { static byte[] clientHelloWithoutExtensionBytes = ArrayConverter .hexStringToByteArray("01000059030336CCE3E132A0C5B5DE2C0560B4FF7F6CDF7AE226120E4A99C07E2D9B68B275BB20FA6F8E9770106ACE8ACAB73E18B5D867CAF8AF7E206EF496F23A206A379FC7110012C02BC02FC00AC009C013C014002F0035000A0100"); static byte[] clientHelloWithHeartbeatandEllipticCurvesBytes = ArrayConverter .hexStringToByteArray("0100003A0303561EAC1C71D111AB0186813D11808C3EEA236E37C0110A75B929D6E0A3F53F42000002C0300100000F000F000101000A00060004000F0001"); static byte[] clientHelloWithHeartbeatBytes = ArrayConverter .hexStringToByteArray("010000300303561EAC1C71D111AB0186813D11808C3EEA236E37C0110A75B929D6E0A3F53F42000002C03001000005000F000101"); // DTLS clientHello with the dtls handshake fields (messageSeq, // fragmentOffset and fragmentLength) already stripped out. // Thus, only the cookie remains. static byte[] dtlsClientHelloWithoutExtensionBytes = ArrayConverter .hexStringToByteArray("0100005eFEFD36CCE3E132A0C5B5DE2C0560B4FF7F6CDF7AE226120E4A99C07E2D9B68B275BB20FA6F8E9770106ACE8ACAB73E18B5D867CAF8AF7E206EF496F23A206A379FC711061122334455660012C02BC02FC00AC009C013C014002F0035000A0100"); static byte[] cookie = ArrayConverter.hexStringToByteArray("1122334455667788"); ClientHelloHandler<ClientHelloDtlsMessage> handler; ClientHelloHandler<ClientHelloDtlsMessage> dtlshandler; TlsContext tlsContext = new TlsContext(); TlsContext dtlsContext = new TlsContext(); public ClientHelloHandlerTest() { tlsContext.setProtocolVersion(ProtocolVersion.TLS12); handler = new ClientHelloHandler<>(tlsContext); dtlsContext.setDtlsHandshakeCookie(cookie); dtlsContext.setProtocolVersion(ProtocolVersion.DTLS12); dtlshandler = new ClientHelloHandler<>(dtlsContext); } /** * Test of prepareMessageAction method, of class ClientHelloHandler. */ @Test public void testPrepareMessage() { dtlshandler.setProtocolMessage(new ClientHelloDtlsMessage()); ClientHelloDtlsMessage message = (ClientHelloDtlsMessage) dtlshandler.getProtocolMessage(); List<CipherSuite> cipherSuites = new ArrayList<>(); cipherSuites.add(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384); message.setSupportedCipherSuites(cipherSuites); List<CompressionMethod> compressionMethods = new ArrayList<>(); compressionMethods.add(CompressionMethod.NULL); message.setSupportedCompressionMethods(compressionMethods); byte[] returned = dtlshandler.prepareMessageAction(); byte[] expected = ArrayConverter.concatenate(new byte[] { HandshakeMessageType.CLIENT_HELLO.getValue() }, new byte[] { 0x00, 0x00, 0x32 }, ProtocolVersion.DTLS12.getValue(), message.getUnixTime().getValue(), message.getRandom().getValue(), new byte[] { 0x00, 0x08 }, cookie, new byte[] { 0x00, 0x02 }, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384.getByteValue(), new byte[] { 0x01, CompressionMethod.NULL.getValue() }); assertNotNull("Confirm function didn't return 'NULL'", returned); assertArrayEquals("Confirm returned message equals the expected message", expected, returned); } @Test public void testPrepareMessageWithExtensions() { handler.setProtocolMessage(new ClientHelloDtlsMessage()); de.rub.nds.tlsattacker.tls.protocol.handshake.ClientHelloMessage message = (de.rub.nds.tlsattacker.tls.protocol.handshake.ClientHelloMessage) handler .getProtocolMessage(); List<CipherSuite> cipherSuites = new ArrayList<>(); cipherSuites.add(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384); message.setSupportedCipherSuites(cipherSuites); List<CompressionMethod> compressionMethods = new ArrayList<>(); compressionMethods.add(CompressionMethod.NULL); message.setSupportedCompressionMethods(compressionMethods); HeartbeatExtensionMessage heart; heart = new HeartbeatExtensionMessage(); heart.setHeartbeatModeConfig(HeartbeatMode.PEER_ALLOWED_TO_SEND); EllipticCurvesExtensionMessage ecc; ecc = new EllipticCurvesExtensionMessage(); List<NamedCurve> curve = new ArrayList<>(); curve.add(NamedCurve.SECP160K1); curve.add(NamedCurve.SECT163K1); ecc.setSupportedCurvesConfig(curve); List<ExtensionMessage> extensions = new ArrayList<>(); extensions.add(heart); extensions.add(ecc); message.setExtensions(extensions); byte[] returned = handler.prepareMessageAction(); byte[] expected = ArrayConverter.concatenate(new byte[] { HandshakeMessageType.CLIENT_HELLO.getValue() }, new byte[] { 0x00, 0x00, 0x3A }, ProtocolVersion.TLS12.getValue(), message.getUnixTime().getValue(), message.getRandom().getValue(), ArrayConverter.intToBytes(message.getSessionIdLength().getValue(), 1), new byte[] { 0x00, 0x02 }, CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384.getByteValue(), new byte[] { 0x01, CompressionMethod.NULL.getValue() }, new byte[] { 0x00, 0x0F }, ExtensionType.HEARTBEAT.getValue(), new byte[] { 0x00, 0x01, HeartbeatMode.PEER_ALLOWED_TO_SEND.getValue() }, ExtensionType.ELLIPTIC_CURVES.getValue(), new byte[] { 0x00, 0x06 }, new byte[] { 0x00, 0x04 }, NamedCurve.SECP160K1.getValue(), NamedCurve.SECT163K1.getValue()); assertNotNull("Confirm function didn't return 'NULL'", returned); assertArrayEquals("Confirm returned message equals the expected message", expected, returned); } @Test public void testParseMessageAction() { dtlshandler.setProtocolMessage(new ClientHelloDtlsMessage()); int endPointer = dtlshandler.parseMessageAction(dtlsClientHelloWithoutExtensionBytes, 0); ClientHelloDtlsMessage message = (ClientHelloDtlsMessage) dtlshandler.getProtocolMessage(); byte[] expectedRandom = ArrayConverter .hexStringToByteArray("36cce3e132a0c5b5de2c0560b4ff7f6cdf7ae226120e4a99c07e2d9b68b275bb"); byte[] actualRandom = ArrayConverter.concatenate(message.getUnixTime().getValue(), message.getRandom() .getValue()); byte[] expectedSessionID = ArrayConverter .hexStringToByteArray("fa6f8e9770106ace8acab73e18b5d867caf8af7e206ef496f23a206a379fc711"); byte[] actualSessionID = message.getSessionId().getValue(); byte expectedCookieLength = 6; byte actualCookieLength = message.getCookieLength().getValue(); byte[] expectedCookie = ArrayConverter.hexStringToByteArray("112233445566"); byte[] actualCookie = message.getCookie().getValue(); byte[] expectedCipherSuites = ArrayConverter.hexStringToByteArray("c02bc02fc00ac009c013c014002f0035000a"); byte[] actualCipherSuites = message.getCipherSuites().getValue(); assertEquals("Check message type", HandshakeMessageType.CLIENT_HELLO, message.getHandshakeMessageType()); assertEquals("Message length should be 94 bytes", new Integer(94), message.getLength().getValue()); assertArrayEquals("Check Protocol Version", ProtocolVersion.DTLS12.getValue(), message.getProtocolVersion() .getValue()); assertArrayEquals("Check random", expectedRandom, actualRandom); assertEquals("Check session_id length", new Integer(32), message.getSessionIdLength().getValue()); assertArrayEquals("Check session_id", expectedSessionID, actualSessionID); assertEquals("Check cookie length", expectedCookieLength, actualCookieLength); assertArrayEquals("Check cookie", expectedCookie, actualCookie); assertEquals("Check cipher_suites length", new Integer(18), message.getCipherSuiteLength().getValue()); assertArrayEquals("Check cipher_suites", expectedCipherSuites, actualCipherSuites); assertEquals("Check compressions length", new Integer(1), message.getCompressionLength().getValue()); assertArrayEquals("Check compressions", new byte[] { 0x00 }, message.getCompressions().getValue()); assertEquals("Check protocol message length pointer", dtlsClientHelloWithoutExtensionBytes.length, endPointer); } /** * Test of parseMessageActionwithExtensions method, of class * ClientHelloHandler. */ @Test public void testParseMessageWithExtensions() { handler.initializeProtocolMessage(); int endPointer = handler.parseMessageAction(clientHelloWithHeartbeatBytes, 0); de.rub.nds.tlsattacker.tls.protocol.handshake.ClientHelloMessage message = (de.rub.nds.tlsattacker.tls.protocol.handshake.ClientHelloMessage) handler .getProtocolMessage(); assertEquals("Message type must be ClientHello", HandshakeMessageType.CLIENT_HELLO, message.getHandshakeMessageType()); assertEquals("Message length must be 48", new Integer(48), message.getLength().getValue()); assertEquals("Protocol version must be TLS 1.2", ProtocolVersion.TLS12, tlsContext.getProtocolVersion()); assertEquals("Client Session ID Length", new Integer(0), message.getSessionIdLength().getValue()); assertArrayEquals( "Client Random", ArrayConverter.hexStringToByteArray("561EAC1C71D111AB0186813D11808C3EEA236E37C0110A75B929D6E0A3F53F42"), tlsContext.getClientRandom()); assertEquals("Cipersuite Length", new Integer(2), message.getCipherSuiteLength().getValue()); assertArrayEquals("Ciphersuite must be TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384.getByteValue(), message.getCipherSuites().getValue()); assertEquals("Compression Length", new Integer(1), message.getCompressionLength().getValue()); assertArrayEquals("Compression must be null", CompressionMethod.NULL.getArrayValue(), message.getCompressions() .getValue()); assertTrue("Extension must be Heartbeat", message.containsExtension(ExtensionType.HEARTBEAT)); assertEquals("The pointer has to return the length of this message + starting position", clientHelloWithHeartbeatBytes.length, endPointer); } }