Bypass SSL validation option (#1289)

* Bypass ssl validation option
* TrustManager inclusion
This commit is contained in:
Jeff Banks 2023-07-06 11:32:22 -05:00 committed by GitHub
parent 656960f483
commit 27644273fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 145 additions and 55 deletions

View File

@ -54,3 +54,8 @@ For `openssl` type, the following options are available:
Examples: Examples:
- `keyFilePath=file.key` - `keyFilePath=file.key`
- **sslValidation** - optional boolean flag to enable/disable SSLValidation.
Examples:
- `sslValidation=true` (the default)
- `sslValidation=false`

View File

@ -178,8 +178,8 @@ public class SSLKsFactoryTest {
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThatExceptionOfType(RuntimeException.class) assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg)) .isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg))
.withMessageMatching("Unable to init KeyManagerFactory. Please check.*"); .withMessageMatching("Unable to init KeyManagerFactory. Please check.*");
} }
@Test @Test
@ -196,6 +196,62 @@ public class SSLKsFactoryTest {
.withMessageMatching("Unable to load the truststore: .*"); .withMessageMatching("Unable to load the truststore: .*");
} }
@Test
void testSSLValidationActive() {
{
final String[] params1 = {
"ssl=openssl",
"certFilePath=src/test/resources/ssl/client_cert.pem",
"keyFilePath=src/test/resources/ssl/client.key",
"sslValidation=true"
};
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params1));
NBConfiguration sslCfg1 = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg1)).isNotNull();
}
{
final String[] params2 = {
"ssl=jdk",
"keystore=src/test/resources/ssl/client_diff_password.p12",
"kspass=nosqlbench_client",
"keyPassword=nosqlbench",
"sslValidation=true"
};
ActivityDef activityDef2 = ActivityDef.parseActivityDef(String.join(";", params2));
NBConfiguration sslCfg2 = SSLKsFactory.get().getConfigModel().extractConfig(activityDef2.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg2)).isNotNull();
}
}
@Test
void testSSLValidationNotActive() {
{
final String[] params1 = {
"ssl=openssl",
"certFilePath=src/test/resources/ssl/client_cert.pem",
"keyFilePath=src/test/resources/ssl/client.key",
"sslValidation=false"
};
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params1));
NBConfiguration sslCfg1 = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg1)).isNotNull();
}
{
final String[] params2 = {
"ssl=jdk",
"keystore=src/test/resources/ssl/client_diff_password.p12",
"kspass=nosqlbench_client",
"keyPassword=nosqlbench",
"sslValidation=false"
};
ActivityDef activityDef2 = ActivityDef.parseActivityDef(String.join(";", params2));
NBConfiguration sslCfg2 = SSLKsFactory.get().getConfigModel().extractConfig(activityDef2.getParams());
assertThat(SSLKsFactory.get().getContext(sslCfg2)).isNotNull();
}
}
@Test @Test
public void testOpenSSLGetContextWithCaCertError() { public void testOpenSSLGetContextWithCaCertError() {
String[] params = { String[] params = {
@ -241,16 +297,16 @@ public class SSLKsFactoryTest {
@Test @Test
public void testOpenSSLGetContextWithMissingCertError() { public void testOpenSSLGetContextWithMissingCertError() {
String[] params = { String[] params = {
"ssl=openssl", "ssl=openssl",
"caCertFilePath=src/test/resources/ssl/cacert.crt", "caCertFilePath=src/test/resources/ssl/cacert.crt",
"keyFilePath=src/test/resources/ssl/client.key" "keyFilePath=src/test/resources/ssl/client.key"
}; };
ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params)); ActivityDef activityDef = ActivityDef.parseActivityDef(String.join(";", params));
NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams()); NBConfiguration sslCfg = SSLKsFactory.get().getConfigModel().extractConfig(activityDef.getParams());
assertThatExceptionOfType(RuntimeException.class) assertThatExceptionOfType(RuntimeException.class)
.isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg)) .isThrownBy(() -> SSLKsFactory.get().getContext(sslCfg))
.withMessageContaining("Unable to load key from") .withMessageContaining("Unable to load key from")
.withCauseInstanceOf(IllegalArgumentException.class); .withCauseInstanceOf(IllegalArgumentException.class);
} }
} }

View File

