diff --git a/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java b/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java
new file mode 100644
index 0000000000..a8d55144d1
--- /dev/null
+++ b/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java
@@ -0,0 +1,19 @@
+package org.keycloak.common.crypto;
+
+/**
+ * @author Marek Posolda
+ */
+public class CryptoConstants {
+
+ // JWE algorithms
+ public static final String A128KW = "A128KW";
+ public static final String RSA1_5 = "RSA1_5";
+ public static final String RSA_OAEP = "RSA-OAEP";
+ public static final String RSA_OAEP_256 = "RSA-OAEP-256";
+
+ /** Name of Java security provider used with non-fips BouncyCastle. Should be used in non-FIPS environment */
+ public static final String BC_PROVIDER_ID = "BC";
+
+ /** Name of Java security provider used with fips BouncyCastle. Should be used in FIPS environment */
+ public static final String BCFIPS_PROVIDER_ID = "BCFIPS";
+}
diff --git a/common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java b/common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java
index 4d6f47d169..bffb7eaa7f 100644
--- a/common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java
+++ b/common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java
@@ -1,5 +1,6 @@
package org.keycloak.common.crypto;
+import java.security.Provider;
import java.security.spec.ECParameterSpec;
/**
@@ -9,6 +10,11 @@ import java.security.spec.ECParameterSpec;
*/
public interface CryptoProvider {
+ /**
+ * @return BouncyCastle security provider. Can be either non-FIPS or FIPS based provider
+ */
+ Provider getBouncyCastleProvider();
+
/**
* Get some algorithm provider implementation. Returned implementation can be dependent according to if we have
* non-fips bouncycastle or fips bouncycastle on the classpath.
@@ -25,7 +31,7 @@ public interface CryptoProvider {
*
* @return
*/
- public CertificateUtilsProvider getCertificateUtils();
+ CertificateUtilsProvider getCertificateUtils();
/**
@@ -34,7 +40,7 @@ public interface CryptoProvider {
*
* @return
*/
- public PemUtilsProvider getPemUtils();
+ PemUtilsProvider getPemUtils();
/**
@@ -43,6 +49,6 @@ public interface CryptoProvider {
* @param curveName
* @return
*/
- public ECParameterSpec createECParams(String curveName);
+ ECParameterSpec createECParams(String curveName);
}
diff --git a/common/src/main/java/org/keycloak/common/crypto/CryptoProviderTypes.java b/common/src/main/java/org/keycloak/common/crypto/CryptoProviderTypes.java
deleted file mode 100644
index 0b9811f1ba..0000000000
--- a/common/src/main/java/org/keycloak/common/crypto/CryptoProviderTypes.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.keycloak.common.crypto;
-
-/**
- * @author Marek Posolda
- */
-public class CryptoProviderTypes {
-
- public static final String BC_SECURITY_PROVIDER = "bc-provider";
-
- public static final String AES_KEY_WRAP_ALGORITHM_PROVIDER = "aes-keywrap-alg";
-}
diff --git a/common/src/main/java/org/keycloak/common/util/BouncyIntegration.java b/common/src/main/java/org/keycloak/common/util/BouncyIntegration.java
index 4447a25f86..6022d936b5 100755
--- a/common/src/main/java/org/keycloak/common/util/BouncyIntegration.java
+++ b/common/src/main/java/org/keycloak/common/util/BouncyIntegration.java
@@ -19,7 +19,7 @@ package org.keycloak.common.util;
import org.jboss.logging.Logger;
import org.keycloak.common.crypto.CryptoIntegration;
-import org.keycloak.common.crypto.CryptoProviderTypes;
+import org.keycloak.common.crypto.CryptoConstants;
import java.security.Provider;
import java.security.Security;
@@ -35,7 +35,7 @@ public class BouncyIntegration {
public static final String PROVIDER = loadProvider();
private static String loadProvider() {
- Provider provider = CryptoIntegration.getProvider().getAlgorithmProvider(Provider.class, CryptoProviderTypes.BC_SECURITY_PROVIDER);
+ Provider provider = CryptoIntegration.getProvider().getBouncyCastleProvider();
if (provider == null) {
throw new RuntimeException("Failed to load required security provider: BouncyCastleProvider or BouncyCastleFipsProvider");
}
diff --git a/common/src/main/java/org/keycloak/common/util/CertificateUtils.java b/common/src/main/java/org/keycloak/common/util/CertificateUtils.java
index 9dca0728f3..1a4f3585e1 100755
--- a/common/src/main/java/org/keycloak/common/util/CertificateUtils.java
+++ b/common/src/main/java/org/keycloak/common/util/CertificateUtils.java
@@ -30,10 +30,6 @@ import org.keycloak.common.crypto.CryptoIntegration;
*/
public class CertificateUtils {
- static {
- CryptoIntegration.init(ClassLoader.getSystemClassLoader());
- }
-
/**
* Generates version 3 {@link java.security.cert.X509Certificate}.
diff --git a/common/src/main/java/org/keycloak/common/util/Environment.java b/common/src/main/java/org/keycloak/common/util/Environment.java
index 4f9d976d64..02aa6da79d 100644
--- a/common/src/main/java/org/keycloak/common/util/Environment.java
+++ b/common/src/main/java/org/keycloak/common/util/Environment.java
@@ -43,6 +43,13 @@ public class Environment {
* @return true if java is FIPS mode
*/
public static boolean isJavaInFipsMode() {
+ // Check if FIPS explicitly enabled by system property
+ String property = System.getProperty("com.redhat.fips");
+ if (property != null) {
+ return Boolean.parseBoolean(property);
+ }
+
+ // Otherwise try to auto-detect
for (Provider provider : Security.getProviders()) {
if (provider.getName().equals("BCFIPS")) continue; // Ignore BCFIPS provider for the detection as we may register it programatically
if (provider.getName().toUpperCase().contains("FIPS")) return true;
diff --git a/common/src/main/java/org/keycloak/common/util/PemUtils.java b/common/src/main/java/org/keycloak/common/util/PemUtils.java
index f0bfbd2838..0029150462 100755
--- a/common/src/main/java/org/keycloak/common/util/PemUtils.java
+++ b/common/src/main/java/org/keycloak/common/util/PemUtils.java
@@ -37,10 +37,6 @@ public class PemUtils {
public static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
public static final String END_CERT = "-----END CERTIFICATE-----";
- static {
- CryptoIntegration.init(ClassLoader.getSystemClassLoader());
- }
-
/**
* Decode a X509 Certificate from a PEM string
*
diff --git a/core/src/main/java/org/keycloak/jose/jwe/JWEConstants.java b/core/src/main/java/org/keycloak/jose/jwe/JWEConstants.java
index 6cd9279c48..ad33e73f7b 100644
--- a/core/src/main/java/org/keycloak/jose/jwe/JWEConstants.java
+++ b/core/src/main/java/org/keycloak/jose/jwe/JWEConstants.java
@@ -17,16 +17,18 @@
package org.keycloak.jose.jwe;
+import org.keycloak.common.crypto.CryptoConstants;
+
/**
* @author Marek Posolda
*/
public class JWEConstants {
- public static final String DIR = "dir";
- public static final String A128KW = "A128KW";
- public static final String RSA1_5 = "RSA1_5";
- public static final String RSA_OAEP = "RSA-OAEP";
- public static final String RSA_OAEP_256 = "RSA-OAEP-256";
+ public static final String DIRECT = "dir";
+ public static final String A128KW = CryptoConstants.A128KW;
+ public static final String RSA1_5 = CryptoConstants.RSA1_5;
+ public static final String RSA_OAEP = CryptoConstants.RSA_OAEP;
+ public static final String RSA_OAEP_256 = CryptoConstants.RSA_OAEP_256;
public static final String A128CBC_HS256 = "A128CBC-HS256";
public static final String A192CBC_HS384 = "A192CBC-HS384";
diff --git a/core/src/main/java/org/keycloak/jose/jwe/JWERegistry.java b/core/src/main/java/org/keycloak/jose/jwe/JWERegistry.java
index 15f9e969e3..dc9aa1f80e 100644
--- a/core/src/main/java/org/keycloak/jose/jwe/JWERegistry.java
+++ b/core/src/main/java/org/keycloak/jose/jwe/JWERegistry.java
@@ -21,11 +21,8 @@ import java.util.HashMap;
import java.util.Map;
import org.keycloak.common.crypto.CryptoIntegration;
-import org.keycloak.common.crypto.CryptoProviderTypes;
import org.keycloak.jose.jwe.alg.DirectAlgorithmProvider;
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
-import org.keycloak.jose.jwe.alg.RsaKeyEncryption256JWEAlgorithmProvider;
-import org.keycloak.jose.jwe.alg.RsaKeyEncryptionJWEAlgorithmProvider;
import org.keycloak.jose.jwe.enc.AesCbcHmacShaEncryptionProvider;
import org.keycloak.jose.jwe.enc.AesGcmJWEEncryptionProvider;
import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
@@ -36,23 +33,11 @@ import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
*/
class JWERegistry {
- // https://tools.ietf.org/html/rfc7518#page-12
+ // https://tools.ietf.org/html/rfc7518#page-22
// Registry not pluggable for now. Just supported algorithms included
private static final Map ENC_PROVIDERS = new HashMap<>();
- // https://tools.ietf.org/html/rfc7518#page-22
- // Registry not pluggable for now. Just supported algorithms included
- private static final Map ALG_PROVIDERS = new HashMap<>();
-
-
static {
- // Provider 'dir' just directly uses encryption keys for encrypt/decrypt content.
- ALG_PROVIDERS.put(JWEConstants.DIR, new DirectAlgorithmProvider());
- ALG_PROVIDERS.put(JWEConstants.A128KW, CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER));
- ALG_PROVIDERS.put(JWEConstants.RSA_OAEP, new RsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"));
- ALG_PROVIDERS.put(JWEConstants.RSA_OAEP_256, new RsaKeyEncryption256JWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"));
-
-
ENC_PROVIDERS.put(JWEConstants.A256GCM, new AesGcmJWEEncryptionProvider(JWEConstants.A256GCM));
ENC_PROVIDERS.put(JWEConstants.A128CBC_HS256, new AesCbcHmacShaEncryptionProvider.Aes128CbcHmacSha256Provider());
ENC_PROVIDERS.put(JWEConstants.A192CBC_HS384, new AesCbcHmacShaEncryptionProvider.Aes192CbcHmacSha384Provider());
@@ -61,7 +46,12 @@ class JWERegistry {
static JWEAlgorithmProvider getAlgProvider(String alg) {
- return ALG_PROVIDERS.get(alg);
+ // https://tools.ietf.org/html/rfc7518#page-12
+ if (JWEConstants.DIRECT.equals(alg)) {
+ return new DirectAlgorithmProvider();
+ } else {
+ return CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, alg);
+ }
}
diff --git a/core/src/main/java/org/keycloak/jose/jwe/alg/KeyEncryptionJWEAlgorithmProvider.java b/core/src/main/java/org/keycloak/jose/jwe/alg/KeyEncryptionJWEAlgorithmProvider.java
deleted file mode 100644
index 778a77d47e..0000000000
--- a/core/src/main/java/org/keycloak/jose/jwe/alg/KeyEncryptionJWEAlgorithmProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2018 Red Hat, Inc. and/or its affiliates
- * and other contributors as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.keycloak.jose.jwe.alg;
-
-import java.security.Key;
-
-import javax.crypto.Cipher;
-
-import org.keycloak.jose.jwe.JWEKeyStorage;
-import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
-
-public abstract class KeyEncryptionJWEAlgorithmProvider implements JWEAlgorithmProvider {
-
- @Override
- public byte[] decodeCek(byte[] encodedCek, Key privateKey) throws Exception {
- Cipher cipher = getCipherProvider();
- cipher.init(Cipher.DECRYPT_MODE, privateKey);
- return cipher.doFinal(encodedCek);
- }
-
- @Override
- public byte[] encodeCek(JWEEncryptionProvider encryptionProvider, JWEKeyStorage keyStorage, Key publicKey) throws Exception {
- Cipher cipher = getCipherProvider();
- cipher.init(Cipher.ENCRYPT_MODE, publicKey);
- byte[] cekBytes = keyStorage.getCekBytes();
- return cipher.doFinal(cekBytes);
- }
-
- protected abstract Cipher getCipherProvider() throws Exception;
-
-}
diff --git a/core/src/main/java/org/keycloak/jose/jwe/alg/RsaKeyEncryption256JWEAlgorithmProvider.java b/core/src/main/java/org/keycloak/jose/jwe/alg/RsaKeyEncryption256JWEAlgorithmProvider.java
deleted file mode 100644
index c5b06e33aa..0000000000
--- a/core/src/main/java/org/keycloak/jose/jwe/alg/RsaKeyEncryption256JWEAlgorithmProvider.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2018 Red Hat, Inc. and/or its affiliates
- * and other contributors as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.keycloak.jose.jwe.alg;
-
-import org.keycloak.jose.jwe.JWEKeyStorage;
-import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
-
-import javax.crypto.Cipher;
-import javax.crypto.spec.OAEPParameterSpec;
-import javax.crypto.spec.PSource;
-import java.security.AlgorithmParameters;
-import java.security.Key;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.MGF1ParameterSpec;
-
-public class RsaKeyEncryption256JWEAlgorithmProvider extends KeyEncryptionJWEAlgorithmProvider {
-
- private final String jcaAlgorithmName;
-
- public RsaKeyEncryption256JWEAlgorithmProvider(String jcaAlgorithmName) {
- this.jcaAlgorithmName = jcaAlgorithmName;
- }
-
- @Override
- protected Cipher getCipherProvider() throws Exception {
- return Cipher.getInstance(jcaAlgorithmName);
- }
-
- @Override
- public byte[] decodeCek(byte[] encodedCek, Key privateKey) throws Exception {
- AlgorithmParameters algp = AlgorithmParameters.getInstance("OAEP");
- AlgorithmParameterSpec paramSpec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
- PSource.PSpecified.DEFAULT);
- algp.init(paramSpec);
- Cipher cipher = getCipherProvider();
- cipher.init(Cipher.DECRYPT_MODE, privateKey, algp);
- return cipher.doFinal(encodedCek);
- }
-
- @Override
- public byte[] encodeCek(JWEEncryptionProvider encryptionProvider, JWEKeyStorage keyStorage, Key publicKey)
- throws Exception {
- AlgorithmParameters algp = AlgorithmParameters.getInstance("OAEP");
- AlgorithmParameterSpec paramSpec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
- PSource.PSpecified.DEFAULT);
- algp.init(paramSpec);
- Cipher cipher = getCipherProvider();
- cipher.init(Cipher.ENCRYPT_MODE, publicKey, algp);
- byte[] cekBytes = keyStorage.getCekBytes();
- return cipher.doFinal(cekBytes);
- }
-}
diff --git a/core/src/main/java/org/keycloak/jose/jwe/alg/RsaKeyEncryptionJWEAlgorithmProvider.java b/core/src/main/java/org/keycloak/jose/jwe/alg/RsaKeyEncryptionJWEAlgorithmProvider.java
deleted file mode 100644
index c6909027dc..0000000000
--- a/core/src/main/java/org/keycloak/jose/jwe/alg/RsaKeyEncryptionJWEAlgorithmProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2018 Red Hat, Inc. and/or its affiliates
- * and other contributors as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.keycloak.jose.jwe.alg;
-
-import javax.crypto.Cipher;
-
-public class RsaKeyEncryptionJWEAlgorithmProvider extends KeyEncryptionJWEAlgorithmProvider {
-
- private final String jcaAlgorithmName;
-
- public RsaKeyEncryptionJWEAlgorithmProvider(String jcaAlgorithmName) {
- this.jcaAlgorithmName = jcaAlgorithmName;
- }
-
- @Override
- protected Cipher getCipherProvider() throws Exception {
- return Cipher.getInstance(jcaAlgorithmName);
- }
-
-}
diff --git a/core/src/main/java/org/keycloak/util/TokenUtil.java b/core/src/main/java/org/keycloak/util/TokenUtil.java
index 587e1ea8a5..5e48b65c57 100644
--- a/core/src/main/java/org/keycloak/util/TokenUtil.java
+++ b/core/src/main/java/org/keycloak/util/TokenUtil.java
@@ -203,7 +203,7 @@ public class TokenUtil {
default: throw new IllegalArgumentException("Bad size for Encryption key: " + aesKey + ". Valid sizes are 16, 24, 32.");
}
- JWEHeader jweHeader = new JWEHeader(JWEConstants.DIR, encAlgorithm, null);
+ JWEHeader jweHeader = new JWEHeader(JWEConstants.DIRECT, encAlgorithm, null);
JWE jwe = new JWE()
.header(jweHeader)
.content(contentBytes);
diff --git a/core/src/test/java/org/keycloak/jose/JWETest.java b/core/src/test/java/org/keycloak/jose/JWETest.java
index 1bb19c1082..220478a015 100644
--- a/core/src/test/java/org/keycloak/jose/JWETest.java
+++ b/core/src/test/java/org/keycloak/jose/JWETest.java
@@ -21,6 +21,7 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.jose.jwe.JWE;
@@ -30,7 +31,6 @@ import org.keycloak.jose.jwe.JWEHeader;
import org.keycloak.jose.jwe.JWEKeyStorage;
import org.keycloak.jose.jwe.JWEUtils;
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
-import org.keycloak.jose.jwe.alg.RsaKeyEncryptionJWEAlgorithmProvider;
import org.keycloak.jose.jwe.enc.AesCbcHmacShaJWEEncryptionProvider;
import org.keycloak.jose.jwe.enc.AesGcmJWEEncryptionProvider;
import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
@@ -80,7 +80,7 @@ public abstract class JWETest {
private void testDirectEncryptAndDecrypt(Key aesKey, Key hmacKey, String encAlgorithm, String payload, boolean sysout) throws Exception {
- JWEHeader jweHeader = new JWEHeader(JWEConstants.DIR, encAlgorithm, null);
+ JWEHeader jweHeader = new JWEHeader(JWEConstants.DIRECT, encAlgorithm, null);
JWE jwe = new JWE()
.header(jweHeader)
.content(payload.getBytes(StandardCharsets.UTF_8));
@@ -273,7 +273,7 @@ public abstract class JWETest {
private void testKeyEncryption_ContentEncryptionAesGcm(String jweAlgorithmName, String jweEncryptionName) throws Exception {
// generate key pair for KEK
KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048);
- JWEAlgorithmProvider jweAlgorithmProvider = new RsaKeyEncryptionJWEAlgorithmProvider(getJcaAlgorithmName(jweAlgorithmName));
+ JWEAlgorithmProvider jweAlgorithmProvider = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, jweAlgorithmName);
JWEEncryptionProvider jweEncryptionProvider = new AesGcmJWEEncryptionProvider(jweEncryptionName);
JWEHeader jweHeader = new JWEHeader(jweAlgorithmName, jweEncryptionName, null);
@@ -306,7 +306,7 @@ public abstract class JWETest {
final SecretKey aesKey = new SecretKeySpec(AES_128_KEY, "AES");
final SecretKey hmacKey = new SecretKeySpec(HMAC_SHA256_KEY, "HMACSHA2");
- JWEAlgorithmProvider jweAlgorithmProvider = new RsaKeyEncryptionJWEAlgorithmProvider(getJcaAlgorithmName(jweAlgorithmName));
+ JWEAlgorithmProvider jweAlgorithmProvider = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, jweAlgorithmName);
JWEEncryptionProvider jweEncryptionProvider = new AesCbcHmacShaJWEEncryptionProvider(jweEncryptionName);
JWEHeader jweHeader = new JWEHeader(jweAlgorithmName, jweEncryptionName, null);
@@ -339,15 +339,4 @@ public abstract class JWETest {
Assert.assertEquals(PAYLOAD, decodedContent);
}
- private String getJcaAlgorithmName(String jweAlgorithmName) {
- String jcaAlgorithmName = null;
- if (JWEConstants.RSA1_5.equals(jweAlgorithmName)) {
- jcaAlgorithmName = "RSA/ECB/PKCS1Padding";
- } else if (JWEConstants.RSA_OAEP.equals(jweAlgorithmName)) {
- jcaAlgorithmName = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
- } else if (JWEConstants.RSA_OAEP_256.equals(jweAlgorithmName)) {
- jcaAlgorithmName = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
- }
- return jcaAlgorithmName;
- }
}
diff --git a/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java b/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java
index 9f3f91ae0b..57b46910c4 100644
--- a/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java
+++ b/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultCryptoProvider.java
@@ -1,5 +1,7 @@
package org.keycloak.crypto.def;
+import java.security.Provider;
+import java.security.Security;
import java.security.spec.ECParameterSpec;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -9,7 +11,7 @@ import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.keycloak.common.crypto.CryptoProvider;
-import org.keycloak.common.crypto.CryptoProviderTypes;
+import org.keycloak.common.crypto.CryptoConstants;
import org.keycloak.common.crypto.CertificateUtilsProvider;
import org.keycloak.common.crypto.PemUtilsProvider;
@@ -18,18 +20,33 @@ import org.keycloak.common.crypto.PemUtilsProvider;
*/
public class DefaultCryptoProvider implements CryptoProvider {
+ private final BouncyCastleProvider bcProvider;
+
private Map providers = new ConcurrentHashMap<>();
public DefaultCryptoProvider() {
- providers.put(CryptoProviderTypes.BC_SECURITY_PROVIDER, new BouncyCastleProvider());
- providers.put(CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER, new AesKeyWrapAlgorithmProvider());
+ // Make sure to instantiate this only once due it is expensive. And skip registration if already available in Java security providers (EG. due explicitly configured in java security file)
+ BouncyCastleProvider existingBc = (BouncyCastleProvider) Security.getProvider(CryptoConstants.BC_PROVIDER_ID);
+ this.bcProvider = existingBc == null ? new BouncyCastleProvider() : existingBc;
+
+ providers.put(CryptoConstants.A128KW, new AesKeyWrapAlgorithmProvider());
+ providers.put(CryptoConstants.RSA1_5, new DefaultRsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/PKCS1Padding"));
+ providers.put(CryptoConstants.RSA_OAEP, new DefaultRsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"));
+ providers.put(CryptoConstants.RSA_OAEP_256, new DefaultRsaKeyEncryption256JWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"));
}
+
@Override
- public T getAlgorithmProvider(Class clazz, String algorithm) {
- Object o = providers.get(algorithm);
+ public Provider getBouncyCastleProvider() {
+ return bcProvider;
+ }
+
+
+ @Override
+ public T getAlgorithmProvider(Class clazz, String algorithmType) {
+ Object o = providers.get(algorithmType);
if (o == null) {
- throw new IllegalArgumentException("Not found provider of algorithm: " + algorithm);
+ throw new IllegalArgumentException("Not found provider of algorithm type: " + algorithmType);
}
return clazz.cast(o);
}
diff --git a/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultRsaKeyEncryption256JWEAlgorithmProvider.java b/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultRsaKeyEncryption256JWEAlgorithmProvider.java
new file mode 100644
index 0000000000..54878f0231
--- /dev/null
+++ b/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultRsaKeyEncryption256JWEAlgorithmProvider.java
@@ -0,0 +1,27 @@
+package org.keycloak.crypto.def;
+
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+
+public class DefaultRsaKeyEncryption256JWEAlgorithmProvider extends DefaultRsaKeyEncryptionJWEAlgorithmProvider {
+
+ public DefaultRsaKeyEncryption256JWEAlgorithmProvider(String jcaAlgorithmName) {
+ super(jcaAlgorithmName);
+ }
+
+ @Override
+ protected void initCipher(Cipher cipher, int mode, Key key) throws Exception {
+ AlgorithmParameters algp = AlgorithmParameters.getInstance("OAEP");
+ AlgorithmParameterSpec paramSpec = new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256,
+ PSource.PSpecified.DEFAULT);
+ algp.init(paramSpec);
+ cipher.init(mode, key, algp);
+ }
+}
diff --git a/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultRsaKeyEncryptionJWEAlgorithmProvider.java b/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultRsaKeyEncryptionJWEAlgorithmProvider.java
new file mode 100644
index 0000000000..b0bc523e7c
--- /dev/null
+++ b/crypto/default/src/main/java/org/keycloak/crypto/def/DefaultRsaKeyEncryptionJWEAlgorithmProvider.java
@@ -0,0 +1,40 @@
+package org.keycloak.crypto.def;
+
+import java.security.Key;
+
+import javax.crypto.Cipher;
+import org.keycloak.jose.jwe.JWEKeyStorage;
+import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
+import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
+
+public class DefaultRsaKeyEncryptionJWEAlgorithmProvider implements JWEAlgorithmProvider {
+
+ private final String jcaAlgorithmName;
+
+ public DefaultRsaKeyEncryptionJWEAlgorithmProvider(String jcaAlgorithmName) {
+ this.jcaAlgorithmName = jcaAlgorithmName;
+ }
+
+ @Override
+ public byte[] decodeCek(byte[] encodedCek, Key privateKey) throws Exception {
+ Cipher cipher = getCipherProvider();
+ initCipher(cipher, Cipher.DECRYPT_MODE, privateKey);
+ return cipher.doFinal(encodedCek);
+ }
+
+ @Override
+ public byte[] encodeCek(JWEEncryptionProvider encryptionProvider, JWEKeyStorage keyStorage, Key publicKey) throws Exception {
+ Cipher cipher = getCipherProvider();
+ initCipher(cipher, Cipher.ENCRYPT_MODE, publicKey);
+ byte[] cekBytes = keyStorage.getCekBytes();
+ return cipher.doFinal(cekBytes);
+ }
+
+ private Cipher getCipherProvider() throws Exception {
+ return Cipher.getInstance(jcaAlgorithmName);
+ }
+
+ protected void initCipher(Cipher cipher, int mode, Key key) throws Exception {
+ cipher.init(mode, key);
+ }
+}
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoHmacTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoHmacTest.java
index fe7c6f25a6..fa9cae6884 100644
--- a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoHmacTest.java
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoHmacTest.java
@@ -1,5 +1,8 @@
package org.keycloak.crypto.def.test;
+import org.junit.Assume;
+import org.junit.Before;
+import org.keycloak.common.util.Environment;
import org.keycloak.jose.HmacTest;
@@ -8,4 +11,10 @@ import org.keycloak.jose.HmacTest;
*
*/
public class DefaultCryptoHmacTest extends HmacTest {
+
+ @Before
+ public void before() {
+ // Run this test just if java is not in FIPS mode
+ Assume.assumeFalse("Java is in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
+ }
}
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWKSUtilsTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWKSUtilsTest.java
index 8a24cd859a..06785c34a8 100644
--- a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWKSUtilsTest.java
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoJWKSUtilsTest.java
@@ -1,5 +1,8 @@
package org.keycloak.crypto.def.test;
+import org.junit.Assume;
+import org.junit.Before;
+import org.keycloak.common.util.Environment;
import org.keycloak.util.JWKSUtilsTest;
/**
@@ -7,4 +10,10 @@ import org.keycloak.util.JWKSUtilsTest;
*
*/
public class DefaultCryptoJWKSUtilsTest extends JWKSUtilsTest {
+
+ @Before
+ public void before() {
+ // Run this test just if java is not in FIPS mode
+ Assume.assumeFalse("Java is in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
+ }
}
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoRSAVerifierTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoRSAVerifierTest.java
index cb6541286f..2d8daf0977 100644
--- a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoRSAVerifierTest.java
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoRSAVerifierTest.java
@@ -1,10 +1,19 @@
package org.keycloak.crypto.def.test;
+import org.junit.Assume;
+import org.junit.Before;
import org.keycloak.RSAVerifierTest;
+import org.keycloak.common.util.Environment;
/**
* Test with bouncycastle security provider
*
*/
public class DefaultCryptoRSAVerifierTest extends RSAVerifierTest {
+
+ @Before
+ public void before() {
+ // Run this test just if java is not in FIPS mode
+ Assume.assumeFalse("Java is in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
+ }
}
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoUnitTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoUnitTest.java
index 6fa4faf7c0..ff978f1188 100644
--- a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoUnitTest.java
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultCryptoUnitTest.java
@@ -2,25 +2,25 @@ package org.keycloak.crypto.def.test;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.common.crypto.CryptoIntegration;
-import org.keycloak.common.crypto.CryptoProviderTypes;
+import org.keycloak.common.crypto.CryptoConstants;
import org.keycloak.crypto.def.AesKeyWrapAlgorithmProvider;
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
+import org.keycloak.rule.CryptoInitRule;
/**
* @author Marek Posolda
*/
public class DefaultCryptoUnitTest {
- @Before
- public void init() {
- CryptoIntegration.init(ClassLoader.getSystemClassLoader());
- }
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
@Test
public void testDefaultCrypto() throws Exception {
- JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER);
+ JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoConstants.A128KW);
Assert.assertEquals(jweAlg.getClass(), AesKeyWrapAlgorithmProvider.class);
}
}
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultSecureRandomTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultSecureRandomTest.java
index d5f62ac191..eb68d0776f 100644
--- a/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultSecureRandomTest.java
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/DefaultSecureRandomTest.java
@@ -4,9 +4,12 @@ import java.security.SecureRandom;
import org.jboss.logging.Logger;
import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.util.Environment;
import org.keycloak.rule.CryptoInitRule;
/**
@@ -17,6 +20,12 @@ public class DefaultSecureRandomTest {
@ClassRule
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
+ @Before
+ public void before() {
+ // Run this test just if java is not in FIPS mode
+ Assume.assumeFalse("Java is in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
+ }
+
protected static final Logger logger = Logger.getLogger(DefaultSecureRandomTest.class);
@Test
diff --git a/crypto/default/src/test/java/org/keycloak/crypto/def/test/PemUtilsBCTest.java b/crypto/default/src/test/java/org/keycloak/crypto/def/test/PemUtilsBCTest.java
index 8e899d746a..0d5d42fddf 100644
--- a/crypto/default/src/test/java/org/keycloak/crypto/def/test/PemUtilsBCTest.java
+++ b/crypto/default/src/test/java/org/keycloak/crypto/def/test/PemUtilsBCTest.java
@@ -1,6 +1,9 @@
package org.keycloak.crypto.def.test;
+import org.junit.Assume;
+import org.junit.Before;
import org.junit.Test;
+import org.keycloak.common.util.Environment;
import java.security.NoSuchAlgorithmException;
@@ -8,6 +11,11 @@ import static org.junit.Assert.assertEquals;
public class PemUtilsBCTest {
+ @Before
+ public void before() {
+ // Run this test just if java is not in FIPS mode
+ Assume.assumeFalse("Java is in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
+ }
@Test
public void testGenerateThumbprintSha1() throws NoSuchAlgorithmException {
diff --git a/crypto/fips1402/pom.xml b/crypto/fips1402/pom.xml
index 0373eef80d..386e9c897a 100644
--- a/crypto/fips1402/pom.xml
+++ b/crypto/fips1402/pom.xml
@@ -34,34 +34,12 @@
org.keycloak
keycloak-core
-
-
-
- org.bouncycastle
- bcprov-jdk15on
-
-
- org.bouncycastle
- bcpkix-jdk15on
-
-
org.keycloak
keycloak-core
test
test-jar
-
-
-
- org.bouncycastle
- bcprov-jdk15on
-
-
- org.bouncycastle
- bcpkix-jdk15on
-
-
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 df989d3375..2282c8ac2d 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,5 +1,6 @@
package org.keycloak.crypto.fips;
+import java.security.Provider;
import java.security.spec.ECField;
import java.security.spec.ECFieldF2m;
import java.security.spec.ECFieldFp;
@@ -12,10 +13,12 @@ import java.util.concurrent.ConcurrentHashMap;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.fips.FipsRSA;
+import org.bouncycastle.crypto.fips.FipsSHS;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.bouncycastle.math.ec.ECCurve;
import org.keycloak.common.crypto.CryptoProvider;
-import org.keycloak.common.crypto.CryptoProviderTypes;
+import org.keycloak.common.crypto.CryptoConstants;
import org.keycloak.common.crypto.CertificateUtilsProvider;
import org.keycloak.common.crypto.PemUtilsProvider;
@@ -27,16 +30,28 @@ import org.keycloak.common.crypto.PemUtilsProvider;
*/
public class FIPS1402Provider implements CryptoProvider {
+ private final BouncyCastleFipsProvider bcFipsProvider;
private final Map providers = new ConcurrentHashMap<>();
public FIPS1402Provider() {
- BouncyCastleFipsProvider bcFipsProvider = new BouncyCastleFipsProvider();
- providers.put(CryptoProviderTypes.BC_SECURITY_PROVIDER, bcFipsProvider);
- providers.put(CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER, new FIPSAesKeyWrapAlgorithmProvider());
+ // Case when BCFIPS provider already registered in Java security file
+ BouncyCastleFipsProvider existingBcFipsProvider = (BouncyCastleFipsProvider) Security.getProvider(CryptoConstants.BCFIPS_PROVIDER_ID);
+ this.bcFipsProvider = existingBcFipsProvider == null ? new BouncyCastleFipsProvider() : existingBcFipsProvider;
+
+ providers.put(CryptoConstants.A128KW, new FIPSAesKeyWrapAlgorithmProvider());
+ providers.put(CryptoConstants.RSA1_5, new FIPSRsaKeyEncryptionJWEAlgorithmProvider(FipsRSA.WRAP_PKCS1v1_5));
+ providers.put(CryptoConstants.RSA_OAEP, new FIPSRsaKeyEncryptionJWEAlgorithmProvider(FipsRSA.WRAP_OAEP));
+ providers.put(CryptoConstants.RSA_OAEP_256, new FIPSRsaKeyEncryptionJWEAlgorithmProvider(FipsRSA.WRAP_OAEP.withDigest(FipsSHS.Algorithm.SHA256)));
Security.insertProviderAt(new KeycloakFipsSecurityProvider(bcFipsProvider), 1);
}
+
+ @Override
+ public Provider getBouncyCastleProvider() {
+ return bcFipsProvider;
+ }
+
@Override
public T getAlgorithmProvider(Class clazz, String algorithm) {
Object o = providers.get(algorithm);
diff --git a/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPSRsaKeyEncryptionJWEAlgorithmProvider.java b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPSRsaKeyEncryptionJWEAlgorithmProvider.java
new file mode 100644
index 0000000000..a9a23c08e5
--- /dev/null
+++ b/crypto/fips1402/src/main/java/org/keycloak/crypto/fips/FIPSRsaKeyEncryptionJWEAlgorithmProvider.java
@@ -0,0 +1,56 @@
+package org.keycloak.crypto.fips;
+
+import java.security.Key;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyUnwrapperUsingSecureRandom;
+import org.bouncycastle.crypto.KeyWrapperUsingSecureRandom;
+import org.bouncycastle.crypto.asymmetric.AsymmetricRSAPrivateKey;
+import org.bouncycastle.crypto.asymmetric.AsymmetricRSAPublicKey;
+import org.bouncycastle.crypto.fips.FipsRSA;
+import org.keycloak.jose.jwe.JWEKeyStorage;
+import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
+import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
+
+/**
+ * Fips note: Based on https://downloads.bouncycastle.org/fips-java/BC-FJA-UserGuide-1.0.2.pdf, Section 4
+ * There are no direct public/private key ciphers available in approved mode. Available ciphers are
+ * restricted to use for key wrapping and key transport, see section 7 and section 8 for details.
+ * Our solution is to pull out the CEK signature and encryption keys , encode them separately , and then
+ */
+public class FIPSRsaKeyEncryptionJWEAlgorithmProvider implements JWEAlgorithmProvider {
+
+ private final FipsRSA.WrapParameters wrapParameters;
+
+ public FIPSRsaKeyEncryptionJWEAlgorithmProvider(FipsRSA.WrapParameters wrapParameters) {
+ this.wrapParameters = wrapParameters;
+ }
+
+ @Override
+ public byte[] decodeCek(byte[] encodedCek, Key privateKey) throws Exception {
+ AsymmetricRSAPrivateKey rsaPrivateKey =
+ new AsymmetricRSAPrivateKey(FipsRSA.ALGORITHM, privateKey.getEncoded());
+
+ FipsRSA.KeyWrapOperatorFactory wrapFact =
+ new FipsRSA.KeyWrapOperatorFactory();
+ KeyUnwrapperUsingSecureRandom unwrapper =
+ wrapFact.createKeyUnwrapper(rsaPrivateKey, wrapParameters)
+ .withSecureRandom(SecureRandom.getInstance("DEFAULT"));
+ return unwrapper.unwrap(encodedCek, 0, encodedCek.length);
+ }
+
+
+ @Override
+ public byte[] encodeCek(JWEEncryptionProvider encryptionProvider, JWEKeyStorage keyStorage, Key publicKey) throws Exception {
+ AsymmetricRSAPublicKey rsaPubKey =
+ new AsymmetricRSAPublicKey(FipsRSA.ALGORITHM, publicKey.getEncoded());
+ byte[] inputKeyBytes = keyStorage.getCekBytes();
+ FipsRSA.KeyWrapOperatorFactory wrapFact =
+ new FipsRSA.KeyWrapOperatorFactory();
+
+ KeyWrapperUsingSecureRandom wrapper =
+ wrapFact.createKeyWrapper(rsaPubKey, wrapParameters).withSecureRandom( SecureRandom.getInstance("DEFAULT"));
+ return wrapper.wrap(inputKeyBytes, 0, inputKeyBytes.length);
+ }
+
+}
diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402HmacTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402HmacTest.java
index a07307ac3e..b3cb5f6f5c 100644
--- a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402HmacTest.java
+++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402HmacTest.java
@@ -7,8 +7,11 @@ import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.SecretKeySpec;
import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
import org.junit.Test;
import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.util.Environment;
import org.keycloak.jose.HmacTest;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput;
@@ -21,6 +24,12 @@ import org.keycloak.jose.jws.crypto.HMACProvider;
*/
public class FIPS1402HmacTest extends HmacTest {
+ @Before
+ public void before() {
+ // Run this test just if java is in FIPS mode
+ Assume.assumeTrue("Java is not in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
+ }
+
@Test
public void testHmacSignaturesFIPS() throws Exception {
//
diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402KeyPairVerifierTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402KeyPairVerifierTest.java
index cab849bafe..7bb1367f28 100644
--- a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402KeyPairVerifierTest.java
+++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402KeyPairVerifierTest.java
@@ -60,6 +60,8 @@ public class FIPS1402KeyPairVerifierTest extends KeyPairVerifierTest {
"jLsXjc2CPf/lwNFqsVl7dlPNmg==";
}
+
+ @Before
public void before() {
// Run this test just if java is in FIPS mode
Assume.assumeTrue("Java is not in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
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 32ae1dd026..004c20c4ab 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
@@ -2,6 +2,8 @@ package org.keycloak.crypto.fips.test;
import java.security.SecureRandom;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.crypto.fips.FipsStatus;
import org.jboss.logging.Logger;
import org.junit.Assert;
import org.junit.Assume;
@@ -32,6 +34,8 @@ public class FIPS1402SecureRandomTest {
public void testSecureRandom() throws Exception {
logger.info(CryptoIntegration.dumpJavaSecurityProviders());
+ logger.infof("BC FIPS approved mode: %b, FIPS Status: %s", CryptoServicesRegistrar.isInApprovedOnlyMode(), FipsStatus.getStatusMessage());
+
SecureRandom sc1 = new SecureRandom();
logger.infof(dumpSecureRandom("new SecureRandom()", sc1));
diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402UnitTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402UnitTest.java
index 2d6336e6d8..611883a0c2 100644
--- a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402UnitTest.java
+++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/FIPS1402UnitTest.java
@@ -2,9 +2,8 @@ package org.keycloak.crypto.fips.test;
import org.junit.Assert;
import org.junit.ClassRule;
-import org.junit.Rule;
import org.junit.Test;
-import org.keycloak.common.crypto.CryptoProviderTypes;
+import org.keycloak.common.crypto.CryptoConstants;
import org.keycloak.crypto.fips.FIPSAesKeyWrapAlgorithmProvider;
import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
@@ -20,7 +19,7 @@ public class FIPS1402UnitTest {
@Test
public void testFips() throws Exception {
- JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER);
+ JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoConstants.A128KW);
Assert.assertEquals(jweAlg.getClass(), FIPSAesKeyWrapAlgorithmProvider.class);
}
}
diff --git a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/PemUtilsBCFIPSTest.java b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/PemUtilsBCFIPSTest.java
index 215b45d8b4..68f57026d2 100644
--- a/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/PemUtilsBCFIPSTest.java
+++ b/crypto/fips1402/src/test/java/org/keycloak/crypto/fips/test/PemUtilsBCFIPSTest.java
@@ -1,6 +1,9 @@
package org.keycloak.crypto.fips.test;
+import org.junit.Assume;
+import org.junit.Before;
import org.junit.Test;
+import org.keycloak.common.util.Environment;
import org.keycloak.common.util.PemUtils;
import java.security.NoSuchAlgorithmException;
@@ -9,6 +12,12 @@ import static org.junit.Assert.assertEquals;
public class PemUtilsBCFIPSTest {
+ @Before
+ public void before() {
+ // Run this test just if java is in FIPS mode
+ Assume.assumeTrue("Java is not in FIPS mode. Skipping the test.", Environment.isJavaInFipsMode());
+ }
+
@Test
public void testGenerateThumbprintSha1() throws NoSuchAlgorithmException {
String[] test = new String[] {"abcdefg"};
diff --git a/docs/fips.md b/docs/fips.md
index ed97e6d82c..8a817054a1 100644
--- a/docs/fips.md
+++ b/docs/fips.md
@@ -38,4 +38,20 @@ cd keycloak-999-SNAPSHOT/bin
```
NOTE: Right now, server should start, and I am able to create admin user on `http://localhost:8080`, but I am not able to finish
-login to the admin console. However the Keycloak uses bouncycastle-fips libraries and the `CryptoIntegration` uses `FIPS1402Provider`. More fixes are required to have Keycloak server working...
\ No newline at end of file
+login to the admin console. However the Keycloak uses bouncycastle-fips libraries and the `CryptoIntegration` uses `FIPS1402Provider`. More fixes are required to have Keycloak server working...
+
+Run the tests in the FIPS environment
+-------------------------------------
+This instruction is about running automated tests on the FIPS enabled RHEL 8.6 system with the FIPS enabled OpenJDK 11.
+
+So far only the unit tests inside the `crypto` module are supported. More effort is needed to have whole testsuite passing.
+
+First it is needed to build the project (See above). Then run the tests in the `crypto` module.
+```
+mvn clean install -f crypto
+```
+
+The tests should work also with the BouncyCastle approved mode, which is more strict in the used crypto algorithms
+```
+mvn clean install -f crypto -Dorg.bouncycastle.fips.approved_only=true
+```
diff --git a/services/src/main/java/org/keycloak/crypto/RsaCekManagementProvider.java b/services/src/main/java/org/keycloak/crypto/RsaCekManagementProvider.java
index 50af9a22b3..a075f9a107 100644
--- a/services/src/main/java/org/keycloak/crypto/RsaCekManagementProvider.java
+++ b/services/src/main/java/org/keycloak/crypto/RsaCekManagementProvider.java
@@ -17,10 +17,9 @@
package org.keycloak.crypto;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.jose.jwe.JWEConstants;
import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
-import org.keycloak.jose.jwe.alg.RsaKeyEncryption256JWEAlgorithmProvider;
-import org.keycloak.jose.jwe.alg.RsaKeyEncryptionJWEAlgorithmProvider;
import org.keycloak.models.KeycloakSession;
public class RsaCekManagementProvider implements CekManagementProvider {
@@ -35,15 +34,12 @@ public class RsaCekManagementProvider implements CekManagementProvider {
@Override
public JWEAlgorithmProvider jweAlgorithmProvider() {
- String jcaAlgorithmName = null;
- if (JWEConstants.RSA1_5.equals(jweAlgorithmName)) {
- jcaAlgorithmName = "RSA/ECB/PKCS1Padding";
- } else if (JWEConstants.RSA_OAEP.equals(jweAlgorithmName)) {
- jcaAlgorithmName = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
- } else if (JWEConstants.RSA_OAEP_256.equals(jweAlgorithmName)) {
- return new RsaKeyEncryption256JWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
+ if (JWEConstants.RSA1_5.equals(jweAlgorithmName) || JWEConstants.RSA_OAEP.equals(jweAlgorithmName) ||
+ JWEConstants.RSA_OAEP_256.equals(jweAlgorithmName)) {
+ return CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, jweAlgorithmName);
+ } else {
+ return null;
}
- return new RsaKeyEncryptionJWEAlgorithmProvider(jcaAlgorithmName);
}
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AuthorizationTokenEncryptionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AuthorizationTokenEncryptionTest.java
index b6fd1e8ee4..7353b65a10 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AuthorizationTokenEncryptionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/AuthorizationTokenEncryptionTest.java
@@ -230,12 +230,7 @@ public class AuthorizationTokenEncryptionTest extends AbstractTestRealmKeycloakT
}
private JWEAlgorithmProvider getJweAlgorithmProvider(String algAlgorithm) {
- JWEAlgorithmProvider jweAlgorithmProvider = null;
- if (JWEConstants.RSA1_5.equals(algAlgorithm) || JWEConstants.RSA_OAEP.equals(algAlgorithm) ||
- JWEConstants.RSA_OAEP_256.equals(algAlgorithm)) {
- jweAlgorithmProvider = new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider();
- }
- return jweAlgorithmProvider;
+ return new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider();
}
private JWEEncryptionProvider getJweEncryptionProvider(String encAlgorithm) {
JWEEncryptionProvider jweEncryptionProvider = null;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/IdTokenEncryptionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/IdTokenEncryptionTest.java
index 5fbf02fb08..67c418243d 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/IdTokenEncryptionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/IdTokenEncryptionTest.java
@@ -262,12 +262,7 @@ public class IdTokenEncryptionTest extends AbstractTestRealmKeycloakTest {
}
private JWEAlgorithmProvider getJweAlgorithmProvider(String algAlgorithm) {
- JWEAlgorithmProvider jweAlgorithmProvider = null;
- if (JWEConstants.RSA1_5.equals(algAlgorithm) || JWEConstants.RSA_OAEP.equals(algAlgorithm) ||
- JWEConstants.RSA_OAEP_256.equals(algAlgorithm)) {
- jweAlgorithmProvider = new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider();
- }
- return jweAlgorithmProvider;
+ return new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider();
}
private JWEEncryptionProvider getJweEncryptionProvider(String encAlgorithm) {
JWEEncryptionProvider jweEncryptionProvider = null;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
index 5c4edf11f9..4c231348c6 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
@@ -386,12 +386,7 @@ public class UserInfoTest extends AbstractKeycloakTest {
}
private JWEAlgorithmProvider getJweAlgorithmProvider(String algAlgorithm) {
- JWEAlgorithmProvider jweAlgorithmProvider = null;
- if (JWEConstants.RSA1_5.equals(algAlgorithm) || JWEConstants.RSA_OAEP.equals(algAlgorithm) ||
- JWEConstants.RSA_OAEP_256.equals(algAlgorithm)) {
- jweAlgorithmProvider = new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider();
- }
- return jweAlgorithmProvider;
+ return new RsaCekManagementProvider(null, algAlgorithm).jweAlgorithmProvider();
}
private JWEEncryptionProvider getJweEncryptionProvider(String encAlgorithm) {
JWEEncryptionProvider jweEncryptionProvider = null;