Quellcode durchsuchen

Update TLS ciphers and protocols for JDK 11 (#41808)

* Update TLS ciphers and protocols for JDK 11 (#41385)

This commit updates the default ciphers and TLS protocols that are used
after the minimum supported JDK is JDK 11. The conditionals around
TLSv1.3 and 256-bit cipher support have been removed. JDK 11 no longer
requires an unlimited JCE policy file for 256 bit cipher support and
TLSv1.3 is supported in JDK 11+. New cipher support has been introduced
in the newer JDK versions as well. The ciphers are ordered with PFS
ciphers being most preferred, then AEAD ciphers, and finally those with
mainstream hardware support.

* Fixes for TLSv1.3 on JDK11

* fix for JDK-8212885
Jay Modi vor 6 Jahren
Ursprung
Commit
96bf049ef3
32 geänderte Dateien mit 350 neuen und 186 gelöschten Zeilen
  1. 34 1
      client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java
  2. 16 15
      docs/reference/settings/security-settings.asciidoc
  3. 1 7
      libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java
  4. 16 49
      libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java
  5. 4 0
      modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexRestClientSslTests.java
  6. 21 1
      plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java
  7. 12 40
      x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java
  8. 1 5
      x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLService.java
  9. 2 3
      x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/TrustConfig.java
  10. 3 29
      x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/XPackSettingsTests.java
  11. BIN
      x-pack/plugin/core/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks
  12. 8 0
      x-pack/plugin/core/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.pem
  13. 25 0
      x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/exporter/http/HttpExporterSslIT.java
  14. 0 2
      x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java
  15. 4 2
      x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java
  16. 9 6
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java
  17. 23 0
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/saml/SamlRealmTests.java
  18. 3 1
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/AbstractSimpleSecurityTransportTestCase.java
  19. 5 5
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java
  20. 4 1
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java
  21. 31 7
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/SslMultiPortTests.java
  22. 25 3
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java
  23. 4 0
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java
  24. 16 5
      x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java
  25. BIN
      x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks
  26. BIN
      x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks
  27. BIN
      x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12
  28. 13 0
      x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.crt
  29. 8 0
      x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.pem
  30. 24 0
      x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/actions/webhook/WebhookHttpsIntegrationTests.java
  31. 32 4
      x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/http/HttpClientTests.java
  32. 6 0
      x-pack/qa/reindex-tests-with-security/build.gradle

+ 34 - 1
client/rest/src/test/java/org/elasticsearch/client/RestClientBuilderIntegTests.java

@@ -38,8 +38,10 @@ import java.net.InetAddress;
 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 @@ public class RestClientBuilderIntegTests extends RestClientTestCase {
     }
 
     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,35 @@ public class RestClientBuilderIntegTests extends RestClientTestCase {
         }
         return sslContext;
     }
+
+    /**
+     * 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() {
+        String version = AccessController.doPrivileged((PrivilegedAction<String>) () -> System.getProperty("java.version"));
+        String[] components = version.split("\\.");
+        if (components.length > 0) {
+            final int major = Integer.valueOf(components[0]);
+            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";
+    }
 }

+ 16 - 15
docs/reference/settings/security-settings.asciidoc

@@ -513,8 +513,7 @@ and `full`. Defaults to `full`.
 See <<ssl-tls-settings,`ssl.verification_mode`>> for an explanation of these values.
 
 `ssl.supported_protocols`::
-Supported protocols for TLS/SSL (with versions). Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
-the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
+Supported protocols for TLS/SSL (with versions). Defaults to `TLSv1.3,TLSv1.2,TLSv1.1`.
 
 `ssl.cipher_suites`:: Specifies the cipher suites that should be supported when 
 communicating with the LDAP server. 
@@ -765,8 +764,7 @@ and `full`. Defaults to `full`.
 See <<ssl-tls-settings,`ssl.verification_mode`>> for an explanation of these values.
 
 `ssl.supported_protocols`::
-Supported protocols for TLS/SSL (with versions). Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
-the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
+Supported protocols for TLS/SSL (with versions). Defaults to `TLSv1.3,TLSv1.2,TLSv1.1`.
 
 `ssl.cipher_suites`:: Specifies the cipher suites that should be supported when 
 communicating with the Active Directory server. 
@@ -1173,8 +1171,7 @@ Defaults to `full`.
 See <<ssl-tls-settings,`ssl.verification_mode`>> for a more detailed explanation of these values.
 
 `ssl.supported_protocols`::
-Specifies the supported protocols for TLS/SSL. Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
-the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
+Specifies the supported protocols for TLS/SSL. Defaults to `TLSv1.3,TLSv1.2,TLSv1.1`.
 
 `ssl.cipher_suites`::
 Specifies the
@@ -1494,8 +1491,7 @@ For more information, see
 
 `*.ssl.supported_protocols`::
 Supported protocols with versions. Valid protocols: `SSLv2Hello`,
-`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, `TLSv1.3`. Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
-the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
+`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, `TLSv1.3`. Defaults to `TLSv1.3,TLSv1.2,TLSv1.1`.
 +
 --
 NOTE: If `xpack.security.fips_mode.enabled` is `true`, you cannot use `SSLv2Hello` 
@@ -1526,13 +1522,18 @@ 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`.
 
 [float]
 [[tls-ssl-key-settings]]

+ 1 - 7
libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfiguration.java

@@ -24,7 +24,6 @@ import javax.net.ssl.X509ExtendedKeyManager;
 import javax.net.ssl.X509ExtendedTrustManager;
 import java.nio.file.Path;
 import java.security.GeneralSecurityException;
-import java.security.NoSuchAlgorithmException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -52,12 +51,7 @@ public class SslConfiguration {
     static final Map<String, String> ORDERED_PROTOCOL_ALGORITHM_MAP;
     static {
         LinkedHashMap<String, String> protocolAlgorithmMap = new LinkedHashMap<>();
-        try {
-            SSLContext.getInstance("TLSv1.3");
-            protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
-        } catch (NoSuchAlgorithmException e) {
-            // ignore since we support JVMs that do not support TLSv1.3
-        }
+        protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
         protocolAlgorithmMap.put("TLSv1.2", "TLSv1.2");
         protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
         protocolAlgorithmMap.put("TLSv1", "TLSv1");

+ 16 - 49
libs/ssl-config/src/main/java/org/elasticsearch/common/ssl/SslConfigurationLoader.java

@@ -19,21 +19,15 @@
 
 package org.elasticsearch.common.ssl;
 
-import javax.crypto.Cipher;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.TrustManagerFactory;
 import java.nio.file.Path;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import static org.elasticsearch.common.ssl.KeyStoreUtil.inferKeyStoreType;
-import static org.elasticsearch.common.ssl.SslConfiguration.ORDERED_PROTOCOL_ALGORITHM_MAP;
 import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE;
 import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE_AUTHORITIES;
 import static org.elasticsearch.common.ssl.SslConfigurationKeys.CIPHERS;
@@ -70,10 +64,22 @@ import static org.elasticsearch.common.ssl.SslConfigurationKeys.VERIFICATION_MOD
  */
 public abstract class SslConfigurationLoader {
 
-    static final List<String> DEFAULT_PROTOCOLS = Collections.unmodifiableList(
-        ORDERED_PROTOCOL_ALGORITHM_MAP.containsKey("TLSv1.3") ?
-            Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1") : Arrays.asList("TLSv1.2", "TLSv1.1"));
-    static final List<String> DEFAULT_CIPHERS = loadDefaultCiphers();
+    static final List<String> DEFAULT_PROTOCOLS = List.of("TLSv1.3", "TLSv1.2", "TLSv1.1");
+
+    /**
+     * This list has been created with ordering
+     */
+    static final List<String> DEFAULT_CIPHERS = List.of(
+        "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", // TLSv1.3 cipher has PFS, AEAD, hardware support
+        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // PFS, AEAD, hardware support
+        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // PFS, AEAD, hardware support
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",  "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", // PFS, hardware support
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", // PFS, hardware support
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", // PFS, hardware support
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // PFS, hardware support
+        "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", // AEAD, hardware support
+        "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", // hardware support
+        "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA"); // hardware support
     private static final char[] EMPTY_PASSWORD = new char[0];
 
     private final String settingPrefix;
@@ -141,9 +147,6 @@ public abstract class SslConfigurationLoader {
 
     /**
      * Change the default supported ciphers.
-     * The initial cipher list depends on the availability of {@link #has256BitAES() 256 bit AES}.
-     *
-     * @see #loadDefaultCiphers()
      */
     public void setDefaultCiphers(List<String> defaultCiphers) {
         this.defaultCiphers = defaultCiphers;
@@ -336,40 +339,4 @@ public abstract class SslConfigurationLoader {
             throw new SslConfigException("cannot retrieve setting [" + settingPrefix + key + "]", e);
         }
     }
-
-    private static List<String> loadDefaultCiphers() {
-        final List<String> 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<String> 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<String> ciphers = new ArrayList<>(ciphers256.size() + ciphers128.size());
-            ciphers.addAll(ciphers256);
-            ciphers.addAll(ciphers128);
-            return ciphers;
-        } else {
-            return ciphers128;
-        }
-    }
-
-    private static boolean has256BitAES() {
-        try {
-            return Cipher.getMaxAllowedKeyLength("AES") > 128;
-        } catch (NoSuchAlgorithmException e) {
-            // No AES? Things are going to be very weird, but technically that means we don't have 256 bit AES, so ...
-            return false;
-        }
-    }
 }

+ 4 - 0
modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexRestClientSslTests.java

@@ -120,6 +120,7 @@ public class ReindexRestClientSslTests extends ESTestCase {
         final List<Thread> 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 class ReindexRestClientSslTests extends ESTestCase {
         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 class ReindexRestClientSslTests extends ESTestCase {
         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 class ReindexRestClientSslTests extends ESTestCase {
             .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<Certificate[]> clientCertificates = new AtomicReference<>();
         handler = https -> {

+ 21 - 1
plugins/discovery-azure-classic/src/test/java/org/elasticsearch/discovery/azure/classic/AzureDiscoveryClusterFormationTests.java

@@ -25,6 +25,7 @@ import com.sun.net.httpserver.Headers;
 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.net.InetSocketAddress;
 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,28 @@ public class AzureDiscoveryClusterFormationTests extends ESIntegTestCase {
         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("12")) < 0) {
+            return "TLSv1.2";
+        } else {
+            JavaVersion full =
+                AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> 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++) {

+ 12 - 40
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackSettings.java

@@ -6,7 +6,6 @@
 
 package org.elasticsearch.xpack.core;
 
-import org.apache.logging.log4j.LogManager;
 import org.elasticsearch.common.settings.Setting;
 import org.elasticsearch.common.settings.Setting.Property;
 import org.elasticsearch.xpack.core.security.SecurityField;
@@ -15,13 +14,10 @@ import org.elasticsearch.xpack.core.ssl.SSLClientAuth;
 import org.elasticsearch.xpack.core.ssl.SSLConfigurationSettings;
 import org.elasticsearch.xpack.core.ssl.VerificationMode;
 
-import javax.crypto.Cipher;
 import javax.crypto.SecretKeyFactory;
-import javax.net.ssl.SSLContext;
 
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -38,7 +34,6 @@ public class XPackSettings {
         throw new IllegalStateException("Utility class should not be instantiated");
     }
 
-
     /**
      * Setting for controlling whether or not CCR is enabled.
      */
@@ -122,28 +117,17 @@ public class XPackSettings {
      * 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.*)
      */
-    public static final List<String> DEFAULT_CIPHERS;
-
-    static {
-        List<String> 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");
-        try {
-            final boolean use256Bit = Cipher.getMaxAllowedKeyLength("AES") > 128;
-            if (use256Bit) {
-                List<String> 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;
-            }
-        } catch (NoSuchAlgorithmException e) {
-            // ignore it here - there will be issues elsewhere and its not nice to throw in a static initializer
-        }
-
-        DEFAULT_CIPHERS = ciphers;
-    }
+    public static final List<String> DEFAULT_CIPHERS = List.of(
+        "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", // TLSv1.3 cipher has PFS, AEAD, hardware support
+        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // PFS, AEAD, hardware support
+        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // PFS, AEAD, hardware support
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",  "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", // PFS, hardware support
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", // PFS, hardware support
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", // PFS, hardware support
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // PFS, hardware support
+        "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", // AEAD, hardware support
+        "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", // hardware support
+        "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA"); // hardware support
 
     /*
      * Do not allow insecure hashing algorithms to be used for password hashing
@@ -164,19 +148,7 @@ public class XPackSettings {
         }
     }, Setting.Property.NodeScope);
 
-    public static final List<String> 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 List<String> DEFAULT_SUPPORTED_PROTOCOLS = List.of("TLSv1.3", "TLSv1.2", "TLSv1.1");
 
     public static final SSLClientAuth CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED;
     public static final SSLClientAuth HTTP_CLIENT_AUTH_DEFAULT = SSLClientAuth.NONE;

+ 1 - 5
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLService.java

@@ -57,8 +57,6 @@ import java.util.Set;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 
-import static org.elasticsearch.xpack.core.XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
-
 /**
  * Provides access to {@link SSLEngine} and {@link SSLSocketFactory} objects based on a provided configuration. All
  * configurations loaded by this service must be configured on construction.
@@ -75,9 +73,7 @@ public class SSLService {
     private static final Map<String, String> ORDERED_PROTOCOL_ALGORITHM_MAP;
     static {
         LinkedHashMap<String, String> protocolAlgorithmMap = new LinkedHashMap<>();
-        if (DEFAULT_SUPPORTED_PROTOCOLS.contains("TLSv1.3")) {
-            protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
-        }
+        protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
         protocolAlgorithmMap.put("TLSv1.2", "TLSv1.2");
         protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
         protocolAlgorithmMap.put("TLSv1", "TLSv1");

+ 2 - 3
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/TrustConfig.java

@@ -119,9 +119,8 @@ abstract class TrustConfig {
 
             try {
                 return CertParsingUtils.trustManager(trustConfigs.stream()
-                        .flatMap((tc) -> Arrays.stream(tc.createTrustManager(environment).getAcceptedIssuers()))
-                        .collect(Collectors.toList())
-                        .toArray(new X509Certificate[0]));
+                    .flatMap((tc) -> Arrays.stream(tc.createTrustManager(environment).getAcceptedIssuers()))
+                    .toArray(X509Certificate[]::new));
             } catch (Exception e) {
                 throw new ElasticsearchException("failed to create trust manager", e);
             }

+ 3 - 29
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/XPackSettingsTests.java

@@ -7,30 +7,19 @@ package org.elasticsearch.xpack.core;
 
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.test.ESTestCase;
-import javax.crypto.Cipher;
 import javax.crypto.SecretKeyFactory;
-import javax.net.ssl.SSLContext;
 
 import java.security.NoSuchAlgorithmException;
 
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.hasItem;
-import static org.hamcrest.Matchers.not;
 
 public class XPackSettingsTests extends ESTestCase {
 
-    public void testDefaultSSLCiphers() throws Exception {
+    public void testDefaultSSLCiphers() {
         assertThat(XPackSettings.DEFAULT_CIPHERS, hasItem("TLS_RSA_WITH_AES_128_CBC_SHA"));
-
-        final boolean useAES256 = Cipher.getMaxAllowedKeyLength("AES") > 128;
-        if (useAES256) {
-            logger.info("AES 256 is available");
-            assertThat(XPackSettings.DEFAULT_CIPHERS, hasItem("TLS_RSA_WITH_AES_256_CBC_SHA"));
-        } else {
-            logger.info("AES 256 is not available");
-            assertThat(XPackSettings.DEFAULT_CIPHERS, not(hasItem("TLS_RSA_WITH_AES_256_CBC_SHA")));
-        }
+        assertThat(XPackSettings.DEFAULT_CIPHERS, hasItem("TLS_RSA_WITH_AES_256_CBC_SHA"));
     }
 
     public void testPasswordHashingAlgorithmSettingValidation() {
@@ -50,16 +39,10 @@ public class XPackSettingsTests extends ESTestCase {
             Settings.builder().put(XPackSettings.PASSWORD_HASHING_ALGORITHM.getKey(), bcryptAlgo).build()));
     }
 
-    public void testDefaultSupportedProtocolsWithTLSv13() throws Exception {
-        assumeTrue("current JVM does not support TLSv1.3", supportTLSv13());
+    public void testDefaultSupportedProtocols() {
         assertThat(XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS, contains("TLSv1.3", "TLSv1.2", "TLSv1.1"));
     }
 
-    public void testDefaultSupportedProtocolsWithoutTLSv13() throws Exception {
-        assumeFalse("current JVM supports TLSv1.3", supportTLSv13());
-        assertThat(XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS, contains("TLSv1.2", "TLSv1.1"));
-    }
-
     private boolean isSecretkeyFactoryAlgoAvailable(String algorithmId) {
         try {
             SecretKeyFactory.getInstance(algorithmId);
@@ -68,13 +51,4 @@ public class XPackSettingsTests extends ESTestCase {
             return false;
         }
     }
-
-    private boolean supportTLSv13() {
-        try {
-            SSLContext.getInstance("TLSv1.3");
-            return true;
-        } catch (NoSuchAlgorithmException e) {
-            return false;
-        }
-    }
 }

BIN
x-pack/plugin/core/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks


+ 8 - 0
x-pack/plugin/core/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.pem

@@ -0,0 +1,8 @@
+Bag Attributes
+    friendlyName: testnode_ec
+    localKeyID: 54 69 6D 65 20 31 35 35 36 30 33 32 36 30 37 32 33 30 
+Key Attributes: <No Attributes>
+-----BEGIN PRIVATE KEY-----
+MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCxFwoKqfcGailZhuh0
+xEj3gssdjuEw6BasiC8+zhqHBA==
+-----END PRIVATE KEY-----

+ 25 - 0
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.env.TestEnvironment;
 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,9 @@ import javax.net.ssl.SSLContext;
 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.List;
 
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.instanceOf;
@@ -98,6 +104,7 @@ public class HttpExporterSslIT extends MonitoringIntegTestCase {
             .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 +192,22 @@ public class HttpExporterSslIT extends MonitoringIntegTestCase {
         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<String> getProtocols() {
+        if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) {
+            return List.of("TLSv1.2");
+        } else {
+            JavaVersion full =
+                AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
+            if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
+                return List.of("TLSv1.2");
+            }
+        }
+        return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
+    }
 }

+ 0 - 2
x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecurityIntegTestCase.java

@@ -243,8 +243,6 @@ public abstract class SecurityIntegTestCase extends ESIntegTestCase {
         Settings customSettings = customSecuritySettingsSource.nodeSettings(nodeOrdinal);
         builder.put(customSettings, false); // handle secure settings separately
         builder.put(LicenseService.SELF_GENERATED_LICENSE_TYPE.getKey(), "trial");
-        builder.put(NetworkModule.TRANSPORT_TYPE_KEY, randomBoolean() ? SecurityField.NAME4 : SecurityField.NIO);
-        builder.put(NetworkModule.HTTP_TYPE_KEY, randomBoolean() ? SecurityField.NAME4 : SecurityField.NIO);
         Settings.Builder customBuilder = Settings.builder().put(customSettings);
         if (customBuilder.getSecureSettings() != null) {
             SecuritySettingsSource.addSecureSettings(builder, secureSettings ->

+ 4 - 2
x-pack/plugin/security/src/test/java/org/elasticsearch/test/SecuritySettingsSource.java

@@ -218,7 +218,8 @@ public class SecuritySettingsSource extends NodeConfigurationSource {
                 "/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 class SecuritySettingsSource extends NodeConfigurationSource {
                 "/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/testnode_ec.crt",
+                    "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.crt"),
                 hostnameVerificationEnabled, true);
         } else {
             addSSLSettingsForStore(builder, prefix, "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks",

+ 9 - 6
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiAuthenticationTests.java

@@ -66,8 +66,9 @@ public class PkiAuthenticationTests extends SecuritySingleNodeTestCase {
             .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 class PkiAuthenticationTests extends SecuritySingleNodeTestCase {
             "/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();
@@ -119,7 +120,8 @@ public class PkiAuthenticationTests extends SecuritySingleNodeTestCase {
             "testnode",
             "/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt",
             Arrays.asList("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.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"));
         try (CloseableHttpClient client = HttpClients.custom().setSSLContext(context).build()) {
             HttpPut put = new HttpPut(getNodeUrl() + "foo");
             try (CloseableHttpResponse response = SocketAccess.doPrivileged(() -> client.execute(put))) {
@@ -133,7 +135,8 @@ public class PkiAuthenticationTests extends SecuritySingleNodeTestCase {
         SSLContext context = getRestSSLContext("/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/testclient.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"));
         try (CloseableHttpClient client = HttpClients.custom().setSSLContext(context).build()) {
             HttpPut put = new HttpPut(getNodeUrl() + "foo");
             try (CloseableHttpResponse response = SocketAccess.doPrivileged(() -> client.execute(put))) {

+ 23 - 0
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.license.XPackLicenseState;
 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.io.OutputStream;
 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 class SamlRealmTests extends SamlTestCase {
                 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,21 @@ public class SamlRealmTests extends SamlTestCase {
         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<String> getProtocols() {
+        if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) {
+            return List.of("TLSv1.2");
+        } else {
+            JavaVersion full =
+                AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
+            if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
+                return List.of("TLSv1.2");
+            }
+        }
+        return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
+    }
 }

+ 3 - 1
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/AbstractSimpleSecurityTransportTestCase.java

@@ -155,7 +155,9 @@ public abstract class AbstractSimpleSecurityTransportTestCase extends AbstractSi
 
     @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()) {

+ 5 - 5
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ServerTransportFilterIntegrationTests.java

@@ -19,7 +19,6 @@ import org.elasticsearch.node.NodeValidationException;
 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;
@@ -40,6 +39,7 @@ import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
 import static org.elasticsearch.discovery.SettingsBasedSeedHostsProvider.DISCOVERY_SEED_HOSTS_SETTING;
@@ -80,8 +80,6 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
             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 +110,8 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
             "/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"));
+            List.of("/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 +150,8 @@ public class ServerTransportFilterIntegrationTests extends SecurityIntegTestCase
             "/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"));
+            List.of("/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);

+ 4 - 1
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/transport/ssl/EllipticCurveSSLTests.java

@@ -33,7 +33,9 @@ import java.util.Collections;
 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.is;
 
 public class EllipticCurveSSLTests extends SecurityIntegTestCase {
 
@@ -106,7 +108,8 @@ public class EllipticCurveSSLTests extends SecurityIntegTestCase {
             Certificate[] peerChain = session.getPeerCertificates();
             assertEquals(1, peerChain.length);
             assertEquals(certs[0], peerChain[0]);
-            assertThat(session.getCipherSuite(), containsString("ECDSA"));
+            assertThat(session.getCipherSuite(),
+                anyOf(containsString("ECDSA"), is("TLS_AES_256_GCM_SHA384"), is("TLS_AES_128_GCM_SHA256")));
         }
     }
 

+ 31 - 7
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.common.transport.TransportAddress;
 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 org.junit.BeforeClass;
 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;
@@ -114,11 +119,12 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
      */
     public void testThatStandardTransportClientCanConnectToNoClientAuthProfile() throws Exception {
         try(TransportClient transportClient = new TestXPackTransportClient(Settings.builder()
-                .put(transportClientSettings())
-                .put("xpack.security.transport.ssl.enabled", true)
-                .put("node.name", "programmatic_transport_client")
-                .put("cluster.name", internalCluster().getClusterName())
-                .build(), LocalStateSecurity.class)) {
+            .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)) {
             transportClient.addTransportAddress(new TransportAddress(localAddress,
                     getProfilePort("no_client_auth")));
             assertGreenClusterState(transportClient);
@@ -154,7 +160,8 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
             "/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,8 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
             "/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"));
+            List.of("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.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")));
@@ -275,6 +283,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
             .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.supported_protocols", getProtocols())
             .build();
         try (TransportClient transportClient = new TestXPackTransportClient(settings,
                                                                             Collections.singletonList(LocalStateSecurity.class))) {
@@ -386,6 +395,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
             .put("cluster.name", internalCluster().getClusterName())
             .put("xpack.security.transport.ssl.client_authentication", SSLClientAuth.REQUIRED)
             .put("xpack.security.transport.ssl.enabled", true)
+            .putList("xpack.security.transport.ssl.supported_protocols", getProtocols())
             .build();
         try (TransportClient transportClient = new TestXPackTransportClient(settings,
                                                                             Collections.singletonList(LocalStateSecurity.class))) {
@@ -409,4 +419,18 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
         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<String> getProtocols() {
+        JavaVersion full =
+            AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
+        if (full.compareTo(JavaVersion.parse("11.0.3")) < 0) {
+            return List.of("TLSv1.2");
+        }
+        return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
+    }
 }

+ 25 - 3
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLClientAuthTests.java

@@ -11,6 +11,7 @@ import org.apache.http.ssl.SSLContexts;
 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.common.transport.TransportAddress;
 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.InputStream;
 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;
@@ -135,6 +140,7 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
         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 class SSLClientAuthTests extends SecurityIntegTestCase {
             .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,13 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
         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");
+            SSLContext context = SSLContext.getInstance(randomFrom("TLSv1.3", "TLSv1.2"));
             context.init(new KeyManager[] { km }, new TrustManager[] { tm }, new SecureRandom());
             return context;
         } catch (Exception e) {
@@ -188,4 +196,18 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
         }
         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<String> getProtocols() {
+        JavaVersion full =
+            AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
+        if (full.compareTo(JavaVersion.parse("11.0.3")) < 0) {
+            return List.of("TLSv1.2");
+        }
+        return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
+    }
 }

+ 4 - 0
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadIntegTests.java

@@ -115,6 +115,10 @@ public class SSLReloadIntegTests extends SecurityIntegTestCase {
         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);

+ 16 - 5
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLTrustRestrictionsTests.java

@@ -31,6 +31,7 @@ import javax.net.ssl.SSLSocket;
 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 @@ public class SSLTrustRestrictionsTests extends SecurityIntegTestCase {
     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 class SSLTrustRestrictionsTests extends SecurityIntegTestCase {
     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 class SSLTrustRestrictionsTests extends SecurityIntegTestCase {
         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 class SSLTrustRestrictionsTests extends SecurityIntegTestCase {
         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 @@ public class SSLTrustRestrictionsTests extends SecurityIntegTestCase {
         }
     }
 
-    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 @@ public class SSLTrustRestrictionsTests extends SecurityIntegTestCase {
             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());
+                }
+            }
         }
     }
 

BIN
x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testclient.jks


BIN
x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks


BIN
x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12


+ 13 - 0
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-----

+ 8 - 0
x-pack/plugin/security/src/test/resources/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode_ec.pem

@@ -0,0 +1,8 @@
+Bag Attributes
+    friendlyName: testnode_ec
+    localKeyID: 54 69 6D 65 20 31 35 35 36 30 33 32 36 30 37 32 33 30 
+Key Attributes: <No Attributes>
+-----BEGIN PRIVATE KEY-----
+MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCxFwoKqfcGailZhuh0
+xEj3gssdjuEw6BasiC8+zhqHBA==
+-----END PRIVATE KEY-----

+ 24 - 0
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,9 @@ import org.junit.After;
 import org.junit.Before;
 
 import java.nio.file.Path;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.List;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
 import static org.elasticsearch.xpack.watcher.client.WatchSourceBuilders.watchBuilder;
@@ -51,6 +57,7 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest
             .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 +138,21 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest
         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<String> getProtocols() {
+        if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) {
+            return List.of("TLSv1.2");
+        } else {
+            JavaVersion full =
+                AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
+            if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
+                return List.of("TLSv1.2");
+            }
+        }
+        return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
+    }
 }

