-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Support PKCS#11 tokens as keystores and truststores #34063
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
9c18d80
6f6eb3a
430b998
8a0b64e
365d675
92248a1
5fda332
6dde2f7
2df67f4
c37c5e3
efe542c
60da02b
777554b
41c74ac
4ec50c6
ba90235
88f80c3
6604aa1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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 | ||
|
|
@@ -1062,7 +1066,7 @@ Must be either a Java Keystore (jks) or a PKCS#12 file. | |
| same time. | ||
|
|
||
| `ssl.truststore.type`:: | ||
| The type of the truststore (`ssl.truststore.path`). Must be either `jks` or | ||
| The type of the truststore (`ssl.truststore.path`). Must be either `jks` or | ||
| `PKCS12`. If the keystore path ends in ".p12", ".pfx" or "pkcs12", this setting | ||
| defaults to `PKCS12`. Otherwise, it defaults to `jks`. | ||
|
|
||
|
|
@@ -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 | ||
jaymode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| truststore will be usable for configuration in Elasticsearch. 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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |
|
|
||
| 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 @@ | |
| */ | ||
| 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 @@ public int hashCode() { | |
| /** | ||
| * Merges the default trust configuration with the provided {@link TrustConfig} | ||
| * @param trustConfig the trust configuration to merge with | ||
| * @param trustStorePassword he 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) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add the parameter to the javadocs and include that this password is for the default jdk store? |
||
| 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 @@ static TrustConfig merge(TrustConfig 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; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -212,12 +212,11 @@ private static TrustConfig createTrustConfig(Settings settings, KeyConfig keyCon | |
|
|
||
| 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,24 +227,40 @@ private static TrustConfig createCertChainTrustConfig(Settings settings, KeyConf | |
| 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); | ||
| return new StoreTrustConfig(trustStorePath, trustStoreType, trustStorePassword, trustStoreAlgorithm); | ||
| try (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) { | ||
| try (SecureString truststorePassword = new SecureString(System.getProperty("javax.net.ssl.trustStorePassword", ""))) { | ||
| return new StoreTrustConfig(System.getProperty("javax.net.ssl.trustStore"), KeyStore.getDefaultType(), truststorePassword, | ||
| System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())); | ||
| System.getProperty("ssl.TrustManagerFactory.algorithm", TrustManagerFactory.getDefaultAlgorithm())); | ||
| } | ||
| } 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) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resolve the deafult JDK TrustStore password here for the case of PKCS11 tokens, so that we don't need to pass the trustStorePassword to the |
||
| // 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) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for calling out PKCS11 in the settings is that the implementation now includes specific handling if this is set as the keystore.type ( As opposed to for instance
BCFKSwhich can be used with the BouncyCastle FIPS Security Provider if configured, but handled transparently )