Make https-trust-store-type set to bcfks by default in strict-mode

Closes #17119
This commit is contained in:
mposolda 2023-02-14 18:57:18 +01:00 committed by Pedro Igor
parent e76418e3de
commit 4f068fcdcc
20 changed files with 72 additions and 50 deletions

View file

@ -80,7 +80,6 @@ public class CryptoIntegration {
.append(" Default keystore type: " + KeyStore.getDefaultType() + "\n")
.append(" KeyManagerFactory.getDefaultAlgorithm(): " + KeyManagerFactory.getDefaultAlgorithm() + "\n")
.append(" TrustManagerFactory.getDefaultAlgorithm(): " + TrustManagerFactory.getDefaultAlgorithm() + "\n")
.append(" Default keystore type: " + KeyStore.getDefaultType() + "\n")
.append(" keystore.type.compat: " + Security.getProperty("keystore.type.compat") + "\n");
Stream.of("javax.net.ssl.trustStoreType", "javax.net.ssl.trustStore", "javax.net.ssl.trustStoreProvider",
"javax.net.ssl.keyStoreType", "javax.net.ssl.keyStore", "javax.net.ssl.keyStoreProvider")

View file

@ -23,7 +23,7 @@ public class KeycloakFipsSecurityProvider extends Provider {
super("KC(" +
bcFipsProvider.toString() +
(isInApprovedOnlyMode() ? " Approved Mode" : "") +
(isSystemFipsEnabled() ? " FIPS-enabled JVM" : "") +
", FIPS-JVM: " + isSystemFipsEnabled() +
")", 1, "Keycloak pseudo provider");
this.bcFipsProvider = bcFipsProvider;
}
@ -39,22 +39,22 @@ public class KeycloakFipsSecurityProvider extends Provider {
}
}
private static boolean isSystemFipsEnabled() {
public static String isSystemFipsEnabled() {
Method isSystemFipsEnabled = null;
try {
Class<?> securityConfigurator = KeycloakFipsSecurityProvider.class.getClassLoader().loadClass("java.security.SystemConfigurator");
isSystemFipsEnabled = securityConfigurator.getDeclaredMethod("isSystemFipsEnabled");
isSystemFipsEnabled.setAccessible(true);
return (boolean) isSystemFipsEnabled.invoke(null);
boolean isEnabled = (boolean) isSystemFipsEnabled.invoke(null);
return isEnabled ? "enabled" : "disabled";
} catch (Throwable ignore) {
logger.debug("Could not detect if FIPS is enabled from the host");
logger.debug("Could not detect if FIPS is enabled from the host", ignore);
return "unknown";
} finally {
if (isSystemFipsEnabled != null) {
isSystemFipsEnabled.setAccessible(false);
}
}
return false;
}
}

View file

@ -97,10 +97,11 @@ public class HttpOptions {
.description("The password of the trust store file.")
.build();
public static final Option HTTPS_TRUST_STORE_TYPE = new OptionBuilder<>("https-trust-store-type", File.class)
public static final Option<String> HTTPS_TRUST_STORE_TYPE = new OptionBuilder<>("https-trust-store-type", String.class)
.category(OptionCategory.HTTP)
.description("The type of the trust store file. " +
"If not given, the type is automatically detected based on the file name.")
"If not given, the type is automatically detected based on the file name. " +
"If '" + SecurityOptions.FIPS_MODE.getKey() + "' is set to '" + FipsMode.strict.name() + "' and no value is set, it defaults to 'BCFKS'.")
.build();
public static final Option<Boolean> HTTP_SERVER_ENABLED = new OptionBuilder<>("http-server-enabled", Boolean.class)

View file

@ -98,6 +98,8 @@ final class HttpPropertyMappers {
.build(),
fromOption(HttpOptions.HTTPS_TRUST_STORE_TYPE)
.to("quarkus.http.ssl.certificate.trust-store-file-type")
.mapFrom(SecurityOptions.FIPS_MODE.getKey())
.transformer(HttpPropertyMappers::resolveKeyStoreType)
.paramLabel("type")
.build()
};

