Skip to content

Commit

Permalink
upgrade bouncy castle jars (#100923)
Browse files Browse the repository at this point in the history
This commit upgrades the Bouncy Castle jars. Bouncy Castle is used for 
some internal build concners as well as a comnand line application. 
Most notably Bouncy Castle is also used as the FIPs certified JCE/JSEE provider 
we use to test our ability to use a FIPs compliant crypto provider. 

The following changes here are a result of the upgraded Bouncy Castle jars:
* TLSv1.3 is now supported when running in FIPs mode 
* RSA PKCS#1 v1.5 is no longer allowed in FIPS mode
* Triple DES (3DES) is no longer allowed in FIPS mode
* Minor updates the security manager configuration used to test FIPs (to read permissions from the security provider)
* Minor adjustments to tests to accommodate the above changes. 
* Minor adjustments to the gradle build to accommodate new dependencies 

Note - update to the documentation will come in a later commit.
  • Loading branch information
jakelandis authored and gmarouli committed Nov 22, 2023
1 parent d249a0f commit 4c5e750
Show file tree
Hide file tree
Showing 20 changed files with 116 additions and 85 deletions.
12 changes: 9 additions & 3 deletions build-tools-internal/src/main/groovy/elasticsearch.fips.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,15 @@ if (BuildParams.inFipsJvm) {
File fipsSecurity = new File(fipsResourcesDir, javaSecurityFilename)
File fipsPolicy = new File(fipsResourcesDir, 'fips_java.policy')
File fipsTrustStore = new File(fipsResourcesDir, 'cacerts.bcfks')
def bcFips = dependencies.create('org.bouncycastle:bc-fips:1.0.2')
def bcTlsFips = dependencies.create('org.bouncycastle:bctls-fips:1.0.9')

def bcFips = dependencies.create('org.bouncycastle:bc-fips:1.0.2.4')
def bcTlsFips = dependencies.create('org.bouncycastle:bctls-fips:1.0.17')
def manualDebug = false; //change this to manually debug bouncy castle in an IDE
if(manualDebug) {
bcFips = dependencies.create('org.bouncycastle:bc-fips-debug:1.0.2.4')
bcTlsFips = dependencies.create('org.bouncycastle:bctls-fips:1.0.17'){
exclude group: 'org.bouncycastle', module: 'bc-fips' // to avoid jar hell
}
}
pluginManager.withPlugin('java-base') {
TaskProvider<ExportElasticsearchBuildResourcesTask> fipsResourcesTask = project.tasks.register('fipsResources', ExportElasticsearchBuildResourcesTask)
fipsResourcesTask.configure {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ public void runThirdPartyAudit() throws IOException {
if (bogousExcludesCount != 0 && bogousExcludesCount == missingClassExcludes.size() + violationsExcludes.size()) {
logForbiddenAPIsOutput(forbiddenApisOutput);
throw new IllegalStateException(
"All excluded classes seem to have no issues. This is sometimes an indication that the check silently failed"
"All excluded classes seem to have no issues. This is sometimes an indication that the check silently failed "
+ "or that exclusions are configured unnecessarily"
);
}
assertNoPointlessExclusions("are not missing", missingClassExcludes, missingClasses);
Expand Down
4 changes: 4 additions & 0 deletions build-tools-internal/src/main/resources/fips_java.policy
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
grant {
permission java.security.SecurityPermission "putProviderProperty.BCFIPS";
permission java.security.SecurityPermission "putProviderProperty.BCJSSE";
permission java.security.SecurityPermission "getProperty.keystore.type.compat";
permission java.security.SecurityPermission "getProperty.jdk.tls.disabledAlgorithms";
permission java.security.SecurityPermission "getProperty.jdk.certpath.disabledAlgorithms";
permission java.security.SecurityPermission "getProperty.jdk.tls.server.defaultDHEParameters";
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.util.PropertyPermission "java.runtime.name", "read";
permission org.bouncycastle.crypto.CryptoServicesPermission "tlsAlgorithmsEnabled";
Expand Down
3 changes: 1 addition & 2 deletions build-tools-internal/version.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@ google_oauth_client = 1.34.1

antlr4 = 4.11.1
# when updating this version, you need to ensure compatibility with:
# - modules/ingest-attachment (transitive dependency, check the upstream POM)
# - distribution/tools/plugin-cli
# - x-pack/plugin/security
bouncycastle=1.64
bouncycastle=1.76
# used by security and idp (need to be in sync due to cross-dependency in testing)
opensaml = 4.3.0

Expand Down
4 changes: 2 additions & 2 deletions distribution/tools/plugin-cli/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ dependencies {
implementation 'org.ow2.asm:asm:9.5'
implementation 'org.ow2.asm:asm-tree:9.5'

api "org.bouncycastle:bcpg-fips:1.0.4"
api "org.bouncycastle:bc-fips:1.0.2"
api "org.bouncycastle:bcpg-fips:1.0.7.1"
api "org.bouncycastle:bc-fips:1.0.2.4"
testImplementation project(":test:framework")
testImplementation "com.google.jimfs:jimfs:${versions.jimfs}"
testRuntimeOnly "com.google.guava:guava:${versions.jimfs_guava}"
Expand Down
44 changes: 27 additions & 17 deletions gradle/verification-metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2997,14 +2997,19 @@
<sha256 value="d749db58c2bd353f1c03541d747b753931d4b84da8e48993ef51efe8694b4ed7" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bc-fips" version="1.0.2">
<artifact name="bc-fips-1.0.2.jar">
<sha256 value="b4340d7a9cc0d3664d6c560e2fcee9c7da6e6ae314855923c758fa32fff5b94e" origin="Generated by Gradle"/>
<component group="org.bouncycastle" name="bc-fips" version="1.0.2.4">
<artifact name="bc-fips-1.0.2.4.jar">
<sha256 value="703ecd8a3a619800269bc8cd442f2ebf469bd2fe70478364f58ddc6460c35f9f" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcpg-fips" version="1.0.4">
<artifact name="bcpg-fips-1.0.4.jar">
<sha256 value="b73c80be1099c4756c088cb457a82040509b787519af5c72c9c3d1bff357565e" origin="Generated by Gradle"/>
<component group="org.bouncycastle" name="bc-fips-debug" version="1.0.2.4">
<artifact name="bc-fips-debug-1.0.2.4.jar">
<sha256 value="a025e947c9c91d023bf2a0a3a74d78d5f8b9f6f0f4de13dc52025f2b996a306b" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcpg-fips" version="1.0.7.1">
<artifact name="bcpg-fips-1.0.7.1.jar">
<sha256 value="fea1a096c098395eb67d48700c349d5f75321ef0c7c6af9198bc38f4cc836622" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcpg-jdk15on" version="1.69">
Expand All @@ -3017,29 +3022,34 @@
<sha256 value="a82ac5bc24bcbf6ba9eb70f334d6782e25245c8da36d9848ad553b5b7b68efd1" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcpkix-jdk15on" version="1.64">
<artifact name="bcpkix-jdk15on-1.64.jar">
<sha256 value="84669138b1d99143e2c009024f67824ab8d3edb9b05b7591f5ebfb020a4bda71" origin="Generated by Gradle"/>
<component group="org.bouncycastle" name="bcpkix-jdk18on" version="1.76">
<artifact name="bcpkix-jdk18on-1.76.jar">
<sha256 value="935a388854c329f9a6f32708f30c90045d2f91294fa687281273145d4cf9834a" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcprov-jdk15on" version="1.60">
<artifact name="bcprov-jdk15on-1.60.jar">
<sha256 value="7f1a0e6badab38666f8467a9a0ee96656b2f8ec8623867ed34f3cdc173b7ee07" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcprov-jdk15on" version="1.64">
<artifact name="bcprov-jdk15on-1.64.jar">
<sha256 value="a4f463ce552b908a722fa198ef4892a226b3225e453f8df10d5c0a5bfe5db6b6" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcprov-jdk15on" version="1.69">
<artifact name="bcprov-jdk15on-1.69.jar">
<sha256 value="e469bd39f936999f256002631003ff022a22951da9d5bd9789c7abfa9763a292" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bctls-fips" version="1.0.9">
<artifact name="bctls-fips-1.0.9.jar">
<sha256 value="ada8549467dda0017e098f2362bd7f00841244351d1fc6f89b9da5ff25890151" origin="Generated by Gradle"/>
<component group="org.bouncycastle" name="bcprov-jdk18on" version="1.76">
<artifact name="bcprov-jdk18on-1.76.jar">
<sha256 value="fda85d777aaae168015860b23a77cad9b8d3a1d5c904fda875313427bd560179" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bctls-fips" version="1.0.17">
<artifact name="bctls-fips-1.0.17.jar">
<sha256 value="51dfd28ec370f27ba4efc10ec8e21129e34e2f2340ac465a6d17a468e0a4696d" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.bouncycastle" name="bcutil-jdk18on" version="1.76">
<artifact name="bcutil-jdk18on-1.76.jar">
<sha256 value="1a65ad02958223a3f31373bd72eea942cafd1b1877a3ed0b492c2487e77c3c27" origin="Generated by Gradle"/>
</artifact>
</component>
<component group="org.carrot2" name="morfologik-fsa" version="2.1.1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import java.nio.file.Path;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -53,12 +52,7 @@ public record SslConfiguration(

static {
LinkedHashMap<String, String> protocolAlgorithmMap = new LinkedHashMap<>();
try {
SSLContext.getInstance("TLSv1.3");
protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
} catch (NoSuchAlgorithmException e) {
// ignore since we support JVMs using BCJSSE in FIPS mode which doesn't support TLSv1.3
}
protocolAlgorithmMap.put("TLSv1.3", "TLSv1.3");
protocolAlgorithmMap.put("TLSv1.2", "TLSv1.2");
protocolAlgorithmMap.put("TLSv1.1", "TLSv1.1");
protocolAlgorithmMap.put("TLSv1", "TLSv1");
Expand Down
5 changes: 4 additions & 1 deletion plugins/discovery-ec2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ tasks.register("writeTestJavaPolicy") {
"permission org.bouncycastle.crypto.CryptoServicesPermission \"exportSecretKey\";",
"permission org.bouncycastle.crypto.CryptoServicesPermission \"exportPrivateKey\";",
"permission java.io.FilePermission \"\${javax.net.ssl.trustStore}\", \"read\";",
" permission java.util.PropertyPermission \"com.amazonaws.sdk.ec2MetadataServiceEndpointOverride\", \"write\";",
"permission java.util.PropertyPermission \"com.amazonaws.sdk.ec2MetadataServiceEndpointOverride\", \"write\";",
"permission java.security.SecurityPermission \"getProperty.jdk.tls.disabledAlgorithms\";",
"permission java.security.SecurityPermission \"getProperty.jdk.certpath.disabledAlgorithms\";",
"permission java.security.SecurityPermission \"getProperty.keystore.type.compat\";",
"};"
].join("\n")
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,14 @@ public void test50AutoConfigurationFailsWhenCertificatesNotGenerated() throws Ex
FileUtils.assertPathsDoNotExist(installation.data);
Path tempDir = createTempDir("bc-backup");
Files.move(
installation.lib.resolve("tools").resolve("security-cli").resolve("bcprov-jdk15on-1.64.jar"),
tempDir.resolve("bcprov-jdk15on-1.64.jar")
installation.lib.resolve("tools").resolve("security-cli").resolve("bcprov-jdk18on-1.76.jar"),
tempDir.resolve("bcprov-jdk18on-1.76.jar")
);
Shell.Result result = runElasticsearchStartCommand(null, false, false);
assertElasticsearchFailure(result, "java.lang.NoClassDefFoundError: org/bouncycastle/", null);
Files.move(
tempDir.resolve("bcprov-jdk15on-1.64.jar"),
installation.lib.resolve("tools").resolve("security-cli").resolve("bcprov-jdk15on-1.64.jar")
tempDir.resolve("bcprov-jdk18on-1.76.jar"),
installation.lib.resolve("tools").resolve("security-cli").resolve("bcprov-jdk18on-1.76.jar")
);
Platforms.onWindows(() -> sh.chown(installation.config));
FileUtils.rm(tempDir);
Expand Down
4 changes: 4 additions & 0 deletions test/test-clusters/src/main/resources/fips/fips_java.policy
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
grant {
permission java.security.SecurityPermission "putProviderProperty.BCFIPS";
permission java.security.SecurityPermission "putProviderProperty.BCJSSE";
permission java.security.SecurityPermission "getProperty.keystore.type.compat";
permission java.security.SecurityPermission "getProperty.jdk.tls.disabledAlgorithms";
permission java.security.SecurityPermission "getProperty.jdk.certpath.disabledAlgorithms";
permission java.security.SecurityPermission "getProperty.jdk.tls.server.defaultDHEParameters";
permission java.lang.RuntimePermission "getProtectionDomain";
permission java.util.PropertyPermission "java.runtime.name", "read";
permission org.bouncycastle.crypto.CryptoServicesPermission "tlsAlgorithmsEnabled";
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugin/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ dependencies {
testImplementation project(path: ':modules:health-shards-availability')
testImplementation project(":client:rest-high-level")
// Needed for Fips140ProviderVerificationTests
testCompileOnly('org.bouncycastle:bc-fips:1.0.2')
testCompileOnly('org.bouncycastle:bc-fips:1.0.2.4')

testImplementation(project(':x-pack:license-tools')) {
transitive = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

package org.elasticsearch.xpack.core;

import org.apache.logging.log4j.LogManager;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.settings.Settings;
Expand All @@ -30,7 +29,6 @@
import java.util.function.Function;

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

import static org.elasticsearch.xpack.core.security.SecurityField.USER_SETTING;
import static org.elasticsearch.xpack.core.security.authc.RealmSettings.DOMAIN_TO_REALM_ASSOC_SETTING;
Expand Down Expand Up @@ -255,19 +253,7 @@ public static Setting<String> defaultStoredHashAlgorithmSetting(String key, Func
}, Property.NodeScope);
}

public static final List<String> DEFAULT_SUPPORTED_PROTOCOLS;

static {
boolean supportsTLSv13 = false;
try {
SSLContext.getInstance("TLSv1.3");
supportsTLSv13 = true;
} catch (NoSuchAlgorithmException e) {
// BCJSSE in FIPS mode doesn't support TLSv1.3 yet.
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 List<String> DEFAULT_SUPPORTED_PROTOCOLS = Arrays.asList("TLSv1.3", "TLSv1.2", "TLSv1.1");

public static final SslClientAuthenticationMode CLIENT_AUTH_DEFAULT = SslClientAuthenticationMode.REQUIRED;
public static final SslClientAuthenticationMode HTTP_CLIENT_AUTH_DEFAULT = SslClientAuthenticationMode.NONE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@
import org.elasticsearch.transport.RemoteClusterPortSettings;

import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.util.List;
import java.util.Locale;

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

import static org.hamcrest.Matchers.contains;
import static org.elasticsearch.xpack.core.XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItem;
Expand Down Expand Up @@ -69,13 +73,29 @@ public void testDefaultPasswordHashingAlgorithmInFips() {
}
}

public void testDefaultSupportedProtocols() {
if (inFipsJvm()) {
assertThat(XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS, contains("TLSv1.2", "TLSv1.1"));
} else {
assertThat(XPackSettings.DEFAULT_SUPPORTED_PROTOCOLS, contains("TLSv1.3", "TLSv1.2", "TLSv1.1"));

public void testDefaultSupportedProtocols() throws NoSuchAlgorithmException {
// TLSv1.3 is recommended but is not required for FIPS-140-3 compliance, government-only applications must use TLS 1.2 or higher
// https://www.gsa.gov/system/files?file=SSL-TLS-Implementation-%5BCIO-IT-Security-14-69-Rev-7%5D-06-12-2023.pdf
List<String> defaultSupportedProtocols = DEFAULT_SUPPORTED_PROTOCOLS.stream().map(s -> s.toLowerCase(Locale.ROOT)).toList();
int i = 0;
Provider[] providers = Security.getProviders();
for (Provider provider : providers) {
for (Provider.Service service : provider.getServices()) {
if ("SSLContext".equalsIgnoreCase(service.getType())) {
if (defaultSupportedProtocols.contains(service.getAlgorithm().toLowerCase(Locale.ROOT))) {
i++;
if (inFipsJvm()) {
// ensure bouncy castle is the provider
assertEquals("BCJSSE", provider.getName());
}
SSLContext.getInstance(service.getAlgorithm()); // ensure no exceptions
}

}

}
}
assertEquals("did not find all supported TLS protocols", i, defaultSupportedProtocols.size());
}

public void testServiceTokenHashingAlgorithmSettingValidation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,7 @@ public void testThatDelegateTrustManagerIsRespected() throws Exception {
if (cert.endsWith("/ca")) {
assertTrusted(trustManager, cert);
} else {
assertNotValid(
trustManager,
cert,
inFipsJvm() ? "unable to process certificates: Unable to find certificate chain." : "PKIX path building failed.*"
);
assertNotValid(trustManager, cert, inFipsJvm() ? "Unable to find certificate chain." : "PKIX path building failed.*");
}
}
}
Expand Down
13 changes: 3 additions & 10 deletions x-pack/plugin/security/cli/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ base {
dependencies {
compileOnly project(":server")
compileOnly project(path: xpackModule('core'))
api "org.bouncycastle:bcpkix-jdk15on:${versions.bouncycastle}"
api "org.bouncycastle:bcprov-jdk15on:${versions.bouncycastle}"
api "org.bouncycastle:bcpkix-jdk18on:${versions.bouncycastle}"
api "org.bouncycastle:bcprov-jdk18on:${versions.bouncycastle}"
api "org.bouncycastle:bcutil-jdk18on:${versions.bouncycastle}"
testImplementation("com.google.jimfs:jimfs:${versions.jimfs}") {
// this is provided by the runtime classpath, from the security project
exclude group: "com.google.guava", module: "guava"
Expand All @@ -35,14 +36,6 @@ tasks.named("test").configure {
systemProperty 'tests.security.manager', 'false' // the main code under test runs without the SecurityManager
}

tasks.named("thirdPartyAudit").configure {
ignoreMissingClasses(
// Used in org.bouncycastle.pqc.crypto.qtesla.QTeslaKeyEncodingTests
'junit.framework.Assert',
'junit.framework.TestCase'
)
}

if (BuildParams.inFipsJvm) {
tasks.named("test").configure {
enabled = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@
/**
* Unit tests for the tool used to simplify SSL certificate generation
*/
// TODO baz - fix this to work in intellij+java9, its complaining about java.sql.Date not being on the classpath
public class CertificateGenerateToolTests extends ESTestCase {

private FileSystem jimfs;
Expand Down Expand Up @@ -515,8 +514,8 @@ private void assertSubjAltNames(GeneralNames subjAltNames, CertificateInformatio
assertThat(seq.getObjectAt(1), instanceOf(DLTaggedObject.class));
DLTaggedObject taggedName = (DLTaggedObject) seq.getObjectAt(1);
assertThat(taggedName.getTagNo(), equalTo(0));
assertThat(taggedName.getObject(), instanceOf(ASN1String.class));
assertThat(taggedName.getObject().toString(), is(in(certInfo.commonNames)));
assertThat(taggedName.getBaseObject(), instanceOf(ASN1String.class));
assertThat(taggedName.getBaseObject().toString(), is(in(certInfo.commonNames)));
} else {
fail("unknown general name with tag " + generalName.getTagNo());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -970,8 +970,8 @@ private void assertSubjAltNames(GeneralNames subjAltNames, CertificateInformatio
assertThat(seq.getObjectAt(0).toString(), equalTo(CN_OID));
assertThat(seq.getObjectAt(1), instanceOf(ASN1TaggedObject.class));
ASN1TaggedObject tagged = (ASN1TaggedObject) seq.getObjectAt(1);
assertThat(tagged.getObject(), instanceOf(ASN1String.class));
assertThat(tagged.getObject().toString(), is(in(certInfo.commonNames)));
assertThat(tagged.getBaseObject(), instanceOf(ASN1String.class));
assertThat(tagged.getBaseObject().toString(), is(in(certInfo.commonNames)));
} else {
fail("unknown general name with tag " + generalName.getTagNo());
}
Expand Down

0 comments on commit 4c5e750

Please sign in to comment.