Skip to content
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

Enable TLSv1.3 by default for JDKs with support #38103

Merged
merged 1 commit into from
Feb 1, 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
4 changes: 2 additions & 2 deletions docs/reference/migration/migrate_7_0/settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,11 @@ used.

TLS version 1.0 is now disabled by default as it suffers from
https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet#Rule_-_Only_Support_Strong_Protocols[known security issues].
The default protocols are now TLSv1.2 and TLSv1.1.
The default protocols are now TLSv1.3 (if supported), TLSv1.2 and TLSv1.1.
You can enable TLS v1.0 by configuring the relevant `ssl.supported_protocols` setting to include `"TLSv1"`, for example:
[source,yaml]
--------------------------------------------------
xpack.security.http.ssl.supported_protocols: [ "TLSv1.2", "TLSv1.1", "TLSv1" ]
xpack.security.http.ssl.supported_protocols: [ "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" ]
--------------------------------------------------

[float]
Expand Down
12 changes: 8 additions & 4 deletions docs/reference/settings/security-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,8 @@ 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.2,TLSv1.1`.
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`.

`ssl.cipher_suites`:: Specifies the cipher suites that should be supported when
communicating with the LDAP server.
Expand Down Expand Up @@ -724,7 +725,8 @@ 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.2, TLSv1.1`.
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`.

