Update ciphers for TLSv1.3 and JDK11 if available (#42082)

This commit updates the default ciphers and TLS protocols that are used
when the runtime JDK supports them. New cipher support has been
introduced in JDK 11 and 12 along with performance fixes for AES GCM.
The ciphers are ordered with PFS ciphers being most preferred, then
AEAD ciphers, and finally those with mainstream hardware support. When
available stronger encryption is preferred for a given cipher.

This is a backport of #41385 and #41808. There are known JDK bugs with
TLSv1.3 that have been fixed in various versions. These are:

1. The JDK's bundled HttpsServer will endless loop under JDK11 and JDK
12.0 (Fixed in 12.0.1) based on the way the Apache HttpClient performs
a close (half close).
2. In all versions of JDK 11 and 12, the HttpsServer will endless loop
when certificates are not trusted or another handshake error occurs. An
email has been sent to the openjdk security-dev list and #38646 is open
to track this.
3. In JDK 11.0.2 and prior there is a race condition with session
resumption that leads to handshake errors when multiple concurrent
handshakes are going on between the same client and server. This bug
does not appear when client authentication is in use. This is
JDK-8213202, which was fixed in 11.0.3 and 12.0.
4. In JDK 11.0.2 and prior there is a bug where resumed TLS sessions do
not retain peer certificate information. This is JDK-8212885.

The way these issues are addressed is that the current java version is
checked and used to determine the supported protocols for tests that
provoke these issues.
This commit is contained in:
Jay Modi 2019-05-20 09:45:36 -04:00 committed by GitHub
parent fd2d4d761b
commit dbbdcea128
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 554 additions and 89 deletions

View File

@ -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,37 @@ public class RestClientBuilderIntegTests extends RestClientTestCase {
}
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";
}
}

View File

@ -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]]

View File

