/**
* 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.constants;
import java.util.HashSet;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Resolves crypto algorithms and their properties from a given cipehr suite
* (and TLS version).
*
* @author Juraj Somorovsky - juraj.somorovsky@rub.de
*/
public class AlgorithmResolver {
private static final Logger LOGGER = LogManager.getLogger(AlgorithmResolver.class);
private AlgorithmResolver() {
}
/**
* Returns a PRF algorithm based on the protocol version and the cipher
* suite. TLS 1.0 and 1.1 used a legacy PRF based on MD5 and SHA-1. TLS 1.2
* uses per default SHA256 PRF, but allows for definition of further PRFs in
* specific cipher suites (the last part of a cipher suite string identifies
* the PRF).
*
* @param protocolVersion
* @param cipherSuite
* @return
*/
public static PRFAlgorithm getPRFAlgorithm(ProtocolVersion protocolVersion, CipherSuite cipherSuite) {
PRFAlgorithm result;
if (protocolVersion == ProtocolVersion.TLS10 || protocolVersion == ProtocolVersion.TLS11
|| protocolVersion == ProtocolVersion.DTLS10) {
result = PRFAlgorithm.TLS_PRF_LEGACY;
} else if (cipherSuite.name().endsWith("SHA384")) {
result = PRFAlgorithm.TLS_PRF_SHA384;
} else {
result = PRFAlgorithm.TLS_PRF_SHA256;
}
LOGGER.debug("Using the following PRF Algorithm: {}", result);
return result;
}
/**
* Returns a digest algorithm based on the protocol version and the cipher
* suite. The digest algorithm is used to compute a message digest over the
* handshake messages and to compute valid finished messages. TLS 1.0 and
* 1.1 used a legacy digest based on MD5 and SHA-1. TLS 1.2 uses per default
* SHA256 digest algorithm, but allows for definition of further digest
* algorithms in specific cipher suites (the last part of a cipher suite
* string identifies the digest).
*
* @param protocolVersion
* @param cipherSuite
* @return
*/
public static DigestAlgorithm getDigestAlgorithm(ProtocolVersion protocolVersion, CipherSuite cipherSuite) {
DigestAlgorithm result;
if (protocolVersion == ProtocolVersion.TLS10 || protocolVersion == ProtocolVersion.TLS11
|| protocolVersion == ProtocolVersion.DTLS10) {
result = DigestAlgorithm.LEGACY;
} else if (cipherSuite.name().endsWith("SHA384")) {
result = DigestAlgorithm.SHA384;
} else {
result = DigestAlgorithm.SHA256;
}
LOGGER.debug("Using the following Digest Algorithm: {}", result);
return result;
}
public static KeyExchangeAlgorithm getKeyExchangeAlgorithm(CipherSuite cipherSuite) {
String cipher = cipherSuite.toString().toUpperCase();
if (cipher.startsWith("TLS_RSA_")) {
return KeyExchangeAlgorithm.RSA;
} else if (cipher.startsWith("TLS_DH_DSS_")) {
return KeyExchangeAlgorithm.DH_DSS;
} else if (cipher.startsWith("TLS_DH_RSA_")) {
return KeyExchangeAlgorithm.DH_RSA;
} else if (cipher.startsWith("TLS_DHE_DSS_")) {
return KeyExchangeAlgorithm.DHE_DSS;
} else if (cipher.startsWith("TLS_DHE_RSA_")) {
return KeyExchangeAlgorithm.DHE_RSA;
} else if (cipher.startsWith("TLS_DHE_PSK")) {
return KeyExchangeAlgorithm.DHE_PSK;
} else if (cipher.startsWith("TLS_DH_ANON_")) {
return KeyExchangeAlgorithm.DH_ANON;
} else if (cipher.startsWith("TLS_ECDH_")) {
return KeyExchangeAlgorithm.EC_DIFFIE_HELLMAN;
} else if (cipher.startsWith("TLS_ECDHE_")) {
return KeyExchangeAlgorithm.EC_DIFFIE_HELLMAN;
} else if (cipher.startsWith("TLS_NULL_")) {
return KeyExchangeAlgorithm.NULL;
} else if (cipher.startsWith("TLS_KRB5_")) {
return KeyExchangeAlgorithm.KRB5;
} else if (cipher.startsWith("TLS_PSK_")) {
return KeyExchangeAlgorithm.PSK;
} else if (cipher.startsWith("TLS_SRP_")) {
return KeyExchangeAlgorithm.SRP;
} else if (cipher.startsWith("TLS_GOSTR341001_")) {
return KeyExchangeAlgorithm.GOSTR341001;
} else if (cipher.startsWith("TLS_GOSTR341094_")) {
return KeyExchangeAlgorithm.GOSTR341094;
} else if (cipher.startsWith("TLS_CECPQ1_")) {
return KeyExchangeAlgorithm.CECPQ1;
}
throw new UnsupportedOperationException("The key exchange algorithm in " + cipherSuite.toString() + " is not supported yet.");
}
/**
* Depending on the provided cipher suite, the server needs to be
* initialized with proper public key(s). Depending on the cipher suite,
* there are possibly more than one cipher suites needed.
*
* This function returns a list of public key algorithms needed when running
* a server with a cipher suite.
*
* @param cipherSuite
* @return
*/
public static Set<PublicKeyAlgorithm> getRequiredKeystoreAlgorithms(CipherSuite cipherSuite) {
String cipher = cipherSuite.toString().toUpperCase();
Set<PublicKeyAlgorithm> result = new HashSet<>();
if (cipher.contains("RSA")) {
result.add(PublicKeyAlgorithm.RSA);
} else if (cipher.contains("ECDSA")) {
result.add(PublicKeyAlgorithm.EC);
} else if (cipher.contains("DSS")) {
result.add(PublicKeyAlgorithm.DH);
}
if (cipher.contains("_ECDH_")) {
result.add(PublicKeyAlgorithm.EC);
} else if (cipher.contains("_DH_")) {
result.add(PublicKeyAlgorithm.DH);
}
return result;
}
public static CipherAlgorithm getCipher(CipherSuite cipherSuite) {
String cipher = cipherSuite.toString().toUpperCase();
if (cipher.contains("NULL")) {
return CipherAlgorithm.NULL;
} else if (cipher.contains("IDEA")) {
return CipherAlgorithm.IDEA_128;
} else if (cipher.contains("RC2")) {
return CipherAlgorithm.RC2_128;
} else if (cipher.contains("RC4")) {
return CipherAlgorithm.RC4_128;
} else if (cipher.contains("DES_EDE_CBC")) {
return CipherAlgorithm.DES_EDE_CBC;
} else if (cipher.contains("AES_128_CBC")) {
return CipherAlgorithm.AES_128_CBC;
} else if (cipher.contains("AES_256_CBC")) {
return CipherAlgorithm.AES_256_CBC;
} else if (cipher.contains("AES_128_GCM")) {
return CipherAlgorithm.AES_128_GCM;
} else if (cipher.contains("AES_256_GCM")) {
return CipherAlgorithm.AES_256_GCM;
} else if (cipher.contains("CAMELLIA_128_CBC")) {
return CipherAlgorithm.CAMELLIA_128_CBC;
} else if (cipher.contains("CAMELLIA_256_CBC")) {
return CipherAlgorithm.CAMELLIA_256_CBC;
} else if (cipher.contains("SEED_CBC")) {
return CipherAlgorithm.SEED_CBC;
}
throw new UnsupportedOperationException("The cipher algorithm in " + cipherSuite + " is not supported yet.");
}
/**
* TODO handle aead ciphers
*
* @param cipherSuite
* @return
*/
public static CipherType getCipherType(CipherSuite cipherSuite) {
String cipher = cipherSuite.toString().toUpperCase();
if (cipher.contains("AES") || cipher.contains("DES")) {
return CipherType.BLOCK;
} else if (cipher.contains("RC4")) {
return CipherType.STREAM;
}
throw new UnsupportedOperationException("Cipher suite " + cipherSuite + " is not supported yet.");
}
public static MacAlgorithm getMacAlgorithm(CipherSuite cipherSuite) {
MacAlgorithm result = null;
if (cipherSuite.isAEAD()) {
result = MacAlgorithm.AEAD;
} else {
String cipher = cipherSuite.toString();
if (cipher.endsWith("MD5")) {
result = MacAlgorithm.HMAC_MD5;
} else if (cipher.endsWith("SHA")) {
result = MacAlgorithm.HMAC_SHA1;
} else if (cipher.endsWith("SHA256")) {
result = MacAlgorithm.HMAC_SHA256;
} else if (cipher.endsWith("SHA384")) {
result = MacAlgorithm.HMAC_SHA384;
} else if (cipher.endsWith("SHA512")) {
result = MacAlgorithm.HMAC_SHA512;
} else if (cipher.endsWith("NULL")) {
result = MacAlgorithm.NULL;
}
}
if (result != null) {
LOGGER.debug("Using the following Mac Algorithm: {}", result);
return result;
} else {
throw new UnsupportedOperationException("The Mac algorithm for cipher " + cipherSuite
+ " is not supported yet");
}
}
}