View file

@ -19,6 +19,7 @@ package org.keycloak.it.cli.dist;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import org.keycloak.crypto.fips.KeycloakFipsSecurityProvider;
import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.it.junit5.extension.DistributionTest;
import org.keycloak.it.junit5.extension.RawDistOnly;
@ -38,7 +39,7 @@ public class FipsDistTest {
CLIResult cliResult = dist.run("start", "--fips-mode=enabled");
cliResult.assertStarted();
cliResult.assertMessage("Java security providers: [ \n"
+ " KC(BCFIPS version 1.000203) version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider");
+ " KC(BCFIPS version 1.000203, FIPS-JVM: " + KeycloakFipsSecurityProvider.isSystemFipsEnabled() + ") version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider");
});
}
@ -53,7 +54,7 @@ public class FipsDistTest {
cliResult.assertMessage(
"org.bouncycastle.crypto.fips.FipsUnapprovedOperationError: password must be at least 112 bits");
cliResult.assertMessage("Java security providers: [ \n"
+ " KC(BCFIPS version 1.000203 Approved Mode) version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider");
+ " KC(BCFIPS version 1.000203 Approved Mode, FIPS-JVM: " + KeycloakFipsSecurityProvider.isSystemFipsEnabled() + ") version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider");
dist.setEnvVar("KEYCLOAK_ADMIN_PASSWORD", "adminadminadmin");
cliResult = dist.run("start", "--fips-mode=strict");
@ -87,6 +88,21 @@ public class FipsDistTest {
});
}
@Test
void testHttpsBcfksTrustStoreInStrictMode(KeycloakDistribution dist) {
runOnFipsEnabledDistribution(dist, () -> {
dist.copyOrReplaceFileFromClasspath("/server.keystore.bcfks", Path.of("conf", "server.keystore"));
RawKeycloakDistribution rawDist = dist.unwrap(RawKeycloakDistribution.class);
Path truststorePath = rawDist.getDistPath().resolve("conf").resolve("server.keystore").toAbsolutePath();
// https-trust-store-type should be automatically set to bcfks in fips-mode=strict
CLIResult cliResult = dist.run("--verbose", "start", "--fips-mode=strict", "--https-key-store-password=passwordpassword",
"--https-trust-store-file=" + truststorePath, "--https-trust-store-password=passwordpassword");
cliResult.assertStarted();
});
}
@Test
void testUnsupportedHttpsPkcs12KeyStoreInStrictMode(KeycloakDistribution dist) {
runOnFipsEnabledDistribution(dist, () -> {
@ -105,6 +121,21 @@ public class FipsDistTest {
});
}
@Test
void testHttpsPkcs12TrustStoreInNonApprovedMode(KeycloakDistribution dist) {
runOnFipsEnabledDistribution(dist, () -> {
dist.copyOrReplaceFileFromClasspath("/server.keystore.pkcs12", Path.of("conf", "server.keystore"));
RawKeycloakDistribution rawDist = dist.unwrap(RawKeycloakDistribution.class);
Path truststorePath = rawDist.getDistPath().resolve("conf").resolve("server.keystore").toAbsolutePath();
// https-trust-store-type should be automatically set to pkcs12 in fips-mode=enabled
CLIResult cliResult = dist.run("--verbose", "start", "--fips-mode=enabled", "--https-key-store-password=passwordpassword",
"--https-trust-store-file=" + truststorePath, "--https-trust-store-password=passwordpassword");
cliResult.assertStarted();
});
}
private void runOnFipsEnabledDistribution(KeycloakDistribution dist, Runnable runnable) {
installBcFips(dist);
runnable.run();

View file

@ -143,7 +143,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Health:

View file

@ -143,7 +143,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Health:

View file

@ -203,7 +203,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Health:

View file

@ -203,7 +203,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Health:

View file

@ -149,7 +149,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Health:

View file

@ -149,7 +149,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Health:

View file

@ -209,7 +209,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Health:

View file

@ -209,7 +209,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Health:

View file

@ -108,7 +108,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Proxy:

View file

@ -108,7 +108,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Proxy:

View file

@ -127,7 +127,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Proxy:

View file

@ -127,7 +127,8 @@ HTTP/TLS:
The password of the trust store file.
--https-trust-store-type <type>
The type of the trust store file. If not given, the type is automatically
detected based on the file name.
detected based on the file name. If 'fips-mode' is set to 'strict' and no
value is set, it defaults to 'BCFKS'.
Proxy:

View file

@ -979,5 +979,5 @@ For running testsuite with server using BCFIPS approved mode, those additional p
```
The log should contain `KeycloakFipsSecurityProvider` mentioning "Approved mode". Something like:
```
KC(BCFIPS version 1.000203 Approved Mode) version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider,
KC(BCFIPS version 1.000203 Approved Mode, FIPS-JVM: enabled) version 1.0 - class org.keycloak.crypto.fips.KeycloakFipsSecurityProvider,
```

View file

@ -327,18 +327,15 @@ public abstract class AbstractQuarkusDeployableContainer implements DeployableCo
private void addFipsOptions(List<String> commands) {
commands.add("--fips-mode=" + configuration.getFipsMode().toString());
log.debugf("Keystore file: %s, keystore type: %s, truststore file: %s, truststore type: %s",
configuration.getKeystoreFile(), configuration.getKeystoreType(),
configuration.getTruststoreFile(), configuration.getTruststoreType());
log.debugf("Keystore file: %s, truststore file: %s",
configuration.getKeystoreFile(),
configuration.getTruststoreFile());
commands.add("--https-key-store-file=" + configuration.getKeystoreFile());
commands.add("--https-key-store-type=" + configuration.getKeystoreType());
commands.add("--https-key-store-password=" + configuration.getKeystorePassword());
commands.add("--https-trust-store-file=" + configuration.getTruststoreFile());
commands.add("--https-trust-store-type=" + configuration.getTruststoreType());
commands.add("--https-trust-store-password=" + configuration.getTruststorePassword());
commands.add("--spi-truststore-file-file=" + configuration.getTruststoreFile());
commands.add("--spi-truststore-file-password=" + configuration.getTruststorePassword());
commands.add("--spi-truststore-file-type=" + configuration.getTruststoreType());
// BCFIPS approved mode requires passwords of at least 112 bits (14 characters) to be used. To bypass this, we use this by default
// as testsuite uses shorter passwords everywhere

View file

@ -29,15 +29,11 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration {
private String keystorePassword = System.getProperty("auth.server.keystore.password");
private String keystoreType = System.getProperty("auth.server.keystore.type");
private String truststoreFile = System.getProperty("auth.server.truststore");
private String truststorePassword = System.getProperty("auth.server.truststore.password");
private String truststoreType = System.getProperty("auth.server.truststore.type");
private int debugPort = -1;
private Path providersPath = Paths.get(System.getProperty("auth.server.home"));
private int startupTimeoutInSeconds = 300;
@ -121,14 +117,6 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration {
this.keystorePassword = keystorePassword;
}
public String getKeystoreType() {
return keystoreType;
}
public void setKeystoreType(String keystoreType) {
this.keystoreType = keystoreType;
}
public String getTruststoreFile() {
return truststoreFile;
}
@ -145,14 +133,6 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration {
this.truststorePassword = truststorePassword;
}
public String getTruststoreType() {
return truststoreType;
}
public void setTruststoreType(String truststoreType) {
this.truststoreType = truststoreType;
}
public Path getProvidersPath() {
return providersPath;
}