/** * 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.heartbeat; import de.rub.nds.tlsattacker.tls.protocol.ProtocolMessageHandler; import de.rub.nds.tlsattacker.tls.constants.HandshakeByteLength; import de.rub.nds.tlsattacker.tls.constants.HeartbeatByteLength; import de.rub.nds.tlsattacker.tls.constants.HeartbeatMessageType; import de.rub.nds.tlsattacker.tls.workflow.TlsContext; import de.rub.nds.tlsattacker.util.ArrayConverter; import de.rub.nds.tlsattacker.util.RandomHelper; import java.util.Arrays; /** * Handler for Heartbeat messages: http://tools.ietf.org/html/rfc6520#page-4 * * @author Juraj Somorovsky <juraj.somorovsky@rub.de> */ public class HeartbeatHandler extends ProtocolMessageHandler<HeartbeatMessage> { /** * max payload length used in our application (not set by the spec) */ static final int MAX_PAYLOAD_LENGTH = 256; /** * according to the specification, the min padding length is 16 */ static final int MIN_PADDING_LENGTH = 16; /** * max padding length used in our application (not set by the spec) */ static final int MAX_PADDING_LENGTH = 256; public HeartbeatHandler(TlsContext tlsContext) { super(tlsContext); correctProtocolMessageClass = HeartbeatMessage.class; } @Override public byte[] prepareMessageAction() { protocolMessage.setHeartbeatMessageType(HeartbeatMessageType.HEARTBEAT_REQUEST.getValue()); int payloadLength = RandomHelper.getRandom().nextInt(MAX_PAYLOAD_LENGTH); byte[] payload = new byte[payloadLength]; RandomHelper.getRandom().nextBytes(payload); protocolMessage.setPayload(payload); protocolMessage.setPayloadLength(protocolMessage.getPayload().getValue().length); // we create only 16 bytes of 0x00 padding (for convenience) // int paddingLength = randomGenerator.nextInt(MAX_PADDING_LENGTH) + // MIN_PADDING_LENGTH; int paddingLength = MIN_PADDING_LENGTH; byte[] padding = new byte[paddingLength]; // randomGenerator.nextBytes(padding); protocolMessage.setPadding(padding); byte[] type = { protocolMessage.getHeartbeatMessageType().getValue() }; byte[] result = ArrayConverter.concatenate(type, ArrayConverter.intToBytes(protocolMessage.getPayloadLength() .getValue(), HeartbeatByteLength.PAYLOAD_LENGTH), protocolMessage.getPayload().getValue(), protocolMessage.getPadding().getValue()); protocolMessage.setCompleteResultingMessage(result); return result; } @Override public int parseMessageAction(byte[] message, int pointer) { protocolMessage.setHeartbeatMessageType(message[pointer]); int currentPointer = pointer + HandshakeByteLength.MESSAGE_TYPE; int nextPointer = currentPointer + HeartbeatByteLength.PAYLOAD_LENGTH; int payloadLength = ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer)); protocolMessage.setPayloadLength(payloadLength); currentPointer = nextPointer; nextPointer = nextPointer + payloadLength; protocolMessage.setPayload(Arrays.copyOfRange(message, currentPointer, nextPointer)); currentPointer = nextPointer; nextPointer = message.length; protocolMessage.setPadding(Arrays.copyOfRange(message, currentPointer, nextPointer)); return nextPointer; } }