+ 32 - 4
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.message.ParameterizedMessage;
 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.ESTestCase;
 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.Socket;
 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 class HttpClientTests extends ESTestCase {
             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 class HttpClientTests extends ESTestCase {
             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 class HttpClientTests extends ESTestCase {
         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 class HttpClientTests extends ESTestCase {
         Settings serverSettings = Settings.builder()
             .put("xpack.http.ssl.key", keyPath)
             .put("xpack.http.ssl.certificate", certPath)
+            .putList("xpack.security.http.ssl.supported_protocols", getProtocols())
             .setSecureSettings(serverSecureSettings)
             .build();
         TestsSSLService sslService = new TestsSSLService(serverSettings, environment);
@@ -379,11 +389,12 @@ public class HttpClientTests extends ESTestCase {
             proxyServer.start();
 
             Settings settings = Settings.builder()
-                    .put(HttpSettings.PROXY_HOST.getKey(), "localhost")
-                    .put(HttpSettings.PROXY_PORT.getKey(), proxyServer.getPort())
-                    .put(HttpSettings.PROXY_SCHEME.getKey(), "https")
+                .put(HttpSettings.PROXY_HOST.getKey(), "localhost")
+                .put(HttpSettings.PROXY_PORT.getKey(), proxyServer.getPort())
+                .put(HttpSettings.PROXY_SCHEME.getKey(), "https")
                 .put("xpack.http.ssl.certificate_authorities", trustedCertPath)
-                    .build();
+                .putList("xpack.security.http.ssl.supported_protocols", getProtocols())
+                .build();
 
             HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webServer.getPort())
                     .method(HttpMethod.GET)
@@ -737,4 +748,21 @@ public class HttpClientTests extends ESTestCase {
     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<String> getProtocols() {
+        if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) {
+            return List.of("TLSv1.2");
+        } else {
+            JavaVersion full =
+                AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
+            if (full.compareTo(JavaVersion.parse("12.0.1")) < 0) {
+                return List.of("TLSv1.2");
+            }
+        }
+        return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
+    }
 }

+ 6 - 0
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',