package com.intrbiz.bergamot.crypto.util;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import javax.security.auth.x500.X500Principal;
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.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
public class RSAUtil
{
public enum KeyType {
CA,
INTERMEDIATE,
SERVER,
CLIENT
}
public static KeyPair generateRSAKeyPair()
{
return generateRSAKeyPair(2048);
}
public static KeyPair generateRSAKeyPair(int size)
{
try
{
KeyPairGenerator jenny = KeyPairGenerator.getInstance("RSA");
jenny.initialize(size, new SecureRandom());
// generate the pair
KeyPair pair = jenny.generateKeyPair();
return pair;
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
}
public static String buildDN(String country, String state, String locality, String org, String orgUnit, String commonName)
{
StringBuilder sb = new StringBuilder();
sb.append("C=").append(country).append(", ");
sb.append("ST=").append(state).append(", ");
sb.append("L=").append(locality).append(", ");
sb.append("O=").append(org).append(", ");
if (orgUnit != null) sb.append("OU=").append(orgUnit).append(", ");
sb.append("CN=").append(commonName);
return sb.toString();
}
public static CertificatePair generateCertificate(String DN, SerialNum serial, int days, int keySize, KeyType type, CertificatePair issuer) throws Exception
{
return generateCertificate(DN, serial, days, keySize, type, null, issuer);
}
public static CertificatePair generateCertificate(String DN, SerialNum serial, int days, int keySize, KeyType type, PublicKey key, CertificatePair issuer) throws Exception
{
// validate
if ((KeyType.INTERMEDIATE == type || KeyType.CLIENT == type || KeyType.SERVER == type) && issuer == null) throw new IllegalArgumentException("Issue must be given to sign requested key type");
if (issuer == null && key != null) throw new IllegalArgumentException("When signing a given public key, an issuer must be given");
// generate the key pair
KeyPair pair = null;
if (key == null)
{
pair = generateRSAKeyPair(keySize);
key = pair.getPublic();
}
// not before
Calendar now = Calendar.getInstance();
// not after
Calendar expiry = Calendar.getInstance();
expiry.add(Calendar.DAY_OF_YEAR, days);
// subject DN
X500Principal subjectDN = new X500Principal(DN);
// issuer DN
X500Principal issuerDN = issuer == null ? subjectDN : issuer.getCertificate().getSubjectX500Principal();
// build the certificate
JcaX509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(issuerDN, serial.toBigInt(), now.getTime(), expiry.getTime(), subjectDN, key);
// set extensions
JcaX509ExtensionUtils utils = new JcaX509ExtensionUtils();
// subject public key
builder.addExtension(Extension.subjectKeyIdentifier, false, utils.createSubjectKeyIdentifier(key));
// issuer public key
if (issuer == null)
{
builder.addExtension(Extension.authorityKeyIdentifier, false, utils.createAuthorityKeyIdentifier(key));
}
else
{
builder.addExtension(Extension.authorityKeyIdentifier, false, utils.createAuthorityKeyIdentifier(issuer.getCertificate()));
}
// constraints
if (KeyType.CA == type || KeyType.INTERMEDIATE == type)
{
builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyEncipherment | KeyUsage.cRLSign | KeyUsage.dataEncipherment | KeyUsage.digitalSignature | KeyUsage.keyCertSign));
builder.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.anyExtendedKeyUsage));
}
else if (KeyType.SERVER == type)
{
builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
builder.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth));
}
else if (KeyType.CLIENT == type)
{
builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
builder.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_clientAuth));
}
// the signer
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").build(issuer == null ? pair.getPrivate() : issuer.getKey());
// go go go
X509CertificateHolder theCertHolder = builder.build(signer);
// extract the actual fucking certificate
X509Certificate theCert = new JcaX509CertificateConverter().getCertificate(theCertHolder);
// check
theCert.verify(issuer == null ? key : issuer.getCertificate().getPublicKey());
// encode
return new CertificatePair(theCert, pair == null ? null : pair.getPrivate());
}
}