`ssl.cipher_suites`:: Specifies the cipher suites that should be supported when
communicating with the Active Directory server.
Expand Down Expand Up @@ -1132,7 +1134,8 @@ 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.
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`.

`ssl.cipher_suites`::
Specifies the
Expand Down Expand Up @@ -1206,7 +1209,8 @@ settings. For more information, see

`ssl.supported_protocols`::
Supported protocols with versions. Valid protocols: `SSLv2Hello`,
`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`. Defaults to `TLSv1.2`, `TLSv1.1`.
`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`.
+
--
NOTE: If `xpack.security.fips_mode.enabled` is `true`, you cannot use `SSLv2Hello`
Expand Down
3 changes: 2 additions & 1 deletion docs/reference/settings/ssl-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ endif::server[]

+{ssl-prefix}.ssl.supported_protocols+::
Supported protocols with versions. Valid protocols: `SSLv2Hello`,
`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`. Defaults to `TLSv1.2`, `TLSv1.1`.
`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`.


ifdef::server[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
import javax.net.ssl.X509ExtendedTrustManager;
import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;

Expand All @@ -40,6 +43,30 @@
*/
public class SslConfiguration {

/**
* An ordered map of protocol algorithms to SSLContext algorithms. The map is ordered from most
* secure to least secure. The names in this map are taken from the
* <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms">
* Java Security Standard Algorithm Names Documentation for Java 11</a>.
*/
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.2", "TLSv1.2");
protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
protocolAlgorithmMap.put("TLSv1", "TLSv1");
protocolAlgorithmMap.put("SSLv3", "SSLv3");
protocolAlgorithmMap.put("SSLv2", "SSL");
protocolAlgorithmMap.put("SSLv2Hello", "SSL");
ORDERED_PROTOCOL_ALGORITHM_MAP = Collections.unmodifiableMap(protocolAlgorithmMap);
}

private final SslTrustConfig trustConfig;
private final SslKeyConfig keyConfig;
private final SslVerificationMode verificationMode;
Expand Down Expand Up @@ -124,12 +151,13 @@ private String contextProtocol() {
if (supportedProtocols.isEmpty()) {
throw new SslConfigException("no SSL/TLS protocols have been configured");
}
for (String tryProtocol : Arrays.asList("TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3")) {
if (supportedProtocols.contains(tryProtocol)) {
return tryProtocol;
for (Entry<String, String> entry : ORDERED_PROTOCOL_ALGORITHM_MAP.entrySet()) {
if (supportedProtocols.contains(entry.getKey())) {
return entry.getValue();
}
}
return "SSL";
throw new SslConfigException("no supported SSL/TLS protocol was found in the configured supported protocols: "
+ supportedProtocols);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@
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 @@ -68,7 +70,9 @@
*/
public abstract class SslConfigurationLoader {

static final List<String> DEFAULT_PROTOCOLS = Arrays.asList("TLSv1.2", "TLSv1.1");
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();
private static final char[] EMPTY_PASSWORD = new char[0];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

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;
Expand All @@ -16,6 +17,7 @@

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.net.ssl.SSLContext;

import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
Expand Down Expand Up @@ -154,7 +156,20 @@ private XPackSettings() {
}
}, Setting.Property.NodeScope);

public static final List<String> DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1.2", "TLSv1.1");
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
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
Expand All @@ -56,13 +57,35 @@
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.
*/
public class SSLService {

private static final Logger logger = LogManager.getLogger(SSLService.class);
/**
* An ordered map of protocol algorithms to SSLContext algorithms. The map is ordered from most
* secure to least secure. The names in this map are taken from the
* <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms">
* Java Security Standard Algorithm Names Documentation for Java 11</a>.
*/
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.2", "TLSv1.2");
protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
protocolAlgorithmMap.put("TLSv1", "TLSv1");
protocolAlgorithmMap.put("SSLv3", "SSLv3");
protocolAlgorithmMap.put("SSLv2", "SSL");
protocolAlgorithmMap.put("SSLv2Hello", "SSL");
ORDERED_PROTOCOL_ALGORITHM_MAP = Collections.unmodifiableMap(protocolAlgorithmMap);
}

private final Settings settings;

Expand Down Expand Up @@ -691,47 +714,19 @@ public SSLConfiguration getSSLConfiguration(String contextName) {
/**
* Maps the supported protocols to an appropriate ssl context algorithm. We make an attempt to use the "best" algorithm when
* possible. The names in this method are taken from the
* <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">JCA Standard Algorithm Name
* Documentation for Java 8</a>.
* <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms">Java Security
* Standard Algorithm Names Documentation for Java 11</a>.
*/
private static String sslContextAlgorithm(List<String> supportedProtocols) {
if (supportedProtocols.isEmpty()) {
return "TLSv1.2";
}

String algorithm = "SSL";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like we got rid of this switch :)

for (String supportedProtocol : supportedProtocols) {
switch (supportedProtocol) {
case "TLSv1.2":
return "TLSv1.2";
case "TLSv1.1":
if ("TLSv1.2".equals(algorithm) == false) {
algorithm = "TLSv1.1";
}
break;
case "TLSv1":
switch (algorithm) {
case "TLSv1.2":
case "TLSv1.1":
break;
default:
algorithm = "TLSv1";
}
break;
case "SSLv3":
switch (algorithm) {
case "SSLv2":
case "SSL":
algorithm = "SSLv3";
}
break;
case "SSLv2":
case "SSLv2Hello":
break;
default:
throw new IllegalArgumentException("found unexpected value in supported protocols: " + supportedProtocol);
throw new IllegalArgumentException("no SSL/TLS protocols have been configured");
}
for (Entry<String, String> entry : ORDERED_PROTOCOL_ALGORITHM_MAP.entrySet()) {
if (supportedProtocols.contains(entry.getKey())) {
return entry.getValue();
}
}
return algorithm;
throw new IllegalArgumentException("no supported SSL/TLS protocol was found in the configured supported protocols: "
+ supportedProtocols);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
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;
Expand Down Expand Up @@ -48,6 +50,16 @@ public void testPasswordHashingAlgorithmSettingValidation() {
Settings.builder().put(XPackSettings.PASSWORD_HASHING_ALGORITHM.getKey(), bcryptAlgo).build()));
}

public void testDefaultSupportedProtocolsWithTLSv13() throws Exception {
assumeTrue("current JVM does not support TLSv1.3", supportTLSv13());
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);
Expand All @@ -56,4 +68,13 @@ private boolean isSecretkeyFactoryAlgoAvailable(String algorithmId) {
return false;
}
}

private boolean supportTLSv13() {
try {
SSLContext.getInstance("TLSv1.3");
return true;
} catch (NoSuchAlgorithmException e) {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLHandshakeException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
Expand Down Expand Up @@ -263,7 +262,7 @@ public void testReloadingPEMTrustConfig() throws Exception {
try (MockWebServer server = getSslServer(serverKeyPath, serverCertPath, "testnode")) {
final Consumer<SSLContext> trustMaterialPreChecks = (context) -> {
try (CloseableHttpClient client = HttpClients.custom().setSSLContext(context).build()) {
privilegedConnect(() -> client.execute(new HttpGet("https://localhost:" + server.getPort())).close());
privilegedConnect(() -> client.execute(new HttpGet("https://localhost:" + server.getPort())));//.close());
} catch (Exception e) {
throw new RuntimeException("Exception connecting to the mock server", e);
}
Expand Down Expand Up @@ -480,7 +479,9 @@ private static MockWebServer getSslServer(Path keyStorePath, String keyStorePass
try (InputStream is = Files.newInputStream(keyStorePath)) {
keyStore.load(is, keyStorePass.toCharArray());
}
final SSLContext sslContext = new SSLContextBuilder().loadKeyMaterial(keyStore, keyStorePass.toCharArray())
final SSLContext sslContext = new SSLContextBuilder()
.loadKeyMaterial(keyStore, keyStorePass.toCharArray())
.setProtocol("TLSv1.2")
.build();
MockWebServer server = new MockWebServer(sslContext, false);
server.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
Expand All @@ -494,7 +495,9 @@ private static MockWebServer getSslServer(Path keyPath, Path certPath, String pa
keyStore.load(null, password.toCharArray());
keyStore.setKeyEntry("testnode_ec", PemUtils.readPrivateKey(keyPath, password::toCharArray), password.toCharArray(),
CertParsingUtils.readCertificates(Collections.singletonList(certPath)));
final SSLContext sslContext = new SSLContextBuilder().loadKeyMaterial(keyStore, password.toCharArray())
final SSLContext sslContext = new SSLContextBuilder()
.loadKeyMaterial(keyStore, password.toCharArray())
.setProtocol("TLSv1.2")
.build();
MockWebServer server = new MockWebServer(sslContext, false);
server.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
Expand All @@ -509,7 +512,10 @@ private static CloseableHttpClient getSSLClient(Path trustStorePath, String trus
try (InputStream is = Files.newInputStream(trustStorePath)) {
trustStore.load(is, trustStorePass.toCharArray());
}
final SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(trustStore, null).build();
final SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(trustStore, null)
.setProtocol("TLSv1.2")
.build();
return HttpClients.custom().setSSLContext(sslContext).build();
}

Expand All @@ -526,7 +532,10 @@ private static CloseableHttpClient getSSLClient(List<Path> trustedCertificatePat
for (Certificate cert : CertParsingUtils.readCertificates(trustedCertificatePaths)) {
trustStore.setCertificateEntry(cert.toString(), cert);
}
final SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(trustStore, null).build();
final SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(trustStore, null)
.setProtocol("TLSv1.2")
.build();
return HttpClients.custom().setSSLContext(sslContext).build();
}

Expand Down