Support PKCS#11 tokens as keystores and truststores (#34063)

This enables Elasticsearch to use the JVM-wide configured
PKCS#11 token as a keystore or a truststore for its TLS configuration.
The JVM is assumed to be configured accordingly with the appropriate
Security Provider implementation that supports PKCS#11 tokens.
For the PKCS#11 token to be used as a keystore or a truststore for an
SSLConfiguration, the .keystore.type or .truststore.type must be
explicitly set to pkcs11 in the configuration.
The fact that the PKCS#11 token configuration is JVM wide implies that
there is only one available keystore and truststore that can be used by TLS
configurations in Elasticsearch.
The PIN for the PKCS#11 token can be set as a truststore parameter in
Elasticsearch or as a JVM parameter ( -Djavax.net.ssl.trustStorePassword).

The basic goal of enabling PKCS#11 token support is to allow PKCS#11-NSS in
FIPS mode to be used as a FIPS 140-2 enabled Security Provider.
This commit is contained in:
Ioannis Kakavas 2018-10-04 10:51:58 +03:00 committed by GitHub
parent e8b986cc37
commit 2c82b80b85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 181 additions and 79 deletions

View File

@ -400,8 +400,9 @@ 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`.
The format of the keystore file. Should be `jks` to use the Java
Keystore format, `PKCS12` to use PKCS#12 files, or `PKCS11` to use a PKCS#11 token.
The default is `jks`.
`ssl.keystore.password`::
The password to the keystore.
@ -426,8 +427,9 @@ The password to the truststore.
The password to the truststore.
`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`.
The format of the keystore file. Should be `jks` to use the Java
Keystore format, `PKCS12` to use PKCS#12 files, or `PKCS11` to use a PKCS#11 token.
The default is `jks`.
`ssl.verification_mode`::
Indicates the type of verification when using `ldaps` to protect against man
@ -649,8 +651,9 @@ The path to the Java Keystore file that contains a private key and certificate.
`ssl.key` and `ssl.keystore.path` cannot 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`.
The format of the keystore file. Should be `jks` to use the Java
Keystore format, `PKCS12` to use PKCS#12 files, or `PKCS11` to use a PKCS#11 token.
The default is `jks`.
`ssl.truststore.password`::
The password to the truststore.
@ -664,8 +667,9 @@ The path to the Java Keystore file that contains the certificates to trust.
same time.
`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`.
The format of the truststore file. Should be `jks` to use the Java
Keystore format, `PKCS12` to use PKCS#12 files, or `PKCS11` to use a PKCS#11 token.
The default is `jks`.
`ssl.verification_mode`::
Indicates the type of verification when using `ldaps` to protect against man
@ -1316,6 +1320,32 @@ a PKCS#12 container includes trusted certificate ("anchor") entries look for
`openssl pkcs12 -info` output, or `trustedCertEntry` in the
`keytool -list` output.
===== PKCS#11 tokens
When using a PKCS#11 cryptographic token, which contains the
private key, certificate, and certificates that should be trusted, use
the following settings:
`xpack.ssl.keystore.type`::
Set this to `PKCS11`.
`xpack.ssl.truststore.type`::
Set this to `PKCS11`.
[[pkcs11-truststore-note]]
[NOTE]
When configuring the PKCS#11 token that your JVM is configured to use as
a keystore or a truststore for Elasticsearch, the PIN for the token can be
configured by setting the appropriate value to `xpack.ssl.truststore.password`
or `xpack.ssl.truststore.secure_password`. In the absence of the above, {es} will
fallback to use he appropriate JVM setting (`-Djavax.net.ssl.trustStorePassword`)
if that s set.
Since there can only be one PKCS#11 token configured, only one keystore and
truststore will be usable for configuration in {es}. This in turn means
that only one certificate can be used for TLS both in the transport and the
http layer.
[[http-tls-ssl-settings]]
:ssl-prefix: xpack.security.http
:component: HTTP

View File

@ -145,3 +145,17 @@ Password to the PKCS#12 file.
+{ssl-prefix}.ssl.truststore.secure_password+ (<<secure-settings,Secure>>)::
Password to the PKCS#12 file.
===== PKCS#11 Tokens
{security} can be configured to use a PKCS#11 token that contains the private key,
certificate and certificates that should be trusted.
PKCS#11 token require additional configuration on the JVM level and can be enabled
via the following settings:
+{ssl-prefix}.keystore.type+::
Set this to `PKCS11` to indicate that the PKCS#11 token should be used as a keystore.
+{ssl-prefix}.truststore.type+::
Set this to `PKCS11` to indicate that the PKCS#11 token should be used as a truststore.

