/** * 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.testtls.impl; import de.rub.nds.tlsattacker.testtls.config.TestServerConfig; import de.rub.nds.tlsattacker.testtls.policy.TlsPeerProperties; import de.rub.nds.tlsattacker.tls.config.ConfigHandler; import de.rub.nds.tlsattacker.tls.constants.CipherSuite; import de.rub.nds.tlsattacker.tls.constants.HandshakeMessageType; import de.rub.nds.tlsattacker.tls.constants.HashAlgorithm; import de.rub.nds.tlsattacker.tls.constants.ProtocolVersion; import de.rub.nds.tlsattacker.tls.constants.SignatureAlgorithm; import de.rub.nds.tlsattacker.tls.constants.SignatureAndHashAlgorithm; import de.rub.nds.tlsattacker.tls.protocol.handshake.ServerKeyExchangeMessage; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Tests the acceptance of the Signature and Hash Algorithm extension. See * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 * * We just send different values in the extension with all the supported * extension values. If the server responds with a ServerHello message, it must * support the proposed signature and hash algorithms. * * This extension is only fully supported in TLS 1.2. In previous versions, it * can be ignored if the server does not understand it. * * From https://tools.ietf.org/html/rfc5246#section-7.4.3 (describing * ServerKeyExchange message): "If the client has offered the * "signature_algorithms" extension, the signature algorithm and hash algorithm * MUST be a pair listed in that extension. Note that there is a possibility for * inconsistencies here. For instance, the client might offer DHE_DSS key * exchange but omit any DSA pairs from its "signature_algorithms" extension. In * order to negotiate correctly, the server MUST check any candidate cipher * suites against the "signature_algorithms" extension before selecting them. * This is somewhat inelegant but is a compromise designed to minimize changes * to the original cipher suite design." * * @author Juraj Somorovsky - juraj.somorovsky@rub.de */ public class SignatureAndHashAlgorithmsTest extends HandshakeTest { private final Set<SignatureAndHashAlgorithm> signatureAndHashAlgorithms; private final HashMap<ProtocolVersion, List<CipherSuite>> supportedCipherSuites; public SignatureAndHashAlgorithmsTest(ConfigHandler configHandler, TestServerConfig serverConfig, HashMap<ProtocolVersion, List<CipherSuite>> supportedCipherSuites) { super(configHandler, serverConfig); this.signatureAndHashAlgorithms = new HashSet<>(); this.supportedCipherSuites = supportedCipherSuites; } @Override public void startTests() { // This extension is only supported in TLS 1.2 // (see https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1) if (!supportedCipherSuites.get(ProtocolVersion.TLS12).isEmpty()) { testSupportedSignatureAndHashAlgorithms(ProtocolVersion.TLS12); } result = "\n Supported signature and hash algorithms: " + signatureAndHashAlgorithmsToString(signatureAndHashAlgorithms); } private void testSupportedSignatureAndHashAlgorithms(ProtocolVersion pv) { for (SignatureAndHashAlgorithm algorithm : SignatureAndHashAlgorithm.values()) { serverConfig.setProtocolVersion(pv); serverConfig.setCipherSuites(supportedCipherSuites.get(pv)); serverConfig.setSignatureAndHashAlgorithms(Collections.singletonList(algorithm)); boolean success = false; try { success = executeHandshake(); } catch (Exception ex) { LOGGER.info(ex.getLocalizedMessage()); LOGGER.debug(ex.getLocalizedMessage(), ex); } if (success) { signatureAndHashAlgorithms.add(algorithm); if (lastTlsContext.getWorkflowTrace().containsHandshakeMessage(HandshakeMessageType.SERVER_KEY_EXCHANGE)) { ServerKeyExchangeMessage skm = (ServerKeyExchangeMessage) lastTlsContext.getWorkflowTrace().getFirstHandshakeMessage(HandshakeMessageType.SERVER_KEY_EXCHANGE); Byte sa = skm.getSignatureAlgorithm().getValue(); Byte ha = skm.getHashAlgorithm().getValue(); signatureAndHashAlgorithms.add(new SignatureAndHashAlgorithm(new byte[]{ha,sa})); } } } } private String signatureAndHashAlgorithmsToString(Set<SignatureAndHashAlgorithm> algorithms) { String output = ""; for (SignatureAndHashAlgorithm sha : algorithms) { output = output + sha.getSignatureAlgorithm() + "-" + sha.getHashAlgorithm() + " "; } return output; } @Override public void fillTlsPeerProperties(TlsPeerProperties properties) { properties.setSignatureAndHashAlgorithms(signatureAndHashAlgorithms); } }