Skip to content
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,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<String>) () -> 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";
}
}
31 changes: 24 additions & 7 deletions docs/reference/settings/security-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -338,30 +340,53 @@ private <V> List<V> resolveListSetting(String key, Function<String, V> parser, L
}

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;
final boolean has256BitAES = has256BitAES();
final boolean useGCM = JavaVersion.current().compareTo(JavaVersion.parse("11")) >= 0;
final boolean tlsV13Supported = DEFAULT_PROTOCOLS.contains("TLSv1.3");
List<String> 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() {
Expand Down
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,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>) () -> 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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -118,31 +119,79 @@ private XPackSettings() {
/** Setting for enabling or disabling sql. Defaults to true. */
public static final Setting<Boolean> SQL_ENABLED = Setting.boolSetting("xpack.sql.enabled", true, 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");
}

/*
* 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");
List<String> 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<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;
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);
}

/*
Expand All @@ -164,20 +213,6 @@ private 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 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;
Expand Down
Binary file not shown.
Loading