View File

@ -34,6 +34,10 @@ The list does not include certificates that are sourced from the default SSL
context of the Java Runtime Environment (JRE), even if those certificates are in
use within {xpack}.
NOTE: When a PKCS#11 token is configured as the truststore of the JRE, the API
will return all the certificates that are included in the PKCS#11 token
irrespectively to whether these are used in the {es} TLS configuration or not.
If {xpack} is configured to use a keystore or truststore, the API output
includes all certificates in that store, even though some of the certificates
might not be in active use within the cluster.

View File

@ -197,6 +197,7 @@ public class CertParsingUtils {
static KeyConfig createKeyConfig(X509KeyPairSettings keyPair, Settings settings, String trustStoreAlgorithm) {
String keyPath = keyPair.keyPath.get(settings).orElse(null);
String keyStorePath = keyPair.keystorePath.get(settings).orElse(null);
String keyStoreType = getKeyStoreType(keyPair.keystoreType, settings, keyStorePath);
if (keyPath != null && keyStorePath != null) {
throw new IllegalArgumentException("you cannot specify a keystore and key file");
@ -212,10 +213,9 @@ public class CertParsingUtils {
return new PEMKeyConfig(keyPath, keyPassword, certPath);
}
if (keyStorePath != null) {
if (keyStorePath != null || keyStoreType.equalsIgnoreCase("pkcs11")) {
SecureString keyStorePassword = keyPair.keystorePassword.get(settings);
String keyStoreAlgorithm = keyPair.keystoreAlgorithm.get(settings);
String keyStoreType = getKeyStoreType(keyPair.keystoreType, settings, keyStorePath);
SecureString keyStoreKeyPassword = keyPair.keystoreKeyPassword.get(settings);
if (keyStoreKeyPassword.length() == 0) {
keyStoreKeyPassword = keyStorePassword;
@ -224,7 +224,6 @@ public class CertParsingUtils {
trustStoreAlgorithm);
}
return null;
}
/**

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.core.ssl;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.ssl.cert.CertificateInfo;
@ -30,9 +31,14 @@ import java.util.List;
*/
class DefaultJDKTrustConfig extends TrustConfig {
static final DefaultJDKTrustConfig INSTANCE = new DefaultJDKTrustConfig();
private SecureString trustStorePassword;
private DefaultJDKTrustConfig() {
/**
* @param trustStorePassword the password for the default jdk truststore defined either as a system property or in the Elasticsearch
* configuration. It applies only when PKCS#11 tokens are user, is null otherwise
*/
DefaultJDKTrustConfig(@Nullable SecureString trustStorePassword) {
this.trustStorePassword = trustStorePassword;
}
@Override
@ -76,13 +82,14 @@ class DefaultJDKTrustConfig extends TrustConfig {
/**
* Merges the default trust configuration with the provided {@link TrustConfig}
* @param trustConfig the trust configuration to merge with
* @param trustStorePassword the password for the default jdk truststore. It applies only to PKCS#11 tokens
* @return a {@link TrustConfig} that represents a combination of both trust configurations
*/
static TrustConfig merge(TrustConfig trustConfig) {
static TrustConfig merge(TrustConfig trustConfig, SecureString trustStorePassword) {
if (trustConfig == null) {
return INSTANCE;
return new DefaultJDKTrustConfig(trustStorePassword);
} else {
return new CombiningTrustConfig(Arrays.asList(INSTANCE, trustConfig));
return new CombiningTrustConfig(Arrays.asList(new DefaultJDKTrustConfig(trustStorePassword), trustConfig));
}
}
@ -94,9 +101,10 @@ class DefaultJDKTrustConfig extends TrustConfig {
* @return the KeyStore used as truststore for PKCS#11 initialized with the password, null otherwise
*/
private KeyStore getSystemTrustStore() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
if (System.getProperty("javax.net.ssl.trustStoreType", "").equalsIgnoreCase("PKCS11")) {
if (System.getProperty("javax.net.ssl.trustStoreType", "").equalsIgnoreCase("PKCS11")
&& trustStorePassword != null) {
KeyStore keyStore = KeyStore.getInstance("PKCS11");
keyStore.load(null, System.getProperty("javax.net.ssl.trustStorePassword", "").toCharArray());
keyStore.load(null, trustStorePassword.getChars());
return keyStore;
}
return null;

View File

@ -212,12 +212,11 @@ public final class SSLConfiguration {
private static TrustConfig createCertChainTrustConfig(Settings settings, KeyConfig keyConfig, SSLConfiguration global) {
String trustStorePath = SETTINGS_PARSER.truststorePath.get(settings).orElse(null);
String trustStoreType = getKeyStoreType(SETTINGS_PARSER.truststoreType, settings, trustStorePath);
List<String> caPaths = getListOrNull(SETTINGS_PARSER.caPaths, settings);
if (trustStorePath != null && caPaths != null) {
throw new IllegalArgumentException("you cannot specify a truststore and ca files");
}
VerificationMode verificationMode = SETTINGS_PARSER.verificationMode.get(settings).orElseGet(() -> {
if (global != null) {
return global.verificationMode();
@ -228,10 +227,9 @@ public final class SSLConfiguration {
return TrustAllConfig.INSTANCE;
} else if (caPaths != null) {
return new PEMTrustConfig(caPaths);
} else if (trustStorePath != null) {
SecureString trustStorePassword = SETTINGS_PARSER.truststorePassword.get(settings);
} else if (trustStorePath != null || trustStoreType.equalsIgnoreCase("pkcs11")) {
String trustStoreAlgorithm = SETTINGS_PARSER.truststoreAlgorithm.get(settings);
String trustStoreType = getKeyStoreType(SETTINGS_PARSER.truststoreType, settings, trustStorePath);
SecureString trustStorePassword = SETTINGS_PARSER.truststorePassword.get(settings);
return new StoreTrustConfig(trustStorePath, trustStoreType, trustStorePassword, trustStoreAlgorithm);
} else if (global == null && System.getProperty("javax.net.ssl.trustStore") != null
&& System.getProperty("javax.net.ssl.trustStore").equals("NONE") == false) {
@ -242,12 +240,28 @@ public final class SSLConfiguration {
} else if (global != null && keyConfig == global.keyConfig()) {
return global.trustConfig();
} else if (keyConfig != KeyConfig.NONE) {
return DefaultJDKTrustConfig.merge(keyConfig);
return DefaultJDKTrustConfig.merge(keyConfig, getDefaultTrustStorePassword(settings));
} else {
return DefaultJDKTrustConfig.INSTANCE;
return new DefaultJDKTrustConfig(getDefaultTrustStorePassword(settings));
}
}
private static SecureString getDefaultTrustStorePassword(Settings settings) {
// We only handle the default store password if it's a PKCS#11 token
if (System.getProperty("javax.net.ssl.trustStoreType", "").equalsIgnoreCase("PKCS11")) {
try (SecureString systemTrustStorePassword =
new SecureString(System.getProperty("javax.net.ssl.trustStorePassword", "").toCharArray())) {
if (systemTrustStorePassword.length() == 0) {
try (SecureString trustStorePassword = SETTINGS_PARSER.truststorePassword.get(settings)) {
return trustStorePassword;
}
}
return systemTrustStorePassword;
}
}
return null;
}
private static List<String> getListOrNull(Setting<List<String>> listSetting, Settings settings) {
return getListOrDefault(listSetting, settings, null);
}

View File

@ -15,8 +15,6 @@ import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509ExtendedTrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.Key;
@ -49,7 +47,7 @@ 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 keyStorePath the path to the keystore file or null when keyStoreType is pkcs11
* @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
@ -58,7 +56,7 @@ class StoreKeyConfig extends KeyConfig {
*/
StoreKeyConfig(String keyStorePath, String keyStoreType, SecureString keyStorePassword, SecureString keyPassword,
String keyStoreAlgorithm, String trustStoreAlgorithm) {
this.keyStorePath = Objects.requireNonNull(keyStorePath, "keystore path must be specified");
this.keyStorePath = keyStorePath;
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
@ -71,7 +69,7 @@ class StoreKeyConfig extends KeyConfig {
@Override
X509ExtendedKeyManager createKeyManager(@Nullable Environment environment) {
try {
KeyStore ks = getKeyStore(environment);
KeyStore ks = getStore(environment, keyStorePath, keyStoreType, keyStorePassword);
checkKeyStore(ks);
return CertParsingUtils.keyManager(ks, keyPassword.getChars(), keyStoreAlgorithm);
} catch (IOException | CertificateException | NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException e) {
@ -82,16 +80,16 @@ class StoreKeyConfig extends KeyConfig {
@Override
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
try {
return CertParsingUtils.trustManager(keyStorePath, keyStoreType, keyStorePassword.getChars(), trustStoreAlgorithm, environment);
} catch (Exception e) {
KeyStore ks = getStore(environment, keyStorePath, keyStoreType, keyStorePassword);
return CertParsingUtils.trustManager(ks, trustStoreAlgorithm);
} catch (IOException | CertificateException | NoSuchAlgorithmException | KeyStoreException e) {
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
}
}
@Override
Collection<CertificateInfo> certificates(Environment environment) throws GeneralSecurityException, IOException {
final Path path = CertParsingUtils.resolvePath(keyStorePath, environment);
final KeyStore trustStore = CertParsingUtils.readKeyStore(path, keyStoreType, keyStorePassword.getChars());
final KeyStore trustStore = getStore(environment, keyStorePath, keyStoreType, keyStorePassword);
final List<CertificateInfo> certificates = new ArrayList<>();
final Enumeration<String> aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
@ -112,13 +110,16 @@ class StoreKeyConfig extends KeyConfig {
@Override
List<Path> filesToMonitor(@Nullable Environment environment) {
if (keyStorePath == null) {
return Collections.emptyList();
}
return Collections.singletonList(CertParsingUtils.resolvePath(keyStorePath, environment));
}
@Override
List<PrivateKey> privateKeys(@Nullable Environment environment) {
try {
KeyStore keyStore = getKeyStore(environment);
KeyStore keyStore = getStore(environment, keyStorePath, keyStoreType, keyStorePassword);
List<PrivateKey> privateKeys = new ArrayList<>();
for (Enumeration<String> e = keyStore.aliases(); e.hasMoreElements(); ) {
final String alias = e.nextElement();
@ -135,15 +136,6 @@ class StoreKeyConfig extends KeyConfig {
}
}
private KeyStore getKeyStore(@Nullable Environment environment)
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
try (InputStream in = Files.newInputStream(CertParsingUtils.resolvePath(keyStorePath, environment))) {
KeyStore ks = KeyStore.getInstance(keyStoreType);
ks.load(in, keyStorePassword.getChars());
return ks;
}
}
private void checkKeyStore(KeyStore keyStore) throws KeyStoreException {
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
@ -152,9 +144,11 @@ class StoreKeyConfig extends KeyConfig {
return;
}
}
throw new IllegalArgumentException("the keystore [" + keyStorePath + "] does not contain a private key entry");
final String message = null != keyStorePath ?
"the keystore [" + keyStorePath + "] does not contain a private key entry" :
"the configured PKCS#11 token does not contain a private key entry";
throw new IllegalArgumentException(message);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@ -55,8 +55,8 @@ class StoreTrustConfig extends TrustConfig {
@Override
X509ExtendedTrustManager createTrustManager(@Nullable Environment environment) {
try {
return CertParsingUtils.trustManager(trustStorePath, trustStoreType, trustStorePassword.getChars(),
trustStoreAlgorithm, environment);
KeyStore trustStore = getStore(environment, trustStorePath, trustStoreType, trustStorePassword);
return CertParsingUtils.trustManager(trustStore, trustStoreAlgorithm);
} catch (Exception e) {
throw new ElasticsearchException("failed to initialize a TrustManagerFactory", e);
}
@ -64,8 +64,7 @@ class StoreTrustConfig extends TrustConfig {
@Override
Collection<CertificateInfo> certificates(Environment environment) throws GeneralSecurityException, IOException {
final Path path = CertParsingUtils.resolvePath(trustStorePath, environment);
final KeyStore trustStore = CertParsingUtils.readKeyStore(path, trustStoreType, trustStorePassword.getChars());
final KeyStore trustStore = getStore(environment, trustStorePath, trustStoreType, trustStorePassword);
final List<CertificateInfo> certificates = new ArrayList<>();
final Enumeration<String> aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {

View File

@ -7,14 +7,21 @@ package org.elasticsearch.xpack.core.ssl;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.env.Environment;
import org.elasticsearch.xpack.core.ssl.cert.CertificateInfo;
import javax.net.ssl.X509ExtendedTrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
@ -58,6 +65,38 @@ abstract class TrustConfig {
*/
public abstract int hashCode();
/**
* Loads and returns the appropriate {@link KeyStore} for the given configuration. The KeyStore can be backed by a file
* in any format that the Security Provider might support, or a cryptographic software or hardware token in the case
* of a PKCS#11 Provider.
*
* @param environment the environment to resolve files against or null in the case of running in a transport client
* @param storePath the path to the {@link KeyStore} to load, or null if a PKCS11 token is configured as the keystore/truststore
* of the JVM
* @param storeType the type of the {@link KeyStore}
* @param storePassword the password to be used for decrypting the {@link KeyStore}
* @return the loaded KeyStore to be used as a keystore or a truststore
* @throws KeyStoreException if an instance of the specified type cannot be loaded
* @throws CertificateException if any of the certificates in the keystore could not be loaded
* @throws NoSuchAlgorithmException if the algorithm used to check the integrity of the keystore cannot be found
* @throws IOException if there is an I/O issue with the KeyStore data or the password is incorrect
*/
KeyStore getStore(@Nullable Environment environment, @Nullable String storePath, String storeType, SecureString storePassword)
throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
if (null != storePath) {
try (InputStream in = Files.newInputStream(CertParsingUtils.resolvePath(storePath, environment))) {
KeyStore ks = KeyStore.getInstance(storeType);
ks.load(in, storePassword.getChars());
return ks;
}
} else if (storeType.equalsIgnoreCase("pkcs11")) {
KeyStore ks = KeyStore.getInstance(storeType);
ks.load(null, storePassword.getChars());
return ks;
}
throw new IllegalArgumentException("keystore.path or truststore.path can only be empty when using a PKCS#11 token");
}
/**
* A trust configuration that is a combination of a trust configuration with the default JDK trust configuration. This trust
* configuration returns a trust manager verifies certificates against both the default JDK trusted configurations and the specific

View File

@ -228,20 +228,6 @@ public class SSLConfigurationTests extends ESTestCase {
assertThat(ksTrustInfo.trustStoreAlgorithm, is(equalTo("trusted")));
}
public void testThatEmptySettingsAreEqual() {
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.EMPTY);
SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.EMPTY);
assertThat(sslConfiguration.equals(sslConfiguration1), is(equalTo(true)));
assertThat(sslConfiguration1.equals(sslConfiguration), is(equalTo(true)));
assertThat(sslConfiguration.equals(sslConfiguration), is(equalTo(true)));
assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true)));
SSLConfiguration profileSSLConfiguration = new SSLConfiguration(Settings.EMPTY, sslConfiguration);
assertThat(sslConfiguration.equals(profileSSLConfiguration), is(equalTo(true)));
assertThat(profileSSLConfiguration.equals(sslConfiguration), is(equalTo(true)));
assertThat(profileSSLConfiguration.equals(profileSSLConfiguration), is(equalTo(true)));
}
public void testThatSettingsWithDifferentKeystoresAreNotEqual() {
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder()
.put("keystore.path", "path")
@ -268,15 +254,6 @@ public class SSLConfigurationTests extends ESTestCase {
assertThat(sslConfiguration1.equals(sslConfiguration1), is(equalTo(true)));
}
public void testThatEmptySettingsHaveSameHashCode() {
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.EMPTY);
SSLConfiguration sslConfiguration1 = new SSLConfiguration(Settings.EMPTY);
assertThat(sslConfiguration.hashCode(), is(equalTo(sslConfiguration1.hashCode())));
SSLConfiguration profileSettings = new SSLConfiguration(Settings.EMPTY, sslConfiguration);
assertThat(profileSettings.hashCode(), is(equalTo(sslConfiguration.hashCode())));
}
public void testThatSettingsWithDifferentKeystoresHaveDifferentHashCode() {
SSLConfiguration sslConfiguration = new SSLConfiguration(Settings.builder()
.put("keystore.path", "path")
@ -390,7 +367,8 @@ public class SSLConfigurationTests extends ESTestCase {
private void assertCombiningTrustConfigContainsCorrectIssuers(SSLConfiguration sslConfiguration) {
X509Certificate[] trustConfAcceptedIssuers = sslConfiguration.trustConfig().createTrustManager(null).getAcceptedIssuers();
X509Certificate[] keyConfAcceptedIssuers = sslConfiguration.keyConfig().createTrustManager(null).getAcceptedIssuers();
X509Certificate[] defaultAcceptedIssuers = DefaultJDKTrustConfig.INSTANCE.createTrustManager(null).getAcceptedIssuers();
X509Certificate[] defaultAcceptedIssuers = new DefaultJDKTrustConfig(null).createTrustManager(null)
.getAcceptedIssuers();
assertEquals(keyConfAcceptedIssuers.length + defaultAcceptedIssuers.length, trustConfAcceptedIssuers.length);
assertThat(Arrays.asList(keyConfAcceptedIssuers), everyItem(isIn(trustConfAcceptedIssuers)));
assertThat(Arrays.asList(defaultAcceptedIssuers), everyItem(isIn(trustConfAcceptedIssuers)));

View File

@ -477,8 +477,8 @@ public class SSLServiceTests extends ESTestCase {
public void testEmptyTrustManager() throws Exception {
Settings settings = Settings.builder().build();
final SSLService sslService = new SSLService(settings, env);
SSLConfiguration sslConfig = new SSLConfiguration(settings);
X509ExtendedTrustManager trustManager = sslService.sslContextHolder(sslConfig).getEmptyTrustManager();
X509ExtendedTrustManager trustManager = sslService.sslContextHolder(sslService.getSSLConfiguration("xpack.ssl"))
.getEmptyTrustManager();
assertThat(trustManager.getAcceptedIssuers(), emptyArray());
}

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.core.ssl;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.TestEnvironment;
@ -16,6 +17,7 @@ import javax.net.ssl.X509ExtendedKeyManager;
import java.security.PrivateKey;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
@ -31,6 +33,23 @@ public class StoreKeyConfigTests extends ESTestCase {
tryReadPrivateKeyFromKeyStore("PKCS12", ".p12");
}
public void testKeyStorePathCanBeEmptyForPkcs11() throws Exception {
assumeFalse("Can't run in a FIPS JVM", inFipsJvm());
final Settings settings = Settings.builder().put("path.home", createTempDir()).build();
final SecureString keyStorePassword = new SecureString("password".toCharArray());
final StoreKeyConfig keyConfig = new StoreKeyConfig(null, "PKCS12", keyStorePassword, keyStorePassword,
KeyManagerFactory.getDefaultAlgorithm(), TrustManagerFactory.getDefaultAlgorithm());
Exception e = expectThrows(IllegalArgumentException.class, () ->
keyConfig.createKeyManager(TestEnvironment.newEnvironment(settings)));
assertThat(e.getMessage(), equalTo("keystore.path or truststore.path can only be empty when using a PKCS#11 token"));
final StoreKeyConfig keyConfigPkcs11 = new StoreKeyConfig(null, "PKCS11", keyStorePassword, keyStorePassword,
KeyManagerFactory.getDefaultAlgorithm(), TrustManagerFactory.getDefaultAlgorithm());
ElasticsearchException ee = expectThrows(ElasticsearchException.class, () ->
keyConfigPkcs11.createKeyManager(TestEnvironment.newEnvironment(settings)));
assertThat(ee.getMessage(), containsString("failed to initialize a KeyManagerFactory"));
assertThat(ee.getCause().getMessage(), containsString("PKCS11 not found"));
}
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();

View File

@ -30,4 +30,8 @@ public class TestsSSLService extends SSLService {
public SSLContext sslContext(Settings settings) {
return sslContextHolder(super.sslConfiguration(settings)).sslContext();
}
public SSLContext sslContext(String context) {
return sslContextHolder(super.getSSLConfiguration(context)).sslContext();
}
}

View File

@ -58,7 +58,7 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest
public void startWebservice() throws Exception {
Settings settings = getInstanceFromMaster(Settings.class);
TestsSSLService sslService = new TestsSSLService(settings, getInstanceFromMaster(Environment.class));
webServer = new MockWebServer(sslService.sslContext(settings.getByPrefix("xpack.http.ssl.")), false);
webServer = new MockWebServer(sslService.sslContext("xpack.http.ssl"), false);
webServer.start();
}