/**
* 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.policy;
import de.rub.nds.tlsattacker.tls.constants.CipherAlgorithm;
import de.rub.nds.tlsattacker.tls.constants.HashAlgorithm;
import de.rub.nds.tlsattacker.tls.constants.MacAlgorithm;
import de.rub.nds.tlsattacker.tls.constants.NamedCurve;
import de.rub.nds.tlsattacker.tls.constants.ProtocolVersion;
import de.rub.nds.tlsattacker.tls.constants.SignatureAlgorithm;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
*
* Allows one to explicitly verify their configuration, based on a Botan
* tlsProperties file structure. See for example:
* https://github.com/randombit/botan/tree/master/tls-tlsProperties
*
* @author Juraj Somorovsky - juraj.somorovsky@rub.de
*/
public class BotanPolicyParser {
public static Logger LOGGER = LogManager.getLogger(BotanPolicyParser.class);
private final String delimiter;
private final TlsPeerProperties tlsProperties;
public BotanPolicyParser() {
delimiter = "\\n+\\s*";
tlsProperties = new TlsPeerProperties();
}
public void parsePolicy(String filename) throws FileNotFoundException {
File policyFile = new File(filename);
try (Scanner input = new Scanner(policyFile)) {
input.useDelimiter(delimiter);
while (input.hasNext()) {
String line = input.next();
String rule[] = line.split("\\s*[=]\\s*");
if (rule.length != 2) {
LOGGER.error("Invalid policy rule: {}", line);
continue;
}
switch (rule[0]) {
case "allow_tls10":
if (Boolean.parseBoolean(rule[1])) {
tlsProperties.addProtocolVersion(ProtocolVersion.TLS10);
}
break;
case "allow_tls11":
if (Boolean.parseBoolean(rule[1])) {
tlsProperties.addProtocolVersion(ProtocolVersion.TLS11);
}
break;
case "allow_tls12":
if (Boolean.parseBoolean(rule[1])) {
tlsProperties.addProtocolVersion(ProtocolVersion.TLS12);
}
break;
case "server_uses_own_ciphersuite_preferences":
tlsProperties.setUsingCiphersuitePreferenes(Boolean.parseBoolean(rule[1]));
break;
case "minimum_dh_group_size":
tlsProperties.setMinimumDhGroupSize(Integer.parseInt(rule[1]));
break;
case "minimum_ecdh_group_size":
tlsProperties.setMinimumEcdhGroupSize(Integer.parseInt(rule[1]));
break;
case "minimum_rsa_bits":
tlsProperties.setMinimumRsaBits(Integer.parseInt(rule[1]));
break;
case "ciphers":
tlsProperties.setCiphers(parseBotanCiphers(rule[1]));
break;
case "signature_hashes":
tlsProperties.setHashAlgorithms(parseBotanHashAlgorithms(rule[1]));
break;
case "signature_methods":
tlsProperties.setSignatureAlgorithms(parseBotanSignatureAlgorithms(rule[1]));
break;
case "macs":
tlsProperties.setMacAlgorithms(parseBotanMacAlgorithms(rule[1]));
break;
case "ecc_curves":
tlsProperties.setNamedCurves(parseBotanCurves(rule[1]));
break;
default:
LOGGER.info("Currently cannot handle rule " + rule[0]);
}
}
}
}
private Set<CipherAlgorithm> parseBotanCiphers(String ciphers) {
Set<CipherAlgorithm> result = new HashSet<>();
String[] cs = ciphers.split("\\s+");
for (String c : cs) {
result.add(parseCipherAlgorithm(c));
}
return result;
}
private Set<HashAlgorithm> parseBotanHashAlgorithms(String hashes) {
Set<HashAlgorithm> result = new HashSet();
String[] cs = hashes.split("\\s+");
for (String c : cs) {
result.add(parseHashAlgorithm(c));
}
return result;
}
private Set<SignatureAlgorithm> parseBotanSignatureAlgorithms(String signatures) {
Set<SignatureAlgorithm> result = new HashSet();
String[] sig = signatures.split("\\s+");
for (String s : sig) {
result.add(parseSignatureAlgorithm(s));
}
return result;
}
private Set<MacAlgorithm> parseBotanMacAlgorithms(String macs) {
Set<MacAlgorithm> result = new HashSet();
String[] cs = macs.split("\\s+");
for (String c : cs) {
result.add(parseMacAlgorithm(c));
}
return result;
}
private Set<NamedCurve> parseBotanCurves(String curves) {
Set<NamedCurve> result = new HashSet();
String[] cs = curves.split("\\s+");
for (String c : cs) {
result.add(parseNamedCurve(c));
}
return result;
}
private CipherAlgorithm parseCipherAlgorithm(String botanCipher) {
switch (botanCipher) {
case "AES-256/GCM":
return CipherAlgorithm.AES_256_GCM;
case "AES-128/GCM":
return CipherAlgorithm.AES_128_GCM;
case "ChaCha20Poly1305":
return CipherAlgorithm.ChaCha20Poly1305;
case "AES-256/CCM":
case "AES-256/CCM(8)":
return CipherAlgorithm.AES_256_CCM;
case "AES-128/CCM":
case "AES-128/CCM(8)":
return CipherAlgorithm.AES_128_CCM;
case "AES-256":
return CipherAlgorithm.AES_256_CBC;
case "AES-128":
return CipherAlgorithm.AES_128_CBC;
case "SEED":
return CipherAlgorithm.SEED_CBC;
case "3DES":
return CipherAlgorithm.DES_EDE_CBC;
default:
LOGGER.error("Cannot find the following cipher algorithm: " + botanCipher);
return CipherAlgorithm.NULL;
}
}
private HashAlgorithm parseHashAlgorithm(String botanHash) {
// same hash algorithms in botan and java
for (HashAlgorithm ha : HashAlgorithm.values()) {
if (ha.getJavaName().equalsIgnoreCase(botanHash)) {
return ha;
}
}
LOGGER.error("Cannot find the following cipher algorithm: " + botanHash);
return HashAlgorithm.NONE;
}
private MacAlgorithm parseMacAlgorithm(String botanMac) {
switch (botanMac) {
case "AEAD":
return MacAlgorithm.AEAD;
case "SHA-512":
return MacAlgorithm.HMAC_SHA512;
case "SHA-384":
return MacAlgorithm.HMAC_SHA384;
case "SHA-256":
return MacAlgorithm.HMAC_SHA256;
case "SHA-1":
return MacAlgorithm.HMAC_SHA1;
default:
LOGGER.error("Cannot find the following MAC algorithm: " + botanMac);
return MacAlgorithm.NULL;
}
}
private SignatureAlgorithm parseSignatureAlgorithm(String botanSignature) {
// same signature algorithms in botan and in tls attacker
return SignatureAlgorithm.valueOf(botanSignature);
}
private NamedCurve parseNamedCurve(String botanCurve) {
// nearly the same curves in botan and in tls attacker
switch (botanCurve) {
case "brainpool512r1":
return NamedCurve.BRAINPOOLP512R1;
case "brainpool384r1":
return NamedCurve.BRAINPOOLP384R1;
case "brainpool256r1":
return NamedCurve.BRAINPOOLP256R1;
default:
for (NamedCurve nc : NamedCurve.values()) {
if (nc.toString().equalsIgnoreCase(botanCurve)) {
return nc;
}
}
LOGGER.error("Cannot find the following Curve : " + botanCurve);
return NamedCurve.NONE;
}
}
public TlsPeerProperties getTlsProperties() {
return tlsProperties;
}
}