mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 15:02:05 -03:30
Upgrade xmlsec to 3.0.4 and remove KeycloakFipsSecurityProvider workaround
Closes #43263 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
a77c4a6ad2
commit
248d6d1feb
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
2
pom.xml
2
pom.xml
@ -126,7 +126,7 @@
|
||||
<woodstox.version>6.0.3</woodstox.version>
|
||||
<wildfly.common.quarkus.aligned.version>1.5.4.Final-format-001</wildfly.common.quarkus.aligned.version>
|
||||
<wildfly.common.wildfly.aligned.version>1.6.0.Final</wildfly.common.wildfly.aligned.version>
|
||||
<xmlsec.version>2.2.6</xmlsec.version>
|
||||
<xmlsec.version>3.0.4</xmlsec.version>
|
||||
<nashorn.version>15.4</nashorn.version>
|
||||
<ua-parser.version>1.6.1</ua-parser.version>
|
||||
<org.yaml.snakeyaml.version>2.0</org.yaml.snakeyaml.version>
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -52,7 +52,7 @@ public abstract class AbstractEcKeyProviderFactory<T extends KeyProvider> 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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user