diff --git a/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java b/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java
index 7e4cd54f5da..90a06e2e661 100644
--- a/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java
+++ b/common/src/main/java/org/keycloak/common/crypto/CryptoConstants.java
@@ -19,4 +19,5 @@ public class CryptoConstants {
/** 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/CryptoIntegration.java b/common/src/main/java/org/keycloak/common/crypto/CryptoIntegration.java
index dee1f6bf28f..e02b6dd7edd 100644
--- a/common/src/main/java/org/keycloak/common/crypto/CryptoIntegration.java
+++ b/common/src/main/java/org/keycloak/common/crypto/CryptoIntegration.java
@@ -25,7 +25,8 @@ public class CryptoIntegration {
synchronized (lock) {
if (cryptoProvider == null) {
cryptoProvider = detectProvider(classLoader);
- logger.debugv("BouncyCastle provider: {0}", BouncyIntegration.PROVIDER);
+ logger.debugv("java security provider: {0}", BouncyIntegration.PROVIDER);
+
}
}
}
@@ -54,7 +55,7 @@ public class CryptoIntegration {
throw new IllegalStateException("Multiple crypto providers loaded with the classLoader: " + classLoader +
". Make sure only one cryptoProvider available on the classpath. Available providers: " +foundProviders);
} else {
- logger.infof("Detected crypto provider: %s", foundProviders.get(0).getClass().getName());
+ logger.debugf("Detected crypto provider: %s", foundProviders.get(0).getClass().getName());
return foundProviders.get(0);
}
}
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 2609e5ff358..901b04d6872 100644
--- a/common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java
+++ b/common/src/main/java/org/keycloak/common/crypto/CryptoProvider.java
@@ -1,8 +1,27 @@
package org.keycloak.common.crypto;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.Provider;
+import java.security.Signature;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
import java.security.spec.ECParameterSpec;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+import org.keycloak.common.util.KeystoreUtil.KeystoreFormat;
+
/**
* Abstraction to handle differences between the APIs for non-fips and fips mode
*
@@ -58,4 +77,24 @@ public interface CryptoProvider {
*/
ECParameterSpec createECParams(String curveName);
+ KeyPairGenerator getKeyPairGen(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ Cipher getAesCbcCipher() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException;
+
+ Cipher getAesGcmCipher() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException;
+
+ SecretKeyFactory getSecretKeyFact(String keyAlgorithm) throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyStore getKeyStore(KeystoreFormat format) throws KeyStoreException, NoSuchProviderException;
+
+ CertificateFactory getX509CertFactory() throws CertificateException, NoSuchProviderException;
+
+ CertStore getCertStore(CollectionCertStoreParameters collectionCertStoreParameters) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException;
+
+ CertPathBuilder getCertPathBuilder() throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ Signature getSignature(String sigAlgName) throws NoSuchAlgorithmException, NoSuchProviderException;
+
}
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 6022d936b5f..8c25439aef6 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,6 @@ package org.keycloak.common.util;
import org.jboss.logging.Logger;
import org.keycloak.common.crypto.CryptoIntegration;
-import org.keycloak.common.crypto.CryptoConstants;
import java.security.Provider;
import java.security.Security;
@@ -37,7 +36,8 @@ public class BouncyIntegration {
private static String loadProvider() {
Provider provider = CryptoIntegration.getProvider().getBouncyCastleProvider();
if (provider == null) {
- throw new RuntimeException("Failed to load required security provider: BouncyCastleProvider or BouncyCastleFipsProvider");
+ return Security.getProviders()[0].getName();
+ // throw new RuntimeException("Failed to load required security provider: BouncyCastleProvider or BouncyCastleFipsProvider");
}
if (Security.getProvider(provider.getName()) == null) {
Security.addProvider(provider);
diff --git a/common/src/main/java/org/keycloak/common/util/DerUtils.java b/common/src/main/java/org/keycloak/common/util/DerUtils.java
index d3d2062783c..f00e547d524 100755
--- a/common/src/main/java/org/keycloak/common/util/DerUtils.java
+++ b/common/src/main/java/org/keycloak/common/util/DerUtils.java
@@ -30,6 +30,8 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
+import org.keycloak.common.crypto.CryptoIntegration;
+
/**
* Extract PrivateKey, PublicKey, and X509Certificate from a DER encoded byte array or file. Usually
* generated from openssl
@@ -52,7 +54,7 @@ public final class DerUtils {
PKCS8EncodedKeySpec spec =
new PKCS8EncodedKeySpec(keyBytes);
- KeyFactory kf = KeyFactory.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyFactory kf =CryptoIntegration.getProvider().getKeyFactory("RSA");
return kf.generatePrivate(spec);
}
@@ -63,12 +65,12 @@ public final class DerUtils {
public static PublicKey decodePublicKey(byte[] der, String type) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
X509EncodedKeySpec spec =
new X509EncodedKeySpec(der);
- KeyFactory kf = KeyFactory.getInstance(type, BouncyIntegration.PROVIDER);
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory(type);
return kf.generatePublic(spec);
}
public static X509Certificate decodeCertificate(InputStream is) throws Exception {
- CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyIntegration.PROVIDER);
+ CertificateFactory cf = CryptoIntegration.getProvider().getX509CertFactory();
X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
is.close();
return cert;
@@ -77,7 +79,7 @@ public final class DerUtils {
public static PrivateKey decodePrivateKey(byte[] der) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
PKCS8EncodedKeySpec spec =
new PKCS8EncodedKeySpec(der);
- KeyFactory kf = KeyFactory.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory("RSA");
return kf.generatePrivate(spec);
}
}
diff --git a/common/src/main/java/org/keycloak/common/util/KeyUtils.java b/common/src/main/java/org/keycloak/common/util/KeyUtils.java
index 362f2245ea2..0cbc2c690bb 100644
--- a/common/src/main/java/org/keycloak/common/util/KeyUtils.java
+++ b/common/src/main/java/org/keycloak/common/util/KeyUtils.java
@@ -17,8 +17,6 @@
package org.keycloak.common.util;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
@@ -30,6 +28,11 @@ import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.RSAPublicKeySpec;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.keycloak.common.crypto.CryptoIntegration;
+
/**
* @author Stian Thorgersen
*/
@@ -46,7 +49,7 @@ public class KeyUtils {
public static KeyPair generateRsaKeyPair(int keysize) {
try {
- KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyPairGenerator generator = CryptoIntegration.getProvider().getKeyPairGen("RSA");
generator.initialize(keysize);
KeyPair keyPair = generator.generateKeyPair();
return keyPair;
diff --git a/common/src/main/java/org/keycloak/common/util/KeystoreUtil.java b/common/src/main/java/org/keycloak/common/util/KeystoreUtil.java
index 406e6f99036..b46b92f815a 100755
--- a/common/src/main/java/org/keycloak/common/util/KeystoreUtil.java
+++ b/common/src/main/java/org/keycloak/common/util/KeystoreUtil.java
@@ -18,6 +18,7 @@
package org.keycloak.common.util;
import org.keycloak.common.constants.GenericConstants;
+import org.keycloak.common.crypto.CryptoIntegration;
import java.io.File;
import java.io.FileInputStream;
@@ -65,12 +66,7 @@ public class KeystoreUtil {
InputStream stream = FindFile.findFile(keystoreFile);
try {
- KeyStore keyStore = null;
- if (format == KeystoreFormat.JKS) {
- keyStore = KeyStore.getInstance(format.toString());
- } else {
- keyStore = KeyStore.getInstance(format.toString(), BouncyIntegration.PROVIDER);
- }
+ KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(format);
keyStore.load(stream, storePassword.toCharArray());
PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyPassword.toCharArray());
diff --git a/core/src/main/java/org/keycloak/jose/jwe/enc/AesCbcHmacShaEncryptionProvider.java b/core/src/main/java/org/keycloak/jose/jwe/enc/AesCbcHmacShaEncryptionProvider.java
index 03d41405803..3e17a09f807 100644
--- a/core/src/main/java/org/keycloak/jose/jwe/enc/AesCbcHmacShaEncryptionProvider.java
+++ b/core/src/main/java/org/keycloak/jose/jwe/enc/AesCbcHmacShaEncryptionProvider.java
@@ -34,7 +34,7 @@ import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
-import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.jose.jwe.JWE;
import org.keycloak.jose.jwe.JWEKeyStorage;
import org.keycloak.jose.jwe.JWEUtils;
@@ -117,15 +117,14 @@ public abstract class AesCbcHmacShaEncryptionProvider implements JWEEncryptionPr
private byte[] encryptBytes(byte[] contentBytes, byte[] ivBytes, Key aesKey) throws GeneralSecurityException {
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyIntegration.PROVIDER);
- AlgorithmParameterSpec ivParamSpec = new IvParameterSpec(ivBytes);
+ Cipher cipher = CryptoIntegration.getProvider().getAesCbcCipher();
+ AlgorithmParameterSpec ivParamSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivParamSpec);
return cipher.doFinal(contentBytes);
}
-
private byte[] decryptBytes(byte[] encryptedBytes, byte[] ivBytes, Key aesKey) throws GeneralSecurityException {
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyIntegration.PROVIDER);
+ Cipher cipher = CryptoIntegration.getProvider().getAesCbcCipher();
AlgorithmParameterSpec ivParamSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParamSpec);
return cipher.doFinal(encryptedBytes);
diff --git a/core/src/main/java/org/keycloak/jose/jwe/enc/AesGcmEncryptionProvider.java b/core/src/main/java/org/keycloak/jose/jwe/enc/AesGcmEncryptionProvider.java
index 6f47bcae21c..fe3befc691c 100644
--- a/core/src/main/java/org/keycloak/jose/jwe/enc/AesGcmEncryptionProvider.java
+++ b/core/src/main/java/org/keycloak/jose/jwe/enc/AesGcmEncryptionProvider.java
@@ -27,7 +27,7 @@ import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
-import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.jose.jwe.JWE;
import org.keycloak.jose.jwe.JWEKeyStorage;
import org.keycloak.jose.jwe.JWEUtils;
@@ -89,7 +89,7 @@ public abstract class AesGcmEncryptionProvider implements JWEEncryptionProvider
}
private byte[] encryptBytes(byte[] contentBytes, byte[] ivBytes, Key aesKey, byte[] aad) throws GeneralSecurityException {
- Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", BouncyIntegration.PROVIDER);
+ Cipher cipher = CryptoIntegration.getProvider().getAesGcmCipher();
GCMParameterSpec gcmParams = new GCMParameterSpec(AUTH_TAG_SIZE_BYTE * 8, ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, aesKey, gcmParams);
cipher.updateAAD(aad);
@@ -99,7 +99,7 @@ public abstract class AesGcmEncryptionProvider implements JWEEncryptionProvider
}
private byte[] decryptBytes(byte[] encryptedBytes, byte[] ivBytes, Key aesKey, byte[] aad) throws GeneralSecurityException {
- Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", BouncyIntegration.PROVIDER);
+ Cipher cipher = CryptoIntegration.getProvider().getAesGcmCipher();
GCMParameterSpec gcmParams = new GCMParameterSpec(AUTH_TAG_SIZE_BYTE * 8, ivBytes);
cipher.init(Cipher.DECRYPT_MODE, aesKey, gcmParams);
cipher.updateAAD(aad);
diff --git a/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java b/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java
index d44c09197e9..14d6ee9b1ff 100755
--- a/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java
+++ b/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java
@@ -104,7 +104,7 @@ public class JWKParser {
ECParameterSpec params = CryptoIntegration.getProvider().createECParams(name);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
- KeyFactory kf = KeyFactory.getInstance("ECDSA");
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory("ECDSA");
return kf.generatePublic(pubKeySpec);
} catch (Exception e) {
throw new RuntimeException(e);
diff --git a/core/src/test/java/org/keycloak/jose/JWETest.java b/core/src/test/java/org/keycloak/jose/JWETest.java
index 220478a0158..0848fcd1d6f 100644
--- a/core/src/test/java/org/keycloak/jose/JWETest.java
+++ b/core/src/test/java/org/keycloak/jose/JWETest.java
@@ -52,13 +52,13 @@ public abstract class JWETest {
@ClassRule
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
- private static final String PAYLOAD = "Hello world! How are you man? I hope you are fine. This is some quite a long text, which is much longer than just simple 'Hello World'";
+ protected static final String PAYLOAD = "Hello world! How are you man? I hope you are fine. This is some quite a long text, which is much longer than just simple 'Hello World'";
- private static final byte[] HMAC_SHA256_KEY = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 13, 14, 15, 16 };
- private static final byte[] AES_128_KEY = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ protected static final byte[] HMAC_SHA256_KEY = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 13, 14, 15, 16 };
+ protected static final byte[] AES_128_KEY = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
- private static final byte[] HMAC_SHA512_KEY = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
- private static final byte[] AES_256_KEY = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ protected static final byte[] HMAC_SHA512_KEY = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
+ protected static final byte[] AES_256_KEY = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
@Test
public void testDirect_Aes128CbcHmacSha256() throws Exception {
@@ -79,7 +79,7 @@ public abstract class JWETest {
}
- private void testDirectEncryptAndDecrypt(Key aesKey, Key hmacKey, String encAlgorithm, String payload, boolean sysout) throws Exception {
+ protected void testDirectEncryptAndDecrypt(Key aesKey, Key hmacKey, String encAlgorithm, String payload, boolean sysout) throws Exception {
JWEHeader jweHeader = new JWEHeader(JWEConstants.DIRECT, encAlgorithm, null);
JWE jwe = new JWE()
.header(jweHeader)
diff --git a/core/src/test/java/org/keycloak/jose/jwk/JWKTest.java b/core/src/test/java/org/keycloak/jose/jwk/JWKTest.java
index b051fd7ce67..214a072b330 100644
--- a/core/src/test/java/org/keycloak/jose/jwk/JWKTest.java
+++ b/core/src/test/java/org/keycloak/jose/jwk/JWKTest.java
@@ -23,10 +23,10 @@ import java.util.List;
import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.common.util.Base64Url;
-import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.crypto.JavaAlgorithm;
+import org.keycloak.crypto.KeyType;
import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.rule.CryptoInitRule;
import org.keycloak.util.JsonSerialization;
@@ -61,7 +61,7 @@ public abstract class JWKTest {
@Test
public void publicRs256() throws Exception {
- KeyPair keyPair = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER ).generateKeyPair();
+ KeyPair keyPair = CryptoIntegration.getProvider().getKeyPairGen(KeyType.RSA).generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
X509Certificate certificate = generateV1SelfSignedCertificate(keyPair, "Test");
@@ -96,7 +96,7 @@ public abstract class JWKTest {
@Test
public void publicRs256Chain() throws Exception {
- KeyPair keyPair = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER).generateKeyPair();
+ KeyPair keyPair = CryptoIntegration.getProvider().getKeyPairGen(KeyType.RSA).generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
List certificates = Arrays.asList(generateV1SelfSignedCertificate(keyPair, "Test"), generateV1SelfSignedCertificate(keyPair, "Intermediate"));
@@ -137,7 +137,7 @@ public abstract class JWKTest {
@Test
public void publicEs256() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", BouncyIntegration.PROVIDER);
+ KeyPairGenerator keyGen = CryptoIntegration.getProvider().getKeyPairGen(KeyType.EC);
SecureRandom randomGen = new SecureRandom();
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
keyGen.initialize(ecSpec, randomGen);
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 00efafa7c8f..5b2c0434ca4 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,11 +1,28 @@
package org.keycloak.crypto.def;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.Security;
+import java.security.Signature;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
import java.security.spec.ECParameterSpec;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
@@ -16,6 +33,9 @@ import org.keycloak.common.crypto.ECDSACryptoProvider;
import org.keycloak.common.crypto.CertificateUtilsProvider;
import org.keycloak.common.crypto.PemUtilsProvider;
import org.keycloak.common.crypto.UserIdentityExtractorProvider;
+import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.util.KeystoreUtil.KeystoreFormat;
+import org.keycloak.crypto.JavaAlgorithm;
/**
* @author Marek Posolda
@@ -85,4 +105,65 @@ public class DefaultCryptoProvider implements CryptoProvider {
return clazz.cast(new BCOCSPProvider());
}
+
+ @Override
+ public KeyPairGenerator getKeyPairGen(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException {
+ return KeyPairGenerator.getInstance(algorithm, BouncyIntegration.PROVIDER);
+ }
+
+
+ @Override
+ public KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException {
+ return KeyFactory.getInstance(algorithm, BouncyIntegration.PROVIDER);
+ }
+
+
+ @Override
+ public Cipher getAesCbcCipher() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
+ return Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public Cipher getAesGcmCipher() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
+ return Cipher.getInstance("AES/GCM/NoPadding", BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public SecretKeyFactory getSecretKeyFact(String keyAlgorithm) throws NoSuchAlgorithmException, NoSuchProviderException {
+ return SecretKeyFactory.getInstance(keyAlgorithm, BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public KeyStore getKeyStore(KeystoreFormat format) throws KeyStoreException, NoSuchProviderException {
+ if (format == KeystoreFormat.JKS) {
+ return KeyStore.getInstance(format.toString());
+ } else {
+ return KeyStore.getInstance(format.toString(), BouncyIntegration.PROVIDER);
+ }
+ }
+
+ @Override
+ public CertificateFactory getX509CertFactory() throws CertificateException, NoSuchProviderException {
+ return CertificateFactory.getInstance("X.509", BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public CertStore getCertStore(CollectionCertStoreParameters certStoreParams) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
+
+ return CertStore.getInstance("Collection", certStoreParams, BouncyIntegration.PROVIDER);
+
+ }
+
+
+ @Override
+ public CertPathBuilder getCertPathBuilder() throws NoSuchAlgorithmException, NoSuchProviderException {
+ return CertPathBuilder.getInstance("PKIX", BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public Signature getSignature(String sigAlgName) throws NoSuchAlgorithmException, NoSuchProviderException {
+ return Signature.getInstance(JavaAlgorithm.getJavaAlgorithm(sigAlgName), BouncyIntegration.PROVIDER);
+
+ }
+
}
diff --git a/crypto/elytron/pom.xml b/crypto/elytron/pom.xml
new file mode 100644
index 00000000000..564a5e00c8b
--- /dev/null
+++ b/crypto/elytron/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+ keycloak-crypto-parent
+ org.keycloak
+ 999-SNAPSHOT
+ ../pom.xml
+
+ 4.0.0
+
+ keycloak-crypto-elytron
+ Keycloak Crypto Wildfly Elytron Integration
+
+
+
+
+ org.keycloak
+ keycloak-core
+
+
+ org.keycloak
+ keycloak-core
+ test
+ test-jar
+
+
+
+ org.keycloak
+ keycloak-server-spi
+
+
+ org.keycloak
+ keycloak-server-spi-private
+
+
+
+ org.wildfly.security
+ wildfly-elytron
+
+
+
+ org.jboss.logging
+ jboss-logging
+ provided
+
+
+ junit
+ junit
+ test
+
+
+
+
+
\ No newline at end of file
diff --git a/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/AesKeyWrapAlgorithmProvider.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/AesKeyWrapAlgorithmProvider.java
new file mode 100644
index 00000000000..ffc16e19610
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/AesKeyWrapAlgorithmProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 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.crypto.elytron;
+
+import java.security.Key;
+
+import javax.crypto.Cipher;
+
+import org.keycloak.jose.jwe.JWEKeyStorage;
+import org.keycloak.jose.jwe.JWEKeyStorage.KeyUse;
+import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
+import org.keycloak.jose.jwe.enc.JWEEncryptionProvider;
+
+/**
+ * @author David Anderson
+ */
+public class AesKeyWrapAlgorithmProvider implements JWEAlgorithmProvider {
+
+ @Override
+ public byte[] decodeCek(byte[] encodedCek, Key encryptionKey) throws Exception {
+ Cipher cipher = Cipher.getInstance("AESWrap_128");
+ cipher.init(Cipher.UNWRAP_MODE, encryptionKey);
+ return cipher.unwrap(encodedCek, "AES", Cipher.SECRET_KEY).getEncoded();
+ }
+
+ @Override
+ public byte[] encodeCek(JWEEncryptionProvider encryptionProvider, JWEKeyStorage keyStorage, Key encryptionKey) throws Exception {
+ Cipher cipher = Cipher.getInstance("AESWrap_128");
+ cipher.init(Cipher.WRAP_MODE, encryptionKey);
+ return cipher.wrap(keyStorage.getCEKKey(KeyUse.ENCRYPTION, false));
+ }
+
+
+}
diff --git a/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronCertificateUtils.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronCertificateUtils.java
new file mode 100644
index 00000000000..0bf862b937d
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronCertificateUtils.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2016 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.crypto.elytron;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.time.DateTimeException;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.keycloak.common.crypto.CertificateUtilsProvider;
+import org.wildfly.security.asn1.ASN1;
+import org.wildfly.security.asn1.DERDecoder;
+import org.wildfly.security.x500.X500;
+import org.wildfly.security.x500.cert.AuthorityKeyIdentifierExtension;
+import org.wildfly.security.x500.cert.BasicConstraintsExtension;
+import org.wildfly.security.x500.cert.CertificatePoliciesExtension;
+import org.wildfly.security.x500.cert.CertificatePoliciesExtension.PolicyInformation;
+import org.wildfly.security.x500.cert.ExtendedKeyUsageExtension;
+import org.wildfly.security.x500.cert.KeyUsage;
+import org.wildfly.security.x500.cert.KeyUsageExtension;
+import org.wildfly.security.x500.cert.SubjectKeyIdentifierExtension;
+import org.wildfly.security.x500.cert.X509CertificateBuilder;
+import org.wildfly.security.x500.cert.X509CertificateExtension;
+
+/**
+ * The Class CertificateUtils provides utility functions for generation
+ * and usage of X.509 certificates
+ *
+ * @author David Anderson
+ */
+public class ElytronCertificateUtils implements CertificateUtilsProvider {
+
+ /**
+ * Generates version 3 {@link java.security.cert.X509Certificate}.
+ *
+ * @param keyPair the key pair
+ * @param caPrivateKey the CA private key
+ * @param caCert the CA certificate
+ * @param subject the subject name
+ *
+ * @return the x509 certificate
+ *
+ * @throws Exception the exception
+ */
+ @Override
+ public X509Certificate generateV3Certificate(KeyPair keyPair, PrivateKey caPrivateKey,
+ X509Certificate caCert,
+ String subject) throws Exception {
+ try {
+
+ X500Principal subjectdn = subjectToX500Principle(subject);
+ X500Principal issuerdn = subjectdn;
+ if (caCert != null) {
+ issuerdn = caCert.getSubjectX500Principal();
+ }
+
+ // Validity
+ ZonedDateTime notBefore = ZonedDateTime.ofInstant(new Date(System.currentTimeMillis()).toInstant(),
+ ZoneId.systemDefault());
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.YEAR, 3);
+ Date validityEndDate = new Date(calendar.getTime().getTime());
+ ZonedDateTime notAfter = ZonedDateTime.ofInstant(validityEndDate.toInstant(),
+ ZoneId.systemDefault());
+ // Serial Number
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+ BigInteger serialNumber = BigInteger.valueOf(Math.abs(random.nextInt()));
+ // Extended Key Usage
+ ArrayList ekuList = new ArrayList();
+ ekuList.add(X500.OID_KP_EMAIL_PROTECTION);
+ ekuList.add(X500.OID_KP_SERVER_AUTH);
+
+ X509CertificateBuilder cbuilder = new X509CertificateBuilder()
+ .setSubjectDn(subjectdn)
+ .setIssuerDn(issuerdn)
+
+ .setNotValidBefore(notBefore)
+ .setNotValidAfter(notAfter)
+
+ .setSigningKey(keyPair.getPrivate())
+ .setPublicKey(keyPair.getPublic())
+
+ .setSerialNumber(serialNumber)
+
+ .setSignatureAlgorithmName("SHA256withRSA")
+
+ .setSigningKey(caPrivateKey)
+
+ // Subject Key Identifier Extension
+ .addExtension(new SubjectKeyIdentifierExtension(keyPair.getPublic().getEncoded()))
+
+ // Authority Key Identifier
+ .addExtension(new AuthorityKeyIdentifierExtension(keyPair.getPublic().getEncoded(), null, null))
+
+ // Key Usage
+ .addExtension(
+ new KeyUsageExtension(KeyUsage.digitalSignature, KeyUsage.keyCertSign, KeyUsage.cRLSign))
+
+ .addExtension(new ExtendedKeyUsageExtension(false, ekuList))
+
+ // Basic Constraints
+ .addExtension(new BasicConstraintsExtension(true, true, 0));
+
+ return cbuilder.build();
+
+ } catch (Exception e) {
+ throw new RuntimeException("Error creating X509v3Certificate.", e);
+ }
+ }
+
+ /**
+ * Generate version 1 self signed {@link java.security.cert.X509Certificate}..
+ *
+ * @param caKeyPair the CA key pair
+ * @param subject the subject name
+ *
+ * @return the x509 certificate
+ *
+ * @throws Exception the exception
+ */
+ @Override
+ public X509Certificate generateV1SelfSignedCertificate(KeyPair caKeyPair, String subject) {
+ return generateV1SelfSignedCertificate(caKeyPair, subject, BigInteger.valueOf(System.currentTimeMillis()));
+ }
+
+ @Override
+ public X509Certificate generateV1SelfSignedCertificate(KeyPair caKeyPair, String subject,
+ BigInteger serialNumber) {
+ try {
+
+ X500Principal subjectdn = subjectToX500Principle(subject);
+
+ ZonedDateTime notBefore = ZonedDateTime.ofInstant(
+ (new Date(System.currentTimeMillis() - 100000)).toInstant(),
+ ZoneId.systemDefault());
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.YEAR, 10);
+ Date validityEndDate = new Date(calendar.getTime().getTime());
+ ZonedDateTime notAfter = ZonedDateTime.ofInstant(validityEndDate.toInstant(),
+ ZoneId.systemDefault());
+
+ X509CertificateBuilder cbuilder = new X509CertificateBuilder()
+ .setSubjectDn(subjectdn)
+ .setIssuerDn(subjectdn)
+ .setNotValidBefore(notBefore)
+ .setNotValidAfter(notAfter)
+
+ .setSigningKey(caKeyPair.getPrivate())
+ .setPublicKey(caKeyPair.getPublic())
+
+ .setSerialNumber(serialNumber)
+
+ .setSignatureAlgorithmName("SHA256withRSA");
+
+ return cbuilder.build();
+
+ } catch (Exception e) {
+ throw new RuntimeException("Error creating X509v1Certificate.", e);
+ }
+ }
+
+
+ // Some subject names will not conform to the RFC format
+ private static X500Principal subjectToX500Principle(String subject) {
+ if(!subject.startsWith("CN=")) {
+ subject = "CN="+subject;
+ }
+ return new X500Principal(subject);
+ }
+
+ @Override
+ public List getCertificatePolicyList(X509Certificate cert) throws GeneralSecurityException {
+ byte[] policy = cert.getExtensionValue("2.5.29.32");
+
+ System.out.println("Policy: " + new String(policy));
+ DERDecoder decPolicy = new DERDecoder(policy);
+
+ int type = decPolicy.peekType();
+ System.out.println("type " + type);
+
+ DERDecoder der = new DERDecoder(decPolicy.decodeOctetString());
+
+ List policyList =new ArrayList<>();
+
+ while (der.hasNextElement()) {
+ switch (der.peekType()) {
+ case ASN1.SEQUENCE_TYPE:
+ der.startSequence();
+ break;
+ case ASN1.OBJECT_IDENTIFIER_TYPE:
+ policyList.add(der.decodeObjectIdentifier());
+ der.endSequence();
+ break;
+ default:
+ der.skipElement();
+
+ }
+ }
+
+ return policyList;
+ }
+
+ @Override
+ public List getCRLDistributionPoints(X509Certificate cert) throws IOException {
+ byte[] data = cert.getExtensionValue(CRL_DISTRIBUTION_POINTS_OID);
+ if (data == null) {
+ return Collections.emptyList();
+ }
+ List distPointUrls = new ArrayList<>();
+ DERDecoder der = new DERDecoder(data);
+
+ der = new DERDecoder(der.decodeOctetString());
+
+ while ( der.hasNextElement() ) {
+ switch (der.peekType()) {
+ case ASN1.SEQUENCE_TYPE:
+ der.startSequence();
+ break;
+ case ASN1.UTF8_STRING_TYPE:
+ distPointUrls.add(der.decodeUtf8String());
+ break;
+ case 0xa0:
+ der.decodeImplicit(0xa0);
+ byte[] edata = der.decodeOctetString();
+ while(!Character.isLetterOrDigit(edata[0])) {
+ edata = Arrays.copyOfRange(edata, 1, edata.length);
+ }
+ distPointUrls.add(new String(edata));
+ break;
+ default:
+ der.skipElement();
+
+ }
+ }
+
+ return distPointUrls;
+ }
+
+ @Override
+ public X509Certificate createServicesTestCertificate(String dn, Date startDate, Date expiryDate, KeyPair keyPair,
+ String... certificatePolicyOid) {
+
+ try {
+ X500Principal subjectdn = subjectToX500Principle(dn);
+ X500Principal issuerdn = subjectToX500Principle(dn);
+
+ ZonedDateTime notValidBefore = ZonedDateTime.ofInstant(startDate.toInstant(), ZoneId.systemDefault());
+ ZonedDateTime notValidAfter = ZonedDateTime.ofInstant(expiryDate.toInstant(), ZoneId.systemDefault());
+
+ X509CertificateBuilder cbuilder = new X509CertificateBuilder()
+ .setSubjectDn(subjectdn)
+ .setIssuerDn(issuerdn)
+
+ .setNotValidBefore(notValidBefore)
+ .setNotValidAfter(notValidAfter)
+
+ .setSigningKey(keyPair.getPrivate())
+ .setPublicKey(keyPair.getPublic())
+
+ .addExtension(createPoliciesExtension(certificatePolicyOid))
+
+ .setSignatureAlgorithmName("SHA256withRSA");
+
+ return cbuilder.build();
+ } catch ( DateTimeException | CertificateException e ) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
+ }
+
+ private X509CertificateExtension createPoliciesExtension(String[] certificatePolicyOid) {
+
+ List policyList = new ArrayList<>();
+ for(String policyOid : certificatePolicyOid) {
+ policyList.add(new PolicyInformation(policyOid));
+
+ }
+
+ return new CertificatePoliciesExtension(false, policyList);
+
+ }
+
+}
diff --git a/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronECDSACryptoProvider.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronECDSACryptoProvider.java
new file mode 100644
index 00000000000..ca75b06d02e
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronECDSACryptoProvider.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 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.crypto.elytron;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.keycloak.common.crypto.ECDSACryptoProvider;
+import org.wildfly.security.asn1.DERDecoder;
+import org.wildfly.security.asn1.DEREncoder;
+
+/**
+ * @author David Anderson
+ */
+public class ElytronECDSACryptoProvider implements ECDSACryptoProvider {
+
+ @Override
+ public byte[] concatenatedRSToASN1DER(final byte[] signature, int signLength) throws IOException {
+ int len = signLength / 2;
+ int arraySize = len + 1;
+
+ byte[] r = new byte[arraySize];
+ byte[] s = new byte[arraySize];
+ System.arraycopy(signature, 0, r, 1, len);
+ System.arraycopy(signature, len, s, 1, len);
+ BigInteger rBigInteger = new BigInteger(r);
+ BigInteger sBigInteger = new BigInteger(s);
+
+ DEREncoder seq = new DEREncoder();
+
+ seq.startSequence();
+ seq.encodeInteger(rBigInteger);
+ seq.encodeInteger(sBigInteger);
+
+ return seq.getEncoded();
+
+ }
+
+ @Override
+ public byte[] asn1derToConcatenatedRS(final byte[] derEncodedSignatureValue, int signLength) throws IOException {
+ int len = signLength / 2;
+
+ DERDecoder der = new DERDecoder(derEncodedSignatureValue);
+ der.startSequence();
+ byte[] r = der.decodeInteger().toByteArray();
+ byte[] s = der.decodeInteger().toByteArray();
+ byte[] concatenatedSignatureValue = new byte[signLength];
+ System.arraycopy(r, 0, concatenatedSignatureValue, 0, len);
+ System.arraycopy(s, 0, concatenatedSignatureValue, len, len);
+
+ return concatenatedSignatureValue;
+ }
+
+}
diff --git a/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronOCSPProvider.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronOCSPProvider.java
new file mode 100644
index 00000000000..7054578da4e
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronOCSPProvider.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017 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.crypto.elytron;
+
+import java.io.IOException;
+import java.net.URI;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CRLReason;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.net.ssl.TrustManagerFactory;
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.utils.OCSPProvider;
+import org.wildfly.security.asn1.ASN1;
+import org.wildfly.security.asn1.DERDecoder;
+import org.wildfly.security.ssl.X509RevocationTrustManager;
+import org.wildfly.security.x500.X500;
+
+
+/**
+ * @author David Anderson
+ */
+public class ElytronOCSPProvider extends OCSPProvider {
+
+ private final static Logger logger = Logger.getLogger(ElytronOCSPProvider.class.getName());
+
+ /**
+ * Requests certificate revocation status using OCSP.
+ *
+ * @param cert the certificate to be checked
+ * @param issuerCertificate the issuer certificate
+ * @param responderURIs the OCSP responder URIs
+ * @param responderCert the OCSP responder certificate
+ * @param date if null, the current time is used.
+ * @return a revocation status
+ * @throws CertPathValidatorException
+ */
+ @Override
+ protected OCSPRevocationStatus check(KeycloakSession session, X509Certificate cert, X509Certificate issuerCertificate, List responderURIs, X509Certificate responderCert, Date date) throws CertPathValidatorException {
+ if (responderURIs == null || responderURIs.size() == 0)
+ throw new IllegalArgumentException("Need at least one responder");
+
+ try {
+ KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ trustStore.load(null,"pass".toCharArray());
+ trustStore.setCertificateEntry("trust", cert);
+ TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+
+
+ X509RevocationTrustManager trustMgr = X509RevocationTrustManager.builder()
+ .setOcspResponderCert(responderCert)
+ .setTrustStore(trustStore)
+ .setTrustManagerFactory(trustManagerFactory)
+ .build()
+ ;
+
+ X509Certificate[] certs = { cert };
+ trustMgr.checkClientTrusted(certs, cert.getType());
+ } catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException e) {
+ logger.warn("OSCP Response check failed.", e);
+ return unknownStatus();
+ }
+
+ return new OCSPRevocationStatus() {
+
+ @Override
+ public RevocationStatus getRevocationStatus() {
+ return RevocationStatus.GOOD;
+ }
+
+ @Override
+ public Date getRevocationTime() {
+ return null;
+ }
+
+ @Override
+ public CRLReason getRevocationReason() {
+ return null;
+ }
+
+ };
+ }
+
+ /**
+ * Extracts OCSP responder URI from X509 AIA v3 extension, if available. There can be
+ * multiple responder URIs encoded in the certificate.
+ *
+ * @param cert
+ * @return a list of available responder URIs.
+ * @throws CertificateEncodingException
+ */
+ @Override
+ protected List getResponderURIs(X509Certificate cert) throws CertificateEncodingException {
+
+ LinkedList responderURIs = new LinkedList<>();
+
+ byte[] authinfob = cert.getExtensionValue(X500.OID_PE_AUTHORITY_INFO_ACCESS);
+ DERDecoder der = new DERDecoder(authinfob);
+
+ der = new DERDecoder(der.decodeOctetString());
+
+ while ( der.hasNextElement() ) {
+ switch (der.peekType()) {
+ case ASN1.SEQUENCE_TYPE:
+ der.startSequence();
+ break;
+ case ASN1.OBJECT_IDENTIFIER_TYPE:
+ String oid = der.decodeObjectIdentifier();
+ if ("1.3.6.1.5.5.7.48.1".equals(oid)) {
+ byte[] uri = der.drainElementValue();
+ responderURIs.add(new String(uri));
+ }
+ break;
+ case ASN1.IA5_STRING_TYPE:
+ break;
+ case ASN1.UTF8_STRING_TYPE:
+ responderURIs.add(der.decodeUtf8String());
+ break;
+ case 0xa0:
+ der.decodeImplicit(0xa0);
+ byte[] edata = der.decodeOctetString();
+ while(!Character.isLetterOrDigit(edata[0])) {
+ edata = Arrays.copyOfRange(edata, 1, edata.length);
+ }
+ responderURIs.add(new String(edata));
+ break;
+ default:
+ der.skipElement();
+
+ }
+ }
+
+ return responderURIs;
+ }
+}
diff --git a/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronPEMUtilsProvider.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronPEMUtilsProvider.java
new file mode 100644
index 00000000000..f005469a39c
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronPEMUtilsProvider.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 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.crypto.elytron;
+
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.util.Base64;
+
+import org.jboss.logging.Logger;
+import org.keycloak.common.crypto.PemUtilsProvider;
+import org.keycloak.common.util.DerUtils;
+import org.keycloak.common.util.PemException;
+
+/**
+ * @author David Anderson
+ */
+public class ElytronPEMUtilsProvider extends PemUtilsProvider {
+
+ Logger log = Logger.getLogger(ElytronPEMUtilsProvider.class);
+
+ @Override
+ protected String encode(Object obj) {
+ String encoded = null;
+ if(obj instanceof Key ) {
+ byte[] b = ((Key)obj).getEncoded();
+ encoded = Base64.getEncoder().encodeToString(b);
+ } else if(obj instanceof Certificate) {
+ byte[] c;
+ try {
+ c = ((Certificate)obj).getEncoded();
+ encoded = Base64.getEncoder().encodeToString(c);
+ } catch (CertificateEncodingException e) {
+ log.warn("Failed to encoded certificate.", e);
+ throw new RuntimeException(e);
+ }
+ }
+ return encoded;
+ }
+
+ @Override
+ public PrivateKey decodePrivateKey(String pem) {
+ if (pem == null) {
+ return null;
+ }
+
+ try {
+ byte[] der = pemToDer(pem);
+ return DerUtils.decodePrivateKey(der);
+ } catch (Exception e) {
+ throw new PemException(e);
+ }
+ }
+
+}
diff --git a/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronRsaKeyEncryption256JWEAlgorithmProvider.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronRsaKeyEncryption256JWEAlgorithmProvider.java
new file mode 100644
index 00000000000..a80c60ea1d8
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronRsaKeyEncryption256JWEAlgorithmProvider.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 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.crypto.elytron;
+
+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;
+
+/**
+ * @author David Anderson
+ */
+public class ElytronRsaKeyEncryption256JWEAlgorithmProvider extends ElytronRsaKeyEncryptionJWEAlgorithmProvider {
+
+ public ElytronRsaKeyEncryption256JWEAlgorithmProvider(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/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronRsaKeyEncryptionJWEAlgorithmProvider.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronRsaKeyEncryptionJWEAlgorithmProvider.java
new file mode 100644
index 00000000000..42431bc48ac
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronRsaKeyEncryptionJWEAlgorithmProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 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.crypto.elytron;
+
+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;
+
+/**
+ * @author David Anderson
+ */
+public class ElytronRsaKeyEncryptionJWEAlgorithmProvider implements JWEAlgorithmProvider {
+
+ private final String jcaAlgorithmName;
+
+ public ElytronRsaKeyEncryptionJWEAlgorithmProvider(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/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronUserIdentityExtractorProvider.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronUserIdentityExtractorProvider.java
new file mode 100644
index 00000000000..eb5c4283326
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/ElytronUserIdentityExtractorProvider.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2017 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.crypto.elytron;
+
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Function;
+
+import org.jboss.logging.Logger;
+import org.keycloak.common.crypto.UserIdentityExtractor;
+import org.keycloak.common.crypto.UserIdentityExtractorProvider;
+import org.wildfly.security.asn1.ASN1;
+import org.wildfly.security.asn1.DERDecoder;
+import org.wildfly.security.asn1.OidsUtil;
+import org.wildfly.security.x500.GeneralName;
+import org.wildfly.security.x500.principal.X500AttributePrincipalDecoder;
+
+/**
+ * @author David Anderson
+ */
+public class ElytronUserIdentityExtractorProvider extends UserIdentityExtractorProvider {
+
+ private static final Logger logger = Logger.getLogger(ElytronUserIdentityExtractorProvider.class.getName());
+
+ class X500NameRDNExtractorElytronProvider extends X500NameRDNExtractor {
+
+ private String x500NameStyle;
+ Function x500Name;
+
+ public X500NameRDNExtractorElytronProvider(String attrName, Function x500Name) {
+ //this.x500NameStyle = BCStyle.INSTANCE.attrNameToOID(attrName);
+ this.x500NameStyle = OidsUtil.attributeNameToOid(OidsUtil.Category.RDN, attrName);
+ this.x500Name = x500Name;
+ }
+
+ @Override
+ public Object extractUserIdentity(X509Certificate[] certs) {
+
+ if (certs == null || certs.length == 0)
+ throw new IllegalArgumentException();
+
+ Principal name = x500Name.apply(certs);
+ X500AttributePrincipalDecoder xDecoder = new X500AttributePrincipalDecoder(x500NameStyle);
+ String cn = xDecoder.apply(name);
+
+ return cn;
+
+ }
+ }
+
+ /**
+ * Extracts the subject identifier from the subjectAltName extension.
+ */
+ class SubjectAltNameExtractorEltronProvider extends SubjectAltNameExtractor {
+
+ // User Principal Name. Used typically by Microsoft in certificates for
+ // Smart Card Login
+ private static final String UPN_OID = "1.3.6.1.4.1.311.20.2.3";
+
+ private final int generalName;
+
+ /**
+ * Creates a new instance
+ *
+ * @param generalName an integer representing the general name. See
+ * {@link X509Certificate#getSubjectAlternativeNames()}
+ */
+ SubjectAltNameExtractorEltronProvider(int generalName) {
+ this.generalName = generalName;
+ }
+
+ @Override
+ public Object extractUserIdentity(X509Certificate[] certs) {
+ if (certs == null || certs.length == 0) {
+ throw new IllegalArgumentException();
+ }
+ String subjectName = null;
+
+ logger.info("SubjPrinc " + certs[0].getSubjectX500Principal());
+ Collection> subjectAlternativeNames;
+ try {
+ subjectAlternativeNames = certs[0].getSubjectAlternativeNames();
+ if (subjectAlternativeNames == null) {
+ return null;
+ }
+ for (List> sbjAltName : subjectAlternativeNames) {
+ if (sbjAltName == null)
+ continue;
+
+ Integer nameType = (Integer) sbjAltName.get(0);
+
+ if (nameType == generalName) {
+ logger.info("sbjAltName Type " + nameType);
+ logger.info("sbjAltName[1]: " + sbjAltName.get(1));
+
+ Object sbjObj = sbjAltName.get(1);
+
+ switch (nameType) {
+ case GeneralName.RFC_822_NAME:
+ case GeneralName.DNS_NAME:
+ case GeneralName.DIRECTORY_NAME:
+ subjectName = (String) sbjObj;
+ break;
+ case GeneralName.OTHER_NAME:
+ DERDecoder derDecoder = new DERDecoder((byte[])sbjObj);
+ derDecoder.startSequence();
+ boolean upnOidFound = false;
+ while (derDecoder.hasNextElement() && !upnOidFound) {
+ int asn1Type = derDecoder.peekType();
+ logger.info("ASN.1 Type: " + derDecoder.peekType());
+
+ switch (asn1Type) {
+ case ASN1.OBJECT_IDENTIFIER_TYPE:
+ String oid = derDecoder.decodeObjectIdentifier();
+ logger.info("OID: " + oid);
+ if(UPN_OID.equals(oid)) {
+ derDecoder.decodeImplicit(160);
+ byte[] sb = derDecoder.drainElementValue();
+ while(!Character.isLetterOrDigit(sb[0])) {
+ sb = Arrays.copyOfRange(sb, 1, sb.length);
+ }
+ subjectName = new String(sb, "UTF-8");
+ upnOidFound = true;
+ }
+ break;
+ case ASN1.UTF8_STRING_TYPE:
+ subjectName = derDecoder.decodeUtf8String();
+ break;
+ case ASN1.PRINTABLE_STRING_TYPE:
+ subjectName = derDecoder.decodePrintableString();
+ break;
+ case ASN1.UNIVERSAL_STRING_TYPE:
+ subjectName = derDecoder.decodeUniversalString();
+ break;
+ case ASN1.OCTET_STRING_TYPE:
+ subjectName = derDecoder.decodeOctetStringAsString();
+ break;
+
+ }
+
+
+ }
+ logger.info("Subject Alt Name: " + subjectName);
+ }
+
+ }
+
+ }
+ } catch (CertificateParsingException | UnsupportedEncodingException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return subjectName;
+ }
+ }
+
+
+
+ @Override
+ public UserIdentityExtractor getX500NameExtractor(String identifier, Function x500Name) {
+ return new X500NameRDNExtractorElytronProvider(identifier, x500Name);
+ }
+
+ @Override
+ public SubjectAltNameExtractor getSubjectAltNameExtractor(int generalName) {
+ return new SubjectAltNameExtractorEltronProvider(generalName);
+ }
+
+}
diff --git a/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java
new file mode 100644
index 00000000000..243a1ef06dd
--- /dev/null
+++ b/crypto/elytron/src/main/java/org/keycloak/crypto/elytron/WildFlyElytronProvider.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2017 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.crypto.elytron;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Signature;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
+import org.keycloak.common.crypto.CertificateUtilsProvider;
+import org.keycloak.common.crypto.CryptoConstants;
+import org.keycloak.common.crypto.CryptoProvider;
+import org.keycloak.common.crypto.ECDSACryptoProvider;
+import org.keycloak.common.crypto.PemUtilsProvider;
+import org.keycloak.common.crypto.UserIdentityExtractorProvider;
+import org.keycloak.common.util.KeystoreUtil.KeystoreFormat;
+import org.keycloak.crypto.JavaAlgorithm;
+
+public class WildFlyElytronProvider implements CryptoProvider {
+
+ private Map providers = new ConcurrentHashMap<>();
+
+ public WildFlyElytronProvider() {
+ providers.put(CryptoConstants.A128KW, new AesKeyWrapAlgorithmProvider());
+ providers.put(CryptoConstants.RSA1_5, new ElytronRsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/PKCS1Padding"));
+ providers.put(CryptoConstants.RSA_OAEP, new ElytronRsaKeyEncryptionJWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"));
+ providers.put(CryptoConstants.RSA_OAEP_256, new ElytronRsaKeyEncryption256JWEAlgorithmProvider("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"));
+ }
+
+ @Override
+ public Provider getBouncyCastleProvider() {
+ return null;
+ }
+
+ @Override
+ public T getAlgorithmProvider(Class clazz, String algorithm) {
+ Object o = providers.get(algorithm);
+ if (o == null) {
+ throw new IllegalArgumentException("Not found provider of algorithm type: " + algorithm);
+ }
+ return clazz.cast(o);
+ }
+
+ @Override
+ public CertificateUtilsProvider getCertificateUtils() {
+ return new ElytronCertificateUtils();
+ }
+
+ @Override
+ public PemUtilsProvider getPemUtils() {
+ return new ElytronPEMUtilsProvider();
+ }
+
+ @Override
+ public T getOCSPProver(Class clazz) {
+ return clazz.cast(new ElytronOCSPProvider());
+ }
+
+ @Override
+ public UserIdentityExtractorProvider getIdentityExtractorProvider() {
+ return new ElytronUserIdentityExtractorProvider();
+ }
+
+ @Override
+ public ECDSACryptoProvider getEcdsaCryptoProvider() {
+ return new ElytronECDSACryptoProvider();
+ }
+
+ @Override
+ public ECParameterSpec createECParams(String curveName) {
+ AlgorithmParameters params;
+ try {
+ params = AlgorithmParameters.getInstance("EC");
+ params.init(new ECGenParameterSpec(curveName));
+ return params.getParameterSpec(ECParameterSpec.class);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to generate EC parameter spec", e);
+ }
+ }
+
+ @Override
+ public KeyPairGenerator getKeyPairGen(String algorithm) throws NoSuchAlgorithmException {
+ return KeyPairGenerator.getInstance(algorithm);
+ }
+
+ @Override
+ public KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException {
+ if("ECDSA".equals(algorithm)) {
+ // ECDSA is not a listed JavaSE KeyFactory algorithm
+ // see https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#cipher-algorithm-names
+ algorithm = "EC";
+ }
+ return KeyFactory.getInstance(algorithm);
+ }
+
+ @Override
+ public Cipher getAesCbcCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {
+ return Cipher.getInstance("AES/CBC/PKCS5Padding");
+ }
+
+ @Override
+ public Cipher getAesGcmCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {
+ return Cipher.getInstance("AES/GCM/NoPadding");
+ }
+
+ @Override
+ public SecretKeyFactory getSecretKeyFact(String keyAlgorithm) throws NoSuchAlgorithmException {
+ return SecretKeyFactory.getInstance(keyAlgorithm);
+ }
+
+ @Override
+ public KeyStore getKeyStore(KeystoreFormat format) throws KeyStoreException {
+ return KeyStore.getInstance(format.toString());
+ }
+
+ @Override
+ public CertificateFactory getX509CertFactory() throws CertificateException {
+ return CertificateFactory.getInstance("X.509");
+ }
+
+ @Override
+ public CertStore getCertStore(CollectionCertStoreParameters certStoreParams) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
+
+ return CertStore.getInstance("Collection", certStoreParams);
+
+ }
+
+ @Override
+ public CertPathBuilder getCertPathBuilder() throws NoSuchAlgorithmException {
+ return CertPathBuilder.getInstance("PKIX");
+ }
+
+ @Override
+ public Signature getSignature(String sigAlgName) throws NoSuchAlgorithmException {
+ return Signature.getInstance(JavaAlgorithm.getJavaAlgorithm(sigAlgName));
+
+ }
+}
diff --git a/crypto/elytron/src/main/resources/META-INF/services/org.keycloak.common.crypto.CryptoProvider b/crypto/elytron/src/main/resources/META-INF/services/org.keycloak.common.crypto.CryptoProvider
new file mode 100644
index 00000000000..cc85e879c71
--- /dev/null
+++ b/crypto/elytron/src/main/resources/META-INF/services/org.keycloak.common.crypto.CryptoProvider
@@ -0,0 +1,18 @@
+#
+# Copyright 2022 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.
+#
+
+org.keycloak.crypto.elytron.WildFlyElytronProvider
\ No newline at end of file
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/CRLDistributionPointTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/CRLDistributionPointTest.java
new file mode 100644
index 00000000000..d42e60483c4
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/CRLDistributionPointTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.junit.Test;
+import org.keycloak.crypto.elytron.ElytronCertificateUtils;
+import org.wildfly.security.x500.GeneralName;
+import org.wildfly.security.x500.cert.CRLDistributionPoint;
+import org.wildfly.security.x500.cert.CRLDistributionPoint.DistributionPointName;
+import org.wildfly.security.x500.cert.CRLDistributionPoint.FullNameDistributionPointName;
+import org.wildfly.security.x500.cert.CRLDistributionPointsExtension;
+import org.wildfly.security.x500.cert.X509CertificateBuilder;
+
+/**
+ * @author David Anderson
+ */
+public class CRLDistributionPointTest {
+
+ @Test
+ public void getCrlDistPoint() throws CertificateException, NoSuchAlgorithmException, IOException {
+
+ X509Certificate cert = createCRLcert();
+ List expect = new ArrayList<>();
+ expect.add("http://crl.test.com");
+
+
+ ElytronCertificateUtils bcutil = new ElytronCertificateUtils();
+ List crldp = bcutil.getCRLDistributionPoints(cert);
+
+ assertArrayEquals(expect.toArray(), crldp.toArray());
+
+ }
+
+ private X509Certificate createCRLcert() throws CertificateException, NoSuchAlgorithmException {
+
+ X500Principal dn = new X500Principal("CN=testuser,OU=UNIT,O=TST");
+ List distributionPoints = new ArrayList<>();
+
+ List fullName = new ArrayList<>();
+ fullName.add(new GeneralName.URIName("http://crl.test.com"));
+ DistributionPointName distributionPoint = new FullNameDistributionPointName(fullName);
+ CRLDistributionPoint arg0 = new CRLDistributionPoint(distributionPoint, null, null);
+ distributionPoints.add(arg0);
+ KeyPair keyPair = KeyPairGenerator.getInstance("RSA").genKeyPair();
+ X509CertificateBuilder cbuilder = new X509CertificateBuilder()
+ .setSubjectDn(dn)
+ .setIssuerDn(dn)
+
+ .setSigningKey(keyPair.getPrivate())
+ .setPublicKey(keyPair.getPublic())
+
+ .addExtension(new CRLDistributionPointsExtension(false, distributionPoints))
+
+ .setSignatureAlgorithmName("SHA256withRSA");
+
+ return cbuilder.build();
+ }
+
+
+
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoJWETest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoJWETest.java
new file mode 100644
index 00000000000..f3e5aa3333e
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoJWETest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.junit.Test;
+import org.keycloak.jose.JWETest;
+import org.keycloak.jose.jwe.JWEConstants;
+
+public class ElytronCryptoJWETest extends JWETest {
+
+ @Test
+ public void testDirect_Aes256CbcHmacSha512() throws Exception {
+ final SecretKey aesKey = new SecretKeySpec(AES_256_KEY, "AES");
+ final SecretKey hmacKey = new SecretKeySpec(HMAC_SHA512_KEY, "HMACSHA2");
+
+ testDirectEncryptAndDecrypt(aesKey, hmacKey, JWEConstants.A256CBC_HS512, PAYLOAD, true);
+ }
+
+ @Override
+ public void testAesKW_Aes128CbcHmacSha256() throws Exception {
+ // Skipping this test, this test fails when not using BC provider.
+
+ }
+
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoJWKTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoJWKTest.java
new file mode 100644
index 00000000000..98883392cf1
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoJWKTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import org.keycloak.jose.jwk.JWKTest;
+
+
+public class ElytronCryptoJWKTest extends JWKTest {
+
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoRSAVerifierTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoRSAVerifierTest.java
new file mode 100644
index 00000000000..aefabfb24d0
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronCryptoRSAVerifierTest.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import org.keycloak.RSAVerifierTest;
+
+public class ElytronCryptoRSAVerifierTest extends RSAVerifierTest {
+
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronHmacTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronHmacTest.java
new file mode 100644
index 00000000000..a83722971df
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronHmacTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import java.security.SecureRandom;
+import java.util.UUID;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.jose.HmacTest;
+import org.keycloak.jose.jws.JWSBuilder;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.crypto.HMACProvider;
+
+
+/**
+ * @author David Anderson
+ */
+public class ElytronHmacTest extends HmacTest {
+
+ @Test
+ public void testHmacSignaturesUsingKeyGen() throws Exception {
+
+ KeyGenerator keygen = KeyGenerator.getInstance("HmacSHA256");
+ SecureRandom random = SecureRandom.getInstance("NativePRNG");
+ random.setSeed(UUID.randomUUID().toString().getBytes());
+ keygen.init(random);
+ SecretKey secret = keygen.generateKey();
+
+ String encoded = new JWSBuilder().content("12345678901234567890".getBytes())
+ .hmac256(secret);
+ System.out.println("length: " + encoded.length());
+ JWSInput input = new JWSInput(encoded);
+ Assert.assertTrue(HMACProvider.verify(input, secret));
+ }
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronJWKSUtilsTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronJWKSUtilsTest.java
new file mode 100644
index 00000000000..0a375b064e2
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronJWKSUtilsTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import org.keycloak.util.JWKSUtilsTest;
+
+
+public class ElytronJWKSUtilsTest extends JWKSUtilsTest {
+
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronKeyPairVerifierTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronKeyPairVerifierTest.java
new file mode 100644
index 00000000000..5d9ee6d468d
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronKeyPairVerifierTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import org.junit.Before;
+import org.keycloak.KeyPairVerifierTest;
+
+/**
+ * Test with default security provider and non-fips bouncycastle
+ *
+ * @author Marek Posolda
+ */
+public class ElytronKeyPairVerifierTest extends KeyPairVerifierTest {
+
+ @Before
+ public void initPrivKeys() {
+
+ // The parent private key is not in a supported format, using a PKCS#8 formatted key
+ privateKey1 = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKtWsK5O0CtuBpnM" +
+ "vWG+HTG0vmZzujQ2o9WdheQu+BzCILcGMsbDW0YQaglpcO5JpGWWhubnckGGPHfd" +
+ "Q2/7nP9QwbiTK0FbGF41UqcvoaCqU1psxoV88s8IXyQCAqeyLv00yj6foqdJjxh5" +
+ "SZ5z+na+M7Y2OxIBVxYRAxWEnfUvAgMBAAECgYB+Y7yBWHIHF2qXGYi6CVvPxtyN" +
+ "BuFcktHYShLyeBNeY3VujYv3QzSZQpJ1zuoXXQuARMHOovyNiVAhu357pMfx9wSk" +
+ "oKNSXKrQx/+9Vt9lI1pXJxjXedPOjbuI/JZAcrk0u4nOfXG/HGtR5cjoDZYWkYQE" +
+ "tsePCnHlZAb0D7axwQJBAO92f00Tvkc9NU/EGqwR3bPXRMqSX0JnG7XRBvLeJBCZ" +
+ "YsQn0s2bLdpy8qsTeAyJg1ZvrEc8qIio5HVqzsvbhpMCQQC3K9A6UK+vmQCNWqsQ" +
+ "pdqWPRPN7CPB67FzSmyS8CtMjY6jTvSHrkamggotz2N/5QDr1xG2q7A/3dpkq1bT" +
+ "pTx1AkAXZjjiSz+Yrn57IOqKTeSgIjTypoLwdirbBWXsbZCQnqxsBogu1y8P3ZOg" +
+ "6/IbJ4TR+W+YNnExiW9pmdpDSVxJAkEAplTq6YmLf/F4RuQmox94tyUPbtcYQWg9" +
+ "42uZ3HSrXQDOng18kBj5nwpHJAJHYEQb6g2K0E5n5hcX0oKkfdx2YQJAcSKAmFiD" +
+ "7KQ6+vVqJlQwVPvYdTSOeZB7YVV6S4b4slS3ZObsa0yNMWgal/QnCtW5k3f185gC" +
+ "Wj6dOLGB5btfxg==";
+
+ // The parent private key is not in a supported format, using a PKCS#8 formatted key
+ privateKey2048 = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDhXcyk6e4qx0Ft" +
+ "HVTM2Mr2jmZ4QxDizlWnKSG/UOmpOKUo6IQftVD9e2M3HDTKOcUGKUKekrrI32YM" +
+ "QdsETNpGO12uBWGQh6OJpcUE/kwGFRDmX27wTchkLcTynAONUXRn27RHiUZ5SDaT" +
+ "o740q6aoi/GgsJO4bTN/ndty0axF3nsu4WKmAKQ3LG+xw6G6WxsQxisvCVvlswaD" +
+ "H2/5EKfC+6c0RvtEr7mnM/6IfUxF6NGxf5TuH3MdGfaBCEiXtLMb0Zd5u49avgor" +
+ "B8wdbLQ8S5Cux9ZFeb391MRq9t82S/kTnfNZeNbJ/3d7ORWEFfRiheZ/pQ7s8CW+" +
+ "yuOejdO7AgMBAAECggEBALmIIA5wK0t6aGls6UAPBeA+0SsWg1NE7IzGNusqsIJI" +
+ "iOeJrCPygC9+IerfxLHrJ0FwPFERmMX/7CIRIT6ECnohK3k1IuH6WG7cUrtOosWr" +
+ "GBOf41PfpSab63STbfUsZrmNzPfLkoIMKioXdmIkIfrF4vEYDTSaafgYu+3loX6O" +
+ "I7zQgIaziJSD30iheFzm79VTSEHknvwGKdaKeQIAG4E2QMuAipz0Ggfgvkw7HfMO" +
+ "rOYd996r37ZXhfs2IPlDKLJa0AFpCkQhjmRHjxFOejrE3eG8bjz8PCQ7aAAFItD8" +
+ "4l3ce6m/jCWaZJzXGj3cJpXjiGraLYaxTWKbp3fENbkCgYEA8J+S8+SqvzzGD7wK" +
+ "7cb/cYWlSxDRUSZ77x0iNcxMkdrXcrvFpGEYcJWDhrygcn8/+81LC8/JHvWJFfhy" +
+ "yqQpJqmu8mTy/FtTnf26eYdYqR9QevLBCXOrg65c6M528gss5Oy7f/6Tq8AgTpJk" +
+ "mIOZ/Z4bGL1BubmuXETeHcdEAp8CgYEA78SiAdXzouaclMlvHWE/ch9EeTSpqJKP" +
+ "fmWOUDP7e/oY38pJRgJZO2nYaNEgpjepDwjuX49VMWDdJjtw+rYL1MT7rGuiJaRR" +
+ "3YmV08thLGlakU1iWjvT1LOYuq4OGj5/AkKcDGjEqCGxclqvPtNF83IWoNexxLqh" +
+ "Au6tT0/mVWUCgYEAmHVC8u1Lkme7RnTqp8WSTCdVl75MIZK0q8hVyKhtS2zRXYzD" +
+ "qWcryQmykEgrkOA3dh+ZER7SW59PAHCuqt5ghHK2ujZkDqj+zffZku7CqkWBBKWS" +
+ "0Z5Mad6sV4WZr7qM829bTbnLbuMIlUAEJO4dP6hRmtcvMbIIW8X2xf9fhBkCgYEA" +
+ "gJqnivSHSckIE4Y34zpWHZBH2fs1RQXXkaRHQR2gtk7fKKoHw1VfJ08OlKoXKRCR" +
+ "zU6tDPSEbYfXFrqrTs52ahl+JG1W+3m3r2wswP1Fkdywh19KcbvFU0FBml/hkJIU" +
+ "7dFsgftv//6SfxPFC52m131KRdtrrmmsEzaSHwhsM0ECgYBWwq+Su4ftErsKKYNJ" +
+ "Zx0Aq8cBGqSOz8+h4oQRjxi7rN/Rn1NAzmW4L0TAFqZhxK6xZFx1zP70dgbnxcWe" +
+ "Zer7cRS4Vsn4uNvxhYGB4+NIcOhL/r7/7OoHVvm5Cn+NgVthCXnRQ9E9MX66XV5C" +
+ "jLsXjc2CPf/lwNFqsVl7dlPNmg==";
+
+ }
+
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronOCSPPoviderTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronOCSPPoviderTest.java
new file mode 100644
index 00000000000..631dcd8e1e4
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronOCSPPoviderTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.junit.Test;
+import org.keycloak.crypto.elytron.ElytronOCSPProvider;
+import org.wildfly.security.x500.GeneralName;
+import org.wildfly.security.x500.cert.AccessDescription;
+import org.wildfly.security.x500.cert.AuthorityInformationAccessExtension;
+import org.wildfly.security.x500.cert.X509CertificateBuilder;
+
+/**
+ * @author David Anderson
+ */
+public class ElytronOCSPPoviderTest extends ElytronOCSPProvider {
+
+ @Test
+ public void responderURITest() throws NoSuchAlgorithmException, CertificateException, URISyntaxException, KeyStoreException, IOException, CertPathValidatorException, InvalidAlgorithmParameterException {
+ X509Certificate cert = createCert();
+
+ List luri = getResponderURIs(cert);
+
+ assertEquals(1, luri.size());
+ assertEquals("http://test.localhost/check", luri.get(0));
+
+ }
+
+ private X509Certificate createCert() throws NoSuchAlgorithmException, CertificateException {
+ X500Principal dn = new X500Principal("CN=testuser,OU=UNIT,O=TST");
+
+ KeyPair keyPair = KeyPairGenerator.getInstance("RSA").genKeyPair();
+ List accessDescriptions = new ArrayList<>();
+ String accessMethodId = "1.3.6.1.5.5.7.48.1";
+ GeneralName accessLocation = new GeneralName.URIName("http://test.localhost/check");
+ AccessDescription adesc = new AccessDescription(accessMethodId, accessLocation);
+ accessDescriptions.add(adesc);
+
+
+ X509CertificateBuilder cbuilder = new X509CertificateBuilder()
+ .setSubjectDn(dn)
+ .setIssuerDn(dn)
+
+ .setSigningKey(keyPair.getPrivate())
+ .setPublicKey(keyPair.getPublic())
+
+ .addExtension(new AuthorityInformationAccessExtension(accessDescriptions))
+
+ .setSignatureAlgorithmName("SHA256withRSA");
+
+ return cbuilder.build();
+ }
+
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronPemUtilsTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronPemUtilsTest.java
new file mode 100644
index 00000000000..4653cbc78e1
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronPemUtilsTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.security.NoSuchAlgorithmException;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.keycloak.rule.CryptoInitRule;
+
+public class ElytronPemUtilsTest {
+
+ @ClassRule
+ public static CryptoInitRule cinit = new CryptoInitRule();
+
+ @Test
+ public void testGenerateThumbprintSha1() throws NoSuchAlgorithmException {
+ String[] test = new String[] {"abcdefg"};
+ String encoded = org.keycloak.common.util.PemUtils.generateThumbprint(test, "SHA-1");
+ assertEquals(27, encoded.length());
+ }
+
+ @Test
+ public void testGenerateThumbprintSha256() throws NoSuchAlgorithmException {
+ String[] test = new String[] {"abcdefg"};
+ String encoded = org.keycloak.common.util.PemUtils.generateThumbprint(test, "SHA-256");
+ assertEquals(43, encoded.length());
+ }
+}
+
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronRSAVerifierTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronRSAVerifierTest.java
new file mode 100644
index 00000000000..dbc534a4434
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronRSAVerifierTest.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import org.keycloak.RSAVerifierTest;
+
+public class ElytronRSAVerifierTest extends RSAVerifierTest {
+
+}
diff --git a/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronSecureRandomTest.java b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronSecureRandomTest.java
new file mode 100644
index 00000000000..eddb5a40f6b
--- /dev/null
+++ b/crypto/elytron/src/test/java/org/keycloak/crypto/elytron/test/ElytronSecureRandomTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 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.crypto.elytron.test;
+
+import java.security.SecureRandom;
+
+import org.jboss.logging.Logger;
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.rule.CryptoInitRule;
+
+/**
+ * @author Marek Posolda
+ */
+public class ElytronSecureRandomTest {
+
+ @ClassRule
+ public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
+
+ protected static final Logger logger = Logger.getLogger(ElytronSecureRandomTest.class);
+
+ @Test
+ public void testSecureRandom() throws Exception {
+ logger.info(CryptoIntegration.dumpJavaSecurityProviders());
+
+ SecureRandom sc1 = new SecureRandom();
+ logger.infof(dumpSecureRandom("new SecureRandom()", sc1));
+
+ SecureRandom sc3 = SecureRandom.getInstance("SHA1PRNG");
+ logger.infof(dumpSecureRandom("SecureRandom.getInstance(\"SHA1PRNG\")", sc3));
+ Assert.assertEquals("SHA1PRNG", sc3.getAlgorithm());
+ }
+
+
+ private String dumpSecureRandom(String prefix, SecureRandom secureRandom) {
+ StringBuilder builder = new StringBuilder(prefix + ": algorithm: " + secureRandom.getAlgorithm() + ", provider: " + secureRandom.getProvider() + ", random numbers: ");
+ for (int i=0; i < 5; i++) {
+ builder.append(secureRandom.nextInt(1000) + ", ");
+ }
+ return builder.toString();
+ }
+}
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 1dd04127aaa..477780d5a9b 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,12 @@
package org.keycloak.crypto.fips;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.spec.ECField;
import java.security.spec.ECFieldF2m;
@@ -8,9 +15,19 @@ import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import java.security.Security;
+import java.security.Signature;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKeyFactory;
+
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.fips.FipsRSA;
@@ -23,6 +40,9 @@ import org.keycloak.common.crypto.CryptoConstants;
import org.keycloak.common.crypto.CertificateUtilsProvider;
import org.keycloak.common.crypto.PemUtilsProvider;
import org.keycloak.common.crypto.UserIdentityExtractorProvider;
+import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.util.KeystoreUtil.KeystoreFormat;
+import org.keycloak.crypto.JavaAlgorithm;
/**
@@ -118,4 +138,62 @@ public class FIPS1402Provider implements CryptoProvider {
public T getOCSPProver(Class clazz) {
return clazz.cast(new BCFIPSOCSPProvider());
}
+
+
+ @Override
+ public KeyPairGenerator getKeyPairGen(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException {
+ return KeyPairGenerator.getInstance(algorithm, BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException {
+ return KeyFactory.getInstance(algorithm , BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public Cipher getAesCbcCipher() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
+ return Cipher.getInstance("AES/CBC/PKCS7Padding", BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public Cipher getAesGcmCipher() throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException {
+ return Cipher.getInstance("AES/GCM/NoPadding", BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public SecretKeyFactory getSecretKeyFact(String keyAlgorithm) throws NoSuchAlgorithmException, NoSuchProviderException {
+ return SecretKeyFactory.getInstance(keyAlgorithm, BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public KeyStore getKeyStore(KeystoreFormat format) throws KeyStoreException, NoSuchProviderException {
+ if (format == KeystoreFormat.JKS) {
+ return KeyStore.getInstance(format.toString());
+ } else {
+ return KeyStore.getInstance(format.toString(), BouncyIntegration.PROVIDER);
+ }
+ }
+
+ @Override
+ public CertificateFactory getX509CertFactory() throws CertificateException, NoSuchProviderException {
+ return CertificateFactory.getInstance("X.509", BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public CertStore getCertStore(CollectionCertStoreParameters certStoreParams) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
+
+ return CertStore.getInstance("Collection", certStoreParams, BouncyIntegration.PROVIDER);
+
+ }
+
+ @Override
+ public CertPathBuilder getCertPathBuilder() throws NoSuchAlgorithmException, NoSuchProviderException {
+ return CertPathBuilder.getInstance("PKIX", BouncyIntegration.PROVIDER);
+ }
+
+ @Override
+ public Signature getSignature(String sigAlgName) throws NoSuchAlgorithmException, NoSuchProviderException {
+ return Signature.getInstance(JavaAlgorithm.getJavaAlgorithm(sigAlgName), BouncyIntegration.PROVIDER);
+
+ }
}
diff --git a/crypto/pom.xml b/crypto/pom.xml
index ab4f21bc107..90ddb551227 100644
--- a/crypto/pom.xml
+++ b/crypto/pom.xml
@@ -33,5 +33,6 @@
default
fips1402
+ elytron
\ No newline at end of file
diff --git a/integration/client-cli/admin-cli/pom.xml b/integration/client-cli/admin-cli/pom.xml
index d5d11a2287e..b4777ac2276 100755
--- a/integration/client-cli/admin-cli/pom.xml
+++ b/integration/client-cli/admin-cli/pom.xml
@@ -38,10 +38,18 @@
org.keycloak
keycloak-core
+
+ org.keycloak
+ ${keycloak.crypto.artifactId}
+
org.apache.httpcomponents
httpclient
+
+ org.jboss.logging
+ jboss-logging
+
junit
@@ -67,9 +75,9 @@
org.keycloak:keycloak-core
org/keycloak/util/**
+ org/keycloak/crypto/**
org/keycloak/json/**
- org/keycloak/jose/jws/**
- org/keycloak/jose/jwk/**
+ org/keycloak/jose/**
org/keycloak/representations/adapters/config/**
org/keycloak/representations/adapters/action/**
org/keycloak/representations/AccessTokenResponse.class
@@ -92,24 +100,7 @@
org/keycloak/TokenCategory.class
-
- org.keycloak:keycloak-common
-
- org/keycloak/common/util/**
-
-
-
- org.bouncycastle:bcprov-jdk15on
-
- **/**
-
-
-
- org.bouncycastle:bcpkix-jdk15on
-
- **/**
-
-
+
com.fasterxml.jackson.core:jackson-core
diff --git a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/KcAdmMain.java b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/KcAdmMain.java
index 948007701fb..4afa122b574 100644
--- a/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/KcAdmMain.java
+++ b/integration/client-cli/admin-cli/src/main/java/org/keycloak/client/admin/cli/KcAdmMain.java
@@ -27,6 +27,7 @@ import org.keycloak.client.admin.cli.aesh.AeshEnhancer;
import org.keycloak.client.admin.cli.aesh.Globals;
import org.keycloak.client.admin.cli.aesh.ValveInputStream;
import org.keycloak.client.admin.cli.commands.KcAdmCmd;
+import org.keycloak.common.crypto.CryptoIntegration;
import java.util.ArrayList;
import java.util.Arrays;
@@ -38,57 +39,59 @@ public class KcAdmMain {
public static void main(String [] args) {
+ CryptoIntegration.init(KcAdmMain.class.getClassLoader());
+
Globals.stdin = new ValveInputStream();
Settings settings = new SettingsBuilder()
- .logging(false)
- .readInputrc(false)
- .disableCompletion(true)
- .disableHistory(true)
- .enableAlias(false)
- .enableExport(false)
- .inputStream(Globals.stdin)
- .create();
-
+ .logging(false)
+ .readInputrc(false)
+ .disableCompletion(true)
+ .disableHistory(true)
+ .enableAlias(false)
+ .enableExport(false)
+ .inputStream(Globals.stdin)
+ .create();
+
CommandRegistry registry = new AeshCommandRegistryBuilder()
- .command(KcAdmCmd.class)
+ .command(KcAdmCmd.class)
.create();
-
+
AeshConsoleImpl console = (AeshConsoleImpl) new AeshConsoleBuilder()
- .settings(settings)
- .commandRegistry(registry)
- .prompt(new Prompt(""))
-// .commandInvocationProvider(new CommandInvocationServices() {
-//
-// })
- .create();
-
- AeshEnhancer.enhance(console);
-
- // work around parser issues with quotes and brackets
- ArrayList arguments = new ArrayList<>();
- arguments.add("kcadm");
- arguments.addAll(Arrays.asList(args));
- Globals.args = arguments;
-
- StringBuilder b = new StringBuilder();
- for (String s : args) {
- // quote if necessary
- boolean needQuote = false;
- needQuote = s.indexOf(' ') != -1 || s.indexOf('\"') != -1 || s.indexOf('\'') != -1;
- b.append(' ');
- if (needQuote) {
- b.append('\'');
- }
- b.append(s);
- if (needQuote) {
- b.append('\'');
+ .settings(settings)
+ .commandRegistry(registry)
+ .prompt(new Prompt(""))
+ // .commandInvocationProvider(new CommandInvocationServices() {
+ //
+ // })
+ .create();
+
+ AeshEnhancer.enhance(console);
+
+ // work around parser issues with quotes and brackets
+ ArrayList arguments = new ArrayList<>();
+ arguments.add("kcadm");
+ arguments.addAll(Arrays.asList(args));
+ Globals.args = arguments;
+
+ StringBuilder b = new StringBuilder();
+ for (String s : args) {
+ // quote if necessary
+ boolean needQuote = false;
+ needQuote = s.indexOf(' ') != -1 || s.indexOf('\"') != -1 || s.indexOf('\'') != -1;
+ b.append(' ');
+ if (needQuote) {
+ b.append('\'');
+ }
+ b.append(s);
+ if (needQuote) {
+ b.append('\'');
+ }
}
+ console.setEcho(false);
+
+ console.execute("kcadm" + b.toString());
+
+ console.start();
}
- console.setEcho(false);
-
- console.execute("kcadm" + b.toString());
-
- console.start();
}
-}
diff --git a/integration/client-cli/client-registration-cli/pom.xml b/integration/client-cli/client-registration-cli/pom.xml
index c1b08b5f920..c0299337f34 100755
--- a/integration/client-cli/client-registration-cli/pom.xml
+++ b/integration/client-cli/client-registration-cli/pom.xml
@@ -38,6 +38,14 @@
org.keycloak
keycloak-core
+
+ org.keycloak
+ ${keycloak.crypto.artifactId}
+
+
+ org.jboss.logging
+ jboss-logging
+
org.apache.httpcomponents
httpclient
@@ -66,9 +74,9 @@
org.keycloak:keycloak-core
org/keycloak/util/**
+ org/keycloak/crypto/**
org/keycloak/json/**
- org/keycloak/jose/jws/**
- org/keycloak/jose/jwk/**
+ org/keycloak/jose/**
org/keycloak/representations/adapters/config/**
org/keycloak/representations/AccessTokenResponse.class
org/keycloak/representations/idm/ClientRepresentation.class
@@ -84,6 +92,7 @@
org.keycloak:keycloak-common
org/keycloak/common/util/**
+ org/keycloak/common/crypto/**
diff --git a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/KcRegMain.java b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/KcRegMain.java
index 57fe0f6550b..7036d3dbac6 100644
--- a/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/KcRegMain.java
+++ b/integration/client-cli/client-registration-cli/src/main/java/org/keycloak/client/registration/cli/KcRegMain.java
@@ -11,6 +11,7 @@ import org.keycloak.client.registration.cli.aesh.AeshEnhancer;
import org.keycloak.client.registration.cli.aesh.ValveInputStream;
import org.keycloak.client.registration.cli.aesh.Globals;
import org.keycloak.client.registration.cli.commands.KcRegCmd;
+import org.keycloak.common.crypto.CryptoIntegration;
import java.util.ArrayList;
import java.util.Arrays;
@@ -22,6 +23,8 @@ public class KcRegMain {
public static void main(String [] args) {
+ CryptoIntegration.init(KcRegMain.class.getClassLoader());
+
Globals.stdin = new ValveInputStream();
Settings settings = new SettingsBuilder()
diff --git a/integration/client-registration/pom.xml b/integration/client-registration/pom.xml
index 0994f262698..5b209bfc0b4 100755
--- a/integration/client-registration/pom.xml
+++ b/integration/client-registration/pom.xml
@@ -35,8 +35,8 @@
keycloak-core
- org.apache.httpcomponents
- httpclient
+ org.keycloak
+ ${keycloak.crypto.artifactId}
diff --git a/pom.xml b/pom.xml
index 4bbfd908e24..b5fcf937486 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1610,6 +1610,11 @@
keycloak-crypto-fips1402
${project.version}
+
+ org.keycloak
+ keycloak-crypto-elytron
+ ${project.version}
+
org.keycloak
keycloak-admin-cli
diff --git a/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java b/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java
index a4310bf7c73..dea29500fff 100644
--- a/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java
+++ b/saml-core/src/test/java/org/keycloak/saml/processing/core/saml/v2/util/AssertionUtilTest.java
@@ -10,23 +10,18 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.StringReader;
-import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
+import java.util.Arrays;
import java.util.Scanner;
-import org.bouncycastle.openssl.PEMKeyPair;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-import org.bouncycastle.util.Arrays;
-import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.common.util.Base64;
import org.keycloak.common.util.DerUtils;
+import org.keycloak.common.util.PemUtils;
import org.keycloak.dom.saml.v2.assertion.NameIDType;
import org.keycloak.dom.saml.v2.assertion.SubjectType.STSubType;
import org.keycloak.dom.saml.v2.protocol.ResponseType;
@@ -66,7 +61,7 @@ public class AssertionUtilTest {
byte[] validSignature = Base64.decode(signatureElement.getTextContent());
// change the signature value slightly
- byte[] invalidSignature = Arrays.clone(validSignature);
+ byte[] invalidSignature = Arrays.copyOf(validSignature, validSignature.length);
invalidSignature[0] ^= invalidSignature[0];
signatureElement.setTextContent(Base64.encodeBytes(invalidSignature));
@@ -107,6 +102,7 @@ public class AssertionUtilTest {
}
private PrivateKey extractPrivateKey() throws IOException {
+
StringBuilder sb = new StringBuilder();
try (Scanner sc = new Scanner(getEncryptedIdTestFileInputStream())) {
while (sc.hasNextLine()) {
@@ -124,11 +120,7 @@ public class AssertionUtilTest {
}
}
assertNotEquals("PEM certificate not found in test data", 0, sb.length());
- PEMParser pp = new PEMParser(new StringReader(sb.toString()));
- PEMKeyPair pemKeyPair = (PEMKeyPair) pp.readObject();
- KeyPair kp = new JcaPEMKeyConverter().getKeyPair(pemKeyPair);
- pp.close();
- return kp.getPrivate();
+ return PemUtils.decodePrivateKey(sb.toString());
}
}
diff --git a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java
index b49c2e6f32d..1e6b25cd2ad 100644
--- a/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java
+++ b/server-spi-private/src/main/java/org/keycloak/credential/hash/Pbkdf2PasswordHashProvider.java
@@ -17,8 +17,8 @@
package org.keycloak.credential.hash;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.Base64;
-import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.credential.PasswordCredentialModel;
@@ -126,7 +126,8 @@ public class Pbkdf2PasswordHashProvider implements PasswordHashProvider {
private SecretKeyFactory getSecretKeyFactory() {
try {
- return SecretKeyFactory.getInstance(pbkdf2Algorithm, BouncyIntegration.PROVIDER);
+ return CryptoIntegration.getProvider().getSecretKeyFact(pbkdf2Algorithm);
+
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException("PBKDF2 algorithm not found", e);
}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/x509/CertificateValidator.java b/services/src/main/java/org/keycloak/authentication/authenticators/x509/CertificateValidator.java
index ae8788508a6..9db6fbe8396 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/x509/CertificateValidator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/x509/CertificateValidator.java
@@ -18,28 +18,8 @@
package org.keycloak.authentication.authenticators.x509;
-import org.apache.http.client.methods.HttpGet;
-import org.keycloak.common.crypto.CryptoConstants;
-import org.keycloak.common.crypto.CryptoIntegration;
-import org.keycloak.utils.OCSPProvider;
-import org.keycloak.common.util.BouncyIntegration;
-import org.keycloak.common.util.Time;
-import org.keycloak.connections.httpclient.HttpClientProvider;
-import org.keycloak.models.Constants;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.saml.common.exceptions.ProcessingException;
-import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
-import org.keycloak.services.ServicesLogger;
-import org.keycloak.truststore.TruststoreProvider;
-import org.keycloak.utils.CRLUtils;
+import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CERTIFICATE_POLICY_MODE_ANY;
-import javax.naming.Context;
-import javax.naming.NamingException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-import javax.security.auth.x500.X500Principal;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
@@ -49,19 +29,19 @@ import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.GeneralSecurityException;
+import java.security.cert.CRLException;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertStore;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
-import java.security.cert.CRLException;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.security.cert.X509CertSelector;
import java.security.cert.X509CRL;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -73,11 +53,30 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.security.auth.x500.X500Principal;
+
import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
-
-import static org.keycloak.authentication.authenticators.x509.AbstractX509ClientCertificateAuthenticator.CERTIFICATE_POLICY_MODE_ANY;
+import org.keycloak.common.crypto.CryptoIntegration;
+import org.keycloak.common.util.Time;
+import org.keycloak.connections.httpclient.HttpClientProvider;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.saml.common.exceptions.ProcessingException;
+import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
+import org.keycloak.services.ServicesLogger;
+import org.keycloak.truststore.TruststoreProvider;
+import org.keycloak.utils.CRLUtils;
+import org.keycloak.utils.OCSPProvider;
/**
* @author Peter Nalyvayko
@@ -643,12 +642,11 @@ public class CertificateValidator {
for (X509Certificate clientCert : certChain) {
intermediateCerts.add(clientCert);
}
- CertStore intermediateCertStore = CertStore.getInstance("Collection",
- new CollectionCertStoreParameters(intermediateCerts), BouncyIntegration.PROVIDER);
+ CertStore intermediateCertStore = CryptoIntegration.getProvider().getCertStore(new CollectionCertStoreParameters(intermediateCerts));
pkixParams.addCertStore(intermediateCertStore);
// Build and verify the certification chain
- CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", BouncyIntegration.PROVIDER);
+ CertPathBuilder builder = CryptoIntegration.getProvider().getCertPathBuilder();
PKIXCertPathBuilderResult result =
(PKIXCertPathBuilderResult) builder.build(pkixParams);
return result;
diff --git a/services/src/main/java/org/keycloak/protocol/docker/installation/compose/DockerComposeCertsDirectory.java b/services/src/main/java/org/keycloak/protocol/docker/installation/compose/DockerComposeCertsDirectory.java
index 01ffa9516a9..2d5746c42de 100644
--- a/services/src/main/java/org/keycloak/protocol/docker/installation/compose/DockerComposeCertsDirectory.java
+++ b/services/src/main/java/org/keycloak/protocol/docker/installation/compose/DockerComposeCertsDirectory.java
@@ -1,7 +1,8 @@
package org.keycloak.protocol.docker.installation.compose;
-import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.CertificateUtils;
+import org.keycloak.crypto.KeyType;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@@ -24,9 +25,8 @@ public class DockerComposeCertsDirectory {
public DockerComposeCertsDirectory(final String directoryName, final Certificate realmCert, final String registryCertFilename, final String registryKeyFilename, final String idpCertTrustChainFilename, final String realmName) {
this.directoryName = directoryName;
- final KeyPairGenerator keyGen;
try {
- keyGen = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER);
+ final KeyPairGenerator keyGen = CryptoIntegration.getProvider().getKeyPairGen(KeyType.RSA);
keyGen.initialize(2048, new SecureRandom());
final KeyPair keypair = keyGen.generateKeyPair();
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
index 22cf0a40c33..02944c5c181 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
@@ -23,9 +23,10 @@ import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput;
import javax.ws.rs.NotAcceptableException;
import javax.ws.rs.NotFoundException;
-import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.PemUtils;
import org.keycloak.common.util.StreamUtil;
+import org.keycloak.common.util.KeystoreUtil.KeystoreFormat;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.jose.jwk.JSONWebKeySet;
@@ -228,9 +229,7 @@ public class ClientAttributeCertificateResource {
PrivateKey privateKey = null;
X509Certificate certificate = null;
try {
- KeyStore keyStore = null;
- if (keystoreFormat.equals("JKS")) keyStore = KeyStore.getInstance("JKS");
- else keyStore = KeyStore.getInstance(keystoreFormat, BouncyIntegration.PROVIDER);
+ KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(KeystoreFormat.valueOf(keystoreFormat));
keyStore.load(inputParts.get(0).getBody(InputStream.class, null), storePassword);
try {
privateKey = (PrivateKey)keyStore.getKey(keyAlias, keyPassword);
@@ -332,9 +331,7 @@ public class ClientAttributeCertificateResource {
private byte[] getKeystore(KeyStoreConfig config, String privatePem, String certPem) {
try {
String format = config.getFormat();
- KeyStore keyStore;
- if (format.equals("JKS")) keyStore = KeyStore.getInstance("JKS");
- else keyStore = KeyStore.getInstance(format, BouncyIntegration.PROVIDER);
+ KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(KeystoreFormat.valueOf(format));
keyStore.load(null, null);
String keyAlias = config.getKeyAlias();
if (keyAlias == null) keyAlias = client.getClientId();
diff --git a/services/src/main/java/org/keycloak/services/x509/NginxProxySslClientCertificateLookup.java b/services/src/main/java/org/keycloak/services/x509/NginxProxySslClientCertificateLookup.java
index b4a117fdcab..54093bc6f14 100644
--- a/services/src/main/java/org/keycloak/services/x509/NginxProxySslClientCertificateLookup.java
+++ b/services/src/main/java/org/keycloak/services/x509/NginxProxySslClientCertificateLookup.java
@@ -24,7 +24,7 @@ import java.util.Set;
import org.jboss.logging.Logger;
import org.jboss.logging.Logger.Level;
import org.jboss.resteasy.spi.HttpRequest;
-import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.PemException;
import org.keycloak.common.util.PemUtils;
import org.keycloak.models.KeycloakSession;
@@ -186,11 +186,11 @@ public class NginxProxySslClientCertificateLookup extends AbstractClientCertific
// Adding the list of intermediate certificates + end user certificate
intermediateCerts.add(end_user_auth_cert);
CollectionCertStoreParameters intermediateCA_userCert = new CollectionCertStoreParameters(intermediateCerts);
- CertStore intermediateCertStore = CertStore.getInstance("Collection", intermediateCA_userCert, BouncyIntegration.PROVIDER);
+ CertStore intermediateCertStore = CryptoIntegration.getProvider().getCertStore(intermediateCA_userCert);
pkixParams.addCertStore(intermediateCertStore);
// Build and verify the certification chain (revocation status excluded)
- CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX",BouncyIntegration.PROVIDER);
+ CertPathBuilder certPathBuilder = CryptoIntegration.getProvider().getCertPathBuilder();
CertPath certPath = certPathBuilder.build(pkixParams).getCertPath();
log.debug("Certification path building OK, and contains " + certPath.getCertificates().size() + " X509 Certificates");
diff --git a/services/src/test/java/org/keycloak/authentication/authenticators/x509/CertificateValidatorTest.java b/services/src/test/java/org/keycloak/authentication/authenticators/x509/CertificateValidatorTest.java
index 80b1c0ef40a..696878c0194 100644
--- a/services/src/test/java/org/keycloak/authentication/authenticators/x509/CertificateValidatorTest.java
+++ b/services/src/test/java/org/keycloak/authentication/authenticators/x509/CertificateValidatorTest.java
@@ -6,7 +6,7 @@ import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.common.crypto.CryptoIntegration;
-import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.crypto.KeyType;
import org.keycloak.rule.CryptoInitRule;
import java.security.GeneralSecurityException;
@@ -34,7 +34,7 @@ public class CertificateValidatorTest {
*/
@Test
public void testValidityOfCertificatesSuccess() throws GeneralSecurityException {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyPairGenerator kpg = CryptoIntegration.getProvider().getKeyPairGen(KeyType.RSA);
kpg.initialize(512);
KeyPair keyPair = kpg.generateKeyPair();
X509Certificate certificate = CryptoIntegration.getProvider().getCertificateUtils()
@@ -60,7 +60,7 @@ public class CertificateValidatorTest {
*/
@Test
public void testValidityOfCertificatesNotValidYet() throws GeneralSecurityException {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyPairGenerator kpg = CryptoIntegration.getProvider().getKeyPairGen(KeyType.RSA);
kpg.initialize(512);
KeyPair keyPair = kpg.generateKeyPair();
X509Certificate certificate = CryptoIntegration.getProvider().getCertificateUtils()
@@ -87,7 +87,7 @@ public class CertificateValidatorTest {
*/
@Test
public void testValidityOfCertificatesHasExpired() throws GeneralSecurityException {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyPairGenerator kpg = CryptoIntegration.getProvider().getKeyPairGen(KeyType.RSA);
kpg.initialize(512);
KeyPair keyPair = kpg.generateKeyPair();
X509Certificate certificate = CryptoIntegration.getProvider().getCertificateUtils()
@@ -330,9 +330,7 @@ public class CertificateValidatorTest {
private void testCertificatePolicyValidation(String expectedPolicy, String mode, String... certificatePolicyOid)
throws GeneralSecurityException
{
-
-
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyPairGenerator kpg = CryptoIntegration.getProvider().getKeyPairGen(KeyType.RSA);
kpg.initialize(512);
KeyPair keyPair = kpg.generateKeyPair();
X509Certificate certificate = CryptoIntegration.getProvider().getCertificateUtils()
diff --git a/services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java b/services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java
index d704a927f1f..3bcff1ba420 100644
--- a/services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java
+++ b/services/src/test/java/org/keycloak/procotol/docker/installation/DockerComposeYamlInstallationProviderTest.java
@@ -33,9 +33,10 @@ import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
-import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.PemUtils;
+import org.keycloak.crypto.KeyType;
import org.keycloak.protocol.docker.installation.DockerComposeYamlInstallationProvider;
import org.keycloak.rule.CryptoInitRule;
@@ -49,8 +50,7 @@ public class DockerComposeYamlInstallationProviderTest {
@Before
public void setUp() throws Exception {
- final KeyPairGenerator keyGen;
- keyGen = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER);
+ final KeyPairGenerator keyGen = CryptoIntegration.getProvider().getKeyPairGen(KeyType.RSA);
keyGen.initialize(2048, new SecureRandom());
final KeyPair keypair = keyGen.generateKeyPair();
diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml
index 788d9680178..45873f872e1 100644
--- a/testsuite/integration-arquillian/tests/base/pom.xml
+++ b/testsuite/integration-arquillian/tests/base/pom.xml
@@ -61,6 +61,12 @@
+
+ org.keycloak
+ keycloak-core
+ test
+ test-jar
+
commons-configuration
commons-configuration
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
index d1a4f596b83..c451634db33 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/KeyUtils.java
@@ -1,7 +1,8 @@
package org.keycloak.testsuite.util;
-import org.keycloak.common.util.BouncyIntegration;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.crypto.KeyStatus;
+import org.keycloak.crypto.KeyType;
import org.keycloak.crypto.KeyUse;
import org.keycloak.representations.idm.KeysMetadataRepresentation;
@@ -22,7 +23,7 @@ public class KeyUtils {
public static PublicKey publicKeyFromString(String key) {
try {
- KeyFactory kf = KeyFactory.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory(KeyType.RSA);
byte[] encoded = Base64.getDecoder().decode(key);
return kf.generatePublic(new X509EncodedKeySpec(encoded));
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
@@ -32,7 +33,7 @@ public class KeyUtils {
public static PrivateKey privateKeyFromString(String key) {
try {
- KeyFactory kf = KeyFactory.getInstance("RSA", BouncyIntegration.PROVIDER);
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory(KeyType.RSA);
byte[] encoded = Base64.getDecoder().decode(key);
return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/TokenSignatureUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/TokenSignatureUtil.java
index 3fd8307c8ee..5c5fb3cd176 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/TokenSignatureUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/TokenSignatureUtil.java
@@ -29,8 +29,8 @@ import javax.ws.rs.core.Response;
import org.jboss.logging.Logger;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.Base64;
-import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.crypto.Algorithm;
import org.keycloak.crypto.JavaAlgorithm;
@@ -188,8 +188,7 @@ public class TokenSignatureUtil {
private static Signature getSignature(String sigAlgName) {
try {
- // use Bouncy Castle for signature verification intentionally
- Signature signature = Signature.getInstance(JavaAlgorithm.getJavaAlgorithm(sigAlgName), BouncyIntegration.PROVIDER);
+ Signature signature = CryptoIntegration.getProvider().getSignature(JavaAlgorithm.getJavaAlgorithm(sigAlgName));
return signature;
} catch (Exception e) {
throw new RuntimeException(e);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientPoliciesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientPoliciesTest.java
index d5e784b86c7..1bbaf3de6c4 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientPoliciesTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/AbstractClientPoliciesTest.java
@@ -61,7 +61,6 @@ import org.hamcrest.Matchers;
import org.jboss.logging.Logger;
import org.junit.After;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Rule;
import org.keycloak.OAuth2Constants;
import org.keycloak.OAuthErrorException;
@@ -71,9 +70,9 @@ import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
import org.keycloak.client.registration.Auth;
import org.keycloak.client.registration.ClientRegistration;
import org.keycloak.client.registration.ClientRegistrationException;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.Base64;
import org.keycloak.common.util.Base64Url;
-import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.Time;
@@ -400,14 +399,14 @@ public abstract class AbstractClientPoliciesTest extends AbstractKeycloakTest {
private PrivateKey decodePrivateKey(byte[] der, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(der);
String keyAlg = getKeyAlgorithmFromJwaAlgorithm(algorithm);
- KeyFactory kf = KeyFactory.getInstance(keyAlg, BouncyIntegration.PROVIDER);
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory(keyAlg);
return kf.generatePrivate(spec);
}
private PublicKey decodePublicKey(byte[] der, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
X509EncodedKeySpec spec = new X509EncodedKeySpec(der);
String keyAlg = getKeyAlgorithmFromJwaAlgorithm(algorithm);
- KeyFactory kf = KeyFactory.getInstance(keyAlg, BouncyIntegration.PROVIDER);
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory(keyAlg);
return kf.generatePublic(spec);
}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
index 8a22142fa78..4588321d6dd 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
@@ -43,15 +43,16 @@ import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.authentication.AuthenticationFlowError;
import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
import org.keycloak.common.constants.ServiceAccountConstants;
+import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.util.Base64;
import org.keycloak.common.util.Base64Url;
-import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.KeycloakUriBuilder;
import org.keycloak.common.util.KeystoreUtil;
import org.keycloak.common.util.PemUtils;
import org.keycloak.common.util.Time;
import org.keycloak.common.util.UriUtils;
+import org.keycloak.common.util.KeystoreUtil.KeystoreFormat;
import org.keycloak.constants.ServiceUrlConstants;
import org.keycloak.crypto.Algorithm;
import org.keycloak.crypto.ECDSASignatureProvider;
@@ -1382,7 +1383,7 @@ public class ClientAuthSignedJWTTest extends AbstractKeycloakTest {
}
private static KeyStore getKeystore(InputStream is, String storePassword, String format) throws Exception {
- KeyStore keyStore = format.equals("JKS") ? KeyStore.getInstance(format) : KeyStore.getInstance(format, BouncyIntegration.PROVIDER);
+ KeyStore keyStore = CryptoIntegration.getProvider().getKeyStore(KeystoreFormat.valueOf(format));
keyStore.load(is, storePassword.toCharArray());
return keyStore;
}
@@ -1455,14 +1456,14 @@ public class ClientAuthSignedJWTTest extends AbstractKeycloakTest {
private static PrivateKey decodePrivateKey(byte[] der, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(der);
String keyAlg = getKeyAlgorithmFromJwaAlgorithm(algorithm);
- KeyFactory kf = KeyFactory.getInstance(keyAlg, BouncyIntegration.PROVIDER);
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory(keyAlg);
return kf.generatePrivate(spec);
}
private static PublicKey decodePublicKey(byte[] der, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
X509EncodedKeySpec spec = new X509EncodedKeySpec(der);
String keyAlg = getKeyAlgorithmFromJwaAlgorithm(algorithm);
- KeyFactory kf = KeyFactory.getInstance(keyAlg, BouncyIntegration.PROVIDER);
+ KeyFactory kf = CryptoIntegration.getProvider().getKeyFactory(keyAlg);
return kf.generatePublic(spec);
}