Adds support for reading PKCSelastic/x-pack-elasticsearch#12 files as SSL keystores/truststores.

Original commit: elastic/x-pack-elasticsearch@1855ad6173
This commit is contained in:
Tim Vernum 2017-07-25 17:31:37 +10:00 committed by GitHub
parent 15f5c5a632
commit 9ab6d3cbc3
11 changed files with 219 additions and 44 deletions

View File

@ -298,6 +298,10 @@ List of paths to PEM encoded certificate files that should be trusted.
The path to the Java Keystore file that contains a private key and certificate.
`ssl.key` and `ssl.keystore.path` may not be used at the same time.
`ssl.keystore.type`::
The format of the keystore file. Should be either `jks` to use the Java
Keystore format, or `PKCS12` to use PKCS#12 files. The default is `jks`.
`ssl.keystore.password`::
The password to the keystore.
@ -308,6 +312,10 @@ The password for the key in the keystore. Defaults to the keystore password.
The path to the Java Keystore file that contains the certificates to trust.
`ssl.certificate_authorities` and `ssl.truststore.path` may not be used at the same time.
`ssl.truststore.type`::
The format of the keystore file. Should be either `jks` to use the Java
Keystore format, or `PKCS12` to use PKCS#12 files. The default is `jks`.
`ssl.truststore.password`::
The password to the truststore.
@ -482,6 +490,10 @@ List of paths to PEM encoded certificate files that should be trusted.
`ssl.keystore.path`::
The path to the Java Keystore file that contains a private key and certificate.
`ssl.keystore.type`::
The format of the keystore file. Should be either `jks` to use the Java
Keystore format, or `PKCS12` to use PKCS#12 files. The default is `jks`.
`ssl.keystore.password`::
The password to the keystore.
@ -491,6 +503,10 @@ The password for the key in the keystore. Defaults to the keystore password.
`ssl.truststore.path`::
The path to the Java Keystore file that contains the certificates to trust.
`ssl.truststore.type`::
The format of the truststore file. Should be either `jks` to use the Java
Keystore format, or `PKCS12` to use PKCS#12 files. The default is `jks`.
`ssl.truststore.password`::
The password to the truststore.
@ -636,6 +652,35 @@ Path to the truststore file.
`xpack.ssl.truststore.password`::
Password to the truststore.
[float]
===== PKCS#12 Files
When using PKCS#12 container files (`.p12` or `.pfx`), which contain the
private key, certificate, and certificates that should be trusted, use
the following settings:
`xpack.ssl.keystore.path`::
Path to the PKCS#12 file that holds the private key and certificate.
`xpack.ssl.keystore.type`::
Set this to `PKCS12`.
`xpack.ssl.keystore.password`::
Password to the PKCS#12 file.
`xpack.ssl.keystore.key_password`::
Password for the private key in the PKCS12 file.
Defaults to the same value as `xpack.ssl.keystore.password`.
`xpack.ssl.truststore.path`::
Path to the truststore file.
`xpack.ssl.truststore.type`::
Set this to `PKCS12`.
`xpack.ssl.truststore.password`::
Password to the truststore.
[[http-tls-ssl-settings]]
:ssl-prefix: xpack.security.http
:component: HTTP

View File

@ -93,3 +93,32 @@ Path to the truststore file.
+{ssl-prefix}.ssl.truststore.password+::
Password to the truststore.
===== PKCS#12 Files
{security} can be configured to use PKCS#12 container files (`.p12` or `.pfx` files)
that contain the private key, certificate and certificates that should be trusted.
PKCS#12 files are configured in the same way as Java Keystore Files:
+{ssl-prefix}.ssl.keystore.path+::
Path to the PKCS#12 file that holds the private key and certificate.
+{ssl-prefix}.ssl.keystore.type+::
Set this to `PKCS12` to indicate that the keystore is a PKCS#12 file.
+{ssl-prefix}.ssl.keystore.password+::
Password to the PKCS#12 file.
+{ssl-prefix}.ssl.keystore.key_password+::
Password for the private key stored in the PKCS#12 file.
Defaults to the same value as +{ssl-prefix}.ssl.keystore.password+.
+{ssl-prefix}.ssl.truststore.path+::
Path to the PKCS#12 file that holds the certificates to be trusted.
+{ssl-prefix}.ssl.truststore.type+::
Set this to `PKCS12` to indicate that the truststore is a PKCS#12 file.
+{ssl-prefix}.ssl.truststore.password+::
Password to the PKCS#12 file.

