Skip to content

Commit 239ada1

Browse files
authored
Test adjustments for FIPS 140 (#56526)
This change aims to fix our setup in CI so that we can run 7.x in FIPS 140 mode. The major issue that we have in 7.x and did not have in master is that we can't use the diagnostic trust manager in FIPS mode in Java 8 with SunJSSE in FIPS approved mode as it explicitly disallows the wrapping of X509TrustManager. Previous attempts like #56427 and #52211 focused on disabling the setting in all of our tests when creating a Settings object or on setting fips_mode.enabled accordingly (which implicitly disables the diagnostic trust manager). The attempts weren't future proof though as nothing would forbid someone to add new tests without setting the necessary setting and forcing this would be very inconvenient for any other case ( see #56427 (comment) for the full argumentation). This change introduces a runtime check in SSLService that overrides the configuration value of xpack.security.ssl.diagnose.trust and disables the diagnostic trust manager when we are running in Java 8 and the SunJSSE provider is set in FIPS mode.
1 parent 2a21d4d commit 239ada1

File tree

8 files changed

+89
-27
lines changed

8 files changed

+89
-27
lines changed

libs/ssl-config/src/test/java/org/elasticsearch/common/ssl/PemUtilsTests.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@
2424
import java.io.InputStream;
2525
import java.nio.file.Files;
2626
import java.nio.file.Path;
27+
import java.security.AlgorithmParameters;
2728
import java.security.Key;
2829
import java.security.KeyStore;
2930
import java.security.PrivateKey;
3031
import java.security.interfaces.ECPrivateKey;
32+
import java.security.spec.ECGenParameterSpec;
3133
import java.security.spec.ECParameterSpec;
3234
import java.util.function.Supplier;
3335

@@ -72,8 +74,10 @@ public void testReadEcKeyCurves() throws Exception {
7274
PrivateKey privateKey = PemUtils.readPrivateKey(getDataPath("/certs/pem-utils/private_" + curve + ".pem"), ""::toCharArray);
7375
assertThat(privateKey, instanceOf(ECPrivateKey.class));
7476
ECParameterSpec parameterSpec = ((ECPrivateKey) privateKey).getParams();
75-
// This is brittle but we can't access sun.security.util.NamedCurve
76-
assertThat(parameterSpec.toString(), containsString(curve));
77+
ECGenParameterSpec algorithmParameterSpec = new ECGenParameterSpec(curve);
78+
AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
79+
algoParameters.init(algorithmParameterSpec);
80+
assertThat(parameterSpec, equalTo(algoParameters.getParameterSpec(ECParameterSpec.class)));
7781
}
7882

7983
public void testReadPKCS8EcKey() throws Exception {

plugins/discovery-ec2/build.gradle

+36-8
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,34 @@ task writeTestJavaPolicy {
6464
throw new GradleException("failed to create temporary directory [${tmp}]")
6565
}
6666
final File javaPolicy = file("${tmp}/java.policy")
67-
javaPolicy.write(
68-
[
69-
"grant {",
70-
" permission java.util.PropertyPermission \"com.amazonaws.sdk.ec2MetadataServiceEndpointOverride\", \"write\";",
71-
"};"
72-
].join("\n"))
67+
if (BuildParams.inFipsJvm) {
68+
javaPolicy.write(
69+
[
70+
"grant {",
71+
" permission java.security.SecurityPermission \"putProviderProperty.BCFIPS\";",
72+
" permission java.security.SecurityPermission \"putProviderProperty.BCJSSE\";",
73+
" permission java.lang.RuntimePermission \"getProtectionDomain\";",
74+
" permission java.util.PropertyPermission \"java.runtime.name\", \"read\";",
75+
" permission org.bouncycastle.crypto.CryptoServicesPermission \"tlsAlgorithmsEnabled\";",
76+
" permission java.lang.RuntimePermission \"accessClassInPackage.sun.security.internal.spec\";",
77+
" permission java.lang.RuntimePermission \"accessDeclaredMembers\";",
78+
" permission java.util.PropertyPermission \"intellij.debug.agent\", \"read\";",
79+
" permission java.util.PropertyPermission \"intellij.debug.agent\", \"write\";",
80+
" permission org.bouncycastle.crypto.CryptoServicesPermission \"exportSecretKey\";",
81+
" permission org.bouncycastle.crypto.CryptoServicesPermission \"exportPrivateKey\";",
82+
" permission java.io.FilePermission \"\${javax.net.ssl.trustStore}\", \"read\";",
83+
" permission java.util.PropertyPermission \"com.amazonaws.sdk.ec2MetadataServiceEndpointOverride\", \"write\";",
84+
"};"
85+
].join("\n")
86+
)
87+
} else {
88+
javaPolicy.write(
89+
[
90+
"grant {",
91+
" permission java.util.PropertyPermission \"com.amazonaws.sdk.ec2MetadataServiceEndpointOverride\", \"write\";",
92+
"};"
93+
].join("\n"))
94+
}
7395
}
7496
}
7597

@@ -78,9 +100,15 @@ test {
78100
// this is needed for insecure plugins, remove if possible!
79101
systemProperty 'tests.artifact', project.name
80102

81-
// this is needed to manipulate com.amazonaws.sdk.ec2MetadataServiceEndpointOverride system property
103+
// Setting a custom policy to manipulate com.amazonaws.sdk.ec2MetadataServiceEndpointOverride system property
82104
// it is better rather disable security manager at all with `systemProperty 'tests.security.manager', 'false'`
83-
systemProperty 'java.security.policy', "file://${buildDir}/tmp/java.policy"
105+
if (BuildParams.inFipsJvm){
106+
// Using the key==value format to override default JVM security settings and policy
107+
// see also: https://docs.oracle.com/javase/8/docs/technotes/guides/security/PolicyFiles.html
108+
systemProperty 'java.security.policy', "=file://${buildDir}/tmp/java.policy"
109+
} else {
110+
systemProperty 'java.security.policy', "file://${buildDir}/tmp/java.policy"
111+
}
84112
}
85113

86114
check {

plugins/ingest-attachment/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,6 @@ if (BuildParams.inFipsJvm) {
103103
// rather than provide a long list of exclusions, disable the check on FIPS.
104104
jarHell.enabled = false
105105
test.enabled = false
106-
integTest.enabled = false;
107-
testingConventions.enabled = false;
106+
integTest.enabled = false
107+
testingConventions.enabled = false
108108
}

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.apache.logging.log4j.Logger;
1515
import org.elasticsearch.ElasticsearchException;
1616
import org.elasticsearch.ElasticsearchSecurityException;
17+
import org.elasticsearch.bootstrap.JavaVersion;
1718
import org.elasticsearch.common.CheckedSupplier;
1819
import org.elasticsearch.common.Strings;
1920
import org.elasticsearch.common.logging.DeprecationLogger;
@@ -46,6 +47,7 @@
4647
import java.security.GeneralSecurityException;
4748
import java.security.KeyManagementException;
4849
import java.security.NoSuchAlgorithmException;
50+
import java.security.Security;
4951
import java.security.cert.Certificate;
5052
import java.security.cert.X509Certificate;
5153
import java.util.ArrayList;
@@ -829,11 +831,21 @@ private static String sslContextAlgorithm(List<String> supportedProtocols) {
829831
}
830832

831833
private boolean shouldEnableDiagnoseTrust() {
832-
if (XPackSettings.FIPS_MODE_ENABLED.get(settings) && DIAGNOSE_TRUST_EXCEPTIONS_SETTING.exists(settings) == false ) {
834+
// We disable the DiagnosticTrustManager in Java 8 when SunJSSE is set in FIPS 140 mode, as it doesn't allow X509TrustManager to be
835+
// wrapped
836+
if (inSunJsseInFipsMode()) {
837+
logger.info("diagnostic messages for SSL/TLS trust cannot be enabled for SunJSSE in FIPS mode.");
838+
return false;
839+
} else if (XPackSettings.FIPS_MODE_ENABLED.get(settings) && DIAGNOSE_TRUST_EXCEPTIONS_SETTING.exists(settings) == false) {
833840
logger.info("diagnostic messages for SSL/TLS trust failures are not enabled in FIPS 140 mode by default.");
834841
return false;
835842
} else {
836843
return DIAGNOSE_TRUST_EXCEPTIONS_SETTING.get(settings);
837844
}
838845
}
846+
847+
static boolean inSunJsseInFipsMode() {
848+
return JavaVersion.current().getVersion().get(0) == 8 && Arrays.stream(Security.getProviders())
849+
.anyMatch(provider -> provider.getName().equals("SunJSSE") && provider.getInfo().contains("FIPS mode"));
850+
}
839851
}

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/transport/ProfileConfigurationsTests.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,10 @@ public void testGetInsecureTransportProfileConfigurations() {
5858
}
5959

6060
private Settings.Builder getBaseSettings() {
61-
final Path keystore = randomBoolean()
62-
? getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks")
63-
: getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12");
64-
61+
final Path keystore = inFipsJvm()
62+
? getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12")
63+
: getDataPath(randomFrom("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks",
64+
"/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12"));
6565
MockSecureSettings secureSettings = new MockSecureSettings();
6666
secureSettings.setString("xpack.security.transport.ssl.keystore.secure_password", "testnode");
6767

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
import java.io.InputStream;
1212
import java.nio.file.Files;
1313
import java.nio.file.Path;
14+
import java.security.AlgorithmParameters;
1415
import java.security.Key;
1516
import java.security.KeyStore;
1617
import java.security.PrivateKey;
1718
import java.security.interfaces.ECPrivateKey;
19+
import java.security.spec.ECGenParameterSpec;
1820
import java.security.spec.ECParameterSpec;
1921

2022
import static org.hamcrest.Matchers.equalTo;
@@ -70,8 +72,10 @@ public void testReadEcKeyCurves() throws Exception {
7072
("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/private_" + curve + ".pem"), ""::toCharArray);
7173
assertThat(privateKey, instanceOf(ECPrivateKey.class));
7274
ECParameterSpec parameterSpec = ((ECPrivateKey) privateKey).getParams();
73-
// This is brittle but we can't access sun.security.util.NamedCurve
74-
assertThat(parameterSpec.toString(), containsString(curve));
75+
ECGenParameterSpec algorithmParameterSpec = new ECGenParameterSpec(curve);
76+
AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
77+
algoParameters.init(algorithmParameterSpec);
78+
assertThat(parameterSpec, equalTo(algoParameters.getParameterSpec(ECParameterSpec.class)));
7579
}
7680

7781
public void testReadEncryptedPKCS8Key() throws Exception {

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

+16-8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import java.util.concurrent.atomic.AtomicInteger;
6363

6464
import static org.elasticsearch.test.TestMatchers.throwableWithMessage;
65+
import static org.elasticsearch.xpack.core.ssl.SSLService.inSunJsseInFipsMode;
6566
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
6667
import static org.hamcrest.Matchers.contains;
6768
import static org.hamcrest.Matchers.containsString;
@@ -90,14 +91,19 @@ public class SSLServiceTests extends ESTestCase {
9091

9192
@Before
9293
public void setup() throws Exception {
93-
// Randomise the keystore type (jks/PKCS#12)
94-
if (randomBoolean()) {
95-
testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
96-
// The default is to use JKS. Randomly test with explicit and with the default value.
97-
testnodeStoreType = "jks";
98-
} else {
94+
// Randomise the keystore type (jks/PKCS#12) when possible
95+
if (inFipsJvm()) {
9996
testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12");
10097
testnodeStoreType = randomBoolean() ? "PKCS12" : null;
98+
} else {
99+
if (randomBoolean()) {
100+
testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks");
101+
// The default is to use JKS. Randomly test with explicit and with the default value.
102+
testnodeStoreType = "jks";
103+
} else {
104+
testnodeStore = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.p12");
105+
testnodeStoreType = randomBoolean() ? "PKCS12" : null;
106+
}
101107
}
102108
logger.info("Using [{}] key/truststore [{}]", testnodeStoreType, testnodeStore);
103109
testnodeCert = getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt");
@@ -820,6 +826,7 @@ public void testThatSSLIOSessionStrategyTrustsJDKTrustedCAs() throws Exception {
820826
}
821827

822828
public void testWrapTrustManagerWhenDiagnosticsEnabled() {
829+
assumeFalse("We explicitly disable diagnostic trust manager in SunJSSE in FIPS mode ", inSunJsseInFipsMode());
823830
final Settings.Builder builder = Settings.builder();
824831
if (randomBoolean()) { // randomly select between default, and explicit enabled
825832
builder.put("xpack.security.ssl.diagnose.trust", true);
@@ -841,7 +848,7 @@ public void testDontWrapTrustManagerWhenDiagnosticsDisabled() {
841848
assertThat(sslService.wrapWithDiagnostics(baseTrustManager, sslConfiguration), sameInstance(baseTrustManager));
842849
}
843850

844-
public void testDontWrapTrustManagerByDefaultWhenInFips(){
851+
public void testDontWrapTrustManagerByDefaultWhenInFips() {
845852
final Settings.Builder builder = Settings.builder();
846853
builder.put("xpack.security.fips_mode.enabled", true);
847854
final SSLService sslService = new SSLService(builder.build(), env);
@@ -850,7 +857,8 @@ public void testDontWrapTrustManagerByDefaultWhenInFips(){
850857
assertThat(sslService.wrapWithDiagnostics(baseTrustManager, sslConfiguration), sameInstance(baseTrustManager));
851858
}
852859

853-
public void testWrapTrustManagerWhenInFipsAndExplicitlyConfigured(){
860+
public void testWrapTrustManagerWhenInFipsAndExplicitlyConfigured() {
861+
assumeFalse("We explicitly disable diagnostic trust manager in SunJSSE in FIPS mode ", inSunJsseInFipsMode());
854862
final Settings.Builder builder = Settings.builder();
855863
builder.put("xpack.security.fips_mode.enabled", true);
856864
builder.put("xpack.security.ssl.diagnose.trust", true);

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/ssl/SSLReloadDuringStartupIntegTests.java

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
1414
import org.elasticsearch.test.InternalTestCluster.RestartCallback;
1515
import org.elasticsearch.test.SecurityIntegTestCase;
16+
import org.junit.BeforeClass;
1617

1718
import java.io.IOException;
1819
import java.io.UncheckedIOException;
@@ -28,6 +29,11 @@
2829
@ClusterScope(transportClientRatio = 0)
2930
public class SSLReloadDuringStartupIntegTests extends SecurityIntegTestCase {
3031

32+
@BeforeClass
33+
public static void skipInFips() {
34+
assumeFalse("Can't use JKS keystores in FIPS JVM", inFipsJvm());
35+
}
36+
3137
@Override
3238
public Settings nodeSettings(int nodeOrdinal) {
3339
Settings settings = super.nodeSettings(nodeOrdinal);

0 commit comments

Comments
 (0)