/**
* 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 de.rub.nds.tlsattacker.tls.constants.AlgorithmResolver;
import de.rub.nds.tlsattacker.tls.crypto.PseudoRandomFunction;
import de.rub.nds.tlsattacker.tls.exceptions.WorkflowExecutionException;
import de.rub.nds.tlsattacker.tls.constants.HandshakeByteLength;
import de.rub.nds.tlsattacker.tls.constants.KeyExchangeAlgorithm;
import de.rub.nds.tlsattacker.tls.constants.PRFAlgorithm;
import de.rub.nds.tlsattacker.tls.exceptions.ConfigurationException;
import de.rub.nds.tlsattacker.tls.workflow.TlsContext;
import de.rub.nds.tlsattacker.util.ArrayConverter;
import de.rub.nds.tlsattacker.util.RandomHelper;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* @author Juraj Somorovsky <juraj.somorovsky@rub.de>
* @author Philip Riese <philip.riese@rub.de>
*/
public class RSAClientKeyExchangeHandler extends ClientKeyExchangeHandler<RSAClientKeyExchangeMessage> {
private static final Logger LOGGER = LogManager.getLogger(RSAClientKeyExchangeHandler.class);
public RSAClientKeyExchangeHandler(TlsContext tlsContext) {
super(tlsContext);
this.correctProtocolMessageClass = RSAClientKeyExchangeMessage.class;
this.keyExchangeAlgorithm = KeyExchangeAlgorithm.RSA;
}
@Override
byte[] prepareKeyExchangeMessage() {
RSAPublicKey publicKey = (RSAPublicKey) tlsContext.getX509ServerCertificateObject().getPublicKey();
int keyByteLength = publicKey.getModulus().bitLength() / 8;
// the number of random bytes in the pkcs1 message
int randomByteLength = keyByteLength - HandshakeByteLength.PREMASTER_SECRET - 3;
byte[] padding = new byte[randomByteLength];
RandomHelper.getRandom().nextBytes(padding);
ArrayConverter.makeArrayNonZero(padding);
byte[] premasterSecret = new byte[HandshakeByteLength.PREMASTER_SECRET];
// forward the PMS with the key of the target server during MitM
if (tlsContext.isMitMAttack()) {
premasterSecret = protocolMessage.getPremasterSecret().getValue();
} else {
RandomHelper.getRandom().nextBytes(premasterSecret);
premasterSecret[0] = tlsContext.getProtocolVersion().getMajor();
premasterSecret[1] = tlsContext.getProtocolVersion().getMinor();
}
protocolMessage.setPremasterSecret(premasterSecret);
LOGGER.debug("Computed PreMaster Secret: {}",
ArrayConverter.bytesToHexString(protocolMessage.getPremasterSecret().getValue()));
protocolMessage.setPlainPaddedPremasterSecret(ArrayConverter.concatenate(new byte[] { 0x00, 0x02 }, padding,
new byte[] { 0x00 }, protocolMessage.getPremasterSecret().getValue()));
byte[] paddedPremasterSecret = protocolMessage.getPlainPaddedPremasterSecret().getValue();
byte[] random = tlsContext.getClientServerRandom();
PRFAlgorithm prfAlgorithm = AlgorithmResolver.getPRFAlgorithm(tlsContext.getProtocolVersion(),
tlsContext.getSelectedCipherSuite());
byte[] masterSecret = PseudoRandomFunction.compute(prfAlgorithm, protocolMessage.getPremasterSecret()
.getValue(), PseudoRandomFunction.MASTER_SECRET_LABEL, random, HandshakeByteLength.MASTER_SECRET);
protocolMessage.setMasterSecret(masterSecret);
LOGGER.debug("Computed Master Secret: {}", ArrayConverter.bytesToHexString(masterSecret));
tlsContext.setMasterSecret(protocolMessage.getMasterSecret().getValue());
try {
Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
LOGGER.debug("Encrypting the following padded premaster secret: {}",
ArrayConverter.bytesToHexString(paddedPremasterSecret));
byte[] encrypted = cipher.doFinal(paddedPremasterSecret);
protocolMessage.setEncryptedPremasterSecret(encrypted);
protocolMessage
.setEncryptedPremasterSecretLength(protocolMessage.getEncryptedPremasterSecret().getValue().length);
return ArrayConverter.concatenate(ArrayConverter.intToBytes(protocolMessage
.getEncryptedPremasterSecretLength().getValue(),
HandshakeByteLength.ENCRYPTED_PREMASTER_SECRET_LENGTH), protocolMessage
.getEncryptedPremasterSecret().getValue());
} catch (BadPaddingException | IllegalBlockSizeException | NoSuchProviderException | InvalidKeyException
| NoSuchAlgorithmException | NoSuchPaddingException ex) {
LOGGER.info(ex);
throw new WorkflowExecutionException(ex.getLocalizedMessage());
}
}
@Override
int parseKeyExchangeMessage(byte[] message, int currentPointer) {
int nextPointer = currentPointer + HandshakeByteLength.ENCRYPTED_PREMASTER_SECRET_LENGTH;
int length = ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer));
protocolMessage.setEncryptedPremasterSecretLength(length);
currentPointer = nextPointer;
nextPointer = currentPointer + length;
protocolMessage.setEncryptedPremasterSecret(Arrays.copyOfRange(message, currentPointer, nextPointer));
byte[] encryptedPremasterSecret = protocolMessage.getEncryptedPremasterSecret().getValue();
KeyStore ks = tlsContext.getKeyStore();
try {
Key key = ks.getKey(tlsContext.getAlias(), tlsContext.getPassword().toCharArray());
RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
cipher.init(Cipher.DECRYPT_MODE, rsaKey);
LOGGER.debug("Decrypting the following encrypted premaster secret: {}",
ArrayConverter.bytesToHexString(encryptedPremasterSecret));
byte[] decrypted = cipher.doFinal(encryptedPremasterSecret);
protocolMessage.setPlainPaddedPremasterSecret(decrypted);
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | InvalidKeyException
| NoSuchProviderException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException ex) {
throw new ConfigurationException(
"Something went wrong loading key from Keystore or decrypting Premastersecret", ex);
}
byte[] plainPaddedPremasterSecret = protocolMessage.getPlainPaddedPremasterSecret().getValue();
int plainPaddedPremasterSecretLength = plainPaddedPremasterSecret.length;
int plainPaddedPremasterSecretoffset = plainPaddedPremasterSecretLength - 48;
byte[] premasterSecret = Arrays.copyOfRange(plainPaddedPremasterSecret, plainPaddedPremasterSecretoffset,
plainPaddedPremasterSecretLength);
LOGGER.debug("Resulting premaster secret: {}", ArrayConverter.bytesToHexString(premasterSecret));
protocolMessage.setPremasterSecret(premasterSecret);
tlsContext.setPreMasterSecret(premasterSecret);
byte[] random = tlsContext.getClientServerRandom();
PRFAlgorithm prfAlgorithm = AlgorithmResolver.getPRFAlgorithm(tlsContext.getProtocolVersion(),
tlsContext.getSelectedCipherSuite());
byte[] masterSecret = PseudoRandomFunction.compute(prfAlgorithm, protocolMessage.getPremasterSecret()
.getValue(), PseudoRandomFunction.MASTER_SECRET_LABEL, random, HandshakeByteLength.MASTER_SECRET);
protocolMessage.setMasterSecret(masterSecret);
LOGGER.debug("Computed Master Secret: {}", ArrayConverter.bytesToHexString(masterSecret));
tlsContext.setMasterSecret(protocolMessage.getMasterSecret().getValue());
currentPointer = nextPointer;
return currentPointer;
}
}