View File

@ -180,8 +180,9 @@ public class PkiRealm extends Realm {
}
try (SecureString password = SSL_SETTINGS.truststorePassword.get(settings)) {
String trustStoreAlgorithm = SSL_SETTINGS.truststoreAlgorithm.get(settings);
String trustStoreType = SSL_SETTINGS.truststoreType.get(settings);
try {
return CertUtils.trustManager(truststorePath, password.getChars(), trustStoreAlgorithm, realmConfig.env());
return CertUtils.trustManager(truststorePath, trustStoreType, password.getChars(), trustStoreAlgorithm, realmConfig.env());
} catch (Exception e) {
throw new IllegalArgumentException("failed to load specified truststore", e);
}

View File

@ -160,12 +160,11 @@ public class CertUtils {
* @param env the environment to use for file resolution. May be {@code null}
* @return a trust manager with the trust material from the store
*/
public static X509ExtendedTrustManager trustManager(String trustStorePath, char[] trustStorePassword, String trustStoreAlgorithm,
@Nullable Environment env)
public static X509ExtendedTrustManager trustManager(String trustStorePath, String trustStoreType, char[] trustStorePassword,
String trustStoreAlgorithm, @Nullable Environment env)
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, IOException, CertificateException {
try (InputStream in = Files.newInputStream(resolvePath(trustStorePath, env))) {
// TODO remove reliance on JKS since we can PKCS12 stores...
KeyStore trustStore = KeyStore.getInstance("jks");
KeyStore trustStore = KeyStore.getInstance(trustStoreType);
assert trustStorePassword != null;
trustStore.load(in, trustStorePassword);
return trustManager(trustStore, trustStoreAlgorithm);

View File

@ -15,6 +15,7 @@ import org.elasticsearch.xpack.XPackSettings;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import java.nio.file.Path;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -186,8 +187,7 @@ public final class SSLConfiguration {
} else if (System.getProperty("javax.net.ssl.keyStore") != null) {
// TODO: we should not support loading a keystore from sysprops...
try (SecureString keystorePassword = new SecureString(System.getProperty("javax.net.ssl.keyStorePassword", ""))) {
return new StoreKeyConfig(System.getProperty("javax.net.ssl.keyStore"),
keystorePassword, keystorePassword,
return new StoreKeyConfig(System.getProperty("javax.net.ssl.keyStore"), "jks", keystorePassword, keystorePassword,
System.getProperty("ssl.KeyManagerFactory.algorithm", KeyManagerFactory.getDefaultAlgorithm()),
System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()));
}
@ -205,12 +205,14 @@ public final class SSLConfiguration {
} else {
SecureString keyStorePassword = SETTINGS_PARSER.keystorePassword.get(settings);
String keyStoreAlgorithm = SETTINGS_PARSER.keystoreAlgorithm.get(settings);
String keyStoreType = SETTINGS_PARSER.keystoreType.get(settings);
SecureString keyStoreKeyPassword = SETTINGS_PARSER.keystoreKeyPassword.get(settings);;
if (keyStoreKeyPassword.length() == 0) {
keyStoreKeyPassword = keyStorePassword;
}
String trustStoreAlgorithm = SETTINGS_PARSER.truststoreAlgorithm.get(settings);
return new StoreKeyConfig(keyStorePath, keyStorePassword, keyStoreKeyPassword, keyStoreAlgorithm, trustStoreAlgorithm);
return new StoreKeyConfig(keyStorePath, keyStoreType, keyStorePassword, keyStoreKeyPassword, keyStoreAlgorithm,
trustStoreAlgorithm);
}
}
@ -242,10 +244,11 @@ public final class SSLConfiguration {
} else if (trustStorePath != null) {
SecureString trustStorePassword = SETTINGS_PARSER.truststorePassword.get(settings);
String trustStoreAlgorithm = SETTINGS_PARSER.truststoreAlgorithm.get(settings);
return new StoreTrustConfig(trustStorePath, trustStorePassword, trustStoreAlgorithm);
String trustStoreType = SETTINGS_PARSER.truststoreType.get(settings);
return new StoreTrustConfig(trustStorePath, trustStoreType, trustStorePassword, trustStoreAlgorithm);
} else if (global == null && System.getProperty("javax.net.ssl.trustStore") != null) {
try (SecureString truststorePassword = new SecureString(System.getProperty("javax.net.ssl.trustStorePassword", ""))) {
return new StoreTrustConfig(System.getProperty("javax.net.ssl.trustStore"), truststorePassword,
return new StoreTrustConfig(System.getProperty("javax.net.ssl.trustStore"), "jks", truststorePassword,
System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm()));
}
} else if (global != null && keyConfig == global.keyConfig()) {

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.ssl;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@ -32,10 +33,12 @@ public class SSLConfigurationSettings {
public final Setting<Optional<String>> keystorePath;
public final Setting<SecureString> keystorePassword;
public final Setting<String> keystoreAlgorithm;
public final Setting<String> keystoreType;
public final Setting<SecureString> keystoreKeyPassword;
public final Setting<Optional<String>> truststorePath;
public final Setting<SecureString> truststorePassword;
public final Setting<String> truststoreAlgorithm;
public final Setting<String> truststoreType;
public final Setting<Optional<String>> trustRestrictionsPath;
public final Setting<Optional<String>> keyPath;
public final Setting<SecureString> keyPassword;
@ -52,6 +55,12 @@ public class SSLConfigurationSettings {
private final List<Setting<?>> allSettings;
/**
* We explicitly default to "jks" here (rather than {@link KeyStore#getDefaultType()}) for backwards compatibility.
* Older versions of X-Pack only supported JKS and never looked at the JVM's configured default.
*/
private static final String DEFAULT_KEYSTORE_TYPE = "jks";
private static final Function<String, Setting<List<String>>> CIPHERS_SETTING_TEMPLATE = key -> Setting.listSetting(key, Collections
.emptyList(), Function.identity(), Property.NodeScope, Property.Filtered);
public static final Setting<List<String>> CIPHERS_SETTING_PROFILES = Setting.affixKeySetting("transport.profiles.",
@ -121,6 +130,16 @@ public class SSLConfigurationSettings {
public static final Setting<String> TRUST_STORE_ALGORITHM_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.truststore.algorithm", TRUST_STORE_ALGORITHM_TEMPLATE);
private static final Function<String, Setting<String>> KEY_STORE_TYPE_TEMPLATE = key ->
new Setting<>(key, DEFAULT_KEYSTORE_TYPE, Function.identity(), Property.NodeScope, Property.Filtered);
public static final Setting<String> KEY_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.keystore.type", KEY_STORE_TYPE_TEMPLATE);
private static final Function<String, Setting<String>> TRUST_STORE_TYPE_TEMPLATE = key ->
new Setting<>(key, DEFAULT_KEYSTORE_TYPE, Function.identity(), Property.NodeScope, Property.Filtered);
public static final Setting<String> TRUST_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.",
"xpack.security.ssl.truststore.type", TRUST_STORE_TYPE_TEMPLATE);
private static final Function<String, Setting<Optional<String>>> TRUST_RESTRICTIONS_TEMPLATE = key -> new Setting<>(key, s -> null,
Optional::ofNullable, Property.NodeScope, Property.Filtered);
public static final Setting<Optional<String>> TRUST_RESTRICTIONS_PROFILES = Setting.affixKeySetting("transport.profiles.",
@ -179,6 +198,8 @@ public class SSLConfigurationSettings {
truststorePassword = TRUSTSTORE_PASSWORD_TEMPLATE.apply(prefix + "truststore.secure_password");
keystoreAlgorithm = KEY_STORE_ALGORITHM_TEMPLATE.apply(prefix + "keystore.algorithm");
truststoreAlgorithm = TRUST_STORE_ALGORITHM_TEMPLATE.apply(prefix + "truststore.algorithm");
keystoreType = KEY_STORE_TYPE_TEMPLATE.apply(prefix + "keystore.type");
truststoreType = KEY_STORE_TYPE_TEMPLATE.apply(prefix + "truststore.type");
trustRestrictionsPath = TRUST_RESTRICTIONS_TEMPLATE.apply(prefix + "trust_restrictions.path");
keyPath = KEY_PATH_TEMPLATE.apply(prefix + "key");
legacyKeyPassword = LEGACY_KEY_PASSWORD_TEMPLATE.apply(prefix + "key_passphrase");
@ -189,8 +210,8 @@ public class SSLConfigurationSettings {
verificationMode = VERIFICATION_MODE_SETTING_TEMPLATE.apply(prefix + "verification_mode");
this.allSettings = Arrays.asList(ciphers, supportedProtocols,
keystorePath, keystorePassword, keystoreAlgorithm, keystoreKeyPassword,
truststorePath, truststorePassword, truststoreAlgorithm, trustRestrictionsPath,
keystorePath, keystorePassword, keystoreAlgorithm, keystoreType, keystoreKeyPassword,
truststorePath, truststorePassword, truststoreAlgorithm, truststoreType, trustRestrictionsPath,
keyPath, keyPassword, cert, caPaths, clientAuth, verificationMode,
legacyKeystorePassword, legacyKeystoreKeyPassword, legacyKeyPassword, legacyTruststorePassword);
}
@ -222,7 +243,8 @@ public class SSLConfigurationSettings {
return Arrays.asList(CIPHERS_SETTING_PROFILES, SUPPORTED_PROTOCOLS_PROFILES, KEYSTORE_PATH_PROFILES,
LEGACY_KEYSTORE_PASSWORD_PROFILES, KEYSTORE_PASSWORD_PROFILES, LEGACY_KEYSTORE_KEY_PASSWORD_PROFILES,
KEYSTORE_KEY_PASSWORD_PROFILES, TRUST_STORE_PATH_PROFILES, LEGACY_TRUSTSTORE_PASSWORD_PROFILES,
TRUSTSTORE_PASSWORD_PROFILES, KEY_STORE_ALGORITHM_PROFILES, TRUST_STORE_ALGORITHM_PROFILES, TRUST_RESTRICTIONS_PROFILES,
TRUSTSTORE_PASSWORD_PROFILES, KEY_STORE_ALGORITHM_PROFILES, TRUST_STORE_ALGORITHM_PROFILES,
KEY_STORE_TYPE_PROFILES, TRUST_STORE_TYPE_PROFILES, TRUST_RESTRICTIONS_PROFILES,
KEY_PATH_PROFILES, LEGACY_KEY_PASSWORD_PROFILES, KEY_PASSWORD_PROFILES,CERT_PROFILES,CAPATH_SETTING_PROFILES,
CLIENT_AUTH_SETTING_PROFILES, VERIFICATION_MODE_SETTING_PROFILES);
}

View File

@ -35,6 +35,7 @@ import java.util.Objects;
class StoreKeyConfig extends KeyConfig {
final String keyStorePath;
final String keyStoreType;
final SecureString keyStorePassword;
final String keyStoreAlgorithm;
final SecureString keyPassword;
@ -43,14 +44,16 @@ class StoreKeyConfig extends KeyConfig {
/**
* Creates a new configuration that can be used to load key and trust material from a {@link KeyStore}
* @param keyStorePath the path to the keystore file
* @param keyStoreType the type of the keystore file
* @param keyStorePassword the password for the keystore
* @param keyPassword the password for the private key in the keystore
* @param keyStoreAlgorithm the algorithm for the keystore
* @param trustStoreAlgorithm the algorithm to use when loading as a truststore
*/
StoreKeyConfig(String keyStorePath, SecureString keyStorePassword, SecureString keyPassword, String keyStoreAlgorithm,
String trustStoreAlgorithm) {
StoreKeyConfig(String keyStorePath, String keyStoreType, SecureString keyStorePassword, SecureString keyPassword,
String keyStoreAlgorithm, String trustStoreAlgorithm) {
this.keyStorePath = Objects.requireNonNull(keyStorePath, "keystore path must be specified");
this.keyStoreType = Objects.requireNonNull(keyStoreType, "keystore type must be specified");
// since we support reloading the keystore, we must store the passphrase in memory for the life of the node, so we
// clone the password and never close it during our uses below
this.keyStorePassword = Objects.requireNonNull(keyStorePassword, "keystore password must be specified").clone();
@ -73,7 +76,7 @@ class StoreKeyConfig extends KeyConfig {
@Override
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
try {
return CertUtils.trustManager(keyStorePath, keyStorePassword.getChars(), trustStoreAlgorithm, environment);
return CertUtils.trustManager(keyStorePath, keyStoreType, keyStorePassword.getChars(), trustStoreAlgorithm, environment);
} catch (Exception e) {
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
}
@ -107,8 +110,7 @@ class StoreKeyConfig extends KeyConfig {
private KeyStore getKeyStore(@Nullable Environment environment)
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
try (InputStream in = Files.newInputStream(CertUtils.resolvePath(keyStorePath, environment))) {
// TODO remove reliance on JKS since we can use PKCS12 stores in JDK8+...
KeyStore ks = KeyStore.getInstance("jks");
KeyStore ks = KeyStore.getInstance(keyStoreType);
ks.load(in, keyStorePassword.getChars());
return ks;
}
@ -154,6 +156,7 @@ class StoreKeyConfig extends KeyConfig {
@Override
public String toString() {
return "keyStorePath=[" + keyStorePath +
"], keyStoreType=[" + keyStoreType +
"], keyStoreAlgorithm=[" + keyStoreAlgorithm +
"], trustStoreAlgorithm=[" + trustStoreAlgorithm +
"]";

View File

@ -22,6 +22,7 @@ import java.util.Objects;
class StoreTrustConfig extends TrustConfig {
final String trustStorePath;
final String trustStoreType;
final SecureString trustStorePassword;
final String trustStoreAlgorithm;
@ -31,8 +32,9 @@ class StoreTrustConfig extends TrustConfig {
* @param trustStorePassword the password for the truststore
* @param trustStoreAlgorithm the algorithm to use for reading the truststore
*/
StoreTrustConfig(String trustStorePath, SecureString trustStorePassword, String trustStoreAlgorithm) {
StoreTrustConfig(String trustStorePath, String trustStoreType, SecureString trustStorePassword, String trustStoreAlgorithm) {
this.trustStorePath = trustStorePath;
this.trustStoreType = trustStoreType;
// since we support reloading the truststore, we must store the passphrase in memory for the life of the node, so we
// clone the password and never close it during our uses below
this.trustStorePassword = Objects.requireNonNull(trustStorePassword, "truststore password must be specified").clone();
@ -42,7 +44,7 @@ class StoreTrustConfig extends TrustConfig {
@Override
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
try {
return CertUtils.trustManager(trustStorePath, trustStorePassword.getChars(), trustStoreAlgorithm, environment);
return CertUtils.trustManager(trustStorePath, trustStoreType, trustStorePassword.getChars(), trustStoreAlgorithm, environment);
} catch (Exception e) {
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
}

View File

@ -75,13 +75,16 @@ public class SSLConfigurationSettingsTests extends ESTestCase {
assertThat(ssl.keyPassword.exists(settings), is(false));
assertThat(ssl.keyPath.get(settings).isPresent(), is(false));
assertThat(ssl.keystoreAlgorithm.get(settings), is(KeyManagerFactory.getDefaultAlgorithm()));
assertThat(ssl.keystoreType.get(settings), is("jks"));
assertThat(ssl.keystoreKeyPassword.exists(settings), is(false));
assertThat(ssl.keystorePassword.exists(settings), is(false));
assertThat(ssl.keystorePath.get(settings).isPresent(), is(false));
assertThat(ssl.supportedProtocols.get(settings).size(), is(0));
assertThat(ssl.truststoreAlgorithm.get(settings), is(TrustManagerFactory.getDefaultAlgorithm()));
assertThat(ssl.truststoreType.get(settings), is("jks"));
assertThat(ssl.truststorePassword.exists(settings), is(false));
assertThat(ssl.truststorePath.get(settings).isPresent(), is(false));
assertThat(ssl.trustRestrictionsPath.get(settings).isPresent(), is(false));
assertThat(ssl.verificationMode.get(settings).isPresent(), is(false));
}

View File

@ -5,29 +5,6 @@
*/
package org.elasticsearch.xpack.ssl;
import org.elasticsearch.client.http.HttpHost;
import org.elasticsearch.client.http.HttpResponse;
import org.elasticsearch.client.http.client.methods.HttpGet;
import org.elasticsearch.client.http.concurrent.FutureCallback;
import org.elasticsearch.client.http.conn.ssl.DefaultHostnameVerifier;
import org.elasticsearch.client.http.conn.ssl.NoopHostnameVerifier;
import org.elasticsearch.client.http.impl.client.CloseableHttpClient;
import org.elasticsearch.client.http.impl.client.HttpClients;
import org.elasticsearch.client.http.impl.nio.client.CloseableHttpAsyncClient;
import org.elasticsearch.client.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.CheckedRunnable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.xpack.XPackSettings;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
@ -45,6 +22,29 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.http.HttpHost;
import org.elasticsearch.client.http.HttpResponse;
import org.elasticsearch.client.http.client.methods.HttpGet;
import org.elasticsearch.client.http.concurrent.FutureCallback;
import org.elasticsearch.client.http.conn.ssl.DefaultHostnameVerifier;
import org.elasticsearch.client.http.conn.ssl.NoopHostnameVerifier;
import org.elasticsearch.client.http.impl.client.CloseableHttpClient;
import org.elasticsearch.client.http.impl.client.HttpClients;
import org.elasticsearch.client.http.impl.nio.client.CloseableHttpAsyncClient;
import org.elasticsearch.client.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.http.nio.conn.ssl.SSLIOSessionStrategy;
import org.elasticsearch.common.CheckedRunnable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.MockSecureSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.junit.annotations.Network;
import org.elasticsearch.xpack.XPackSettings;
import org.junit.Before;
import org.mockito.ArgumentCaptor;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
@ -64,12 +64,22 @@ import static org.mockito.Mockito.when;
public class SSLServiceTests extends ESTestCase {
private Path testnodeStore;
private String testnodeStoreType;
private Path testclientStore;
private Environment env;
@Before
public void setup() throws Exception {
// Randomise the keystore type (jks/PKCS#12)
if (randomBoolean()) {
testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
// The default is to use JKS. Randomly test with explicit and with the default value.
testnodeStoreType = randomBoolean() ? "jks" : null;
} else {
testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12");
testnodeStoreType = "PKCS12";
}
logger.info("Using [{}] key/truststore [{}]", testnodeStoreType, testnodeStore);
testclientStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks");
env = new Environment(Settings.builder().put("path.home", createTempDir()).build());
}
@ -81,6 +91,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("transport.profiles.foo.xpack.security.ssl.truststore.secure_password", "testclient");
Settings settings = Settings.builder()
.put("xpack.ssl.truststore.path", testnodeStore)
.put("xpack.ssl.truststore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.put("transport.profiles.foo.xpack.security.ssl.truststore.path", testClientStore)
.build();
@ -105,6 +116,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
@ -150,6 +162,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
@ -181,6 +194,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
@ -193,6 +207,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.truststore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.truststore.path", testnodeStore)
.put("xpack.ssl.truststore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
@ -201,8 +216,10 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode");
settings = Settings.builder()
.put("xpack.ssl.truststore.path", testnodeStore)
.put("xpack.ssl.truststore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.put("xpack.security.transport.ssl.keystore.path", testnodeStore)
.put("xpack.security.transport.ssl.keystore.type", testnodeStoreType)
.build();
sslService = new SSLService(settings, env);
assertFalse(sslService.isConfigurationValidForServerUsage(sslService.sslConfiguration(Settings.EMPTY)));
@ -268,8 +285,10 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.put("xpack.ssl.truststore.path", testnodeStore)
.put("xpack.ssl.truststore.type", testnodeStoreType)
.build();
ElasticsearchException e =
expectThrows(ElasticsearchException.class, () -> new SSLService(settings, env));
@ -279,6 +298,7 @@ public class SSLServiceTests extends ESTestCase {
public void testThatKeystorePasswordIsRequired() throws Exception {
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.build();
ElasticsearchException e =
expectThrows(ElasticsearchException.class, () -> new SSLService(settings, env));
@ -293,6 +313,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.putArray("xpack.ssl.ciphers", ciphers.toArray(new String[ciphers.size()]))
.build();
@ -309,6 +330,7 @@ public class SSLServiceTests extends ESTestCase {
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.putArray("xpack.ssl.cipher_suites", new String[]{"foo", "bar"})
.build();
@ -322,6 +344,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
@ -335,6 +358,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);
@ -359,6 +383,7 @@ public class SSLServiceTests extends ESTestCase {
secureSettings.setString("xpack.ssl.keystore.secure_password", "testnode");
Settings settings = Settings.builder()
.put("xpack.ssl.keystore.path", testnodeStore)
.put("xpack.ssl.keystore.type", testnodeStoreType)
.setSecureSettings(secureSettings)
.build();
SSLService sslService = new SSLService(settings, env);

View File

@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.ssl;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
import java.security.PrivateKey;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
public class StoreKeyConfigTests extends ESTestCase {
public void testCreateKeyManagerUsingJKS() throws Exception {
tryReadPrivateKeyFromKeyStore("jks", ".jks");
}
public void testCreateKeyManagerUsingPKCS12() throws Exception {
tryReadPrivateKeyFromKeyStore("PKCS12", ".p12");
}
private void tryReadPrivateKeyFromKeyStore(String type, String extension) {
final Settings settings = Settings.builder().put("path.home", createTempDir()).build();
final String path = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode" + extension).toString();
final SecureString keyStorePassword = new SecureString("testnode".toCharArray());
final StoreKeyConfig keyConfig = new StoreKeyConfig(path, type, keyStorePassword, keyStorePassword,
KeyManagerFactory.getDefaultAlgorithm(), TrustManagerFactory.getDefaultAlgorithm());
final X509ExtendedKeyManager keyManager = keyConfig.createKeyManager(new Environment(settings));
final PrivateKey key = keyManager.getPrivateKey("testnode");
assertThat(key, notNullValue());
assertThat(key.getAlgorithm(), equalTo("RSA"));
assertThat(key.getFormat(), equalTo("PKCS#8"));
}
}