Skip to content

Update TLS ciphers and protocols for JDK 11 #41808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand All @@ -126,4 +128,35 @@ private static SSLContext getSslContext() throws Exception {
}
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";
}
}
31 changes: 16 additions & 15 deletions docs/reference/settings/security-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -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]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
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;
Expand Down Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -70,10 +64,22 @@
*/
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;
Expand Down Expand Up @@ -141,9 +147,6 @@ public void setDefaultClientAuth(SslClientAuthenticationMode defaultClientAuth)

/**
* 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;
Expand Down Expand Up @@ -336,40 +339,4 @@ private <V> List<V> resolveListSetting(String key, Function<String, V> parser, L
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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public void testClientFailsWithUntrustedCertificate() throws IOException {
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));
Expand All @@ -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));
Expand All @@ -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));
Expand All @@ -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<Certificate[]> clientCertificates = new AtomicReference<>();
handler = https -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -262,11 +265,28 @@ 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("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++) {
Expand Down
Loading