Remove BC dependancy from keycloak-core (#13235)

Closes #12856
This commit is contained in:
David Anderson 2022-07-23 05:07:16 -05:00 committed by GitHub
parent 9bb1299d89
commit ee0c67c0c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 225 additions and 129 deletions

View file

@ -3,6 +3,7 @@ package org.keycloak.common.crypto;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.spec.ECParameterSpec;
/** /**
* Abstraction to handle differences between the APIs for non-fips and fips mode * Abstraction to handle differences between the APIs for non-fips and fips mode
@ -43,4 +44,13 @@ public interface CryptoProvider {
*/ */
public PemUtilsProvider getPemUtils(); public PemUtilsProvider getPemUtils();
/**
* Create the param spec for the EC curve
*
* @param curveName
* @return
*/
public ECParameterSpec createECParams(String curveName);
} }

View file

@ -46,14 +46,6 @@
<groupId>org.keycloak</groupId> <groupId>org.keycloak</groupId>
<artifactId>keycloak-common</artifactId> <artifactId>keycloak-common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId> <artifactId>jackson-core</artifactId>

View file

@ -36,14 +36,14 @@ public class KeyPairVerifier {
try { try {
privateKey = PemUtils.decodePrivateKey(privateKeyPem); privateKey = PemUtils.decodePrivateKey(privateKeyPem);
} catch (Exception e) { } catch (Exception e) {
throw new VerificationException("Failed to decode private key"); throw new VerificationException("Failed to decode private key", e);
} }
PublicKey publicKey; PublicKey publicKey;
try { try {
publicKey = PemUtils.decodePublicKey(publicKeyPem); publicKey = PemUtils.decodePublicKey(publicKeyPem);
} catch (Exception e) { } catch (Exception e) {
throw new VerificationException("Failed to decode public key"); throw new VerificationException("Failed to decode public key", e);
} }
try { try {

View file

@ -17,9 +17,8 @@
package org.keycloak.jose.jwk; package org.keycloak.jose.jwk;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.keycloak.common.crypto.CryptoIntegration;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.crypto.KeyType; import org.keycloak.crypto.KeyType;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -27,6 +26,7 @@ import org.keycloak.util.JsonSerialization;
import java.math.BigInteger; import java.math.BigInteger;
import java.security.KeyFactory; import java.security.KeyFactory;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint; import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec; import java.security.spec.ECPublicKeySpec;
import java.security.spec.RSAPublicKeySpec; import java.security.spec.RSAPublicKeySpec;
@ -99,9 +99,9 @@ public class JWKParser {
} }
try { try {
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(name);
ECNamedCurveSpec params = new ECNamedCurveSpec("prime256v1", spec.getCurve(), spec.getG(), spec.getN());
ECPoint point = new ECPoint(x, y); ECPoint point = new ECPoint(x, y);
ECParameterSpec params = CryptoIntegration.getProvider().createECParams(name);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params); ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
KeyFactory kf = KeyFactory.getInstance("ECDSA"); KeyFactory kf = KeyFactory.getInstance("ECDSA");

View file

@ -19,7 +19,6 @@ package org.keycloak;
import org.junit.Assert; import org.junit.Assert;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.VerificationException; import org.keycloak.common.VerificationException;
import org.keycloak.rule.CryptoInitRule; import org.keycloak.rule.CryptoInitRule;
@ -34,10 +33,10 @@ public abstract class KeyPairVerifierTest {
@ClassRule @ClassRule
public static CryptoInitRule cryptoInitRule = new CryptoInitRule(); public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
String privateKey1 = "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y="; protected String privateKey1 = "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=";
String publicKey1 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"; String publicKey1 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
String privateKey2048 = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpQIBAAKCAQEA4V3MpOnuKsdBbR1UzNjK9o5meEMQ4s5Vpykhv1DpqTilKOiE\n" protected String privateKey2048 = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpQIBAAKCAQEA4V3MpOnuKsdBbR1UzNjK9o5meEMQ4s5Vpykhv1DpqTilKOiE\n"
+ "H7VQ/XtjNxw0yjnFBilCnpK6yN9mDEHbBEzaRjtdrgVhkIejiaXFBP5MBhUQ5l9u\n" + "8E3IZC3E8pwDjVF0Z9u0R4lGeUg2k6O+NKumqIvxoLCTuG0zf53bctGsRd57LuFi\n" + "H7VQ/XtjNxw0yjnFBilCnpK6yN9mDEHbBEzaRjtdrgVhkIejiaXFBP5MBhUQ5l9u\n" + "8E3IZC3E8pwDjVF0Z9u0R4lGeUg2k6O+NKumqIvxoLCTuG0zf53bctGsRd57LuFi\n"
+ "pgCkNyxvscOhulsbEMYrLwlb5bMGgx9v+RCnwvunNEb7RK+5pzP+iH1MRejRsX+U\n" + "7h9zHRn2gQhIl7SzG9GXebuPWr4KKwfMHWy0PEuQrsfWRXm9/dTEavbfNkv5E53z\n" + "pgCkNyxvscOhulsbEMYrLwlb5bMGgx9v+RCnwvunNEb7RK+5pzP+iH1MRejRsX+U\n" + "7h9zHRn2gQhIl7SzG9GXebuPWr4KKwfMHWy0PEuQrsfWRXm9/dTEavbfNkv5E53z\n"
+ "WXjWyf93ezkVhBX0YoXmf6UO7PAlvsrjno3TuwIDAQABAoIBAQC5iCAOcCtLemhp\n" + "bOlADwXgPtErFoNTROyMxjbrKrCCSIjniawj8oAvfiHq38Sx6ydBcDxREZjF/+wi\n" + "WXjWyf93ezkVhBX0YoXmf6UO7PAlvsrjno3TuwIDAQABAoIBAQC5iCAOcCtLemhp\n" + "bOlADwXgPtErFoNTROyMxjbrKrCCSIjniawj8oAvfiHq38Sx6ydBcDxREZjF/+wi\n"

View file

@ -17,101 +17,44 @@
package org.keycloak; package org.keycloak;
import junit.framework.Assert; import org.junit.Assert;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v1CertificateBuilder;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.OperatorCreationException;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.util.Time; import org.keycloak.common.util.Time;
import org.keycloak.common.VerificationException; import org.keycloak.common.VerificationException;
import org.keycloak.jose.jws.JWSBuilder; import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.rule.CryptoInitRule;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
import org.keycloak.util.TokenUtil; import org.keycloak.util.TokenUtil;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigInteger;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.InvalidKeyException;
import java.security.KeyPair; import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.SignatureException;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RSAVerifierTest { public abstract class RSAVerifierTest {
private static X509Certificate[] idpCertificates; // private static X509Certificate[] idpCertificates;
private static KeyPair idpPair; private static KeyPair idpPair;
private static KeyPair badPair; private static KeyPair badPair;
private static KeyPair clientPair; // private static KeyPair clientPair;
private static X509Certificate[] clientCertificateChain; // private static X509Certificate[] clientCertificateChain;
private AccessToken token; private AccessToken token;
public static X509Certificate generateTestCertificate(String subject, String issuer, KeyPair pair) @ClassRule
throws CertificateException, InvalidKeyException, IOException, public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
NoSuchProviderException, OperatorCreationException,
SignatureException
{
X500Name issuerDN = new X500Name("CN=" + issuer);
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis());
Date notBefore = new Date(System.currentTimeMillis() - 10000);
Date notAfter = new Date(System.currentTimeMillis() + 10000);
X500Name subjectDN = new X500Name("CN=" + subject);
SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo
.getInstance(pair.getPublic().getEncoded());
X509v1CertificateBuilder builder = new X509v1CertificateBuilder(
issuerDN, serialNumber, notBefore, notAfter, subjectDN, subjectPublicKeyInfo
);
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder()
.find("SHA256WithRSAEncryption");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder()
.find(sigAlgId);
ContentSigner signer = new BcRSAContentSignerBuilder(sigAlgId, digAlgId)
.build(PrivateKeyFactory.createKey(pair.getPrivate().getEncoded()));
X509CertificateHolder holder = builder.build(signer);
return new JcaX509CertificateConverter().getCertificate(holder);
}
@BeforeClass @BeforeClass
public static void setupCerts() public static void setupCerts()
throws CertificateException, InvalidKeyException, IOException, throws Exception
NoSuchAlgorithmException, NoSuchProviderException,
OperatorCreationException, SignatureException
{ {
// CryptoIntegration.init(ClassLoader.getSystemClassLoader());
badPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); badPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
idpPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); idpPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
idpCertificates = new X509Certificate[]{generateTestCertificate("CN=IDP", "CN=IDP", idpPair)};
clientPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
clientCertificateChain = new X509Certificate[]{generateTestCertificate("CN=Client", "CN=IDP", idpPair)};
} }
@Before @Before
@ -124,21 +67,6 @@ public class RSAVerifierTest {
.addAccess("service").addRole("admin"); .addAccess("service").addRole("admin");
} }
@Test
public void testPemWriter() {
PublicKey realmPublicKey = idpPair.getPublic();
StringWriter sw = new StringWriter();
JcaPEMWriter writer = new JcaPEMWriter(sw);
try {
writer.writeObject(realmPublicKey);
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println(sw.toString());
}
@Test @Test
public void testSimpleVerification() throws Exception { public void testSimpleVerification() throws Exception {
String encoded = new JWSBuilder() String encoded = new JWSBuilder()
@ -154,7 +82,6 @@ public class RSAVerifierTest {
return RSATokenVerifier.verifyToken(encoded, idpPair.getPublic(), "http://localhost:8080/auth/realm"); return RSATokenVerifier.verifyToken(encoded, idpPair.getPublic(), "http://localhost:8080/auth/realm");
} }
// @Test // @Test
public void testSpeed() throws Exception public void testSpeed() throws Exception
{ {
@ -176,8 +103,6 @@ public class RSAVerifierTest {
System.out.println("took: " + end); System.out.println("took: " + end);
} }
@Test @Test
public void testBadSignature() { public void testBadSignature() {

View file

@ -18,10 +18,12 @@
package org.keycloak.jose; package org.keycloak.jose;
import org.junit.Assert; import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.jose.jws.JWSBuilder; import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.HMACProvider; import org.keycloak.jose.jws.crypto.HMACProvider;
import org.keycloak.rule.CryptoInitRule;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
@ -31,7 +33,10 @@ import java.util.UUID;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class HmacTest { public abstract class HmacTest {
@ClassRule
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
@Test @Test
public void testHmacSignatures() throws Exception { public void testHmacSignatures() throws Exception {
@ -43,5 +48,4 @@ public class HmacTest {
Assert.assertTrue(HMACProvider.verify(input, secret)); Assert.assertTrue(HMACProvider.verify(input, secret));
} }
} }

View file

@ -21,7 +21,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.util.Base64Url; import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.BouncyIntegration; import org.keycloak.common.util.BouncyIntegration;
@ -62,7 +61,7 @@ public abstract class JWKTest {
@Test @Test
public void publicRs256() throws Exception { public void publicRs256() throws Exception {
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); KeyPair keyPair = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER ).generateKeyPair();
PublicKey publicKey = keyPair.getPublic(); PublicKey publicKey = keyPair.getPublic();
X509Certificate certificate = generateV1SelfSignedCertificate(keyPair, "Test"); X509Certificate certificate = generateV1SelfSignedCertificate(keyPair, "Test");
@ -97,7 +96,7 @@ public abstract class JWKTest {
@Test @Test
public void publicRs256Chain() throws Exception { public void publicRs256Chain() throws Exception {
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); KeyPair keyPair = KeyPairGenerator.getInstance("RSA", BouncyIntegration.PROVIDER).generateKeyPair();
PublicKey publicKey = keyPair.getPublic(); PublicKey publicKey = keyPair.getPublic();
List<X509Certificate> certificates = Arrays.asList(generateV1SelfSignedCertificate(keyPair, "Test"), generateV1SelfSignedCertificate(keyPair, "Intermediate")); List<X509Certificate> certificates = Arrays.asList(generateV1SelfSignedCertificate(keyPair, "Test"), generateV1SelfSignedCertificate(keyPair, "Intermediate"));

View file

@ -17,30 +17,25 @@
package org.keycloak.util; package org.keycloak.util;
import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.util.Base64Url;
import org.keycloak.common.util.CertificateUtils;
import org.keycloak.common.util.KeyUtils;
import org.keycloak.common.util.PemUtils;
import org.keycloak.crypto.JavaAlgorithm;
import org.keycloak.crypto.KeyUse; import org.keycloak.crypto.KeyUse;
import org.keycloak.crypto.KeyWrapper; import org.keycloak.crypto.KeyWrapper;
import org.keycloak.jose.jwk.*; import org.keycloak.jose.jwk.*;
import org.keycloak.rule.CryptoInitRule;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.util.Map; import java.util.Map;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class JWKSUtilsTest { public abstract class JWKSUtilsTest {
@ClassRule
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
@Test @Test
public void publicRs256() throws Exception { public void publicRs256() throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
String kidRsa1 = "key1"; String kidRsa1 = "key1";
String kidRsa2 = "key2"; String kidRsa2 = "key2";

View file

@ -2,10 +2,14 @@ package org.keycloak.crypto.def;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.spec.ECParameterSpec;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.keycloak.common.crypto.CryptoProvider; import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.common.crypto.CryptoProviderTypes; import org.keycloak.common.crypto.CryptoProviderTypes;
@ -48,4 +52,10 @@ public class DefaultCryptoProvider implements CryptoProvider {
return new BCPemUtilsProvider(); return new BCPemUtilsProvider();
} }
@Override
public ECParameterSpec createECParams(String curveName) {
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(curveName);
return new ECNamedCurveSpec("prime256v1", spec.getCurve(), spec.getG(), spec.getN());
}
} }

View file

@ -0,0 +1,11 @@
package org.keycloak.crypto.def.test;
import org.keycloak.jose.HmacTest;
/**
* Test with bouncycastle security provider
*
*/
public class DefaultCryptoHmacTest extends HmacTest {
}

View file

@ -0,0 +1,10 @@
package org.keycloak.crypto.def.test;
import org.keycloak.util.JWKSUtilsTest;
/**
* Test with bouncycastle security provider
*
*/
public class DefaultCryptoJWKSUtilsTest extends JWKSUtilsTest {
}

View file

@ -0,0 +1,10 @@
package org.keycloak.crypto.def.test;
import org.keycloak.RSAVerifierTest;
/**
* Test with bouncycastle security provider
*
*/
public class DefaultCryptoRSAVerifierTest extends RSAVerifierTest {
}

View file

@ -1,6 +1,7 @@
package org.keycloak.crypto.def.test; package org.keycloak.crypto.def.test;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.crypto.CryptoIntegration; import org.keycloak.common.crypto.CryptoIntegration;
import org.keycloak.common.crypto.CryptoProviderTypes; import org.keycloak.common.crypto.CryptoProviderTypes;
@ -12,6 +13,11 @@ import org.keycloak.jose.jwe.alg.JWEAlgorithmProvider;
*/ */
public class DefaultCryptoUnitTest { public class DefaultCryptoUnitTest {
@Before
public void init() {
CryptoIntegration.init(ClassLoader.getSystemClassLoader());
}
@Test @Test
public void testDefaultCrypto() throws Exception { public void testDefaultCrypto() throws Exception {
JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER); JWEAlgorithmProvider jweAlg = CryptoIntegration.getProvider().getAlgorithmProvider(JWEAlgorithmProvider.class, CryptoProviderTypes.AES_KEY_WRAP_ALGORITHM_PROVIDER);

View file

@ -3,11 +3,20 @@ package org.keycloak.crypto.fips;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.spec.ECField;
import java.security.spec.ECFieldF2m;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider; import org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider;
import org.bouncycastle.math.ec.ECCurve;
import org.keycloak.common.crypto.CryptoProvider; import org.keycloak.common.crypto.CryptoProvider;
import org.keycloak.common.crypto.CryptoProviderTypes; import org.keycloak.common.crypto.CryptoProviderTypes;
import org.keycloak.common.crypto.CertificateUtilsProvider; import org.keycloak.common.crypto.CertificateUtilsProvider;
@ -51,4 +60,34 @@ public class FIPS1402Provider implements CryptoProvider {
public PemUtilsProvider getPemUtils() { public PemUtilsProvider getPemUtils() {
return new BCFIPSPemUtilsProvider(); return new BCFIPSPemUtilsProvider();
} }
/* Create EC Params using BC FipS APIs.
*
* @see org.keycloak.common.crypto.CryptoProvider#createECParams(java.lang.String)
*/
@Override
public ECParameterSpec createECParams(String curveName) {
X9ECParameters params = ECNamedCurveTable.getByName(curveName);
ECField field ;
ECCurve ecCurve = params.getCurve();
if (ecCurve instanceof ECCurve.F2m) {
ECCurve.F2m f2m = (ECCurve.F2m) ecCurve;
field = new ECFieldF2m(f2m.getM(), new int[] { f2m.getK1(), f2m.getK2(), f2m.getK3()});
}
else
if (ecCurve instanceof ECCurve.Fp) {
ECCurve.Fp fp = (ECCurve.Fp) ecCurve;
field = new ECFieldFp(fp.getQ());
}
else
throw new RuntimeException("Unsupported curve");
EllipticCurve c = new EllipticCurve(field,
ecCurve.getA().toBigInteger(),
ecCurve.getB().toBigInteger(),
params.getSeed());
ECPoint point = new ECPoint( params.getG().getXCoord().toBigInteger(), params.getG().getYCoord().toBigInteger());
return new ECParameterSpec( c,point, params.getN(), params.getH().intValue());
}
} }

View file

@ -0,0 +1,36 @@
package org.keycloak.crypto.fips.test;
import java.util.UUID;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.SecretKeySpec;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.common.util.BouncyIntegration;
import org.keycloak.jose.HmacTest;
import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.HMACProvider;
/**
* Another variation to this test using SecretKeyFactory
*
*/
public class FIPS1402HmacTest extends HmacTest {
@Test
public void testHmacSignaturesFIPS() throws Exception {
//
SecretKeyFactory skFact = SecretKeyFactory.getInstance("HmacSHA256", BouncyIntegration.PROVIDER );
SecretKey secret = skFact.generateSecret(new SecretKeySpec(UUID.randomUUID().toString().getBytes(), "HmacSHA256"));
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));
}
}

View file

@ -1,6 +1,5 @@
package org.keycloak.crypto.fips.test; package org.keycloak.crypto.fips.test;
import org.junit.Ignore;
import org.keycloak.jose.JWETest; import org.keycloak.jose.JWETest;
/** /**
@ -8,6 +7,5 @@ import org.keycloak.jose.JWETest;
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@Ignore("Ignored by default as it does not work on non-fips enabled environment") // TODO: Figure how to test in the FIPS environments, but still keep disabled in the non-FIPS environments
public class FIPS1402JWETest extends JWETest { public class FIPS1402JWETest extends JWETest {
} }

View file

@ -1,6 +1,7 @@
package org.keycloak.crypto.fips.test; package org.keycloak.crypto.fips.test;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.jose.jwk.JWKTest; import org.keycloak.jose.jwk.JWKTest;
/** /**
@ -8,6 +9,12 @@ import org.keycloak.jose.jwk.JWKTest;
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@Ignore("Ignored by default as it does not work on non-fips enabled environment") // TODO: Figure how to test in the FIPS environments, but still keep disabled in the non-FIPS environments
public class FIPS1402JWKTest extends JWKTest { public class FIPS1402JWKTest extends JWKTest {
@Ignore("Test not supported by BC FIPS")
@Test
public void publicEs256() throws Exception {
// Do nothing
}
} }

View file

@ -1,6 +1,6 @@
package org.keycloak.crypto.fips.test; package org.keycloak.crypto.fips.test;
import org.junit.Ignore; import org.junit.Before;
import org.keycloak.KeyPairVerifierTest; import org.keycloak.KeyPairVerifierTest;
/** /**
@ -8,6 +8,54 @@ import org.keycloak.KeyPairVerifierTest;
* *
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@Ignore("Ignored by default as it does not work on non-fips enabled environment") // TODO: Figure how to test in the FIPS environments, but still keep disabled in the non-FIPS environments
public class FIPS1402KeyPairVerifierTest extends KeyPairVerifierTest { public class FIPS1402KeyPairVerifierTest extends KeyPairVerifierTest {
@Before
public void initPrivKeys() {
// The parent private key is not supported in FIPS-140-2, 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 supported in FIPS-140-2, 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==";
}
} }

View file

@ -29,7 +29,6 @@
<module name="com.fasterxml.jackson.core.jackson-databind"/> <module name="com.fasterxml.jackson.core.jackson-databind"/>
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/> <module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
<module name="org.keycloak.keycloak-common" /> <module name="org.keycloak.keycloak-common" />
<module name="org.bouncycastle" />
<module name="org.jboss.logging"/> <module name="org.jboss.logging"/>
<module name="javax.api"/> <module name="javax.api"/>
<module name="javax.activation.api"/> <module name="javax.activation.api"/>

View file

@ -26,7 +26,6 @@
<module name="com.fasterxml.jackson.core.jackson-databind"/> <module name="com.fasterxml.jackson.core.jackson-databind"/>
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/> <module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
<module name="org.keycloak.keycloak-common"/> <module name="org.keycloak.keycloak-common"/>
<module name="org.bouncycastle" />
<module name="org.jboss.logging"/> <module name="org.jboss.logging"/>
<module name="javax.api"/> <module name="javax.api"/>
<module name="javax.activation.api"/> <module name="javax.activation.api"/>

View file

@ -26,7 +26,6 @@
<module name="com.fasterxml.jackson.core.jackson-databind"/> <module name="com.fasterxml.jackson.core.jackson-databind"/>
<module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/> <module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
<module name="org.keycloak.keycloak-common"/> <module name="org.keycloak.keycloak-common"/>
<module name="org.bouncycastle" />
<module name="org.jboss.logging"/> <module name="org.jboss.logging"/>
<module name="javax.api"/> <module name="javax.api"/>
<module name="javax.activation.api"/> <module name="javax.activation.api"/>