diff --git a/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java b/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java index 49eefc527baf1..780cc447ba8a6 100644 --- a/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java +++ b/client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java @@ -38,8 +38,10 @@ import java.net.InetSocketAddress; import java.nio.file.Files; import java.nio.file.Paths; +import java.security.AccessController; import java.security.KeyFactory; import java.security.KeyStore; +import java.security.PrivilegedAction; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.spec.PKCS8EncodedKeySpec; @@ -106,7 +108,7 @@ private RestClient buildRestClient() { } private static SSLContext getSslContext() throws Exception { - SSLContext sslContext = SSLContext.getInstance("TLS"); + SSLContext sslContext = SSLContext.getInstance(getProtocol()); try (InputStream certFile = RestClientBuilderIntegTests.class.getResourceAsStream("/test.crt")) { // Build a keystore of default type programmatically since we can't use JKS keystores to // init a KeyManagerFactory in FIPS 140 JVMs. @@ -126,4 +128,37 @@ private static SSLContext getSslContext() throws Exception { } return sslContext; } + + /** + * The {@link HttpsServer} in the JDK has issues with TLSv1.3 when running in a JDK that supports TLSv1.3 prior to + * 12.0.1 so we pin to TLSv1.2 when running on an earlier JDK. + */ + private static String getProtocol() { + String version = AccessController.doPrivileged((PrivilegedAction) () -> System.getProperty("java.version")); + String[] components = version.split("\\."); + if (components.length > 0) { + final int major = Integer.valueOf(components[0]); + if (major < 11) { + return "TLS"; + } if (major > 12) { + return "TLS"; + } else if (major == 12 && components.length > 2) { + final int minor = Integer.valueOf(components[1]); + if (minor > 0) { + return "TLS"; + } else { + String patch = components[2]; + final int index = patch.indexOf("_"); + if (index > -1) { + patch = patch.substring(0, index); + } + + if (Integer.valueOf(patch) >= 1) { + return "TLS"; + } + } + } + } + return "TLSv1.2"; + } } diff --git a/docs/reference/settings/security-settings.asciidoc b/docs/reference/settings/security-settings.asciidoc index 426605f63d7cb..4185cce13c3ca 100644 --- a/docs/reference/settings/security-settings.asciidoc +++ b/docs/reference/settings/security-settings.asciidoc @@ -1526,13 +1526,30 @@ Controls the verification of certificates. Valid values are: The default value is `full`. `*.ssl.cipher_suites`:: -Supported cipher suites can be found in Oracle's http://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html[ -Java Cryptography Architecture documentation]. Defaults to `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256`, -`TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256`, `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA`, `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA`, -`TLS_RSA_WITH_AES_128_CBC_SHA256`, `TLS_RSA_WITH_AES_128_CBC_SHA`. If the _Java Cryptography Extension (JCE) Unlimited Strength -Jurisdiction Policy Files_ has been installed, the default value also includes `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384`, -`TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384`, `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA`, `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA`, -`TLS_RSA_WITH_AES_256_CBC_SHA256`, `TLS_RSA_WITH_AES_256_CBC_SHA`. +Supported cipher suites can be found in Oracle's +https://docs.oracle.com/en/java/javase/11/security/oracle-providers.html#GUID-7093246A-31A3-4304-AC5F-5FB6400405E2[Java + Cryptography Architecture documentation]. +Defaults to `TLS_AES_256_GCM_SHA384`, `TLS_AES_128_GCM_SHA256`, +`TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`, `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`, +`TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384`, `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256`, +`TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384`, `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256`, +`TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384`, `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256`, +`TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA`, `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA`, +`TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA`, `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA`, +`TLS_RSA_WITH_AES_256_GCM_SHA384`, `TLS_RSA_WITH_AES_128_GCM_SHA256`, +`TLS_RSA_WITH_AES_256_CBC_SHA256`, `TLS_RSA_WITH_AES_128_CBC_SHA256`, +`TLS_RSA_WITH_AES_256_CBC_SHA`, `TLS_RSA_WITH_AES_128_CBC_SHA`. ++ +-- +NOTE: The default cipher suites list above includes TLSv1.3 ciphers and ciphers +that require the _Java Cryptography Extension (JCE) Unlimited Strength +Jurisdiction Policy Files_ for 256-bit AES encryption. If TLSv1.3 is not +available, the TLSv1.3 ciphers TLS_AES_256_GCM_SHA384`, `TLS_AES_128_GCM_SHA256` +will not be included in the default list. If 256-bit AES is unavailable, ciphers +with `AES_256` in their names wil not be included in the default list. Finally, +AES GCM has known performance issues in Java versions prior to 11 and will only +be included in the default list when using Java 11 or above. +-- [float] [[tls-ssl-key-settings]] diff --git a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java index 6e511565a9f53..e53600c251424 100644 --- a/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java +++ b/libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java @@ -19,6 +19,8 @@ package org.elasticsearch.common.ssl; +import org.elasticsearch.bootstrap.JavaVersion; + import javax.crypto.Cipher; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; @@ -338,30 +340,53 @@ private List resolveListSetting(String key, Function parser, L } private static List loadDefaultCiphers() { - final List ciphers128 = Arrays.asList( - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA" - ); - final List ciphers256 = Arrays.asList( - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - "TLS_RSA_WITH_AES_256_CBC_SHA256", - "TLS_RSA_WITH_AES_256_CBC_SHA" - ); - if (has256BitAES()) { - List ciphers = new ArrayList<>(ciphers256.size() + ciphers128.size()); - ciphers.addAll(ciphers256); - ciphers.addAll(ciphers128); - return ciphers; + final boolean has256BitAES = has256BitAES(); + final boolean useGCM = JavaVersion.current().compareTo(JavaVersion.parse("11")) >= 0; + final boolean tlsV13Supported = DEFAULT_PROTOCOLS.contains("TLSv1.3"); + List ciphers = new ArrayList<>(); + if (tlsV13Supported) { // TLSv1.3 cipher has PFS, AEAD, hardware support + if (has256BitAES) { + ciphers.add("TLS_AES_256_GCM_SHA384"); + } + ciphers.add("TLS_AES_128_GCM_SHA256"); + } + if (useGCM) { // PFS, AEAD, hardware support + if (has256BitAES) { + ciphers.addAll(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")); + } else { + ciphers.addAll(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")); + } + } + + // PFS, hardware support + if (has256BitAES) { + ciphers.addAll(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")); + } else { + ciphers.addAll(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")); + } + + // AEAD, hardware support + if (useGCM) { + if (has256BitAES) { + ciphers.addAll(Arrays.asList("TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256")); + } else { + ciphers.add("TLS_RSA_WITH_AES_128_GCM_SHA256"); + } + } + + // hardware support + if (has256BitAES) { + ciphers.addAll(Arrays.asList("TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA")); } else { - return ciphers128; + ciphers.addAll(Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA")); } + return ciphers; } private static boolean has256BitAES() { diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexRestClientSslTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexRestClientSslTests.java index 7c94b94bbb1d5..a2e00e66fd218 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexRestClientSslTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexRestClientSslTests.java @@ -120,6 +120,7 @@ public void testClientFailsWithUntrustedCertificate() throws IOException { final List threads = new ArrayList<>(); final Settings settings = Settings.builder() .put("path.home", createTempDir()) + .put("reindex.ssl.supported_protocols", "TLSv1.2") .build(); final Environment environment = TestEnvironment.newEnvironment(settings); final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class)); @@ -134,6 +135,7 @@ public void testClientSucceedsWithCertificateAuthorities() throws IOException { final Settings settings = Settings.builder() .put("path.home", createTempDir()) .putList("reindex.ssl.certificate_authorities", ca.toString()) + .put("reindex.ssl.supported_protocols", "TLSv1.2") .build(); final Environment environment = TestEnvironment.newEnvironment(settings); final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class)); @@ -149,6 +151,7 @@ public void testClientSucceedsWithVerificationDisabled() throws IOException { final Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("reindex.ssl.verification_mode", "NONE") + .put("reindex.ssl.supported_protocols", "TLSv1.2") .build(); final Environment environment = TestEnvironment.newEnvironment(settings); final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class)); @@ -169,6 +172,7 @@ public void testClientPassesClientCertificate() throws IOException { .put("reindex.ssl.certificate", cert) .put("reindex.ssl.key", key) .put("reindex.ssl.key_passphrase", "client-password") + .put("reindex.ssl.supported_protocols", "TLSv1.2") .build(); AtomicReference clientCertificates = new AtomicReference<>(); handler = https -> { diff --git a/plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java b/plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java index 1ee2e2490727b..8bfb373f644f2 100644 --- a/plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java +++ b/plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java @@ -25,6 +25,7 @@ import com.sun.net.httpserver.HttpsConfigurator; import com.sun.net.httpserver.HttpsServer; import org.apache.logging.log4j.LogManager; +import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.cloud.azure.classic.management.AzureComputeService; import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.io.FileSystemUtils; @@ -59,7 +60,9 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.security.AccessController; import java.security.KeyStore; +import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -262,11 +265,30 @@ private static SSLContext getSSLContext() throws Exception { kmf.init(ks, passphrase); TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); tmf.init(ks); - SSLContext ssl = SSLContext.getInstance("TLS"); + SSLContext ssl = SSLContext.getInstance(getProtocol()); ssl.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); return ssl; } + /** + * The {@link HttpsServer} in the JDK has issues with TLSv1.3 when running in a JDK prior to + * 12.0.1 so we pin to TLSv1.2 when running on an earlier JDK + */ + private static String getProtocol() { + if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) { + return "TLS"; + } else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) { + return "TLSv1.2"; + } else { + JavaVersion full = + AccessController.doPrivileged((PrivilegedAction) () -> JavaVersion.parse(System.getProperty("java.version"))); + if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) { + return "TLSv1.2"; + } + } + return "TLS"; + } + @AfterClass public static void stopHttpd() throws IOException { for (int i = 0; i < internalCluster().size(); i++) { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java index 0eeb173b8b84e..4f6202f2b5c13 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.core; import org.apache.logging.log4j.LogManager; +import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.xpack.core.security.SecurityField; @@ -118,6 +119,20 @@ private XPackSettings() { /** Setting for enabling or disabling sql. Defaults to true. */ public static final Setting SQL_ENABLED = Setting.boolSetting("xpack.sql.enabled", true, Setting.Property.NodeScope); + public static final List DEFAULT_SUPPORTED_PROTOCOLS; + + static { + boolean supportsTLSv13 = false; + try { + SSLContext.getInstance("TLSv1.3"); + supportsTLSv13 = true; + } catch (NoSuchAlgorithmException e) { + LogManager.getLogger(XPackSettings.class).debug("TLSv1.3 is not supported", e); + } + DEFAULT_SUPPORTED_PROTOCOLS = supportsTLSv13 ? + Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1") : Arrays.asList("TLSv1.2", "TLSv1.1"); + } + /* * SSL settings. These are the settings that are specifically registered for SSL. Many are private as we do not explicitly use them * but instead parse based on a prefix (eg *.ssl.*) @@ -125,24 +140,58 @@ private XPackSettings() { public static final List DEFAULT_CIPHERS; static { - List ciphers = Arrays.asList("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA256", - "TLS_RSA_WITH_AES_128_CBC_SHA"); + List ciphers = new ArrayList<>(); + final boolean useGCM = JavaVersion.current().compareTo(JavaVersion.parse("11")) >= 0; + final boolean tlsV13Supported = DEFAULT_SUPPORTED_PROTOCOLS.contains("TLSv1.3"); try { final boolean use256Bit = Cipher.getMaxAllowedKeyLength("AES") > 128; + if (tlsV13Supported) { // TLSv1.3 cipher has PFS, AEAD, hardware support + if (use256Bit) { + ciphers.add("TLS_AES_256_GCM_SHA384"); + } + ciphers.add("TLS_AES_128_GCM_SHA256"); + } + if (useGCM) { // PFS, AEAD, hardware support + if (use256Bit) { + ciphers.addAll(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")); + } else { + ciphers.addAll(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")); + } + } + + // PFS, hardware support + if (use256Bit) { + ciphers.addAll(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")); + } else { + ciphers.addAll(Arrays.asList("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA")); + } + + // AEAD, hardware support + if (useGCM) { + if (use256Bit) { + ciphers.addAll(Arrays.asList("TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256")); + } else { + ciphers.add("TLS_RSA_WITH_AES_128_GCM_SHA256"); + } + } + + // hardware support if (use256Bit) { - List strongerCiphers = new ArrayList<>(ciphers.size() * 2); - strongerCiphers.addAll(Arrays.asList("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA")); - strongerCiphers.addAll(ciphers); - ciphers = strongerCiphers; + ciphers.addAll(Arrays.asList("TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", + "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA")); + } else { + ciphers.addAll(Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA")); } } catch (NoSuchAlgorithmException e) { // ignore it here - there will be issues elsewhere and its not nice to throw in a static initializer } - DEFAULT_CIPHERS = ciphers; + DEFAULT_CIPHERS = Collections.unmodifiableList(ciphers); } /* @@ -164,20 +213,6 @@ private XPackSettings() { } }, Setting.Property.NodeScope); - public static final List DEFAULT_SUPPORTED_PROTOCOLS; - - static { - boolean supportsTLSv13 = false; - try { - SSLContext.getInstance("TLSv1.3"); - supportsTLSv13 = true; - } catch (NoSuchAlgorithmException e) { - LogManager.getLogger(XPackSettings.class).debug("TLSv1.3 is not supported", e); - } - DEFAULT_SUPPORTED_PROTOCOLS = supportsTLSv13 ? - Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1") : Arrays.asList("TLSv1.2", "TLSv1.1"); - } - public static final SSLClientAuth CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED; public static final SSLClientAuth HTTP_CLIENT_AUTH_DEFAULT = SSLClientAuth.NONE; public static final VerificationMode VERIFICATION_MODE_DEFAULT = VerificationMode.FULL; diff --git a/x-pack/plugin/core/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks b/x-pack/plugin/core/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks index d6dc21c1bd5ff..4f897d80f4af4 100644 Binary files a/x-pack/plugin/core/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks and b/x-pack/plugin/core/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks differ diff --git a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterSslIT.java b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterSslIT.java index ae363cd3c8258..9e16f669ae879 100644 --- a/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterSslIT.java +++ b/x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterSslIT.java @@ -5,9 +5,11 @@ */ package org.elasticsearch.xpack.monitoring.exporter.http; +import com.sun.net.httpserver.HttpsServer; import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse; +import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; @@ -15,6 +17,7 @@ import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.Scope; import org.elasticsearch.test.http.MockWebServer; +import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.ssl.TestsSSLService; import org.elasticsearch.xpack.core.ssl.VerificationMode; import org.elasticsearch.xpack.monitoring.exporter.Exporter; @@ -28,6 +31,10 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.List; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.instanceOf; @@ -98,6 +105,7 @@ private MockWebServer buildWebServer() throws IOException { .put("xpack.transport.security.ssl.certificate", cert) .put("xpack.transport.security.ssl.key", key) .put("xpack.transport.security.ssl.key_passphrase", "testnode") + .putList("xpack.transport.security.ssl.supported_protocols", getProtocols()) .put(globalSettings) .build(); @@ -185,4 +193,23 @@ private void clearTransientSettings(String... names) { updateSettings.transientSettings(builder.build()); client().admin().cluster().updateSettings(updateSettings).actionGet(); } + + /** + * The {@link HttpsServer} in the JDK has issues with TLSv1.3 when running in a JDK prior to + * 12.0.1 so we pin to TLSv1.2 when running on an earlier JDK + */ + private static List getProtocols() { + if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) { + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) { + return Collections.singletonList("TLSv1.2"); + } else { + JavaVersion full = + AccessController.doPrivileged((PrivilegedAction) () -> JavaVersion.parse(System.getProperty("java.version"))); + if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) { + return Collections.singletonList("TLSv1.2"); + } + } + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } } diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/transport/nio/SSLDriver.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/transport/nio/SSLDriver.java index e54bc9fa16e57..c5dcb260919b3 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/transport/nio/SSLDriver.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/transport/nio/SSLDriver.java @@ -438,7 +438,7 @@ public void read(InboundChannelBuffer encryptedBuffer, InboundChannelBuffer appl SSLEngineResult result = unwrap(encryptedBuffer, applicationBuffer); boolean renegotiationRequested = result.getStatus() != SSLEngineResult.Status.CLOSED && maybeRenegotiation(result.getHandshakeStatus()); - continueUnwrap = result.bytesProduced() > 0 && renegotiationRequested == false; + continueUnwrap = result.bytesConsumed() > 0 && renegotiationRequested == false; } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java index a8ad2fbd4aad3..491fd66c4530b 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java @@ -218,7 +218,8 @@ public static void addSSLSettingsForNodePEMFiles(Settings.Builder builder, Strin "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/active-directory-ca.crt", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/openldap.crt", - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"), + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt"), hostnameVerificationEnabled, false); } @@ -244,7 +245,8 @@ public void addClientSSLSettings(Settings.Builder builder, String prefix) { "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem", "testclient", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt", Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", - "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"), + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt"), hostnameVerificationEnabled, true); } else { addSSLSettingsForStore(builder, prefix, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks", diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java index 52c87c75a13a7..03d107a50a864 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java @@ -66,8 +66,9 @@ protected Settings nodeSettings() { .put("xpack.security.http.ssl.client_authentication", sslClientAuth) .put("xpack.security.authc.realms.file.file.order", "0") .put("xpack.security.authc.realms.pki.pki1.order", "1") - .put("xpack.security.authc.realms.pki.pki1.certificate_authorities", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .putList("xpack.security.authc.realms.pki.pki1.certificate_authorities", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt").toString(), + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt").toString()) .put("xpack.security.authc.realms.pki.pki1.files.role_mapping", getDataPath("role_mapping.yml")); return builder.build(); } @@ -91,8 +92,8 @@ public void testTransportClientCanAuthenticateViaPki() { "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", - Arrays.asList - ("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); + Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt")); try (TransportClient client = createTransportClient(builder.build())) { client.addTransportAddress(randomFrom(node().injector().getInstance(Transport.class).boundAddress().boundAddresses())); IndexResponse response = client.prepareIndex("foo", "bar").setSource("pki", "auth").get(); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java index d139d99bf9ce2..aea50691119a2 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java @@ -5,9 +5,11 @@ */ package org.elasticsearch.xpack.security.authc.saml; +import com.sun.net.httpserver.HttpsServer; import org.apache.logging.log4j.message.ParameterizedMessage; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.support.PlainActionFuture; +import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.settings.MockSecureSettings; import org.elasticsearch.common.settings.Settings; @@ -19,6 +21,7 @@ import org.elasticsearch.test.http.MockResponse; import org.elasticsearch.test.http.MockWebServer; import org.elasticsearch.watcher.ResourceWatcherService; +import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.security.authc.AuthenticationResult; import org.elasticsearch.xpack.core.security.authc.Realm; import org.elasticsearch.xpack.core.security.authc.RealmConfig; @@ -52,8 +55,10 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.security.AccessController; import java.security.KeyStore; import java.security.PrivateKey; +import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PublicKey; import java.security.cert.Certificate; @@ -131,6 +136,7 @@ public void testReadIdpMetadataFromHttps() throws Exception { getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) .put("xpack.security.http.ssl.certificate_authorities", getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .putList("xpack.security.http.ssl.supported_protocols", getProtocols()) .put("path.home", createTempDir()) .setSecureSettings(mockSecureSettings) .build(); @@ -715,4 +721,23 @@ private void assertIdp1MetadataParsedCorrectly(EntityDescriptor descriptor) { assertEquals(SAMLConstants.SAML2_POST_BINDING_URI, ssoServices.get(0).getBinding()); assertEquals(SAMLConstants.SAML2_REDIRECT_BINDING_URI, ssoServices.get(1).getBinding()); } + + /** + * The {@link HttpsServer} in the JDK has issues with TLSv1.3 when running in a JDK prior to + * 12.0.1 so we pin to TLSv1.2 when running on an earlier JDK + */ + private static List getProtocols() { + if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) { + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) { + return Collections.singletonList("TLSv1.2"); + } else { + JavaVersion full = + AccessController.doPrivileged((PrivilegedAction) () -> JavaVersion.parse(System.getProperty("java.version"))); + if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) { + return Collections.singletonList("TLSv1.2"); + } + } + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/AbstractSimpleSecurityTransportTestCase.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/AbstractSimpleSecurityTransportTestCase.java index ca548251d3713..1b7a7f8d870f2 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/AbstractSimpleSecurityTransportTestCase.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/AbstractSimpleSecurityTransportTestCase.java @@ -155,7 +155,9 @@ public void testTcpHandshake() { @SuppressForbidden(reason = "Need to open socket connection") public void testRenegotiation() throws Exception { - SSLService sslService = createSSLService(); + // force TLSv1.2 since renegotiation is not supported by 1.3 + SSLService sslService = + createSSLService(Settings.builder().put("xpack.security.transport.ssl.supported_protocols", "TLSv1.2").build()); final SSLConfiguration sslConfiguration = sslService.getSSLConfiguration("xpack.security.transport.ssl"); SocketFactory factory = sslService.sslSocketFactory(sslConfiguration); try (SSLSocket socket = (SSLSocket) factory.createSocket()) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java index f8bf1f47a38f1..e3f561c47119b 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java @@ -19,7 +19,6 @@ import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.MockHttpTransport; import org.elasticsearch.test.SecurityIntegTestCase; -import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSourceField; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.ConnectionProfile; @@ -80,8 +79,6 @@ protected Settings nodeSettings(int nodeOrdinal) { settingsBuilder.put("transport.profiles.default.xpack.security.type", "node"); // this is default lets set it randomly } - SecuritySettingsSource.addSecureSettings(settingsBuilder, secureSettings -> - secureSettings.setString("transport.profiles.client.xpack.security.ssl.keystore.secure_password", "testnode")); return settingsBuilder.build(); } @@ -112,7 +109,8 @@ public void testThatConnectionToServerTypeConnectionWorks() throws IOException, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", - Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); + Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt")); try (Node node = new MockNode(nodeSettings.build(), mockPlugins)) { node.start(); ensureStableCluster(cluster().size() + 1); @@ -151,7 +149,8 @@ public void testThatConnectionToClientTypeConnectionIsRejected() throws IOExcept "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.pem", "testnode", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", - Collections.singletonList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); + Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt")); try (Node node = new MockNode(nodeSettings.build(), mockPlugins)) { node.start(); TransportService instance = node.injector().getInstance(TransportService.class); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java index 5f0f3c94e36e8..761726c5f670f 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java @@ -33,7 +33,9 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; +import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; public class EllipticCurveSSLTests extends SecurityIntegTestCase { @@ -106,7 +108,8 @@ public SSLSocket run() throws Exception { Certificate[] peerChain = session.getPeerCertificates(); assertEquals(1, peerChain.length); assertEquals(certs[0], peerChain[0]); - assertThat(session.getCipherSuite(), containsString("ECDSA")); + assertThat(session.getCipherSuite(), + anyOf(containsString("ECDSA"), equalTo("TLS_AES_256_GCM_SHA384"), equalTo("TLS_AES_128_GCM_SHA256"))); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java index 04c1ff03f8270..f12304bd88532 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.security.transport.ssl; +import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.network.NetworkAddress; @@ -13,6 +14,7 @@ import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.core.TestXPackTransportClient; +import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.security.SecurityField; import org.elasticsearch.xpack.core.ssl.SSLClientAuth; import org.elasticsearch.xpack.security.LocalStateSecurity; @@ -21,8 +23,11 @@ import java.net.InetAddress; import java.nio.file.Files; import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Collections; +import java.util.List; import static org.elasticsearch.test.SecuritySettingsSource.TEST_USER_NAME; import static org.elasticsearch.test.SecuritySettingsSource.addSSLSettingsForNodePEMFiles; @@ -116,6 +121,7 @@ public void testThatStandardTransportClientCanConnectToNoClientAuthProfile() thr try(TransportClient transportClient = new TestXPackTransportClient(Settings.builder() .put(transportClientSettings()) .put("xpack.security.transport.ssl.enabled", true) + .putList("xpack.security.transport.ssl.supported_protocols", getProtocols()) .put("node.name", "programmatic_transport_client") .put("cluster.name", internalCluster().getClusterName()) .build(), LocalStateSecurity.class)) { @@ -154,7 +160,8 @@ public void testThatProfileTransportClientCanConnectToClientProfile() throws Exc "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.pem", "testclient-client-profile", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.crt", - Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); + Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt")); try (TransportClient transportClient = createTransportClient(builder.build())) { transportClient.addTransportAddress(new TransportAddress(localAddress, getProfilePort("client"))); assertGreenClusterState(transportClient); @@ -174,7 +181,9 @@ public void testThatProfileTransportClientCanConnectToNoClientAuthProfile() thro "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.pem", "testclient-client-profile", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.crt", - Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); + Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt")); + builder.putList("xpack.security.transport.ssl.supported_protocols", getProtocols()); try (TransportClient transportClient = createTransportClient(builder.build())) { transportClient.addTransportAddress(new TransportAddress(localAddress, getProfilePort("no_client_auth"))); @@ -195,7 +204,8 @@ public void testThatProfileTransportClientCannotConnectToDefaultProfile() throws "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.pem", "testclient-client-profile", "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.crt", - Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); + Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt", + "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt")); try (TransportClient transportClient = createTransportClient(builder.build())) { TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses()); transportClient.addTransportAddress(transportAddress); @@ -273,8 +283,10 @@ public void testThatTransportClientWithOnlyTruststoreCanConnectToNoClientAuthPro .put(SecurityField.USER_SETTING.getKey(), TEST_USER_NAME + ":" + TEST_PASSWORD) .put("cluster.name", internalCluster().getClusterName()) .put("xpack.security.transport.ssl.enabled", true) - .put("xpack.security.transport.ssl.certificate_authorities", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .putList("xpack.security.transport.ssl.certificate_authorities", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt").toString(), + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt").toString()) + .putList("xpack.security.transport.ssl.supported_protocols", getProtocols()) .build(); try (TransportClient transportClient = new TestXPackTransportClient(settings, Collections.singletonList(LocalStateSecurity.class))) { @@ -294,8 +306,10 @@ public void testThatTransportClientWithOnlyTruststoreCannotConnectToClientProfil .put("cluster.name", internalCluster().getClusterName()) .put("xpack.security.transport.ssl.enabled", true) .put("xpack.security.transport.ssl.client_authentication", SSLClientAuth.REQUIRED) - .put("xpack.security.transport.ssl.certificate_authorities", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .putList("xpack.security.transport.ssl.certificate_authorities", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt").toString(), + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt").toString()) + .putList("xpack.security.transport.ssl.supported_protocols", getProtocols()) .build(); try (TransportClient transportClient = new TestXPackTransportClient(settings, Collections.singletonList(LocalStateSecurity.class))) { @@ -318,8 +332,10 @@ public void testThatTransportClientWithOnlyTruststoreCannotConnectToDefaultProfi .put("cluster.name", internalCluster().getClusterName()) .put("xpack.security.transport.ssl.enabled", true) .put("xpack.security.transport.ssl.client_authentication", SSLClientAuth.REQUIRED) - .put("xpack.security.transport.ssl.certificate_authorities", - getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")) + .putList("xpack.security.transport.ssl.certificate_authorities", + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt").toString(), + getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt").toString()) + .putList("xpack.security.transport.ssl.supported_protocols", getProtocols()) .build(); try (TransportClient transportClient = new TestXPackTransportClient(settings, Collections.singletonList(LocalStateSecurity.class))) { @@ -409,4 +425,21 @@ private static int getProfilePort(String profile) { throw new IllegalStateException("failed to find transport address equal to [" + NetworkAddress.format(localAddress) + "] " + " in the following bound addresses " + Arrays.toString(transportAddresses)); } + + /** + * TLSv1.3 when running in a JDK prior to 11.0.3 has a race condition when multiple simultaneous connections are established. See + * JDK-8213202. This issue is not triggered when using client authentication, which we do by default for transport connections. + * However if client authentication is turned off and TLSv1.3 is used on the affected JVMs then we will hit this issue. + */ + private static List getProtocols() { + if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) { + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } + JavaVersion full = + AccessController.doPrivileged((PrivilegedAction) () -> JavaVersion.parse(System.getProperty("java.version"))); + if (full.compareTo(JavaVersion.parse("11.0.3")) < 0) { + return Collections.singletonList("TLSv1.2"); + } + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java index 7075a677a26ce..85f18ddff922c 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java @@ -11,6 +11,7 @@ import org.apache.http.util.EntityUtils; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ExceptionsHelper; +import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.client.Request; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; @@ -23,6 +24,7 @@ import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.transport.Transport; import org.elasticsearch.xpack.core.TestXPackTransportClient; +import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.security.SecurityField; import org.elasticsearch.xpack.core.ssl.CertParsingUtils; import org.elasticsearch.xpack.core.ssl.PemUtils; @@ -38,11 +40,14 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.security.SecureRandom; import java.security.cert.CertPathBuilderException; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.hamcrest.Matchers.containsString; @@ -101,7 +106,7 @@ protected boolean transportSSLEnabled() { return true; } - public void testThatHttpFailsWithoutSslClientAuth() throws IOException { + public void testThatHttpFailsWithoutSslClientAuth() { SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(SSLContexts.createDefault(), NoopHostnameVerifier.INSTANCE); try (RestClient restClient = createRestClient(httpClientBuilder -> httpClientBuilder.setSSLStrategy(sessionStrategy), "https")) { restClient.performRequest(new Request("GET", "/")); @@ -130,11 +135,12 @@ public void testThatHttpWorksWithSslClientAuth() throws IOException { } } - public void testThatTransportWorksWithoutSslClientAuth() throws IOException { + public void testThatTransportWorksWithoutSslClientAuth() { // specify an arbitrary key and certificate - not the certs needed to connect to the transport protocol Path keyPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.pem"); Path certPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient-client-profile.crt"); Path nodeCertPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"); + Path nodeECCertPath = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt"); if (Files.notExists(keyPath) || Files.notExists(certPath)) { throw new ElasticsearchException("key or certificate path doesn't exist"); @@ -147,7 +153,8 @@ public void testThatTransportWorksWithoutSslClientAuth() throws IOException { .put("xpack.security.transport.ssl.client_authentication", SSLClientAuth.NONE) .put("xpack.security.transport.ssl.key", keyPath) .put("xpack.security.transport.ssl.certificate", certPath) - .put("xpack.security.transport.ssl.certificate_authorities", nodeCertPath) + .putList("xpack.security.transport.ssl.supported_protocols", getProtocols()) + .putList("xpack.security.transport.ssl.certificate_authorities", nodeCertPath.toString(), nodeECCertPath.toString()) .setSecureSettings(secureSettings) .put("cluster.name", internalCluster().getClusterName()) .put(SecurityField.USER_SETTING.getKey(), transportClientUsername() + ":" + new String(transportClientPassword().getChars())) @@ -165,12 +172,19 @@ private SSLContext getSSLContext() { try { String certPath = "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"; String nodeCertPath = "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"; + String nodeEcCertPath = "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt"; String keyPath = "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.pem"; TrustManager tm = CertParsingUtils.trustManager(CertParsingUtils.readCertificates(Arrays.asList(getDataPath - (certPath), getDataPath(nodeCertPath)))); + (certPath), getDataPath(nodeCertPath), getDataPath(nodeEcCertPath)))); KeyManager km = CertParsingUtils.keyManager(CertParsingUtils.readCertificates(Collections.singletonList(getDataPath (certPath))), PemUtils.readPrivateKey(getDataPath(keyPath), "testclient"::toCharArray), "testclient".toCharArray()); - SSLContext context = SSLContext.getInstance("TLSv1.2"); + + final SSLContext context; + if (XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS.contains("TLSv1.3")) { + context = SSLContext.getInstance(randomBoolean() ? "TLSv1.3" : "TLSv1.2"); + } else { + context = SSLContext.getInstance("TLSv1.2"); + } context.init(new KeyManager[] { km }, new TrustManager[] { tm }, new SecureRandom()); return context; } catch (Exception e) { @@ -188,4 +202,21 @@ private byte[] toByteArray(InputStream is) throws IOException { } return baos.toByteArray(); } + + /** + * TLSv1.3 when running in a JDK prior to 11.0.3 has a race condition when multiple simultaneous connections are established. See + * JDK-8213202. This issue is not triggered when using client authentication, which we do by default for transport connections. + * However if client authentication is turned off and TLSv1.3 is used on the affected JVMs then we will hit this issue. + */ + private static List getProtocols() { + if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) { + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } + JavaVersion full = + AccessController.doPrivileged((PrivilegedAction) () -> JavaVersion.parse(System.getProperty("java.version"))); + if (full.compareTo(JavaVersion.parse("11.0.3")) < 0) { + return Collections.singletonList("TLSv1.2"); + } + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java index dd6985889d7ee..3eeaca1a3f114 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java @@ -115,6 +115,10 @@ public void testThatSSLConfigurationReloadsOnModification() throws Exception { try (SSLSocket socket = (SSLSocket) sslSocketFactory.createSocket(address.getAddress(), address.getPort())) { assertThat(socket.isConnected(), is(true)); socket.startHandshake(); + if (socket.getSession().getProtocol().equals("TLSv1.3")) { + // blocking read for TLSv1.3 to see if the other side closed the connection + socket.getInputStream().read(); + } fail("handshake should not have been successful!"); } catch (SSLException | SocketException expected) { logger.trace("expected exception", expected); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java index a89b8fcdd6981..944c3306763a6 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java @@ -31,6 +31,7 @@ import javax.net.ssl.SSLSocketFactory; import java.io.IOException; import java.net.SocketException; +import java.net.SocketTimeoutException; import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.Files; import java.nio.file.Path; @@ -165,7 +166,7 @@ protected boolean transportSSLEnabled() { public void testCertificateWithTrustedNameIsAccepted() throws Exception { writeRestrictions("*.trusted"); try { - tryConnect(trustedCert); + tryConnect(trustedCert, false); } catch (SSLException | SocketException ex) { logger.warn(new ParameterizedMessage("unexpected handshake failure with certificate [{}] [{}]", trustedCert.certificate.getSubjectDN(), trustedCert.certificate.getSubjectAlternativeNames()), ex); @@ -176,7 +177,7 @@ public void testCertificateWithTrustedNameIsAccepted() throws Exception { public void testCertificateWithUntrustedNameFails() throws Exception { writeRestrictions("*.trusted"); try { - tryConnect(untrustedCert); + tryConnect(untrustedCert, true); fail("handshake should have failed, but was successful"); } catch (SSLException | SocketException ex) { // expected @@ -187,7 +188,7 @@ public void testRestrictionsAreReloaded() throws Exception { writeRestrictions("*"); assertBusy(() -> { try { - tryConnect(untrustedCert); + tryConnect(untrustedCert, false); } catch (SSLException | SocketException ex) { fail("handshake should have been successful, but failed with " + ex); } @@ -196,7 +197,7 @@ public void testRestrictionsAreReloaded() throws Exception { writeRestrictions("*.trusted"); assertBusy(() -> { try { - tryConnect(untrustedCert); + tryConnect(untrustedCert, true); fail("handshake should have failed, but was successful"); } catch (SSLException | SocketException ex) { // expected @@ -221,7 +222,7 @@ private void runResourceWatcher() { } } - private void tryConnect(CertificateInfo certificate) throws Exception { + private void tryConnect(CertificateInfo certificate, boolean shouldFail) throws Exception { Settings settings = Settings.builder() .put("path.home", createTempDir()) .put("xpack.security.transport.ssl.key", certificate.getKeyPath()) @@ -239,6 +240,16 @@ private void tryConnect(CertificateInfo certificate) throws Exception { assertThat(socket.isConnected(), is(true)); // The test simply relies on this (synchronously) connecting (or not), so we don't need a handshake handler socket.startHandshake(); + + // blocking read for TLSv1.3 to see if the other side closed the connection + if (socket.getSession().getProtocol().equals("TLSv1.3")) { + if (shouldFail) { + socket.getInputStream().read(); + } else { + socket.setSoTimeout(1000); // 1 second timeout + expectThrows(SocketTimeoutException.class, () -> socket.getInputStream().read()); + } + } } } diff --git a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/README.asciidoc b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/README.asciidoc index 5b2a6b737d779..0136e967106e1 100644 --- a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/README.asciidoc +++ b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/README.asciidoc @@ -34,3 +34,116 @@ keytool -importkeystore -destkeystore .jks -srckeystore .p12 -srcsto The keystore is now created and has the private/public key pair. You can import additional trusted certificates using `keytool -importcert`. When doing so make sure to specify an alias so that others can recreate the keystore if necessary. + +=== Changes and additions for removing Bouncy Castle Dependency + +`testnode-unprotected.pem` is simply the decrypted `testnode.pem` +------ +openssl rsa -in testnode.pem -out testnode-unprotected.pem +------ + +`rsa_key_pkcs8_plain.pem` is the same plaintext key encoded in `PKCS#8` +------ +openssl pkcs8 -topk8 -inform PEM -outform PEM -in testnode-unprotected.pem -out rsa_key_pkcs8_plain.pem -nocrypt +------ + +`testnode-aes{128,192,256}.pem` is the testnode.pem private key, encrypted with `AES-128`, `AES-192` and `AES-256` +respectively, encoded in `PKCS#1` +[source,shell] +------ +openssl rsa -aes128 -in testnode-unprotected.pem -out testnode-aes128.pem +------ +[source,shell] +------ +openssl rsa -aes192 -in testnode-unprotected.pem -out testnode-aes192.pem +------ +[source,shell] +------ +openssl rsa -aes256 -in testnode-unprotected.pem -out testnode-aes256.pem +------ + +Adding `DSA` and `EC` Keys to the Keystore + +[source,shell] +------ +keytool -genkeypair -keyalg DSA -alias testnode_dsa -keystore testnode.jks -storepass testnode \ + -keypass testnode -validity 10000 -keysize 1024 -dname "CN=Elasticsearch Test Node" \ + -ext SAN=dns:localhost,dns:localhost.localdomain,dns:localhost4,dns:localhost4.localdomain4,dns:localhost6,dns:localhost6.localdomain6,ip:127.0.0.1,ip:0:0:0:0:0:0:0:1 +------ +[source,shell] +------ +keytool -genkeypair -keyalg EC -alias testnode_ec -keystore testnode.jks -storepass testnode \ + -keypass testnode -validity 10000 -keysize 256 -dname "CN=Elasticsearch Test Node" \ + -ext SAN=dns:localhost,dns:localhost.localdomain,dns:localhost4,dns:localhost4.localdomain4,dns:localhost6,dns:localhost6.localdomain6,ip:127.0.0.1,ip:0:0:0:0:0:0:0:1 +------ + +Exporting the `DSA` and `EC` private keys from the keystore + +[source,shell] +---- +keytool -importkeystore -srckeystore testnode.jks -destkeystore dsa.p12 -deststoretype PKCS12 \ + -srcalias testnode_dsa -deststorepass testnode -destkeypass testnode +---- +[source,shell] +---- +openssl pkcs12 -in dsa.p12 -nodes -nocerts | openssl pkcs8 -topk8 -nocrypt -outform pem \ + -out dsa_key_pkcs8_plain.pem +---- +[source,shell] +---- +keytool -importkeystore -srckeystore testnode.jks -destkeystore ec.p12 -deststoretype PKCS12 \ + -srcalias testnode_ec -deststorepass testnode -destkeypass testnode +---- +[source,shell] +---- +openssl pkcs12 -in ec.p12 -nodes -nocerts | openssl pkcs8 -topk8 -nocrypt -outform pem \ + -out ec_key_pkcs8_plain.pem +---- + + + +Create `PKCS#8` encrypted key from the encrypted `PKCS#1` encoded `testnode.pem` +[source,shell] +----- +openssl pkcs8 -topk8 -inform PEM -outform PEM -in testnode.pem -out key_pkcs8_encrypted.pem +----- +[source,shell] +----- +ssh-keygen -t ed25519 -f key_unsupported.pem +----- + + +Convert `prime256v1-key-noparam.pem` to `PKCS#8` format +----- +openssl pkcs8 -topk8 -in prime256v1-key-noparam.pem -nocrypt -out prime256v1-key-noparam-pkcs8.pem +----- + +Generate the keys and self-signed certificates in `nodes/self/` : + +------ +openssl req -newkey rsa:2048 -keyout n1.c1.key -x509 -days 3650 -subj "/CN=n1.c1" -reqexts SAN \ + -extensions SAN -config <(cat /etc/ssl/openssl.cnf \ + <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node1.cluster1")) -out n1.c1.crt +------ + + +Create a `CA` keypair for testing +[source,shell] +----- +openssl req -newkey rsa:2048 -nodes -keyout ca.key -x509 -subj "/CN=certAuth" -days 10000 -out ca.crt +----- + +Generate Certificates signed with our CA for testing +[source,shell] +------ + openssl req -new -newkey rsa:2048 -keyout n2.c2.key -reqexts SAN -extensions SAN \ + -config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node2.cluster2"))\ + -out n2.c2.csr +------ + +[source,shell] +------ +openssl x509 -req -in n2.c2.csr -extensions SAN -CA ca.crt -CAkey ca.key -CAcreateserial \ + -extfile <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node2.cluster2"))\ + -out n2.c2.crt -days 10000 +------ diff --git a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks index d6dc21c1bd5ff..495d43d69eb11 100644 Binary files a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks and b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks differ diff --git a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks index 832a23d2dbf09..ebe6146124e8f 100644 Binary files a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks and b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks differ diff --git a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12 b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12 index 2ac8125b58d31..0e6bcaa4f8b76 100644 Binary files a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12 and b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12 differ diff --git a/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt new file mode 100644 index 0000000000000..f4c9a6a7aaca8 --- /dev/null +++ b/x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB7zCCAZOgAwIBAgIEcmggOzAMBggqhkjOPQQDAgUAMCIxIDAeBgNVBAMTF0Vs +YXN0aWNzZWFyY2ggVGVzdCBOb2RlMB4XDTE4MDUxNzA5MzYxMFoXDTQ1MTAwMjA5 +MzYxMFowIjEgMB4GA1UEAxMXRWxhc3RpY3NlYXJjaCBUZXN0IE5vZGUwWTATBgcq +hkjOPQIBBggqhkjOPQMBBwNCAATuZRlXGn/ROcO7yFJJ50b20YvgV3U+FpRx0nx/ +yigWj6xiEMKnWbbUnM0mKF8c3GHGk5g8OXPnbK96uj6tpMB5o4G0MIGxMB0GA1Ud +DgQWBBRNAGO77mUhG6SQvIXQTbpcFwlf2TCBjwYDVR0RBIGHMIGEgglsb2NhbGhv +c3SCFWxvY2FsaG9zdC5sb2NhbGRvbWFpboIKbG9jYWxob3N0NIIXbG9jYWxob3N0 +NC5sb2NhbGRvbWFpbjSCCmxvY2FsaG9zdDaCF2xvY2FsaG9zdDYubG9jYWxkb21h +aW42hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMAwGCCqGSM49BAMCBQADSAAwRQIg +Z3IvdmY5LFdbxoVSs6pV2tJ5+U833Chu0+ZzPo77IVUCIQDRx1FVitVuzBpqwhSW ++Zprt2RLPllC4s4BCApGDh8i1g== +-----END CERTIFICATE----- diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java index bdaa2377fd1d7..d93657acdc094 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java @@ -5,12 +5,15 @@ */ package org.elasticsearch.xpack.watcher.actions.webhook; +import com.sun.net.httpserver.HttpsServer; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.test.http.MockResponse; import org.elasticsearch.test.http.MockWebServer; +import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.ssl.TestsSSLService; import org.elasticsearch.xpack.core.watcher.history.WatchRecord; import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource; @@ -26,6 +29,10 @@ import org.junit.Before; import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.List; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; import static org.elasticsearch.xpack.watcher.client.WatchSourceBuilders.watchBuilder; @@ -51,6 +58,7 @@ protected Settings nodeSettings(int nodeOrdinal) { .put("xpack.http.ssl.key", keyPath) .put("xpack.http.ssl.certificate", certPath) .put("xpack.http.ssl.keystore.password", "testnode") + .putList("xpack.http.ssl.supported_protocols", getProtocols()) .build(); } @@ -131,4 +139,23 @@ public void testHttpsAndBasicAuth() throws Exception { assertThat(webServer.requests().get(0).getBody(), equalTo("{key=value}")); assertThat(webServer.requests().get(0).getHeader("Authorization"), equalTo("Basic X3VzZXJuYW1lOl9wYXNzd29yZA==")); } + + /** + * The {@link HttpsServer} in the JDK has issues with TLSv1.3 when running in a JDK prior to + * 12.0.1 so we pin to TLSv1.2 when running on an earlier JDK + */ + private static List getProtocols() { + if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) { + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) { + return Collections.singletonList("TLSv1.2"); + } else { + JavaVersion full = + AccessController.doPrivileged((PrivilegedAction) () -> JavaVersion.parse(System.getProperty("java.version"))); + if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) { + return Collections.singletonList("TLSv1.2"); + } + } + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } } diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java index 6bb607d6805a3..3ae96499b6a5a 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack.watcher.common.http; import com.carrotsearch.randomizedtesting.generators.RandomStrings; +import com.sun.net.httpserver.HttpsServer; import org.apache.http.HttpHeaders; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.config.RequestConfig; @@ -13,6 +14,7 @@ import org.apache.logging.log4j.util.Supplier; import org.apache.lucene.util.automaton.CharacterRunAutomaton; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.MockSecureSettings; @@ -28,6 +30,7 @@ import org.elasticsearch.test.http.MockResponse; import org.elasticsearch.test.http.MockWebServer; import org.elasticsearch.test.junit.annotations.Network; +import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.ssl.SSLService; import org.elasticsearch.xpack.core.ssl.TestsSSLService; import org.elasticsearch.xpack.core.ssl.VerificationMode; @@ -44,9 +47,12 @@ import java.net.SocketTimeoutException; import java.nio.charset.StandardCharsets; import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -190,6 +196,7 @@ public void testHttps() throws Exception { Settings settings2 = Settings.builder() .put("xpack.security.http.ssl.key", keyPath) .put("xpack.security.http.ssl.certificate", certPath) + .putList("xpack.security.http.ssl.supported_protocols", getProtocols()) .setSecureSettings(secureSettings) .build(); @@ -218,6 +225,7 @@ public void testHttpsDisableHostnameVerification() throws Exception { Settings settings2 = Settings.builder() .put("xpack.security.http.ssl.key", keyPath) .put("xpack.security.http.ssl.certificate", certPath) + .putList("xpack.security.http.ssl.supported_protocols", getProtocols()) .setSecureSettings(secureSettings) .build(); @@ -234,6 +242,7 @@ public void testHttpsClientAuth() throws Exception { Settings settings = Settings.builder() .put("xpack.http.ssl.key", keyPath) .put("xpack.http.ssl.certificate", certPath) + .putList("xpack.http.ssl.supported_protocols", getProtocols()) .setSecureSettings(secureSettings) .build(); @@ -370,6 +379,7 @@ public void testProxyCanHaveDifferentSchemeThanRequest() throws Exception { Settings serverSettings = Settings.builder() .put("xpack.http.ssl.key", keyPath) .put("xpack.http.ssl.certificate", certPath) + .putList("xpack.http.ssl.supported_protocols", getProtocols()) .setSecureSettings(serverSecureSettings) .build(); TestsSSLService sslService = new TestsSSLService(serverSettings, environment); @@ -383,6 +393,7 @@ public void testProxyCanHaveDifferentSchemeThanRequest() throws Exception { .put(HttpSettings.PROXY_PORT.getKey(), proxyServer.getPort()) .put(HttpSettings.PROXY_SCHEME.getKey(), "https") .put("xpack.http.ssl.certificate_authorities", trustedCertPath) + .putList("xpack.http.ssl.supported_protocols", getProtocols()) .build(); HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webServer.getPort()) @@ -737,4 +748,23 @@ public static ClusterService mockClusterService() { private String getWebserverUri() { return String.format(Locale.ROOT, "http://%s:%s", webServer.getHostName(), webServer.getPort()); } + + /** + * The {@link HttpsServer} in the JDK has issues with TLSv1.3 when running in a JDK prior to + * 12.0.1 so we pin to TLSv1.2 when running on an earlier JDK + */ + private static List getProtocols() { + if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) { + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) { + return Collections.singletonList("TLSv1.2"); + } else { + JavaVersion full = + AccessController.doPrivileged((PrivilegedAction) () -> JavaVersion.parse(System.getProperty("java.version"))); + if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) { + return Collections.singletonList("TLSv1.2"); + } + } + return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS; + } } diff --git a/x-pack/qa/reindex-tests-with-security/build.gradle b/x-pack/qa/reindex-tests-with-security/build.gradle index 64e1c61b60717..7cbdfae5ed48c 100644 --- a/x-pack/qa/reindex-tests-with-security/build.gradle +++ b/x-pack/qa/reindex-tests-with-security/build.gradle @@ -36,6 +36,12 @@ integTestCluster { setting 'xpack.security.http.ssl.key_passphrase', 'http-password' setting 'reindex.ssl.truststore.path', 'ca.p12' setting 'reindex.ssl.truststore.password', 'password' + + // Workaround for JDK-8212885 + if (project.ext.runtimeJavaVersion.isJava12Compatible() == false) { + setting 'reindex.ssl.supported_protocols', 'TLSv1.2' + } + extraConfigFile 'roles.yml', 'roles.yml' [ test_admin: 'superuser',