@ -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;
@ -338,30 +340,53 @@ public abstract class SslConfigurationLoader {
}
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;
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 {
ciphers.addAll(Arrays.asList("TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA"));
}
return ciphers;
}
private static boolean has256BitAES() {

View File

@ -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 -> {

View File

@ -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,30 @@ 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("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++) {

View File

@ -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;
@ -118,6 +119,20 @@ public class 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.*)
@ -125,24 +140,58 @@ public class XPackSettings {
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) {
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_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) {
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);
}
/*
@ -164,20 +213,6 @@ 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 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;

View File

@ -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,10 @@ 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.Collections;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
@ -98,6 +105,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 +193,23 @@ 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("11")) < 0) {
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
} else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) {
return Collections.singletonList("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 Collections.singletonList("TLSv1.2");
}
}
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
}
}

View File

@ -438,7 +438,7 @@ public class SSLDriver implements AutoCloseable {
SSLEngineResult result = unwrap(encryptedBuffer, applicationBuffer);
boolean renegotiationRequested = result.getStatus() != SSLEngineResult.Status.CLOSED
&& maybeRenegotiation(result.getHandshakeStatus());
continueUnwrap = result.bytesProduced() > 0 && renegotiationRequested == false;
continueUnwrap = result.bytesConsumed() > 0 && renegotiationRequested == false;
}
}

View File

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

View File

@ -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();

View File

@ -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,23 @@ 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("11")) < 0) {
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
} else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) {
return Collections.singletonList("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 Collections.singletonList("TLSv1.2");
}
}
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
}
}

View File

@ -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()) {

View File

@ -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;
@ -80,8 +79,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 +109,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"));
Arrays.asList("/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 +149,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"));
Arrays.asList("/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);

View File

@ -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.equalTo;
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"), equalTo("TLS_AES_256_GCM_SHA384"), equalTo("TLS_AES_128_GCM_SHA256")));
}
}

View File

@ -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;
@ -116,6 +121,7 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
try(TransportClient transportClient = new TestXPackTransportClient(Settings.builder()
.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)) {
@ -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,9 @@ 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"));
builder.putList("xpack.security.transport.ssl.supported_protocols", getProtocols());
try (TransportClient transportClient = createTransportClient(builder.build())) {
transportClient.addTransportAddress(new TransportAddress(localAddress,
getProfilePort("no_client_auth")));
@ -195,7 +204,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())) {
TransportAddress transportAddress = randomFrom(internalCluster().getInstance(Transport.class).boundAddress().boundAddresses());
transportClient.addTransportAddress(transportAddress);
@ -273,8 +283,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put(SecurityField.USER_SETTING.getKey(), TEST_USER_NAME + ":" + TEST_PASSWORD)
.put("cluster.name", internalCluster().getClusterName())
.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.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())
.putList("xpack.security.transport.ssl.supported_protocols", getProtocols())
.build();
try (TransportClient transportClient = new TestXPackTransportClient(settings,
Collections.singletonList(LocalStateSecurity.class))) {
@ -294,8 +306,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put("cluster.name", internalCluster().getClusterName())
.put("xpack.security.transport.ssl.enabled", true)
.put("xpack.security.transport.ssl.client_authentication", SSLClientAuth.REQUIRED)
.put("xpack.security.transport.ssl.certificate_authorities",
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"))
.putList("xpack.security.transport.ssl.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())
.putList("xpack.security.transport.ssl.supported_protocols", getProtocols())
.build();
try (TransportClient transportClient = new TestXPackTransportClient(settings,
Collections.singletonList(LocalStateSecurity.class))) {
@ -318,8 +332,10 @@ public class SslMultiPortTests extends SecurityIntegTestCase {
.put("cluster.name", internalCluster().getClusterName())
.put("xpack.security.transport.ssl.enabled", true)
.put("xpack.security.transport.ssl.client_authentication", SSLClientAuth.REQUIRED)
.put("xpack.security.transport.ssl.certificate_authorities",
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt"))
.putList("xpack.security.transport.ssl.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())
.putList("xpack.security.transport.ssl.supported_protocols", getProtocols())
.build();
try (TransportClient transportClient = new TestXPackTransportClient(settings,
Collections.singletonList(LocalStateSecurity.class))) {
@ -409,4 +425,21 @@ 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() {
if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) {
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
}
JavaVersion full =
AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
if (full.compareTo(JavaVersion.parse("11.0.3")) < 0) {
return Collections.singletonList("TLSv1.2");
}
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
}
}

View File

@ -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;
@ -101,7 +106,7 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
return true;
}
public void testThatHttpFailsWithoutSslClientAuth() throws IOException {
public void testThatHttpFailsWithoutSslClientAuth() {
SSLIOSessionStrategy sessionStrategy = new SSLIOSessionStrategy(SSLContexts.createDefault(), NoopHostnameVerifier.INSTANCE);
try (RestClient restClient = createRestClient(httpClientBuilder -> httpClientBuilder.setSSLStrategy(sessionStrategy), "https")) {
restClient.performRequest(new Request("GET", "/"));
@ -130,11 +135,12 @@ public class SSLClientAuthTests extends SecurityIntegTestCase {
}
}
public void testThatTransportWorksWithoutSslClientAuth() throws IOException {
public void testThatTransportWorksWithoutSslClientAuth() {
// specify an arbitrary key and certificate - not the certs needed to connect to the transport protocol
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,19 @@ 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");
final SSLContext context;
if (XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS.contains("TLSv1.3")) {
context = SSLContext.getInstance(randomBoolean() ? "TLSv1.3" : "TLSv1.2");
} else {
context = SSLContext.getInstance("TLSv1.2");
}
context.init(new KeyManager[] { km }, new TrustManager[] { tm }, new SecureRandom());
return context;
} catch (Exception e) {
@ -188,4 +202,21 @@ 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() {
if (JavaVersion.current().compareTo(JavaVersion.parse("11")) < 0) {
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
}
JavaVersion full =
AccessController.doPrivileged((PrivilegedAction<JavaVersion>) () -> JavaVersion.parse(System.getProperty("java.version")));
if (full.compareTo(JavaVersion.parse("11.0.3")) < 0) {
return Collections.singletonList("TLSv1.2");
}
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
}
}

View File

@ -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);

View File

@ -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());
}
}
}
}

View File

@ -34,3 +34,116 @@ keytool -importkeystore -destkeystore <NAME>.jks -srckeystore <NAME>.p12 -srcsto
The keystore is now created and has the private/public key pair. You can import additional trusted certificates using
`keytool -importcert`. When doing so make sure to specify an alias so that others can recreate the keystore if necessary.
=== Changes and additions for removing Bouncy Castle Dependency
`testnode-unprotected.pem` is simply the decrypted `testnode.pem`
------
openssl rsa -in testnode.pem -out testnode-unprotected.pem
------
`rsa_key_pkcs8_plain.pem` is the same plaintext key encoded in `PKCS#8`
------
openssl pkcs8 -topk8 -inform PEM -outform PEM -in testnode-unprotected.pem -out rsa_key_pkcs8_plain.pem -nocrypt
------
`testnode-aes{128,192,256}.pem` is the testnode.pem private key, encrypted with `AES-128`, `AES-192` and `AES-256`
respectively, encoded in `PKCS#1`
[source,shell]
------
openssl rsa -aes128 -in testnode-unprotected.pem -out testnode-aes128.pem
------
[source,shell]
------
openssl rsa -aes192 -in testnode-unprotected.pem -out testnode-aes192.pem
------
[source,shell]
------
openssl rsa -aes256 -in testnode-unprotected.pem -out testnode-aes256.pem
------
Adding `DSA` and `EC` Keys to the Keystore
[source,shell]
------
keytool -genkeypair -keyalg DSA -alias testnode_dsa -keystore testnode.jks -storepass testnode \
-keypass testnode -validity 10000 -keysize 1024 -dname "CN=Elasticsearch Test Node" \
-ext SAN=dns:localhost,dns:localhost.localdomain,dns:localhost4,dns:localhost4.localdomain4,dns:localhost6,dns:localhost6.localdomain6,ip:127.0.0.1,ip:0:0:0:0:0:0:0:1
------
[source,shell]
------
keytool -genkeypair -keyalg EC -alias testnode_ec -keystore testnode.jks -storepass testnode \
-keypass testnode -validity 10000 -keysize 256 -dname "CN=Elasticsearch Test Node" \
-ext SAN=dns:localhost,dns:localhost.localdomain,dns:localhost4,dns:localhost4.localdomain4,dns:localhost6,dns:localhost6.localdomain6,ip:127.0.0.1,ip:0:0:0:0:0:0:0:1
------
Exporting the `DSA` and `EC` private keys from the keystore
[source,shell]
----
keytool -importkeystore -srckeystore testnode.jks -destkeystore dsa.p12 -deststoretype PKCS12 \
-srcalias testnode_dsa -deststorepass testnode -destkeypass testnode
----
[source,shell]
----
openssl pkcs12 -in dsa.p12 -nodes -nocerts | openssl pkcs8 -topk8 -nocrypt -outform pem \
-out dsa_key_pkcs8_plain.pem
----
[source,shell]
----
keytool -importkeystore -srckeystore testnode.jks -destkeystore ec.p12 -deststoretype PKCS12 \
-srcalias testnode_ec -deststorepass testnode -destkeypass testnode
----
[source,shell]
----
openssl pkcs12 -in ec.p12 -nodes -nocerts | openssl pkcs8 -topk8 -nocrypt -outform pem \
-out ec_key_pkcs8_plain.pem
----
Create `PKCS#8` encrypted key from the encrypted `PKCS#1` encoded `testnode.pem`
[source,shell]
-----
openssl pkcs8 -topk8 -inform PEM -outform PEM -in testnode.pem -out key_pkcs8_encrypted.pem
-----
[source,shell]
-----
ssh-keygen -t ed25519 -f key_unsupported.pem
-----
Convert `prime256v1-key-noparam.pem` to `PKCS#8` format
-----
openssl pkcs8 -topk8 -in prime256v1-key-noparam.pem -nocrypt -out prime256v1-key-noparam-pkcs8.pem
-----
Generate the keys and self-signed certificates in `nodes/self/` :
------
openssl req -newkey rsa:2048 -keyout n1.c1.key -x509 -days 3650 -subj "/CN=n1.c1" -reqexts SAN \
-extensions SAN -config <(cat /etc/ssl/openssl.cnf \
<(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node1.cluster1")) -out n1.c1.crt
------
Create a `CA` keypair for testing
[source,shell]
-----
openssl req -newkey rsa:2048 -nodes -keyout ca.key -x509 -subj "/CN=certAuth" -days 10000 -out ca.crt
-----
Generate Certificates signed with our CA for testing
[source,shell]
------
 openssl req -new -newkey rsa:2048 -keyout n2.c2.key -reqexts SAN -extensions SAN \
-config <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node2.cluster2"))\
-out n2.c2.csr
------
[source,shell]
------
openssl x509 -req -in n2.c2.csr -extensions SAN -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(cat /etc/ssl/openssl.cnf <(printf "[SAN]\nsubjectAltName=otherName.1:2.5.4.3;UTF8:node2.cluster2"))\
-out n2.c2.crt -days 10000
------

View File

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB7zCCAZOgAwIBAgIEcmggOzAMBggqhkjOPQQDAgUAMCIxIDAeBgNVBAMTF0Vs
YXN0aWNzZWFyY2ggVGVzdCBOb2RlMB4XDTE4MDUxNzA5MzYxMFoXDTQ1MTAwMjA5
MzYxMFowIjEgMB4GA1UEAxMXRWxhc3RpY3NlYXJjaCBUZXN0IE5vZGUwWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAATuZRlXGn/ROcO7yFJJ50b20YvgV3U+FpRx0nx/
yigWj6xiEMKnWbbUnM0mKF8c3GHGk5g8OXPnbK96uj6tpMB5o4G0MIGxMB0GA1Ud
DgQWBBRNAGO77mUhG6SQvIXQTbpcFwlf2TCBjwYDVR0RBIGHMIGEgglsb2NhbGhv
c3SCFWxvY2FsaG9zdC5sb2NhbGRvbWFpboIKbG9jYWxob3N0NIIXbG9jYWxob3N0
NC5sb2NhbGRvbWFpbjSCCmxvY2FsaG9zdDaCF2xvY2FsaG9zdDYubG9jYWxkb21h
aW42hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMAwGCCqGSM49BAMCBQADSAAwRQIg
Z3IvdmY5LFdbxoVSs6pV2tJ5+U833Chu0+ZzPo77IVUCIQDRx1FVitVuzBpqwhSW
+Zprt2RLPllC4s4BCApGDh8i1g==
-----END CERTIFICATE-----

View File

@ -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,10 @@ import org.junit.After;
import org.junit.Before;
import java.nio.file.Path;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.elasticsearch.xpack.watcher.client.WatchSourceBuilders.watchBuilder;
@ -51,6 +58,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 +139,23 @@ 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("11")) < 0) {
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
} else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) {
return Collections.singletonList("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 Collections.singletonList("TLSv1.2");
}
}
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
}
}

View File

@ -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.http.ssl.supported_protocols", getProtocols())
.setSecureSettings(serverSecureSettings)
.build();
TestsSSLService sslService = new TestsSSLService(serverSettings, environment);
@ -383,6 +393,7 @@ public class HttpClientTests extends ESTestCase {
.put(HttpSettings.PROXY_PORT.getKey(), proxyServer.getPort())
.put(HttpSettings.PROXY_SCHEME.getKey(), "https")
.put("xpack.http.ssl.certificate_authorities", trustedCertPath)
.putList("xpack.http.ssl.supported_protocols", getProtocols())
.build();
HttpRequest.Builder requestBuilder = HttpRequest.builder("localhost", webServer.getPort())
@ -737,4 +748,23 @@ 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("11")) < 0) {
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
} else if (JavaVersion.current().compareTo(JavaVersion.parse("12")) < 0) {
return Collections.singletonList("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 Collections.singletonList("TLSv1.2");
}
}
return XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
}
}

View File

@ -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',