diff --git a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java index c4c948ef168..733d5911c2b 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java @@ -180,7 +180,7 @@ 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); + String trustStoreType = SSLConfigurationSettings.getKeyStoreType(SSL_SETTINGS.truststoreType, settings, truststorePath); try { return CertUtils.trustManager(truststorePath, trustStoreType, password.getChars(), trustStoreAlgorithm, realmConfig.env()); } catch (Exception e) { diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java index cdcae4e214b..1e0e85ea0e0 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfiguration.java @@ -15,7 +15,6 @@ 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; @@ -205,8 +204,8 @@ 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);; + String keyStoreType = SSLConfigurationSettings.getKeyStoreType(SETTINGS_PARSER.keystoreType, settings, keyStorePath); + SecureString keyStoreKeyPassword = SETTINGS_PARSER.keystoreKeyPassword.get(settings); if (keyStoreKeyPassword.length() == 0) { keyStoreKeyPassword = keyStorePassword; } @@ -244,7 +243,7 @@ public final class SSLConfiguration { } else if (trustStorePath != null) { SecureString trustStorePassword = SETTINGS_PARSER.truststorePassword.get(settings); String trustStoreAlgorithm = SETTINGS_PARSER.truststoreAlgorithm.get(settings); - String trustStoreType = SETTINGS_PARSER.truststoreType.get(settings); + String trustStoreType = SSLConfigurationSettings.getKeyStoreType(SETTINGS_PARSER.truststoreType, settings, trustStorePath); 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", ""))) { diff --git a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettings.java b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettings.java index 03a9b244137..4bb2d530d47 100644 --- a/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettings.java +++ b/plugin/src/main/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettings.java @@ -7,21 +7,20 @@ 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; import java.util.List; +import java.util.Locale; import java.util.Optional; import java.util.function.Function; import org.elasticsearch.common.settings.SecureSetting; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Setting; -import org.elasticsearch.common.settings.Settings; - import org.elasticsearch.common.settings.Setting.Property; +import org.elasticsearch.common.settings.Settings; /** * Bridges {@link SSLConfiguration} into the {@link Settings} framework, using {@link Setting} objects. @@ -33,12 +32,12 @@ public class SSLConfigurationSettings { public final Setting> keystorePath; public final Setting keystorePassword; public final Setting keystoreAlgorithm; - public final Setting keystoreType; + public final Setting> keystoreType; public final Setting keystoreKeyPassword; public final Setting> truststorePath; public final Setting truststorePassword; public final Setting truststoreAlgorithm; - public final Setting truststoreType; + public final Setting> truststoreType; public final Setting> trustRestrictionsPath; public final Setting> keyPath; public final Setting keyPassword; @@ -62,6 +61,7 @@ public class SSLConfigurationSettings { * 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 String PKCS12_KEYSTORE_TYPE = "PKCS12"; private static final Function>> CIPHERS_SETTING_TEMPLATE = key -> Setting.listSetting(key, Collections .emptyList(), Function.identity(), Property.NodeScope, Property.Filtered); @@ -132,14 +132,13 @@ public class SSLConfigurationSettings { public static final Setting TRUST_STORE_ALGORITHM_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.truststore.algorithm", TRUST_STORE_ALGORITHM_TEMPLATE); - private static final Function> KEY_STORE_TYPE_TEMPLATE = key -> - new Setting<>(key, DEFAULT_KEYSTORE_TYPE, Function.identity(), Property.NodeScope, Property.Filtered); - public static final Setting KEY_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.", + private static final Function>> KEY_STORE_TYPE_TEMPLATE = key -> + new Setting<>(key, s -> null, Optional::ofNullable, Property.NodeScope, Property.Filtered); + public static final Setting> KEY_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.keystore.type", KEY_STORE_TYPE_TEMPLATE); - private static final Function> TRUST_STORE_TYPE_TEMPLATE = key -> - new Setting<>(key, DEFAULT_KEYSTORE_TYPE, Function.identity(), Property.NodeScope, Property.Filtered); - public static final Setting TRUST_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.", + private static final Function>> TRUST_STORE_TYPE_TEMPLATE = KEY_STORE_TYPE_TEMPLATE; + public static final Setting> TRUST_STORE_TYPE_PROFILES = Setting.affixKeySetting("transport.profiles.", "xpack.security.ssl.truststore.type", TRUST_STORE_TYPE_TEMPLATE); private static final Function>> TRUST_RESTRICTIONS_TEMPLATE = key -> new Setting<>(key, s -> null, @@ -201,7 +200,7 @@ public class SSLConfigurationSettings { 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"); + truststoreType = TRUST_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"); @@ -218,6 +217,19 @@ public class SSLConfigurationSettings { legacyKeystorePassword, legacyKeystoreKeyPassword, legacyKeyPassword, legacyTruststorePassword); } + public static String getKeyStoreType(Setting> setting, Settings settings, String path) { + return setting.get(settings).orElseGet(() -> inferKeyStoreType(path)); + } + + private static String inferKeyStoreType(String path) { + String name = path == null ? "" : path.toLowerCase(Locale.ROOT); + if (name.endsWith(".p12") || name.endsWith(".pfx") || name.endsWith(".pkcs12")) { + return PKCS12_KEYSTORE_TYPE; + } else { + return DEFAULT_KEYSTORE_TYPE; + } + } + public List> getAllSettings() { return allSettings; } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettingsTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettingsTests.java index 135f5e259d4..cccf9abfcd5 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettingsTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationSettingsTests.java @@ -75,17 +75,20 @@ 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.keystoreType.get(settings).isPresent(), is(false)); 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.truststoreType.get(settings).isPresent(), is(false)); 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)); + + assertThat(SSLConfigurationSettings.getKeyStoreType(ssl.keystoreType, settings, null), is("jks")); + assertThat(SSLConfigurationSettings.getKeyStoreType(ssl.truststoreType, settings, null), is("jks")); } } diff --git a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java index 7cef8b415cd..558a9b1544f 100644 --- a/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java +++ b/plugin/src/test/java/org/elasticsearch/xpack/ssl/SSLConfigurationTests.java @@ -5,6 +5,12 @@ */ package org.elasticsearch.xpack.ssl; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.TrustManager; +import java.security.cert.X509Certificate; +import java.util.Arrays; + import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; @@ -12,17 +18,11 @@ import org.elasticsearch.env.Environment; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.ssl.TrustConfig.CombiningTrustConfig; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.TrustManager; -import java.security.cert.X509Certificate; -import java.util.Arrays; - import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.everyItem; import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.isIn; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.isIn; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.sameInstance; @@ -58,6 +58,7 @@ public class SSLConfigurationTests extends ESTestCase { assertThat(ksKeyInfo.keyStorePath, is(equalTo(path))); assertThat(ksKeyInfo.keyStorePassword, is(equalTo("testnode"))); + assertThat(ksKeyInfo.keyStoreType, is(equalTo("jks"))); assertThat(ksKeyInfo.keyPassword, is(equalTo(ksKeyInfo.keyStorePassword))); assertThat(ksKeyInfo.keyStoreAlgorithm, is(KeyManagerFactory.getDefaultAlgorithm())); assertThat(sslConfiguration.trustConfig(), is(instanceOf(CombiningTrustConfig.class))); @@ -123,6 +124,66 @@ public class SSLConfigurationTests extends ESTestCase { SSLConfiguration.SETTINGS_PARSER.legacyKeystorePassword, SSLConfiguration.SETTINGS_PARSER.legacyKeystoreKeyPassword}); } + public void testInferKeystoreTypeFromJksFile() { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("keystore.secure_password", "password"); + secureSettings.setString("keystore.secure_key_password", "keypass"); + Settings settings = Settings.builder() + .put("keystore.path", "xpack/tls/path.jks") + .setSecureSettings(secureSettings) + .build(); + SSLConfiguration sslConfiguration = new SSLConfiguration(settings); + assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class)); + StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig(); + assertThat(ksKeyInfo.keyStoreType, is(equalTo("jks"))); + } + + public void testInferKeystoreTypeFromPkcs12File() { + final String ext = randomFrom("p12", "pfx", "pkcs12"); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("keystore.secure_password", "password"); + secureSettings.setString("keystore.secure_key_password", "keypass"); + Settings settings = Settings.builder() + .put("keystore.path", "xpack/tls/path." + ext) + .setSecureSettings(secureSettings) + .build(); + SSLConfiguration sslConfiguration = new SSLConfiguration(settings); + assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class)); + StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig(); + assertThat(ksKeyInfo.keyStoreType, is(equalTo("PKCS12"))); + } + + public void testInferKeystoreTypeFromUnrecognised() { + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("keystore.secure_password", "password"); + secureSettings.setString("keystore.secure_key_password", "keypass"); + Settings settings = Settings.builder() + .put("keystore.path", "xpack/tls/path.foo") + .setSecureSettings(secureSettings) + .build(); + SSLConfiguration sslConfiguration = new SSLConfiguration(settings); + assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class)); + StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig(); + assertThat(ksKeyInfo.keyStoreType, is(equalTo("jks"))); + } + + public void testExplicitKeystoreType() { + final String ext = randomFrom("p12", "jks"); + final String type = randomAlphaOfLengthBetween(2, 8); + MockSecureSettings secureSettings = new MockSecureSettings(); + secureSettings.setString("keystore.secure_password", "password"); + secureSettings.setString("keystore.secure_key_password", "keypass"); + Settings settings = Settings.builder() + .put("keystore.path", "xpack/tls/path." + ext) + .put("keystore.type", type) + .setSecureSettings(secureSettings) + .build(); + SSLConfiguration sslConfiguration = new SSLConfiguration(settings); + assertThat(sslConfiguration.keyConfig(), instanceOf(StoreKeyConfig.class)); + StoreKeyConfig ksKeyInfo = (StoreKeyConfig) sslConfiguration.keyConfig(); + assertThat(ksKeyInfo.keyStoreType, is(equalTo(type))); + } + public void testThatProfileSettingsOverrideServiceSettings() { MockSecureSettings profileSecureSettings = new MockSecureSettings(); profileSecureSettings.setString("keystore.secure_password", "password");