Support certificate creation for EC keys (#31817)
fixes #31816 Signed-off-by: Captain-P-Goldfish <captain.p.goldfish@gmx.de>
This commit is contained in:
parent
f537343545
commit
4a15e1c2b0
4 changed files with 62 additions and 24 deletions
|
@ -42,7 +42,6 @@ import java.security.Signature;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.interfaces.ECPublicKey;
|
import java.security.interfaces.ECPublicKey;
|
||||||
import java.security.spec.ECGenParameterSpec;
|
import java.security.spec.ECGenParameterSpec;
|
||||||
import java.security.spec.ECPoint;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -50,6 +49,7 @@ import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.keycloak.common.util.CertificateUtils.generateV1SelfSignedCertificate;
|
import static org.keycloak.common.util.CertificateUtils.generateV1SelfSignedCertificate;
|
||||||
|
import static org.keycloak.common.util.CertificateUtils.generateV3Certificate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is not tested in keycloak-core. The subclasses should be created in the crypto modules to make sure it is tested with corresponding modules (bouncycastle VS bouncycastle-fips)
|
* This is not tested in keycloak-core. The subclasses should be created in the crypto modules to make sure it is tested with corresponding modules (bouncycastle VS bouncycastle-fips)
|
||||||
|
@ -143,6 +143,11 @@ public abstract class JWKTest {
|
||||||
ECGenParameterSpec ecSpec = new ECGenParameterSpec(algorithm);
|
ECGenParameterSpec ecSpec = new ECGenParameterSpec(algorithm);
|
||||||
keyGen.initialize(ecSpec, randomGen);
|
keyGen.initialize(ecSpec, randomGen);
|
||||||
KeyPair keyPair = keyGen.generateKeyPair();
|
KeyPair keyPair = keyGen.generateKeyPair();
|
||||||
|
KeyPair keyPair2 = keyGen.generateKeyPair();
|
||||||
|
X509Certificate certificate = generateV1SelfSignedCertificate(keyPair, "root");
|
||||||
|
X509Certificate certificate2 = generateV3Certificate(keyPair2, keyPair.getPrivate(), certificate, "child");
|
||||||
|
certificate.verify(keyPair.getPublic());
|
||||||
|
certificate2.verify(keyPair.getPublic());
|
||||||
|
|
||||||
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
|
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,17 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||||
certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0));
|
certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0));
|
||||||
|
|
||||||
// Content Signer
|
// Content Signer
|
||||||
ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BouncyIntegration.PROVIDER).build(caPrivateKey);
|
ContentSigner sigGen;
|
||||||
|
switch (keyPair.getPublic().getAlgorithm())
|
||||||
|
{
|
||||||
|
case "EC":
|
||||||
|
sigGen = new JcaContentSignerBuilder("SHA256WithECDSA").setProvider(BouncyIntegration.PROVIDER)
|
||||||
|
.build(caPrivateKey);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BouncyIntegration.PROVIDER)
|
||||||
|
.build(caPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
// Certificate
|
// Certificate
|
||||||
return new JcaX509CertificateConverter().setProvider(BouncyIntegration.PROVIDER).getCertificate(certGen.build(sigGen));
|
return new JcaX509CertificateConverter().setProvider(BouncyIntegration.PROVIDER).getCertificate(certGen.build(sigGen));
|
||||||
|
@ -185,6 +195,7 @@ public class BCCertificateUtilsProvider implements CertificateUtilsProvider {
|
||||||
.setProvider(BouncyIntegration.PROVIDER);
|
.setProvider(BouncyIntegration.PROVIDER);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "EC":
|
||||||
case "ECDSA": {
|
case "ECDSA": {
|
||||||
signerBuilder = new JcaContentSignerBuilder("SHA256WithECDSA")
|
signerBuilder = new JcaContentSignerBuilder("SHA256WithECDSA")
|
||||||
.setProvider(BouncyIntegration.PROVIDER);
|
.setProvider(BouncyIntegration.PROVIDER);
|
||||||
|
|
|
@ -71,9 +71,9 @@ public class ElytronCertificateUtilsProvider implements CertificateUtilsProvider
|
||||||
* @param caPrivateKey the CA private key
|
* @param caPrivateKey the CA private key
|
||||||
* @param caCert the CA certificate
|
* @param caCert the CA certificate
|
||||||
* @param subject the subject name
|
* @param subject the subject name
|
||||||
*
|
*
|
||||||
* @return the x509 certificate
|
* @return the x509 certificate
|
||||||
*
|
*
|
||||||
* @throws Exception the exception
|
* @throws Exception the exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,8 +112,6 @@ public class ElytronCertificateUtilsProvider implements CertificateUtilsProvider
|
||||||
|
|
||||||
.setSerialNumber(serialNumber)
|
.setSerialNumber(serialNumber)
|
||||||
|
|
||||||
.setSignatureAlgorithmName("SHA256withRSA")
|
|
||||||
|
|
||||||
.setSigningKey(caPrivateKey)
|
.setSigningKey(caPrivateKey)
|
||||||
|
|
||||||
// Subject Key Identifier Extension
|
// Subject Key Identifier Extension
|
||||||
|
@ -135,6 +133,14 @@ public class ElytronCertificateUtilsProvider implements CertificateUtilsProvider
|
||||||
// Basic Constraints
|
// Basic Constraints
|
||||||
.addExtension(new BasicConstraintsExtension(true, true, 0));
|
.addExtension(new BasicConstraintsExtension(true, true, 0));
|
||||||
|
|
||||||
|
switch (caPrivateKey.getAlgorithm()){
|
||||||
|
case "EC":
|
||||||
|
cbuilder.setSignatureAlgorithmName("SHA256withECDSA");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cbuilder.setSignatureAlgorithmName("SHA256withRSA");
|
||||||
|
}
|
||||||
|
|
||||||
return cbuilder.build();
|
return cbuilder.build();
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -147,9 +153,9 @@ public class ElytronCertificateUtilsProvider implements CertificateUtilsProvider
|
||||||
*
|
*
|
||||||
* @param caKeyPair the CA key pair
|
* @param caKeyPair the CA key pair
|
||||||
* @param subject the subject name
|
* @param subject the subject name
|
||||||
*
|
*
|
||||||
* @return the x509 certificate
|
* @return the x509 certificate
|
||||||
*
|
*
|
||||||
* @throws Exception the exception
|
* @throws Exception the exception
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -182,10 +188,16 @@ public class ElytronCertificateUtilsProvider implements CertificateUtilsProvider
|
||||||
.setSigningKey(caKeyPair.getPrivate())
|
.setSigningKey(caKeyPair.getPrivate())
|
||||||
.setPublicKey(caKeyPair.getPublic())
|
.setPublicKey(caKeyPair.getPublic())
|
||||||
|
|
||||||
.setSerialNumber(serialNumber)
|
.setSerialNumber(serialNumber);
|
||||||
|
|
||||||
|
switch (caKeyPair.getPrivate().getAlgorithm()){
|
||||||
|
case "EC":
|
||||||
|
cbuilder.setSignatureAlgorithmName("SHA256withECDSA");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cbuilder.setSignatureAlgorithmName("SHA256withRSA");
|
||||||
|
}
|
||||||
|
|
||||||
.setSignatureAlgorithmName("SHA256withRSA");
|
|
||||||
|
|
||||||
return cbuilder.build();
|
return cbuilder.build();
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -211,14 +223,14 @@ public class ElytronCertificateUtilsProvider implements CertificateUtilsProvider
|
||||||
|
|
||||||
int type = decPolicy.peekType();
|
int type = decPolicy.peekType();
|
||||||
System.out.println("type " + type);
|
System.out.println("type " + type);
|
||||||
|
|
||||||
DERDecoder der = new DERDecoder(decPolicy.decodeOctetString());
|
DERDecoder der = new DERDecoder(decPolicy.decodeOctetString());
|
||||||
|
|
||||||
List<String> policyList =new ArrayList<>();
|
List<String> policyList =new ArrayList<>();
|
||||||
|
|
||||||
while (der.hasNextElement()) {
|
while (der.hasNextElement()) {
|
||||||
switch (der.peekType()) {
|
switch (der.peekType()) {
|
||||||
case ASN1.SEQUENCE_TYPE:
|
case ASN1.SEQUENCE_TYPE:
|
||||||
der.startSequence();
|
der.startSequence();
|
||||||
break;
|
break;
|
||||||
case ASN1.OBJECT_IDENTIFIER_TYPE:
|
case ASN1.OBJECT_IDENTIFIER_TYPE:
|
||||||
|
@ -247,7 +259,7 @@ public class ElytronCertificateUtilsProvider implements CertificateUtilsProvider
|
||||||
|
|
||||||
while ( der.hasNextElement() ) {
|
while ( der.hasNextElement() ) {
|
||||||
switch (der.peekType()) {
|
switch (der.peekType()) {
|
||||||
case ASN1.SEQUENCE_TYPE:
|
case ASN1.SEQUENCE_TYPE:
|
||||||
der.startSequence();
|
der.startSequence();
|
||||||
break;
|
break;
|
||||||
case ASN1.UTF8_STRING_TYPE:
|
case ASN1.UTF8_STRING_TYPE:
|
||||||
|
@ -290,22 +302,22 @@ public class ElytronCertificateUtilsProvider implements CertificateUtilsProvider
|
||||||
try {
|
try {
|
||||||
X500Principal subjectdn = subjectToX500Principle(dn);
|
X500Principal subjectdn = subjectToX500Principle(dn);
|
||||||
X500Principal issuerdn = subjectToX500Principle(dn);
|
X500Principal issuerdn = subjectToX500Principle(dn);
|
||||||
|
|
||||||
ZonedDateTime notValidBefore = ZonedDateTime.ofInstant(startDate.toInstant(), ZoneId.systemDefault());
|
ZonedDateTime notValidBefore = ZonedDateTime.ofInstant(startDate.toInstant(), ZoneId.systemDefault());
|
||||||
ZonedDateTime notValidAfter = ZonedDateTime.ofInstant(expiryDate.toInstant(), ZoneId.systemDefault());
|
ZonedDateTime notValidAfter = ZonedDateTime.ofInstant(expiryDate.toInstant(), ZoneId.systemDefault());
|
||||||
|
|
||||||
X509CertificateBuilder cbuilder = new X509CertificateBuilder()
|
X509CertificateBuilder cbuilder = new X509CertificateBuilder()
|
||||||
.setSubjectDn(subjectdn)
|
.setSubjectDn(subjectdn)
|
||||||
.setIssuerDn(issuerdn)
|
.setIssuerDn(issuerdn)
|
||||||
|
|
||||||
.setNotValidBefore(notValidBefore)
|
.setNotValidBefore(notValidBefore)
|
||||||
.setNotValidAfter(notValidAfter)
|
.setNotValidAfter(notValidAfter)
|
||||||
|
|
||||||
.setSigningKey(keyPair.getPrivate())
|
.setSigningKey(keyPair.getPrivate())
|
||||||
.setPublicKey(keyPair.getPublic())
|
.setPublicKey(keyPair.getPublic())
|
||||||
|
|
||||||
.addExtension(createPoliciesExtension(certificatePolicyOid))
|
.addExtension(createPoliciesExtension(certificatePolicyOid))
|
||||||
|
|
||||||
.setSignatureAlgorithmName("SHA256withRSA");
|
.setSignatureAlgorithmName("SHA256withRSA");
|
||||||
|
|
||||||
return cbuilder.build();
|
return cbuilder.build();
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.bouncycastle.operator.OperatorCreationException;
|
||||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||||
import org.keycloak.common.util.BouncyIntegration;
|
import org.keycloak.common.util.BouncyIntegration;
|
||||||
import org.keycloak.common.crypto.CertificateUtilsProvider;
|
import org.keycloak.common.crypto.CertificateUtilsProvider;
|
||||||
|
import org.keycloak.crypto.Algorithm;
|
||||||
import org.keycloak.crypto.JavaAlgorithm;
|
import org.keycloak.crypto.JavaAlgorithm;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -83,9 +84,9 @@ public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{
|
||||||
* @param caPrivateKey the CA private key
|
* @param caPrivateKey the CA private key
|
||||||
* @param caCert the CA certificate
|
* @param caCert the CA certificate
|
||||||
* @param subject the subject name
|
* @param subject the subject name
|
||||||
*
|
*
|
||||||
* @return the x509 certificate
|
* @return the x509 certificate
|
||||||
*
|
*
|
||||||
* @throws Exception the exception
|
* @throws Exception the exception
|
||||||
*/
|
*/
|
||||||
public X509Certificate generateV3Certificate(KeyPair keyPair, PrivateKey caPrivateKey, X509Certificate caCert,
|
public X509Certificate generateV3Certificate(KeyPair keyPair, PrivateKey caPrivateKey, X509Certificate caCert,
|
||||||
|
@ -132,7 +133,16 @@ public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{
|
||||||
certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0));
|
certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0));
|
||||||
|
|
||||||
// Content Signer
|
// Content Signer
|
||||||
ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider(BouncyIntegration.PROVIDER).build(caPrivateKey);
|
ContentSigner sigGen;
|
||||||
|
switch (caPrivateKey.getAlgorithm()){
|
||||||
|
case "EC":
|
||||||
|
sigGen = new JcaContentSignerBuilder("SHA256WithECDSA").setProvider(BouncyIntegration.PROVIDER)
|
||||||
|
.build(caPrivateKey);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BouncyIntegration.PROVIDER)
|
||||||
|
.build(caPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
// Certificate
|
// Certificate
|
||||||
return new JcaX509CertificateConverter().setProvider(BouncyIntegration.PROVIDER).getCertificate(certGen.build(sigGen));
|
return new JcaX509CertificateConverter().setProvider(BouncyIntegration.PROVIDER).getCertificate(certGen.build(sigGen));
|
||||||
|
@ -146,9 +156,9 @@ public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{
|
||||||
*
|
*
|
||||||
* @param caKeyPair the CA key pair
|
* @param caKeyPair the CA key pair
|
||||||
* @param subject the subject name
|
* @param subject the subject name
|
||||||
*
|
*
|
||||||
* @return the x509 certificate
|
* @return the x509 certificate
|
||||||
*
|
*
|
||||||
* @throws Exception the exception
|
* @throws Exception the exception
|
||||||
*/
|
*/
|
||||||
public X509Certificate generateV1SelfSignedCertificate(KeyPair caKeyPair, String subject) {
|
public X509Certificate generateV1SelfSignedCertificate(KeyPair caKeyPair, String subject) {
|
||||||
|
@ -213,7 +223,7 @@ public class BCFIPSCertificateUtilsProvider implements CertificateUtilsProvider{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getCertificatePolicyList(X509Certificate cert) throws GeneralSecurityException {
|
public List<String> getCertificatePolicyList(X509Certificate cert) throws GeneralSecurityException {
|
||||||
|
|
||||||
Extensions certExtensions = new JcaX509CertificateHolder(cert).getExtensions();
|
Extensions certExtensions = new JcaX509CertificateHolder(cert).getExtensions();
|
||||||
if (certExtensions == null)
|
if (certExtensions == null)
|
||||||
throw new GeneralSecurityException("Certificate Policy validation was expected, but no certificate extensions were found");
|
throw new GeneralSecurityException("Certificate Policy validation was expected, but no certificate extensions were found");
|
||||||
|
|
Loading…
Reference in a new issue