@ -22,9 +22,7 @@ import org.apache.logging.log4j.Logger;
import javax.net.ServerSocketFactory; import javax.net.ServerSocketFactory;
import javax.net.SocketFactory; import javax.net.SocketFactory;
import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.*;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.KeyFactory; import java.security.KeyFactory;
@ -45,11 +43,31 @@ public class SSLKsFactory implements NBMapConfigurable {
private static final SSLKsFactory instance = new SSLKsFactory(); private static final SSLKsFactory instance = new SSLKsFactory();
private static final Pattern CERT_PATTERN = Pattern.compile("-+BEGIN\\s+.*CERTIFICATE[^-]*-+(?:\\s|\\r|\\n){1,10}([a-z0-9+/=\\r\\n]+)-+END\\s+.*CERTIFICATE[^-]*-+", Pattern.CASE_INSENSITIVE); private static final Pattern CERT_PATTERN = Pattern.compile("-+BEGIN\\s+.*CERTIFICATE[^-]*-+(?:\\s|\\r|\\n)" +
private static final Pattern KEY_PATTERN = Pattern.compile("-+BEGIN\\s+.*PRIVATE\\s+KEY[^-]*-+(?:\\s|\\r|\\n){1,10}([a-z0-9+/=\\r\\n]+)-+END\\s+.*PRIVATE\\s+KEY[^-]*-+", Pattern.CASE_INSENSITIVE); "{1,10}([a-z0-9+/=\\r\\n]+)-+END\\s+.*CERTIFICATE[^-]*-+", Pattern.CASE_INSENSITIVE);
private static final Pattern KEY_PATTERN = Pattern.compile("-+BEGIN\\s+.*PRIVATE\\s+KEY[^-]*-+(?:\\s|\\r|\\n)" +
"{1,10}([a-z0-9+/=\\r\\n]+)-+END\\s+.*PRIVATE\\s+KEY[^-]*-+", Pattern.CASE_INSENSITIVE);
public static final String SSL = "ssl"; public static final String SSL = "ssl";
public static final String DEFAULT_TLSVERSION = "TLSv1.2"; public static final String DEFAULT_TLSVERSION = "TLSv1.2";
private static final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[]{};
}
}
};
/** /**
* Consider: https://gist.github.com/artem-smotrakov/bd14e4bde4d7238f7e5ab12c697a86a3 * Consider: https://gist.github.com/artem-smotrakov/bd14e4bde4d7238f7e5ab12c697a86a3
*/ */
@ -70,6 +88,7 @@ public class SSLKsFactory implements NBMapConfigurable {
public SocketFactory createSocketFactory(NBConfiguration cfg) { public SocketFactory createSocketFactory(NBConfiguration cfg) {
SSLContext context = getContext(cfg); SSLContext context = getContext(cfg);
if (context == null) { if (context == null) {
throw new IllegalArgumentException("SSL is not enabled."); throw new IllegalArgumentException("SSL is not enabled.");
} }
@ -81,18 +100,26 @@ public class SSLKsFactory implements NBMapConfigurable {
if (sslParam.isPresent()) { if (sslParam.isPresent()) {
String tlsVersion = cfg.getOptional("tlsversion").orElse(DEFAULT_TLSVERSION); String tlsVersion = cfg.getOptional("tlsversion").orElse(DEFAULT_TLSVERSION);
KeyStore keyStore; KeyStore keyStore = null;
char[] keyPassword = null; char[] keyPassword = null;
KeyStore trustStore; KeyStore trustStore = null;
boolean activeSSLValidation = true;
if (cfg.getOptional("sslValidation").isPresent() && cfg.getOptional("sslValidation")
.get().equals("false")) {
logger.warn("sslValidation=false, skipping SSL validation. " +
"THIS OPTION SHOULD ONLY BE TESTING AND NON-PROD ENVIRONMENTS");
activeSSLValidation = false;
}
if (sslParam.get().equals("jdk")) { if (sslParam.get().equals("jdk")) {
final char[] keyStorePassword = cfg.getOptional("kspass") final char[] keyStorePassword = cfg.getOptional("kspass")
.map(String::toCharArray) .map(String::toCharArray)
.orElse(null); .orElse(null);
keyPassword = cfg.getOptional("keyPassword", "keypassword") keyPassword = cfg.getOptional("keyPassword", "keypassword")
.map(String::toCharArray) .map(String::toCharArray)
.orElse(keyStorePassword); .orElse(keyStorePassword);
keyStore = cfg.getOptional("keystore").map(ksPath -> { keyStore = cfg.getOptional("keystore").map(ksPath -> {
try { try {
@ -105,9 +132,9 @@ public class SSLKsFactory implements NBMapConfigurable {
trustStore = cfg.getOptional("truststore").map(tsPath -> { trustStore = cfg.getOptional("truststore").map(tsPath -> {
try { try {
return KeyStore.getInstance(new File(tsPath), return KeyStore.getInstance(new File(tsPath),
cfg.getOptional("tspass") cfg.getOptional("tspass")
.map(String::toCharArray) .map(String::toCharArray)
.orElse(null)); .orElse(null));
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Unable to load the truststore: " + e, e); throw new RuntimeException("Unable to load the truststore: " + e, e);
} }
@ -115,8 +142,8 @@ public class SSLKsFactory implements NBMapConfigurable {
} else if (sslParam.get().equals("openssl")) { } else if (sslParam.get().equals("openssl")) {
try { try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
keyStore = KeyStore.getInstance("JKS"); keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null); keyStore.load(null, null);
@ -125,9 +152,8 @@ public class SSLKsFactory implements NBMapConfigurable {
return cf.generateCertificate(is); return cf.generateCertificate(is);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException( throw new RuntimeException(
String.format("Unable to load cert from %s: " + e, certFilePath), String.format("Unable to load cert from %s: due to:%s ", certFilePath,
e e.getMessage()), e);
);
} }
}).orElse(null); }).orElse(null);
@ -135,37 +161,33 @@ public class SSLKsFactory implements NBMapConfigurable {
keyStore.setCertificateEntry("certFile", cert); keyStore.setCertificateEntry("certFile", cert);
File keyFile = cfg.getOptional("keyfilepath").map(File::new) File keyFile = cfg.getOptional("keyfilepath").map(File::new)
.orElse(null); .orElse(null);
if (keyFile != null) { if (keyFile != null) {
try { try {
keyPassword = cfg.getOptional("keyPassword", "keypassword") keyPassword = cfg.getOptional("keyPassword", "keypassword")
.map(String::toCharArray) .map(String::toCharArray)
.orElse("temp_key_password".toCharArray()); .orElse("temp_key_password".toCharArray());
KeyFactory kf = KeyFactory.getInstance("RSA"); KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey key = kf.generatePrivate(new PKCS8EncodedKeySpec(loadKeyFromPem(keyFile))); PrivateKey key = kf.generatePrivate(new PKCS8EncodedKeySpec(loadKeyFromPem(keyFile)));
keyStore.setKeyEntry("key", key, keyPassword, keyStore.setKeyEntry("key", key, keyPassword,
cert != null ? new Certificate[]{cert} : null); cert != null ? new Certificate[]{cert} : null);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(String.format("Unable to load key from %s: " + e, throw new RuntimeException(String.format("Unable to load key from: %s due to: %s ",
keyFile), keyFile, e.getMessage()), e);
e);
} }
} }
trustStore = cfg.getOptional("caCertFilePath", "cacertfilepath").map(caCertFilePath -> { trustStore = cfg.getOptional("caCertFilePath", "cacertfilepath").map(caCertFilePath -> {
try (InputStream is = new FileInputStream(new File(caCertFilePath))) { try (InputStream is = new FileInputStream(caCertFilePath)) {
KeyStore ts = KeyStore.getInstance("JKS"); KeyStore ts = KeyStore.getInstance("JKS");
ts.load(null, null); ts.load(null, null);
ts.setCertificateEntry("caCertFile", cf.generateCertificate(is));
Certificate caCert = cf.generateCertificate(is);
ts.setCertificateEntry("caCertFile", caCert);
return ts; return ts;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(String.format("Unable to load caCert from %s: " + e, throw new RuntimeException(String.format("Unable to load caCert from: %s due to: %s",
caCertFilePath), caCertFilePath, e.getMessage()), e);
e);
} }
}).orElse(null); }).orElse(null);
@ -183,20 +205,26 @@ public class SSLKsFactory implements NBMapConfigurable {
kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyPassword); kmf.init(keyStore, keyPassword);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Unable to init KeyManagerFactory. Please check password and location: " + e, e); throw new RuntimeException("Unable to init KeyManagerFactory. Please check password and location: "
+ e.getMessage(), e);
} }
TrustManagerFactory tmf; TrustManagerFactory tmf;
try { try {
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore != null ? trustStore : keyStore); tmf.init(trustStore != null ? trustStore : keyStore);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException("Unable to init TrustManagerFactory: " + e, e); throw new RuntimeException("Unable to init TrustManagerFactory: " + e.getMessage(), e);
} }
try { try {
SSLContext sslContext = SSLContext.getInstance(tlsVersion); SSLContext sslContext = SSLContext.getInstance(tlsVersion);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); if (!activeSSLValidation) {
sslContext.init(kmf.getKeyManagers(), trustAllCerts, new SecureRandom());
} else {
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
}
return sslContext; return sslContext;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -229,18 +257,19 @@ public class SSLKsFactory implements NBMapConfigurable {
public NBConfigModel getConfigModel() { public NBConfigModel getConfigModel() {
return ConfigModel.of(SSLKsFactory.class, return ConfigModel.of(SSLKsFactory.class,
Param.optional("ssl") Param.optional("ssl")
.setDescription("Enable ssl and set the mode") .setDescription("Enable ssl and set the mode")
.setRegex("jdk|openssl"), .setRegex("jdk|openssl"),
Param.defaultTo("tlsversion", DEFAULT_TLSVERSION), Param.defaultTo("tlsversion", DEFAULT_TLSVERSION),
Param.optional("kspass"), Param.optional("kspass"),
Param.optional("keyPassword"), Param.optional("keyPassword"),
Param.optional("keystore"), Param.optional("keystore"),
Param.optional("truststore"), Param.optional("truststore"),
Param.optional("tspass"), Param.optional("tspass"),
Param.optional(List.of("keyFilePath","keyfilepath")), Param.optional(List.of("keyFilePath", "keyfilepath")),
Param.optional("caCertFilePath"), Param.optional("caCertFilePath"),
Param.optional("certFilePath") Param.optional("certFilePath"),
Param.optional("sslValidation")
).asReadOnly(); ).asReadOnly();
} }
} }