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:
parent
e8b986cc37
commit
2c82b80b85
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue