/** * 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; import de.rub.nds.tlsattacker.tls.config.ClientCommandConfig; import de.rub.nds.tlsattacker.tls.config.ConfigHandler; import de.rub.nds.tlsattacker.tls.config.ConfigHandlerFactory; import de.rub.nds.tlsattacker.tls.config.GeneralConfig; import de.rub.nds.tlsattacker.tls.constants.AlgorithmResolver; import de.rub.nds.tlsattacker.tls.constants.CipherSuite; import de.rub.nds.tlsattacker.tls.constants.ConnectionEnd; import de.rub.nds.tlsattacker.tls.constants.ProtocolVersion; import de.rub.nds.tlsattacker.tls.constants.PublicKeyAlgorithm; import de.rub.nds.tlsattacker.tls.protocol.ccs.ChangeCipherSpecMessage; import de.rub.nds.tlsattacker.tls.protocol.handshake.CertificateMessage; import de.rub.nds.tlsattacker.tls.protocol.handshake.FinishedMessage; import de.rub.nds.tlsattacker.tls.protocol.handshake.RSAClientKeyExchangeMessage; import de.rub.nds.tlsattacker.tls.protocol.handshake.ServerHelloDoneMessage; import de.rub.nds.tlsattacker.tls.protocol.handshake.ServerHelloMessage; import de.rub.nds.tlsattacker.tls.workflow.TlsContext; import de.rub.nds.tlsattacker.tls.workflow.WorkflowExecutor; import de.rub.nds.tlsattacker.tls.workflow.WorkflowTrace; import de.rub.nds.tlsattacker.tls.workflow.WorkflowTraceType; import de.rub.nds.tlsattacker.tlsserver.KeyStoreGenerator; import de.rub.nds.tlsattacker.tlsserver.TLSServer; import de.rub.nds.tlsattacker.transport.TransportHandler; import java.io.IOException; import java.security.InvalidKeyException; import java.security.KeyManagementException; import java.security.KeyPair; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Security; import java.security.SignatureException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.OperatorCreationException; import java.util.Set; import org.junit.Test; import static org.junit.Assert.*; /** * * @author Juraj Somorovsky - juraj.somorovsky@rub.de */ public class TlsClientTest { private static final Logger LOGGER = LogManager.getLogger(TlsClientTest.class); private TLSServer tlsServer; private static final int PORT = 56789; private static final int TIMEOUT = 2000; public TlsClientTest() { Security.addProvider(new BouncyCastleProvider()); } @Test public void testRSAWorkflows() { try { KeyPair k = KeyStoreGenerator.createRSAKeyPair(1024); KeyStore ks = KeyStoreGenerator.createKeyStore(k); tlsServer = new TLSServer(ks, KeyStoreGenerator.PASSWORD, "TLS", PORT); new Thread(tlsServer).start(); while (!tlsServer.isInitialized()); testExecuteWorkflows(PublicKeyAlgorithm.RSA, PORT); tlsServer.shutdown(); } catch (NoSuchAlgorithmException | CertificateException | IOException | InvalidKeyException | KeyStoreException | NoSuchProviderException | SignatureException | OperatorCreationException | UnrecoverableKeyException | KeyManagementException e) { LOGGER.error("Unable to initialize the TLS server with an RSA key, but the build runs further.", e); } } @Test public void testECWorkflows() { try { KeyPair k = KeyStoreGenerator.createECKeyPair(256); KeyStore ks = KeyStoreGenerator.createKeyStore(k); tlsServer = new TLSServer(ks, KeyStoreGenerator.PASSWORD, "TLS", PORT + 1); new Thread(tlsServer).start(); while (!tlsServer.isInitialized()); testExecuteWorkflows(PublicKeyAlgorithm.EC, PORT + 1); tlsServer.shutdown(); } catch (NoSuchAlgorithmException | CertificateException | IOException | InvalidKeyException | KeyStoreException | NoSuchProviderException | SignatureException | OperatorCreationException | UnrecoverableKeyException | KeyManagementException e) { LOGGER.error("Unable to initialize the TLS server with an EC key, but the build runs further.", e); } } /** * Test of executeWorkflow method, of class WorkflowExecutor. * * @param algorithm * @param port */ public void testExecuteWorkflows(PublicKeyAlgorithm algorithm, int port) { GeneralConfig generalConfig = new GeneralConfig(); generalConfig.setLogLevel(Level.INFO); ConfigHandler configHandler = ConfigHandlerFactory.createConfigHandler("client"); configHandler.initialize(generalConfig); ClientCommandConfig config = new ClientCommandConfig(); config.setConnect("localhost:" + port); config.setTlsTimeout(TIMEOUT); List<String> serverList = Arrays.asList(tlsServer.getCipherSuites()); config.setProtocolVersion(ProtocolVersion.TLS10); testProtocolCompatibility(serverList, configHandler, config, algorithm); config.setProtocolVersion(ProtocolVersion.TLS11); testProtocolCompatibility(serverList, configHandler, config, algorithm); config.setProtocolVersion(ProtocolVersion.TLS12); testProtocolCompatibility(serverList, configHandler, config, algorithm); if (algorithm == PublicKeyAlgorithm.RSA) { testCustomWorkflow(port); } } private void testProtocolCompatibility(List<String> serverList, ConfigHandler configHandler, ClientCommandConfig config, PublicKeyAlgorithm algorithm) { LOGGER.info(config.getProtocolVersion()); for (CipherSuite cs : CipherSuite.getImplemented()) { Set<PublicKeyAlgorithm> requiredAlgorithms = AlgorithmResolver.getRequiredKeystoreAlgorithms(cs); requiredAlgorithms.remove(algorithm); if (serverList.contains(cs.toString()) && cs.isSupportedInProtocol(config.getProtocolVersion()) && requiredAlgorithms.isEmpty()) { LOGGER.info("Testing: {}", cs); LinkedList<CipherSuite> cslist = new LinkedList<>(); cslist.add(cs); config.setCipherSuites(cslist); testExecuteWorkflow(configHandler, config); } } } private void testExecuteWorkflow(ConfigHandler configHandler, ClientCommandConfig config) { TransportHandler transportHandler = configHandler.initializeTransportHandler(config); TlsContext tlsContext = configHandler.initializeTlsContext(config); WorkflowExecutor workflowExecutor = configHandler.initializeWorkflowExecutor(transportHandler, tlsContext); workflowExecutor.executeWorkflow(); transportHandler.closeConnection(); assertTrue(tlsContext.getWorkflowTrace().containsServerFinished()); } private void testCustomWorkflow(int port) { GeneralConfig generalConfig = new GeneralConfig(); ConfigHandler configHandler = ConfigHandlerFactory.createConfigHandler("client"); configHandler.initialize(generalConfig); ClientCommandConfig config = new ClientCommandConfig(); config.setConnect("localhost:" + port); config.setTlsTimeout(TIMEOUT); config.setWorkflowTraceType(WorkflowTraceType.CLIENT_HELLO); TransportHandler transportHandler = configHandler.initializeTransportHandler(config); TlsContext tlsContext = configHandler.initializeTlsContext(config); WorkflowTrace trace = tlsContext.getWorkflowTrace(); trace.add(new ServerHelloMessage(ConnectionEnd.SERVER)); trace.add(new CertificateMessage(ConnectionEnd.SERVER)); trace.add(new ServerHelloDoneMessage(ConnectionEnd.SERVER)); trace.add(new RSAClientKeyExchangeMessage(ConnectionEnd.CLIENT)); trace.add(new ChangeCipherSpecMessage(ConnectionEnd.CLIENT)); trace.add(new FinishedMessage(ConnectionEnd.CLIENT)); trace.add(new ChangeCipherSpecMessage(ConnectionEnd.SERVER)); trace.add(new FinishedMessage(ConnectionEnd.SERVER)); WorkflowExecutor workflowExecutor = configHandler.initializeWorkflowExecutor(transportHandler, tlsContext); workflowExecutor.executeWorkflow(); transportHandler.closeConnection(); assertTrue(tlsContext.getWorkflowTrace().containsServerFinished()); } }