mirror of
https://github.com/keycloak/keycloak.git
synced 2026-05-26 13:50:48 +00:00
closes #26936 Signed-off-by: Stefan Wiedemann <wistefan@googlemail.com>
This commit is contained in:
+44
-37
@@ -67,7 +67,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The Class CertificateUtils provides utility functions for generation of V1 and V3 {@link java.security.cert.X509Certificate}
|
||||
* The Class CertificateUtils provides utility functions for generation of V1 and V3 {@link X509Certificate}
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
|
||||
@@ -76,19 +76,17 @@ import java.util.List;
|
||||
public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
|
||||
/**
|
||||
* Generates version 3 {@link java.security.cert.X509Certificate}.
|
||||
* Generates version 3 {@link X509Certificate}.
|
||||
*
|
||||
* @param keyPair the key pair
|
||||
* @param keyPair the key pair
|
||||
* @param caPrivateKey the CA private key
|
||||
* @param caCert the CA certificate
|
||||
* @param subject the subject name
|
||||
*
|
||||
* @param caCert the CA certificate
|
||||
* @param subject the subject name
|
||||
* @return the x509 certificate
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
public X509Certificate generateV3Certificate(KeyPair keyPair, PrivateKey caPrivateKey, X509Certificate caCert,
|
||||
String subject) throws Exception {
|
||||
String subject) throws Exception {
|
||||
try {
|
||||
X500Name subjectDN = new X500Name("CN=" + subject);
|
||||
|
||||
@@ -141,13 +139,11 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate version 1 self signed {@link java.security.cert.X509Certificate}..
|
||||
* Generate version 1 self signed {@link X509Certificate}..
|
||||
*
|
||||
* @param caKeyPair the CA key pair
|
||||
* @param subject the subject name
|
||||
*
|
||||
* @param subject the subject name
|
||||
* @return the x509 certificate
|
||||
*
|
||||
* @throws Exception the exception
|
||||
*/
|
||||
public X509Certificate generateV1SelfSignedCertificate(KeyPair caKeyPair, String subject) {
|
||||
@@ -174,16 +170,30 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the content signer for generation of Version 1 {@link java.security.cert.X509Certificate}.
|
||||
* Creates the content signer for generation of Version 1 {@link X509Certificate}.
|
||||
*
|
||||
* @param privateKey the private key
|
||||
*
|
||||
* @return the content signer
|
||||
*/
|
||||
private ContentSigner createSigner(PrivateKey privateKey) {
|
||||
try {
|
||||
JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
|
||||
.setProvider(BouncyIntegration.PROVIDER);
|
||||
JcaContentSignerBuilder signerBuilder;
|
||||
switch (privateKey.getAlgorithm()) {
|
||||
case "RSA": {
|
||||
signerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
|
||||
.setProvider(BouncyIntegration.PROVIDER);
|
||||
break;
|
||||
}
|
||||
case "ECDSA": {
|
||||
signerBuilder = new JcaContentSignerBuilder("SHA256WithECDSA")
|
||||
.setProvider(BouncyIntegration.PROVIDER);
|
||||
break;
|
||||
|
||||
}
|
||||
default: {
|
||||
throw new RuntimeException(String.format("Keytype %s is not supported.", privateKey.getAlgorithm()));
|
||||
}
|
||||
}
|
||||
return signerBuilder.build(privateKey);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not create content signer.", e);
|
||||
@@ -192,7 +202,7 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
|
||||
@Override
|
||||
public List<String> getCertificatePolicyList(X509Certificate cert) throws GeneralSecurityException {
|
||||
|
||||
|
||||
Extensions certExtensions = new JcaX509CertificateHolder(cert).getExtensions();
|
||||
if (certExtensions == null)
|
||||
throw new GeneralSecurityException("Certificate Policy validation was expected, but no certificate extensions were found");
|
||||
@@ -212,6 +222,7 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
/**
|
||||
* Retrieves a list of CRL distribution points from CRLDP v3 certificate extension
|
||||
* See <a href="www.nakov.com/blog/2009/12/01/x509-certificate-validation-in-java-build-and-verify-cchain-and-verify-clr-with-bouncy-castle/">CRL validation</a>
|
||||
*
|
||||
* @param cert
|
||||
* @return
|
||||
* @throws IOException
|
||||
@@ -225,7 +236,7 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
List<String> distributionPointUrls = new LinkedList<>();
|
||||
DEROctetString octetString;
|
||||
try (ASN1InputStream crldpExtensionInputStream = new ASN1InputStream(new ByteArrayInputStream(data))) {
|
||||
octetString = (DEROctetString)crldpExtensionInputStream.readObject();
|
||||
octetString = (DEROctetString) crldpExtensionInputStream.readObject();
|
||||
}
|
||||
byte[] octets = octetString.getOctets();
|
||||
|
||||
@@ -251,28 +262,26 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
}
|
||||
|
||||
public X509Certificate createServicesTestCertificate(String dn,
|
||||
Date startDate,
|
||||
Date expiryDate,
|
||||
KeyPair keyPair,
|
||||
String... certificatePolicyOid) {
|
||||
Date startDate,
|
||||
Date expiryDate,
|
||||
KeyPair keyPair,
|
||||
String... certificatePolicyOid) {
|
||||
// Cert data
|
||||
X500Name subjectDN = new X500Name(dn);
|
||||
X500Name issuerDN = new X500Name(dn);
|
||||
|
||||
SubjectPublicKeyInfo subjPubKeyInfo = SubjectPublicKeyInfo.getInstance(
|
||||
ASN1Sequence.getInstance(keyPair.getPublic().getEncoded()));
|
||||
ASN1Sequence.getInstance(keyPair.getPublic().getEncoded()));
|
||||
|
||||
BigInteger serialNumber = new BigInteger(130, new SecureRandom());
|
||||
|
||||
// Build the certificate
|
||||
X509v3CertificateBuilder certGen = new X509v3CertificateBuilder(issuerDN, serialNumber, startDate, expiryDate,
|
||||
subjectDN, subjPubKeyInfo);
|
||||
subjectDN, subjPubKeyInfo);
|
||||
|
||||
if (certificatePolicyOid != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (Extension certExtension: certPolicyExtensions(certificatePolicyOid))
|
||||
if (certificatePolicyOid != null) {
|
||||
try {
|
||||
for (Extension certExtension : certPolicyExtensions(certificatePolicyOid))
|
||||
certGen.addExtension(certExtension);
|
||||
} catch (CertIOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
@@ -282,11 +291,11 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
// Sign the cert with the private key
|
||||
try {
|
||||
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256withRSA")
|
||||
.setProvider(BouncyIntegration.PROVIDER)
|
||||
.build(keyPair.getPrivate());
|
||||
.setProvider(BouncyIntegration.PROVIDER)
|
||||
.build(keyPair.getPrivate());
|
||||
X509Certificate x509Certificate = new JcaX509CertificateConverter()
|
||||
.setProvider(BouncyIntegration.PROVIDER)
|
||||
.getCertificate(certGen.build(contentSigner));
|
||||
.setProvider(BouncyIntegration.PROVIDER)
|
||||
.getCertificate(certGen.build(contentSigner));
|
||||
|
||||
return x509Certificate;
|
||||
} catch (CertificateException | OperatorCreationException e) {
|
||||
@@ -297,11 +306,9 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||
private List<Extension> certPolicyExtensions(String... certificatePolicyOid) {
|
||||
List<Extension> certificatePolicies = new LinkedList<>();
|
||||
|
||||
if (certificatePolicyOid != null && certificatePolicyOid.length > 0)
|
||||
{
|
||||
if (certificatePolicyOid != null && certificatePolicyOid.length > 0) {
|
||||
List<PolicyInformation> policyInfoList = new LinkedList<>();
|
||||
for (String oid: certificatePolicyOid)
|
||||
{
|
||||
for (String oid : certificatePolicyOid) {
|
||||
policyInfoList.add(new PolicyInformation(new ASN1ObjectIdentifier(oid)));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
package org.keycloak.crypto.def;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.ASN1Primitive;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.DERSequenceGenerator;
|
||||
import org.bouncycastle.asn1.x9.X9IntegerConverter;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.jce.spec.ECPublicKeySpec;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.keycloak.common.crypto.ECDSACryptoProvider;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
public class BCECDSACryptoProvider implements ECDSACryptoProvider {
|
||||
|
||||
|
||||
@@ -60,5 +69,22 @@ public class BCECDSACryptoProvider implements ECDSACryptoProvider {
|
||||
return concatenatedSignatureValue;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ECPublicKey getPublicFromPrivate(ECPrivateKey ecPrivateKey) {
|
||||
try {
|
||||
BCECPrivateKey bcecPrivateKey = new BCECPrivateKey(ecPrivateKey, BouncyCastleProvider.CONFIGURATION);
|
||||
|
||||
ECPoint q = bcecPrivateKey.getParameters().getG().multiply(bcecPrivateKey.getD());
|
||||
|
||||
ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(q, bcecPrivateKey.getParameters());
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("EC");
|
||||
return (ECPublicKey) keyFactory.generatePublic(publicKeySpec);
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Key algorithm not supported.", e);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new RuntimeException("Received an invalid key spec.", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2023 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.def.test;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.keycloak.common.crypto.CryptoIntegration;
|
||||
import org.keycloak.crypto.def.BCECDSACryptoProvider;
|
||||
import org.keycloak.rule.CryptoInitRule;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class BCECDSACryptoProviderTest {
|
||||
|
||||
|
||||
@ClassRule
|
||||
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(new Object[][]{
|
||||
{"secp256r1"}, {"secp384r1"}, {"secp521r1"}
|
||||
});
|
||||
}
|
||||
|
||||
private String curve;
|
||||
|
||||
public BCECDSACryptoProviderTest(String curve) {
|
||||
this.curve = curve;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPublicFromPrivate() {
|
||||
KeyPair testKey = generateECKey(curve);
|
||||
|
||||
BCECDSACryptoProvider bcecdsaCryptoProvider = new BCECDSACryptoProvider();
|
||||
assertEquals("The derived key should be equal to the originally generated one.",
|
||||
testKey.getPublic(),
|
||||
bcecdsaCryptoProvider.getPublicFromPrivate((ECPrivateKey) testKey.getPrivate()));
|
||||
|
||||
}
|
||||
|
||||
public static KeyPair generateECKey(String curve) {
|
||||
|
||||
try {
|
||||
KeyPairGenerator kpg = CryptoIntegration.getProvider().getKeyPairGen("ECDSA");
|
||||
ECGenParameterSpec parameterSpec = new ECGenParameterSpec(curve);
|
||||
kpg.initialize(parameterSpec);
|
||||
return kpg.generateKeyPair();
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-4
@@ -18,6 +18,8 @@ package org.keycloak.crypto.elytron;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.common.crypto.ECDSACryptoProvider;
|
||||
@@ -51,7 +53,7 @@ public class ElytronECDSACryptoProvider implements ECDSACryptoProvider {
|
||||
seq.endSequence();
|
||||
|
||||
return seq.getEncoded();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,8 +62,8 @@ public class ElytronECDSACryptoProvider implements ECDSACryptoProvider {
|
||||
|
||||
DERDecoder der = new DERDecoder(derEncodedSignatureValue);
|
||||
der.startSequence();
|
||||
byte[] r = convertToBytes(der.decodeInteger(),len);
|
||||
byte[] s = convertToBytes(der.decodeInteger(),len);
|
||||
byte[] r = convertToBytes(der.decodeInteger(), len);
|
||||
byte[] s = convertToBytes(der.decodeInteger(), len);
|
||||
der.endSequence();
|
||||
byte[] concatenatedSignatureValue = new byte[signLength];
|
||||
|
||||
@@ -71,13 +73,18 @@ public class ElytronECDSACryptoProvider implements ECDSACryptoProvider {
|
||||
return concatenatedSignatureValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ECPublicKey getPublicFromPrivate(ECPrivateKey ecPrivateKey) {
|
||||
throw new UnsupportedOperationException("Elytron Crypto Provider currently does not support extraction of EC Public Keys.");
|
||||
}
|
||||
|
||||
// If byte array length doesn't match expected length, copy to new
|
||||
// byte array of the expected length
|
||||
private byte[] convertToBytes(BigInteger decodeInteger, int len) {
|
||||
|
||||
byte[] bytes = decodeInteger.toByteArray();
|
||||
|
||||
if(len < bytes.length) {
|
||||
if (len < bytes.length) {
|
||||
log.debug("Decoded integer byte length greater than expected.");
|
||||
byte[] t = new byte[len];
|
||||
System.arraycopy(bytes, bytes.length - len, t, 0, len);
|
||||
|
||||
+21
-6
@@ -67,7 +67,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The Class CertificateUtils provides utility functions for generation of V1 and V3 {@link java.security.cert.X509Certificate}
|
||||
* The Class CertificateUtils provides utility functions for generation of V1 and V3 {@link X509Certificate}
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
|
||||
@@ -76,7 +76,7 @@ import java.util.List;
|
||||
public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{
|
||||
|
||||
/**
|
||||
* Generates version 3 {@link java.security.cert.X509Certificate}.
|
||||
* Generates version 3 {@link X509Certificate}.
|
||||
*
|
||||
* @param keyPair the key pair
|
||||
* @param caPrivateKey the CA private key
|
||||
@@ -141,7 +141,7 @@ public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate version 1 self signed {@link java.security.cert.X509Certificate}..
|
||||
* Generate version 1 self signed {@link X509Certificate}..
|
||||
*
|
||||
* @param caKeyPair the CA key pair
|
||||
* @param subject the subject name
|
||||
@@ -174,7 +174,7 @@ public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the content signer for generation of Version 1 {@link java.security.cert.X509Certificate}.
|
||||
* Creates the content signer for generation of Version 1 {@link X509Certificate}.
|
||||
*
|
||||
* @param privateKey the private key
|
||||
*
|
||||
@@ -182,8 +182,23 @@ public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{
|
||||
*/
|
||||
private ContentSigner createSigner(PrivateKey privateKey) {
|
||||
try {
|
||||
JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
|
||||
.setProvider(BouncyIntegration.PROVIDER);
|
||||
JcaContentSignerBuilder signerBuilder;
|
||||
switch (privateKey.getAlgorithm()) {
|
||||
case "RSA": {
|
||||
signerBuilder = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
|
||||
.setProvider(BouncyIntegration.PROVIDER);
|
||||
break;
|
||||
}
|
||||
case "EC": {
|
||||
signerBuilder = new JcaContentSignerBuilder("SHA256WithECDSA")
|
||||
.setProvider(BouncyIntegration.PROVIDER);
|
||||
break;
|
||||
|
||||
}
|
||||
default: {
|
||||
throw new RuntimeException(String.format("Keytype %s is not supported.", privateKey.getAlgorithm()));
|
||||
}
|
||||
}
|
||||
return signerBuilder.build(privateKey);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not create content signer.", e);
|
||||
|
||||
+36
-5
@@ -1,17 +1,26 @@
|
||||
package org.keycloak.crypto.fips;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.ASN1Primitive;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.DERSequenceGenerator;
|
||||
import org.bouncycastle.asn1.x9.X9IntegerConverter;
|
||||
import org.bouncycastle.jcajce.spec.ECDomainParameterSpec;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
import org.keycloak.common.crypto.ECDSACryptoProvider;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.security.spec.ECPublicKeySpec;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
||||
public class BCFIPSECDSACryptoProvider implements ECDSACryptoProvider {
|
||||
|
||||
|
||||
@@ -60,5 +69,27 @@ public class BCFIPSECDSACryptoProvider implements ECDSACryptoProvider {
|
||||
return concatenatedSignatureValue;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ECPublicKey getPublicFromPrivate(ECPrivateKey ecPrivateKey) {
|
||||
try {
|
||||
ECParameterSpec parameterSpec = ecPrivateKey.getParams();
|
||||
ECDomainParameterSpec domainParameterSpec = new ECDomainParameterSpec(parameterSpec);
|
||||
|
||||
ECPoint q = domainParameterSpec.getDomainParameters().getG().multiply(ecPrivateKey.getS()).normalize();
|
||||
ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(
|
||||
new java.security.spec.ECPoint(
|
||||
q.getAffineXCoord().toBigInteger(),
|
||||
q.getAffineYCoord().toBigInteger()),
|
||||
domainParameterSpec);
|
||||
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("EC");
|
||||
return (ECPublicKey) keyFactory.generatePublic(ecPublicKeySpec);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException("Key algorithm not supported.", e);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new RuntimeException("Received an invalid key spec.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2023 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.fips.test;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.keycloak.common.crypto.CryptoIntegration;
|
||||
import org.keycloak.crypto.Algorithm;
|
||||
import org.keycloak.crypto.fips.BCFIPSECDSACryptoProvider;
|
||||
import org.keycloak.keys.AbstractEcdsaKeyProviderFactory;
|
||||
import org.keycloak.rule.CryptoInitRule;
|
||||
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.spec.ECGenParameterSpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class BCFIPSECDSACryptoProviderTest {
|
||||
|
||||
@ClassRule
|
||||
public static CryptoInitRule cryptoInitRule = new CryptoInitRule();
|
||||
|
||||
@Parameterized.Parameters
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(new Object[][]{
|
||||
{Algorithm.ES256}, {Algorithm.ES384}, {Algorithm.ES512}
|
||||
});
|
||||
}
|
||||
|
||||
private String algorithm;
|
||||
|
||||
public BCFIPSECDSACryptoProviderTest(String algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getPublicFromPrivate() {
|
||||
KeyPair testKey = generateECKey(algorithm);
|
||||
|
||||
BCFIPSECDSACryptoProvider bcfipsecdsaCryptoProvider = new BCFIPSECDSACryptoProvider();
|
||||
ECPublicKey derivedKey = bcfipsecdsaCryptoProvider.getPublicFromPrivate((ECPrivateKey) testKey.getPrivate());
|
||||
assertEquals("The derived key should be equal to the originally generated one.",
|
||||
testKey.getPublic(),
|
||||
derivedKey);
|
||||
}
|
||||
|
||||
public static KeyPair generateECKey(String algorithm) {
|
||||
|
||||
try {
|
||||
KeyPairGenerator kpg = CryptoIntegration.getProvider().getKeyPairGen("ECDSA");
|
||||
String domainParamNistRep = AbstractEcdsaKeyProviderFactory.convertAlgorithmToECDomainParmNistRep(algorithm);
|
||||
String curve = AbstractEcdsaKeyProviderFactory.convertECDomainParmNistRepToSecRep(domainParamNistRep);
|
||||
ECGenParameterSpec parameterSpec = new ECGenParameterSpec(curve);
|
||||
kpg.initialize(parameterSpec);
|
||||
return kpg.generateKeyPair();
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user