Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updated BC provider versions and deprecated CertificateUtil methods.
- Loading branch information
1 parent
0b67437
commit c3d7ef8
Showing
40 changed files
with
206 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
192 changes: 146 additions & 46 deletions
192
core/src/main/java/org/keycloak/util/CertificateUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,166 @@ | ||
package org.keycloak.util; | ||
|
||
import org.bouncycastle.asn1.x509.X509Extensions; | ||
import org.bouncycastle.x509.X509V1CertificateGenerator; | ||
import org.bouncycastle.x509.X509V3CertificateGenerator; | ||
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure; | ||
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure; | ||
|
||
import javax.security.auth.x500.X500Principal; | ||
import java.math.BigInteger; | ||
import java.security.KeyPair; | ||
import java.security.PrivateKey; | ||
import java.security.SecureRandom; | ||
import java.security.Security; | ||
import java.security.cert.X509Certificate; | ||
import java.util.Calendar; | ||
import java.util.Date; | ||
|
||
import org.bouncycastle.asn1.ASN1Sequence; | ||
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; | ||
import org.bouncycastle.asn1.x500.X500Name; | ||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier; | ||
import org.bouncycastle.asn1.x509.BasicConstraints; | ||
import org.bouncycastle.asn1.x509.ExtendedKeyUsage; | ||
import org.bouncycastle.asn1.x509.Extension; | ||
import org.bouncycastle.asn1.x509.KeyPurposeId; | ||
import org.bouncycastle.asn1.x509.KeyUsage; | ||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; | ||
import org.bouncycastle.cert.X509CertificateHolder; | ||
import org.bouncycastle.cert.X509ExtensionUtils; | ||
import org.bouncycastle.cert.X509v1CertificateBuilder; | ||
import org.bouncycastle.cert.X509v3CertificateBuilder; | ||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; | ||
import org.bouncycastle.crypto.util.PrivateKeyFactory; | ||
import org.bouncycastle.operator.ContentSigner; | ||
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; | ||
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; | ||
import org.bouncycastle.operator.DigestCalculator; | ||
import org.bouncycastle.operator.bc.BcDigestCalculatorProvider; | ||
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder; | ||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; | ||
|
||
/** | ||
* The Class CertificateUtils provides utility functions for generation of V1 and V3 {@link java.security.cert.X509Certificate} | ||
* | ||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> | ||
* @version $Revision: 1 $ | ||
* @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a> | ||
* @version $Revision: 2 $ | ||
*/ | ||
public class CertificateUtils { | ||
static { | ||
BouncyIntegration.init(); | ||
} | ||
public static X509Certificate generateV3Certificate(KeyPair keyPair, PrivateKey caPrivateKey, X509Certificate caCert, String subject) throws Exception { | ||
|
||
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); | ||
X500Principal subjectName = new X500Principal("CN=" + subject); | ||
|
||
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis()); | ||
certGen.setSerialNumber(serialNumber); | ||
certGen.setIssuerDN(caCert.getSubjectX500Principal()); | ||
certGen.setNotBefore(new Date(System.currentTimeMillis() - 100000)); | ||
Calendar calendar = Calendar.getInstance(); | ||
calendar.add(Calendar.YEAR, 10); | ||
certGen.setNotAfter(calendar.getTime()); | ||
certGen.setSubjectDN(subjectName); | ||
certGen.setPublicKey(keyPair.getPublic()); | ||
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); | ||
|
||
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false, | ||
new AuthorityKeyIdentifierStructure(caCert)); | ||
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false, | ||
new SubjectKeyIdentifierStructure(keyPair.getPublic())); | ||
|
||
X509Certificate cert = certGen.generate(caPrivateKey, "BC"); // note: private key of CA | ||
return cert; | ||
|
||
/** | ||
* 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 | ||
*/ | ||
public static X509Certificate generateV3Certificate(KeyPair keyPair, PrivateKey caPrivateKey, X509Certificate caCert, | ||
String subject) throws Exception { | ||
|
||
try { | ||
X500Name subjectDN = new X500Name("CN=" + subject); | ||
|
||
// Serial Number | ||
SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); | ||
BigInteger serialNumber = BigInteger.valueOf(Math.abs(random.nextInt())); | ||
|
||
// Validity | ||
Date notBefore = new Date(System.currentTimeMillis()); | ||
Date notAfter = new Date(System.currentTimeMillis() + (((1000L * 60 * 60 * 24 * 30)) * 12) * 3); | ||
|
||
// SubjectPublicKeyInfo | ||
SubjectPublicKeyInfo subjPubKeyInfo = new SubjectPublicKeyInfo(ASN1Sequence.getInstance(keyPair.getPublic() | ||
.getEncoded())); | ||
|
||
X509v3CertificateBuilder certGen = new X509v3CertificateBuilder(new X500Name(caCert.getSubjectDN().getName()), | ||
serialNumber, notBefore, notAfter, subjectDN, subjPubKeyInfo); | ||
|
||
DigestCalculator digCalc = new BcDigestCalculatorProvider() | ||
.get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1)); | ||
X509ExtensionUtils x509ExtensionUtils = new X509ExtensionUtils(digCalc); | ||
|
||
// Subject Key Identifier | ||
certGen.addExtension(Extension.subjectKeyIdentifier, false, | ||
x509ExtensionUtils.createSubjectKeyIdentifier(subjPubKeyInfo)); | ||
|
||
// Authority Key Identifier | ||
certGen.addExtension(Extension.authorityKeyIdentifier, false, | ||
x509ExtensionUtils.createAuthorityKeyIdentifier(subjPubKeyInfo)); | ||
|
||
// Key Usage | ||
certGen.addExtension(Extension.keyUsage, false, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | ||
| KeyUsage.cRLSign)); | ||
|
||
// Extended Key Usage | ||
KeyPurposeId[] EKU = new KeyPurposeId[2]; | ||
EKU[0] = KeyPurposeId.id_kp_emailProtection; | ||
EKU[1] = KeyPurposeId.id_kp_serverAuth; | ||
|
||
certGen.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(EKU)); | ||
|
||
// Basic Constraints | ||
certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); | ||
|
||
// Content Signer | ||
ContentSigner sigGen = new JcaContentSignerBuilder("SHA1WithRSAEncryption").setProvider("BC").build(caPrivateKey); | ||
|
||
// Certificate | ||
return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certGen.build(sigGen)); | ||
} catch (Exception e) { | ||
throw new RuntimeException("Error creating X509v3Certificate.", e); | ||
} | ||
} | ||
|
||
public static X509Certificate generateV1SelfSignedCertificate(KeyPair keyPair, String subject) throws Exception { | ||
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis()); | ||
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator(); | ||
X500Principal subjectPrincipal = new X500Principal("CN=" + subject); | ||
certGen.setSerialNumber(serialNumber); | ||
certGen.setIssuerDN(subjectPrincipal); | ||
certGen.setNotBefore(new Date(System.currentTimeMillis() - 100000)); | ||
Calendar calendar = Calendar.getInstance(); | ||
calendar.add(Calendar.YEAR, 10); | ||
certGen.setNotAfter(calendar.getTime()); | ||
certGen.setSubjectDN(subjectPrincipal); | ||
certGen.setPublicKey(keyPair.getPublic()); | ||
certGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); | ||
X509Certificate cert = certGen.generate(keyPair.getPrivate(), "BC"); | ||
return cert; | ||
/** | ||
* 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 | ||
*/ | ||
public static X509Certificate generateV1SelfSignedCertificate(KeyPair caKeyPair, String subject) throws Exception { | ||
|
||
try { | ||
X500Name subjectDN = new X500Name("CN=" + subject); | ||
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis()); | ||
Date validityStartDate = new Date(System.currentTimeMillis() - 100000); | ||
Calendar calendar = Calendar.getInstance(); | ||
calendar.add(Calendar.YEAR, 10); | ||
Date validityEndDate = new Date(calendar.getTime().getTime()); | ||
SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(caKeyPair.getPublic().getEncoded()); | ||
|
||
X509v1CertificateBuilder builder = new X509v1CertificateBuilder(subjectDN, serialNumber, validityStartDate, | ||
validityEndDate, subjectDN, subPubKeyInfo); | ||
X509CertificateHolder holder = builder.build(createSigner(caKeyPair.getPrivate())); | ||
|
||
return new JcaX509CertificateConverter().getCertificate(holder); | ||
} catch (Exception e) { | ||
throw new RuntimeException("Error creating X509v1Certificate.", e); | ||
} | ||
} | ||
|
||
/** | ||
* Creates the content signer for generation of Version 1 {@link java.security.cert.X509Certificate}. | ||
* | ||
* @param privateKey the private key | ||
* | ||
* @return the content signer | ||
*/ | ||
public static ContentSigner createSigner(PrivateKey privateKey) { | ||
try { | ||
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption"); | ||
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId); | ||
|
||
return new BcRSAContentSignerBuilder(sigAlgId, digAlgId) | ||
.build(PrivateKeyFactory.createKey(privateKey.getEncoded())); | ||
} catch (Exception e) { | ||
throw new RuntimeException("Could not create content signer.", e); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.