/**
* 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 java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyStoreException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateParsingException;
import java.util.Arrays;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.crypto.tls.Certificate;
import org.bouncycastle.crypto.tls.TlsUtils;
import org.bouncycastle.jce.provider.X509CertificateObject;
import de.rub.nds.tlsattacker.tls.constants.ConnectionEnd;
import de.rub.nds.tlsattacker.tls.constants.HandshakeByteLength;
import de.rub.nds.tlsattacker.tls.constants.HandshakeMessageType;
import de.rub.nds.tlsattacker.tls.exceptions.ConfigurationException;
import de.rub.nds.tlsattacker.tls.exceptions.InvalidMessageTypeException;
import de.rub.nds.tlsattacker.tls.exceptions.WorkflowExecutionException;
import de.rub.nds.tlsattacker.tls.workflow.TlsContext;
import de.rub.nds.tlsattacker.util.ArrayConverter;
/**
* @author Juraj Somorovsky <juraj.somorovsky@rub.de>
* @param <HandshakeMessage>
*/
public class CertificateHandler<Message extends CertificateMessage> extends
HandshakeMessageHandler<Message> {
@SuppressWarnings("unchecked")
public CertificateHandler(TlsContext tlsContext) {
super(tlsContext);
this.correctProtocolMessageClass = (Class<? extends Message>) CertificateMessage.class;
}
@Override
public byte[] prepareMessageAction() {
try {
// todo try to find a better solution for converting sun -> bc
// certificates
String alias = tlsContext.getAlias();
java.security.cert.Certificate sunCert = tlsContext.getKeyStore().getCertificate(alias);
if (alias == null || sunCert == null) {
throw new ConfigurationException("The certificate cannot be fetched. Have you provided correct "
+ "certificate alias and key? (Current alias: " + alias + ")");
}
byte[] certBytes = sunCert.getEncoded();
ASN1Primitive asn1Cert = TlsUtils.readDERObject(certBytes);
org.bouncycastle.asn1.x509.Certificate cert = org.bouncycastle.asn1.x509.Certificate.getInstance(asn1Cert);
org.bouncycastle.asn1.x509.Certificate[] certs = new org.bouncycastle.asn1.x509.Certificate[1];
certs[0] = cert;
Certificate tlsCerts = new Certificate(certs);
X509CertificateObject x509CertObject = new X509CertificateObject(tlsCerts.getCertificateAt(0));
protocolMessage.setX509CertificateObject(x509CertObject);
if (protocolMessage.getMessageIssuer() == ConnectionEnd.SERVER) {
tlsContext.setServerCertificate(tlsCerts.getCertificateAt(0));
tlsContext.setX509ServerCertificateObject(x509CertObject);
} else {
tlsContext.setClientCertificate(tlsCerts.getCertificateAt(0));
tlsContext.setX509ClientCertificateObject(x509CertObject);
}
ByteArrayOutputStream tlsCertBos = new ByteArrayOutputStream();
tlsCerts.encode(tlsCertBos);
protocolMessage.setX509CertificateBytes(tlsCertBos.toByteArray());
// byte[] x509CertBytes = x509CertObject.getEncoded();
protocolMessage.setCertificatesLength(protocolMessage.getX509CertificateBytes().getValue().length
- HandshakeByteLength.CERTIFICATES_LENGTH);
// protocolMessage.setLength(protocolMessage.getCertificatesLength().getValue()
// + HandshakeByteLength.CERTIFICATES_LENGTH);
// BC implicitly includes the certificates length of all the
// certificates, so we only need to set the protocol message length
protocolMessage.setLength(protocolMessage.getX509CertificateBytes().getValue().length);
byte[] result = protocolMessage.getX509CertificateBytes().getValue();
long header = (protocolMessage.getHandshakeMessageType().getValue() << 24)
+ protocolMessage.getLength().getValue();
protocolMessage.setCompleteResultingMessage(ArrayConverter.concatenate(
ArrayConverter.longToUint32Bytes(header), result));
return protocolMessage.getCompleteResultingMessage().getValue();
} catch (KeyStoreException | CertificateEncodingException | IOException | CertificateParsingException ex) {
throw new ConfigurationException("Certificate with the selected alias could not be found", ex);
}
}
@Override
public int parseMessageAction(byte[] message, int pointer) {
if (message[pointer] != HandshakeMessageType.CERTIFICATE.getValue()) {
throw new InvalidMessageTypeException("This is not a certificate message");
}
protocolMessage.setType(message[pointer]);
int currentPointer = pointer + HandshakeByteLength.MESSAGE_TYPE;
int nextPointer = currentPointer + HandshakeByteLength.MESSAGE_TYPE_LENGTH;
int length = ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer));
protocolMessage.setLength(length);
currentPointer = nextPointer;
nextPointer = currentPointer + HandshakeByteLength.CERTIFICATES_LENGTH;
int certificatesLength = ArrayConverter.bytesToInt(Arrays.copyOfRange(message, currentPointer, nextPointer));
protocolMessage.setCertificatesLength(certificatesLength);
try {
Certificate tlsCerts = Certificate.parse(new ByteArrayInputStream(message, currentPointer, protocolMessage
.getCertificatesLength().getValue() + HandshakeByteLength.CERTIFICATES_LENGTH));
X509CertificateObject x509CertObject = new X509CertificateObject(tlsCerts.getCertificateAt(0));
protocolMessage.setX509CertificateObject(x509CertObject);
if (protocolMessage.getMessageIssuer() == ConnectionEnd.SERVER) {
tlsContext.setServerCertificate(tlsCerts.getCertificateAt(0));
tlsContext.setX509ServerCertificateObject(x509CertObject);
} else {
tlsContext.setClientCertificate(tlsCerts.getCertificateAt(0));
tlsContext.setX509ClientCertificateObject(x509CertObject);
}
} catch (IOException | CertificateParsingException ex) {
throw new WorkflowExecutionException(ex.getLocalizedMessage(), ex);
}
nextPointer = nextPointer + protocolMessage.getCertificatesLength().getValue();
protocolMessage.setCompleteResultingMessage(Arrays.copyOfRange(message, pointer, nextPointer));
return nextPointer;
}
}