Skip to content

Commit 2ca2220

Browse files
authored
Enable TLSv1.3 by default for JDKs with support (#38103)
This commit enables the use of TLSv1.3 with security by enabling us to properly map `TLSv1.3` in the supported protocols setting to the algorithm for a SSLContext. Additionally, we also enable TLSv1.3 by default on JDKs that support it. An issue was uncovered with the MockWebServer when TLSv1.3 is used that ultimately winds up in an endless loop when the client does not trust the server's certificate. Due to this, SSLConfigurationReloaderTests has been pinned to TLSv1.2. Closes #32276
1 parent 025bf28 commit 2ca2220

File tree

9 files changed

+134
-57
lines changed

9 files changed

+134
-57
lines changed

docs/reference/migration/migrate_7_0/settings.asciidoc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,11 @@ used.
138138

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

148148
[float]

docs/reference/settings/security-settings.asciidoc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,8 @@ and `full`. Defaults to `full`.
480480
See <<ssl-tls-settings,`ssl.verification_mode`>> for an explanation of these values.
481481

482482
`ssl.supported_protocols`::
483-
Supported protocols for TLS/SSL (with versions). Defaults to `TLSv1.2,TLSv1.1`.
483+
Supported protocols for TLS/SSL (with versions). Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
484+
the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
484485

485486
`ssl.cipher_suites`:: Specifies the cipher suites that should be supported when
486487
communicating with the LDAP server.
@@ -724,7 +725,8 @@ and `full`. Defaults to `full`.
724725
See <<ssl-tls-settings,`ssl.verification_mode`>> for an explanation of these values.
725726

726727
`ssl.supported_protocols`::
727-
Supported protocols for TLS/SSL (with versions). Defaults to `TLSv1.2, TLSv1.1`.
728+
Supported protocols for TLS/SSL (with versions). Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
729+
the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
728730

729731
`ssl.cipher_suites`:: Specifies the cipher suites that should be supported when
730732
communicating with the Active Directory server.
@@ -1132,7 +1134,8 @@ Defaults to `full`.
11321134
See <<ssl-tls-settings,`ssl.verification_mode`>> for a more detailed explanation of these values.
11331135

11341136
`ssl.supported_protocols`::
1135-
Specifies the supported protocols for TLS/SSL.
1137+
Specifies the supported protocols for TLS/SSL. Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
1138+
the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
11361139

11371140
`ssl.cipher_suites`::
11381141
Specifies the
@@ -1206,7 +1209,8 @@ settings. For more information, see
12061209

12071210
`ssl.supported_protocols`::
12081211
Supported protocols with versions. Valid protocols: `SSLv2Hello`,
1209-
`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`. Defaults to `TLSv1.2`, `TLSv1.1`.
1212+
`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, `TLSv1.3`. Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
1213+
the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
12101214
+
12111215
--
12121216
NOTE: If `xpack.security.fips_mode.enabled` is `true`, you cannot use `SSLv2Hello`

docs/reference/settings/ssl-settings.asciidoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ endif::server[]
1111

1212
+{ssl-prefix}.ssl.supported_protocols+::
1313
Supported protocols with versions. Valid protocols: `SSLv2Hello`,
14-
`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`. Defaults to `TLSv1.2`, `TLSv1.1`.
14+
`SSLv3`, `TLSv1`, `TLSv1.1`, `TLSv1.2`, `TLSv1.3`. Defaults to `TLSv1.3,TLSv1.2,TLSv1.1` if
15+
the JVM supports TLSv1.3, otherwise `TLSv1.2,TLSv1.1`.
1516

1617

1718
ifdef::server[]

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

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@
2424
import javax.net.ssl.X509ExtendedTrustManager;
2525
import java.nio.file.Path;
2626
import java.security.GeneralSecurityException;
27-
import java.util.Arrays;
27+
import java.security.NoSuchAlgorithmException;
2828
import java.util.Collection;
2929
import java.util.Collections;
3030
import java.util.HashSet;
31+
import java.util.LinkedHashMap;
3132
import java.util.List;
33+
import java.util.Map;
34+
import java.util.Map.Entry;
3235
import java.util.Objects;
3336
import java.util.Set;
3437

@@ -40,6 +43,30 @@
4043
*/
4144
public class SslConfiguration {
4245

46+
/**
47+
* An ordered map of protocol algorithms to SSLContext algorithms. The map is ordered from most
48+
* secure to least secure. The names in this map are taken from the
49+
* <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms">
50+
* Java Security Standard Algorithm Names Documentation for Java 11</a>.
51+
*/
52+
static final Map<String, String> ORDERED_PROTOCOL_ALGORITHM_MAP;
53+
static {
54+
LinkedHashMap<String, String> protocolAlgorithmMap = new LinkedHashMap<>();
55+
try {
56+
SSLContext.getInstance("TLSv1.3");
57+
protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
58+
} catch (NoSuchAlgorithmException e) {
59+
// ignore since we support JVMs that do not support TLSv1.3
60+
}
61+
protocolAlgorithmMap.put("TLSv1.2", "TLSv1.2");
62+
protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
63+
protocolAlgorithmMap.put("TLSv1", "TLSv1");
64+
protocolAlgorithmMap.put("SSLv3", "SSLv3");
65+
protocolAlgorithmMap.put("SSLv2", "SSL");
66+
protocolAlgorithmMap.put("SSLv2Hello", "SSL");
67+
ORDERED_PROTOCOL_ALGORITHM_MAP = Collections.unmodifiableMap(protocolAlgorithmMap);
68+
}
69+
4370
private final SslTrustConfig trustConfig;
4471
private final SslKeyConfig keyConfig;
4572
private final SslVerificationMode verificationMode;
@@ -124,12 +151,13 @@ private String contextProtocol() {
124151
if (supportedProtocols.isEmpty()) {
125152
throw new SslConfigException("no SSL/TLS protocols have been configured");
126153
}
127-
for (String tryProtocol : Arrays.asList("TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3")) {
128-
if (supportedProtocols.contains(tryProtocol)) {
129-
return tryProtocol;
154+
for (Entry<String, String> entry : ORDERED_PROTOCOL_ALGORITHM_MAP.entrySet()) {
155+
if (supportedProtocols.contains(entry.getKey())) {
156+
return entry.getValue();
130157
}
131158
}
132-
return "SSL";
159+
throw new SslConfigException("no supported SSL/TLS protocol was found in the configured supported protocols: "
160+
+ supportedProtocols);
133161
}
134162

135163
@Override

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@
2626
import java.security.NoSuchAlgorithmException;
2727
import java.util.ArrayList;
2828
import java.util.Arrays;
29+
import java.util.Collections;
2930
import java.util.List;
3031
import java.util.Objects;
3132
import java.util.function.Function;
3233
import java.util.stream.Collectors;
3334

3435
import static org.elasticsearch.common.ssl.KeyStoreUtil.inferKeyStoreType;
36+
import static org.elasticsearch.common.ssl.SslConfiguration.ORDERED_PROTOCOL_ALGORITHM_MAP;
3537
import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE;
3638
import static org.elasticsearch.common.ssl.SslConfigurationKeys.CERTIFICATE_AUTHORITIES;
3739
import static org.elasticsearch.common.ssl.SslConfigurationKeys.CIPHERS;
@@ -68,7 +70,9 @@
6870
*/
6971
public abstract class SslConfigurationLoader {
7072

71-
static final List<String> DEFAULT_PROTOCOLS = Arrays.asList("TLSv1.2", "TLSv1.1");
73+
static final List<String> DEFAULT_PROTOCOLS = Collections.unmodifiableList(
74+
ORDERED_PROTOCOL_ALGORITHM_MAP.containsKey("TLSv1.3") ?
75+
Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1") : Arrays.asList("TLSv1.2", "TLSv1.1"));
7276
static final List<String> DEFAULT_CIPHERS = loadDefaultCiphers();
7377
private static final char[] EMPTY_PASSWORD = new char[0];
7478

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
package org.elasticsearch.xpack.core;
88

9+
import org.apache.logging.log4j.LogManager;
910
import org.elasticsearch.common.settings.Setting;
1011
import org.elasticsearch.common.settings.Setting.Property;
1112
import org.elasticsearch.xpack.core.security.SecurityField;
@@ -16,6 +17,7 @@
1617

1718
import javax.crypto.Cipher;
1819
import javax.crypto.SecretKeyFactory;
20+
import javax.net.ssl.SSLContext;
1921

2022
import java.security.NoSuchAlgorithmException;
2123
import java.util.ArrayList;
@@ -154,7 +156,20 @@ private XPackSettings() {
154156
}
155157
}, Setting.Property.NodeScope);
156158

157-
public static final List<String> DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1.2", "TLSv1.1");
159+
public static final List<String> DEFAULT_SUPPORTED_PROTOCOLS;
160+
161+
static {
162+
boolean supportsTLSv13 = false;
163+
try {
164+
SSLContext.getInstance("TLSv1.3");
165+
supportsTLSv13 = true;
166+
} catch (NoSuchAlgorithmException e) {
167+
LogManager.getLogger(XPackSettings.class).debug("TLSv1.3 is not supported", e);
168+
}
169+
DEFAULT_SUPPORTED_PROTOCOLS = supportsTLSv13 ?
170+
Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1") : Arrays.asList("TLSv1.2", "TLSv1.1");
171+
}
172+
158173
public static final SSLClientAuth CLIENT_AUTH_DEFAULT = SSLClientAuth.REQUIRED;
159174
public static final SSLClientAuth HTTP_CLIENT_AUTH_DEFAULT = SSLClientAuth.NONE;
160175
public static final VerificationMode VERIFICATION_MODE_DEFAULT = VerificationMode.FULL;

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

Lines changed: 32 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.util.Enumeration;
4747
import java.util.HashMap;
4848
import java.util.HashSet;
49+
import java.util.LinkedHashMap;
4950
import java.util.LinkedList;
5051
import java.util.List;
5152
import java.util.Map;
@@ -56,13 +57,35 @@
5657
import java.util.function.Supplier;
5758
import java.util.stream.Collectors;
5859

60+
import static org.elasticsearch.xpack.core.XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
61+
5962
/**
6063
* Provides access to {@link SSLEngine} and {@link SSLSocketFactory} objects based on a provided configuration. All
6164
* configurations loaded by this service must be configured on construction.
6265
*/
6366
public class SSLService {
6467

6568
private static final Logger logger = LogManager.getLogger(SSLService.class);
69+
/**
70+
* An ordered map of protocol algorithms to SSLContext algorithms. The map is ordered from most
71+
* secure to least secure. The names in this map are taken from the
72+
* <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms">
73+
* Java Security Standard Algorithm Names Documentation for Java 11</a>.
74+
*/
75+
private static final Map<String, String> ORDERED_PROTOCOL_ALGORITHM_MAP;
76+
static {
77+
LinkedHashMap<String, String> protocolAlgorithmMap = new LinkedHashMap<>();
78+
if (DEFAULT_SUPPORTED_PROTOCOLS.contains("TLSv1.3")) {
79+
protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
80+
}
81+
protocolAlgorithmMap.put("TLSv1.2", "TLSv1.2");
82+
protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
83+
protocolAlgorithmMap.put("TLSv1", "TLSv1");
84+
protocolAlgorithmMap.put("SSLv3", "SSLv3");
85+
protocolAlgorithmMap.put("SSLv2", "SSL");
86+
protocolAlgorithmMap.put("SSLv2Hello", "SSL");
87+
ORDERED_PROTOCOL_ALGORITHM_MAP = Collections.unmodifiableMap(protocolAlgorithmMap);
88+
}
6689

6790
private final Settings settings;
6891

@@ -691,47 +714,19 @@ public SSLConfiguration getSSLConfiguration(String contextName) {
691714
/**
692715
* Maps the supported protocols to an appropriate ssl context algorithm. We make an attempt to use the "best" algorithm when
693716
* possible. The names in this method are taken from the
694-
* <a href="http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html">JCA Standard Algorithm Name
695-
* Documentation for Java 8</a>.
717+
* <a href="https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#sslcontext-algorithms">Java Security
718+
* Standard Algorithm Names Documentation for Java 11</a>.
696719
*/
697720
private static String sslContextAlgorithm(List<String> supportedProtocols) {
698721
if (supportedProtocols.isEmpty()) {
699-
return "TLSv1.2";
700-
}
701-
702-
String algorithm = "SSL";
703-
for (String supportedProtocol : supportedProtocols) {
704-
switch (supportedProtocol) {
705-
case "TLSv1.2":
706-
return "TLSv1.2";
707-
case "TLSv1.1":
708-
if ("TLSv1.2".equals(algorithm) == false) {
709-
algorithm = "TLSv1.1";
710-
}
711-
break;
712-
case "TLSv1":
713-
switch (algorithm) {
714-
case "TLSv1.2":
715-
case "TLSv1.1":
716-
break;
717-
default:
718-
algorithm = "TLSv1";
719-
}
720-
break;
721-
case "SSLv3":
722-
switch (algorithm) {
723-
case "SSLv2":
724-
case "SSL":
725-
algorithm = "SSLv3";
726-
}
727-
break;
728-
case "SSLv2":
729-
case "SSLv2Hello":
730-
break;
731-
default:
732-
throw new IllegalArgumentException("found unexpected value in supported protocols: " + supportedProtocol);
722+
throw new IllegalArgumentException("no SSL/TLS protocols have been configured");
723+
}
724+
for (Entry<String, String> entry : ORDERED_PROTOCOL_ALGORITHM_MAP.entrySet()) {
725+
if (supportedProtocols.contains(entry.getKey())) {
726+
return entry.getValue();
733727
}
734728
}
735-
return algorithm;
729+
throw new IllegalArgumentException("no supported SSL/TLS protocol was found in the configured supported protocols: "
730+
+ supportedProtocols);
736731
}
737732
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
import org.elasticsearch.test.ESTestCase;
1010
import javax.crypto.Cipher;
1111
import javax.crypto.SecretKeyFactory;
12+
import javax.net.ssl.SSLContext;
1213

1314
import java.security.NoSuchAlgorithmException;
1415

16+
import static org.hamcrest.Matchers.contains;
1517
import static org.hamcrest.Matchers.containsString;
1618
import static org.hamcrest.Matchers.hasItem;
1719
import static org.hamcrest.Matchers.not;
@@ -48,6 +50,16 @@ public void testPasswordHashingAlgorithmSettingValidation() {
4850
Settings.builder().put(XPackSettings.PASSWORD_HASHING_ALGORITHM.getKey(), bcryptAlgo).build()));
4951
}
5052

53+
public void testDefaultSupportedProtocolsWithTLSv13() throws Exception {
54+
assumeTrue("current JVM does not support TLSv1.3", supportTLSv13());
55+
assertThat(XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS, contains("TLSv1.3", "TLSv1.2", "TLSv1.1"));
56+
}
57+
58+
public void testDefaultSupportedProtocolsWithoutTLSv13() throws Exception {
59+
assumeFalse("current JVM supports TLSv1.3", supportTLSv13());
60+
assertThat(XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS, contains("TLSv1.2", "TLSv1.1"));
61+
}
62+
5163
private boolean isSecretkeyFactoryAlgoAvailable(String algorithmId) {
5264
try {
5365
SecretKeyFactory.getInstance(algorithmId);
@@ -56,4 +68,13 @@ private boolean isSecretkeyFactoryAlgoAvailable(String algorithmId) {
5668
return false;
5769
}
5870
}
71+
72+
private boolean supportTLSv13() {
73+
try {
74+
SSLContext.getInstance("TLSv1.3");
75+
return true;
76+
} catch (NoSuchAlgorithmException e) {
77+
return false;
78+
}
79+
}
5980
}

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ssl/SSLConfigurationReloaderTests.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
import javax.net.ssl.SSLContext;
2828
import javax.net.ssl.SSLHandshakeException;
29-
3029
import java.io.IOException;
3130
import java.io.InputStream;
3231
import java.io.OutputStream;
@@ -263,7 +262,7 @@ public void testReloadingPEMTrustConfig() throws Exception {
263262
try (MockWebServer server = getSslServer(serverKeyPath, serverCertPath, "testnode")) {
264263
final Consumer<SSLContext> trustMaterialPreChecks = (context) -> {
265264
try (CloseableHttpClient client = HttpClients.custom().setSSLContext(context).build()) {
266-
privilegedConnect(() -> client.execute(new HttpGet("https://localhost:" + server.getPort())).close());
265+
privilegedConnect(() -> client.execute(new HttpGet("https://localhost:" + server.getPort())));//.close());
267266
} catch (Exception e) {
268267
throw new RuntimeException("Exception connecting to the mock server", e);
269268
}
@@ -480,7 +479,9 @@ private static MockWebServer getSslServer(Path keyStorePath, String keyStorePass
480479
try (InputStream is = Files.newInputStream(keyStorePath)) {
481480
keyStore.load(is, keyStorePass.toCharArray());
482481
}
483-
final SSLContext sslContext = new SSLContextBuilder().loadKeyMaterial(keyStore, keyStorePass.toCharArray())
482+
final SSLContext sslContext = new SSLContextBuilder()
483+
.loadKeyMaterial(keyStore, keyStorePass.toCharArray())
484+
.setProtocol("TLSv1.2")
484485
.build();
485486
MockWebServer server = new MockWebServer(sslContext, false);
486487
server.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
@@ -494,7 +495,9 @@ private static MockWebServer getSslServer(Path keyPath, Path certPath, String pa
494495
keyStore.load(null, password.toCharArray());
495496
keyStore.setKeyEntry("testnode_ec", PemUtils.readPrivateKey(keyPath, password::toCharArray), password.toCharArray(),
496497
CertParsingUtils.readCertificates(Collections.singletonList(certPath)));
497-
final SSLContext sslContext = new SSLContextBuilder().loadKeyMaterial(keyStore, password.toCharArray())
498+
final SSLContext sslContext = new SSLContextBuilder()
499+
.loadKeyMaterial(keyStore, password.toCharArray())
500+
.setProtocol("TLSv1.2")
498501
.build();
499502
MockWebServer server = new MockWebServer(sslContext, false);
500503
server.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
@@ -509,7 +512,10 @@ private static CloseableHttpClient getSSLClient(Path trustStorePath, String trus
509512
try (InputStream is = Files.newInputStream(trustStorePath)) {
510513
trustStore.load(is, trustStorePass.toCharArray());
511514
}
512-
final SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(trustStore, null).build();
515+
final SSLContext sslContext = new SSLContextBuilder()
516+
.loadTrustMaterial(trustStore, null)
517+
.setProtocol("TLSv1.2")
518+
.build();
513519
return HttpClients.custom().setSSLContext(sslContext).build();
514520
}
515521

@@ -526,7 +532,10 @@ private static CloseableHttpClient getSSLClient(List<Path> trustedCertificatePat
526532
for (Certificate cert : CertParsingUtils.readCertificates(trustedCertificatePaths)) {
527533
trustStore.setCertificateEntry(cert.toString(), cert);
528534
}
529-
final SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(trustStore, null).build();
535+
final SSLContext sslContext = new SSLContextBuilder()
536+
.loadTrustMaterial(trustStore, null)
537+
.setProtocol("TLSv1.2")
538+
.build();
530539
return HttpClients.custom().setSSLContext(sslContext).build();
531540
}
532541

0 commit comments

Comments
 (0)