diff --git a/crypto/default/src/main/java/org/keycloak/crypto/def/BCCertificateUtilsProvider.java b/crypto/default/src/main/java/org/keycloak/crypto/def/BCCertificateUtilsProvider.java index 98ca18c9015..af05b681724 100755 --- a/crypto/default/src/main/java/org/keycloak/crypto/def/BCCertificateUtilsProvider.java +++ b/crypto/default/src/main/java/org/keycloak/crypto/def/BCCertificateUtilsProvider.java @@ -91,7 +91,7 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider { X500Name subjectDN = new X500Name("CN=" + subject); // Serial Number - SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); + SecureRandom random = new SecureRandom(); BigInteger serialNumber = BigInteger.valueOf(Math.abs(random.nextInt())); // Validity diff --git a/crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java b/crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java index d9a1db967c7..ac450f0aa6f 100644 --- a/crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java +++ b/crypto/default/src/main/java/org/keycloak/crypto/def/BCEcdhEsAlgorithmProvider.java @@ -130,7 +130,7 @@ public class BCEcdhEsAlgorithmProvider implements JWEAlgorithmProvider { private static KeyPair generateEcKeyPair(ECParameterSpec params) { try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); - SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG"); + SecureRandom randomGen = new SecureRandom(); keyGen.initialize(params, randomGen); return keyGen.generateKeyPair(); } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException e) { diff --git a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSCertificateUtilsProvider.java b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSCertificateUtilsProvider.java index 5a1bd610bea..51e12e096c5 100755 --- a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSCertificateUtilsProvider.java +++ b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/BCFIPSCertificateUtilsProvider.java @@ -92,7 +92,7 @@ public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{ X500Name subjectDN = new X500Name("CN=" + subject); // Serial Number - SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); + SecureRandom random = new SecureRandom(); BigInteger serialNumber = BigInteger.valueOf(Math.abs(random.nextInt())); // Validity diff --git a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java index 5796e4f9d60..e590cef8872 100644 --- a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java +++ b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPS1402Provider.java @@ -1,6 +1,7 @@ package org.keycloak.crypto.fips; import java.io.IOException; +import java.lang.reflect.Method; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; @@ -46,6 +47,7 @@ import javax.net.ssl.TrustManagerFactory; import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.fips.FipsRSA; import org.bouncycastle.crypto.fips.FipsSHS; import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider; @@ -91,17 +93,20 @@ public class FIPS1402Provider implements CryptoProvider { providers.put(CryptoConstants.ECDH_ES_A192KW, new BCFIPSEcdhEsAlgorithmProvider()); providers.put(CryptoConstants.ECDH_ES_A256KW, new BCFIPSEcdhEsAlgorithmProvider()); - Security.insertProviderAt(new KeycloakFipsSecurityProvider(bcFipsProvider), 1); if (existingBcFipsProvider == null) { - checkSecureRandom(() -> Security.insertProviderAt(this.bcFipsProvider, 2)); + checkSecureRandom(() -> Security.insertProviderAt(this.bcFipsProvider, 1)); Provider bcJsseProvider = new BouncyCastleJsseProvider("fips:BCFIPS"); - Security.insertProviderAt(bcJsseProvider, 3); + Security.insertProviderAt(bcJsseProvider, 2); // force the key and trust manager factories if default values not present in BCJSSE modifyKeyTrustManagerSecurityProperties(bcJsseProvider); log.debugf("Inserted security providers: %s", Arrays.asList(this.bcFipsProvider.getName(),bcJsseProvider.getName())); } else { log.debugf("Security provider %s already loaded", existingBcFipsProvider.getName()); } + + log.infof("FIPS1402Provider created: KC(%s%s, FIPS-JVM: %s)", bcFipsProvider, + CryptoServicesRegistrar.isInApprovedOnlyMode() ? " Approved Mode" : "", + isSystemFipsEnabled()); } @@ -388,4 +393,23 @@ public class FIPS1402Provider implements CryptoProvider { throw new IllegalStateException("Provider " + bcJsseProvider.getName() + " does not provide KeyManagerFactory or TrustManagerFactory algorithms for TLS"); } + + public static String isSystemFipsEnabled() { + Method isSystemFipsEnabled = null; + + try { + Class securityConfigurator = FIPS1402Provider.class.getClassLoader().loadClass("java.security.SystemConfigurator"); + isSystemFipsEnabled = securityConfigurator.getDeclaredMethod("isSystemFipsEnabled"); + isSystemFipsEnabled.setAccessible(true); + boolean isEnabled = (boolean) isSystemFipsEnabled.invoke(null); + return isEnabled ? "enabled" : "disabled"; + } catch (Throwable ignore) { + log.debug("Could not detect if FIPS is enabled from the host", ignore); + return "unknown"; + } finally { + if (isSystemFipsEnabled != null) { + isSystemFipsEnabled.setAccessible(false); + } + } + } } diff --git a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/KeycloakFipsSecurityProvider.java b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/KeycloakFipsSecurityProvider.java deleted file mode 100644 index f32b48a2ebb..00000000000 --- a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/KeycloakFipsSecurityProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.keycloak.crypto.fips; - -import static org.bouncycastle.crypto.CryptoServicesRegistrar.isInApprovedOnlyMode; - -import java.lang.reflect.Method; -import java.security.Provider; - -import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider; -import org.jboss.logging.Logger; - -/** - * Security provider to workaround usage of potentially unsecured algorithms by 3rd party dependencies. - * - * @author Marek Posolda - */ -public class KeycloakFipsSecurityProvider extends Provider { - - protected static final Logger logger = Logger.getLogger(KeycloakFipsSecurityProvider.class); - - private final BouncyCastleFipsProvider bcFipsProvider; - - public KeycloakFipsSecurityProvider(BouncyCastleFipsProvider bcFipsProvider) { - super("KC(" + - bcFipsProvider.toString() + - (isInApprovedOnlyMode() ? " Approved Mode" : "") + - ", FIPS-JVM: " + isSystemFipsEnabled() + - ")", 1, "Keycloak pseudo provider"); - this.bcFipsProvider = bcFipsProvider; - logger.infof("KeycloakFipsSecurityProvider created: %s", this.toString()); - } - - @Override - public synchronized final Service getService(String type, String algorithm) { - // Using 'SecureRandom.getInstance("SHA1PRNG")' will delegate to BCFIPS DEFAULT provider instead of returning SecureRandom based on potentially unsecure SHA1PRNG - if ("SHA1PRNG".equals(algorithm) && "SecureRandom".equals(type)) { - logger.debug("Returning DEFAULT algorithm of BCFIPS provider instead of SHA1PRNG"); - return this.bcFipsProvider.getService("SecureRandom", "DEFAULT"); - } else { - return null; - } - } - - public static String isSystemFipsEnabled() { - Method isSystemFipsEnabled = null; - - try { - Class securityConfigurator = KeycloakFipsSecurityProvider.class.getClassLoader().loadClass("java.security.SystemConfigurator"); - isSystemFipsEnabled = securityConfigurator.getDeclaredMethod("isSystemFipsEnabled"); - isSystemFipsEnabled.setAccessible(true); - 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", ignore); - return "unknown"; - } finally { - if (isSystemFipsEnabled != null) { - isSystemFipsEnabled.setAccessible(false); - } - } - } -} diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402SecureRandomTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402SecureRandomTest.java index 004c20c4ab0..509cc2e7650 100644 --- a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402SecureRandomTest.java +++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402SecureRandomTest.java @@ -38,16 +38,13 @@ public class FIPS1402SecureRandomTest { SecureRandom sc1 = new SecureRandom(); logger.infof(dumpSecureRandom("new SecureRandom()", sc1)); + Assert.assertEquals("DEFAULT", sc1.getAlgorithm()); + Assert.assertEquals("BCFIPS", sc1.getProvider().getName()); SecureRandom sc2 = SecureRandom.getInstance("DEFAULT", "BCFIPS"); logger.infof(dumpSecureRandom("SecureRandom.getInstance(\"DEFAULT\", \"BCFIPS\")", sc2)); Assert.assertEquals("DEFAULT", sc2.getAlgorithm()); Assert.assertEquals("BCFIPS", sc2.getProvider().getName()); - - SecureRandom sc3 = SecureRandom.getInstance("SHA1PRNG"); - logger.infof(dumpSecureRandom("SecureRandom.getInstance(\"SHA1PRNG\")", sc3)); - Assert.assertEquals("SHA1PRNG", sc3.getAlgorithm()); - Assert.assertEquals("BCFIPS", sc3.getProvider().getName()); } diff --git a/docs/guides/server/fips.adoc b/docs/guides/server/fips.adoc index b0b9cd77a5f..58d73931108 100644 --- a/docs/guides/server/fips.adoc +++ b/docs/guides/server/fips.adoc @@ -122,7 +122,7 @@ When starting the server, you can check that the startup log contains `KC` provi [source] ---- -KeycloakFipsSecurityProvider created: KC(BCFIPS version 2.0102 Approved Mode, FIPS-JVM: enabled) version 1.0 +FIPS1402Provider created: KC(BCFIPS version 2.0102 Approved Mode, FIPS-JVM: enabled) ---- === Cryptography restrictions in strict mode diff --git a/pom.xml b/pom.xml index 0a528f0bb07..b3579c32d98 100644 --- a/pom.xml +++ b/pom.xml @@ -126,7 +126,7 @@ 6.0.3 1.5.4.Final-format-001 1.6.0.Final - 2.2.6 + 3.0.4 15.4 1.6.1 2.0 diff --git a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java index 3e441e570ed..151c4f72a6c 100644 --- a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java +++ b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/FipsDistTest.java @@ -21,7 +21,7 @@ import java.nio.file.Path; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; -import org.keycloak.crypto.fips.KeycloakFipsSecurityProvider; +import org.keycloak.crypto.fips.FIPS1402Provider; import org.keycloak.it.junit5.extension.CLIResult; import org.keycloak.it.junit5.extension.DistributionTest; import org.keycloak.it.junit5.extension.RawDistOnly; @@ -44,7 +44,7 @@ public class FipsDistTest { cliResult.assertStarted(); // Not shown as FIPS is not a preview anymore cliResult.assertMessageWasShownExactlyNumberOfTimes("Preview features enabled: fips:v1", 0); - cliResult.assertMessage("KeycloakFipsSecurityProvider created: KC(" + BCFIPS_VERSION + ", FIPS-JVM: " + KeycloakFipsSecurityProvider.isSystemFipsEnabled() + ") version 1.0"); + cliResult.assertMessage("FIPS1402Provider created: KC(" + BCFIPS_VERSION + ", FIPS-JVM: " + FIPS1402Provider.isSystemFipsEnabled() + ")"); }); } @@ -56,7 +56,7 @@ public class FipsDistTest { CLIResult cliResult = dist.run("start", "--fips-mode=strict"); cliResult.assertMessage("password must be at least 112 bits"); - cliResult.assertMessage("KeycloakFipsSecurityProvider created: KC(" + BCFIPS_VERSION + " Approved Mode, FIPS-JVM: " + KeycloakFipsSecurityProvider.isSystemFipsEnabled() + ") version 1.0"); + cliResult.assertMessage("FIPS1402Provider created: KC(" + BCFIPS_VERSION + " Approved Mode, FIPS-JVM: " + FIPS1402Provider.isSystemFipsEnabled() + ")"); dist.setEnvVar("KC_BOOTSTRAP_ADMIN_PASSWORD", "adminadminadmin"); cliResult = dist.run("start", "--fips-mode=strict"); diff --git a/services/src/main/java/org/keycloak/keys/AbstractEcKeyProviderFactory.java b/services/src/main/java/org/keycloak/keys/AbstractEcKeyProviderFactory.java index fc145594bd1..c0c5e3010f1 100644 --- a/services/src/main/java/org/keycloak/keys/AbstractEcKeyProviderFactory.java +++ b/services/src/main/java/org/keycloak/keys/AbstractEcKeyProviderFactory.java @@ -52,7 +52,7 @@ public abstract class AbstractEcKeyProviderFactory implem public static KeyPair generateEcKeyPair(String keySpecName) { try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); - SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG"); + SecureRandom randomGen = new SecureRandom(); ECGenParameterSpec ecSpec = new ECGenParameterSpec(keySpecName); keyGen.initialize(ecSpec, randomGen); return keyGen.generateKeyPair(); diff --git a/services/src/main/java/org/keycloak/protocol/saml/DefaultSamlArtifactResolver.java b/services/src/main/java/org/keycloak/protocol/saml/DefaultSamlArtifactResolver.java index dd5cdafd95d..d2c006ab006 100644 --- a/services/src/main/java/org/keycloak/protocol/saml/DefaultSamlArtifactResolver.java +++ b/services/src/main/java/org/keycloak/protocol/saml/DefaultSamlArtifactResolver.java @@ -10,7 +10,6 @@ import org.keycloak.utils.StringUtil; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Base64; import java.util.Collections; @@ -101,7 +100,7 @@ public class DefaultSamlArtifactResolver implements ArtifactResolver { */ public String createArtifact(String entityId) throws ArtifactResolverProcessingException { try { - SecureRandom handleGenerator = SecureRandom.getInstance("SHA1PRNG"); + SecureRandom handleGenerator = new SecureRandom(); byte[] trimmedIndex = new byte[2]; byte[] source = ArtifactBindingUtils.computeArtifactBindingIdentifier(entityId); @@ -118,8 +117,6 @@ public class DefaultSamlArtifactResolver implements ArtifactResolver { byte[] artifact = bos.toByteArray(); return Base64.getEncoder().encodeToString(artifact); - } catch (NoSuchAlgorithmException e) { - throw new ArtifactResolverProcessingException("JVM does not support required cryptography algorithms: SHA-1/SHA1PRNG.", e); } catch (IOException e) { throw new ArtifactResolverProcessingException(e); } diff --git a/services/src/test/java/org/keycloak/protocol/saml/SamlEncryptionTest.java b/services/src/test/java/org/keycloak/protocol/saml/SamlEncryptionTest.java index b5b1ba5c990..e89e4d6ca67 100644 --- a/services/src/test/java/org/keycloak/protocol/saml/SamlEncryptionTest.java +++ b/services/src/test/java/org/keycloak/protocol/saml/SamlEncryptionTest.java @@ -85,18 +85,13 @@ public class SamlEncryptionTest { @BeforeClass public static void beforeClass() { Cipher cipher = null; - SecureRandom random = null; try { - // Apache santuario 2.2.3 needs to have SHA1PRNG (fixed in 3.0.2) - // see: https://issues.apache.org/jira/browse/SANTUARIO-589 - random = SecureRandom.getInstance("SHA1PRNG"); // FIPS mode removes needed ciphers like "RSA/ECB/OAEPPadding" cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); } catch (NoSuchAlgorithmException|NoSuchPaddingException e) { // ignore } Assume.assumeNotNull("OAEPPadding not supported", cipher); - Assume.assumeNotNull("SHA1PRNG required for Apache santuario xmlsec", random); } private void testEncryption(KeyPair pair, String alg, int keySize, String keyWrapAlg, String keyWrapHashMethod, String keyWrapMgf) throws Exception { diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestingOIDCEndpointsApplicationResource.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestingOIDCEndpointsApplicationResource.java index 984166827ae..5a0a73ae8dc 100644 --- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestingOIDCEndpointsApplicationResource.java +++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/resource/TestingOIDCEndpointsApplicationResource.java @@ -190,7 +190,7 @@ public class TestingOIDCEndpointsApplicationResource { private KeyPair generateEcdsaKey(String ecDomainParamName) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); - SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG"); + SecureRandom randomGen = new SecureRandom(); ECGenParameterSpec ecSpec = new ECGenParameterSpec(ecDomainParamName); keyGen.initialize(ecSpec, randomGen); KeyPair keyPair = keyGen.generateKeyPair(); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/BasicSamlTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/BasicSamlTest.java index 29714d4cabe..7a5caeda556 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/BasicSamlTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/saml/BasicSamlTest.java @@ -469,17 +469,17 @@ public class BasicSamlTest extends AbstractSamlTest { @Test public void testEncryptionRsaOaep11Default() throws Exception { - testEncryption(XMLCipher.AES_256_GCM, XMLCipher.RSA_OAEP_11, XMLCipher.SHA1, EncryptionConstants.MGF1_SHA1, XMLCipher.AES_256_GCM, XMLCipher.RSA_OAEP_11, "", ""); + testEncryption(XMLCipher.AES_256_GCM, XMLCipher.RSA_OAEP_11, XMLCipher.SHA1, EncryptionConstants.MGF1_SHA1, XMLCipher.AES_256_GCM, XMLCipher.RSA_OAEP_11, "", EncryptionConstants.MGF1_SHA1); } @Test public void testEncryptionRsaOaep() throws Exception { - testEncryption(XMLCipher.AES_256_GCM, XMLCipher.RSA_OAEP, XMLCipher.SHA256, ""); + testEncryption(XMLCipher.AES_256_GCM, XMLCipher.RSA_OAEP, XMLCipher.SHA256, "", XMLCipher.AES_256_GCM, XMLCipher.RSA_OAEP, XMLCipher.SHA256, EncryptionConstants.MGF1_SHA1); } @Test public void testEncryptionRsaOaepLegacy() throws Exception { - testEncryption(XMLCipher.AES_128, XMLCipher.RSA_OAEP, XMLCipher.SHA1, "", XMLCipher.AES_128, XMLCipher.RSA_OAEP, "", ""); + testEncryption(XMLCipher.AES_128, XMLCipher.RSA_OAEP, XMLCipher.SHA1, "", XMLCipher.AES_128, XMLCipher.RSA_OAEP, "", EncryptionConstants.MGF1_SHA1); } @Test diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientPoliciesUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientPoliciesUtil.java index e72a7f146ae..020f8f6c161 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientPoliciesUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientPoliciesUtil.java @@ -468,7 +468,7 @@ public final class ClientPoliciesUtil { public static KeyPair generateEcdsaKey(String ecDomainParamName) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); - SecureRandom randomGen = SecureRandom.getInstance("SHA1PRNG"); + SecureRandom randomGen = new SecureRandom(); ECGenParameterSpec ecSpec = new ECGenParameterSpec(ecDomainParamName); keyGen.initialize(ecSpec, randomGen); KeyPair keyPair = keyGen.generateKeyPair();