/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.model.crypto.signature;
import org.apache.commons.lang.StringUtils;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.x509.X509V1CertificateGenerator;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.xdi.oxauth.model.crypto.Certificate;
import org.xdi.oxauth.model.crypto.KeyFactory;
import javax.security.auth.x500.X500Principal;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Random;
/**
* Factory to create asymmetric Public and Private Keys for the Elliptic Curve Digital Signature Algorithm (ECDSA)
*
* @author Javier Rojas Blum
* @version June 15, 2016
*/
public class ECDSAKeyFactory extends KeyFactory<ECDSAPrivateKey, ECDSAPublicKey> {
private SignatureAlgorithm signatureAlgorithm;
private KeyPair keyPair;
private ECDSAPrivateKey ecdsaPrivateKey;
private ECDSAPublicKey ecdsaPublicKey;
private Certificate certificate;
public ECDSAKeyFactory(SignatureAlgorithm signatureAlgorithm, String dnName)
throws InvalidParameterException, NoSuchProviderException, NoSuchAlgorithmException,
InvalidAlgorithmParameterException, SignatureException, InvalidKeyException, CertificateEncodingException {
if (signatureAlgorithm == null) {
throw new InvalidParameterException("The signature algorithm cannot be null");
}
this.signatureAlgorithm = signatureAlgorithm;
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(signatureAlgorithm.getCurve().getName());
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDSA", "BC");
keyGen.initialize(ecSpec, new SecureRandom());
this.keyPair = keyGen.generateKeyPair();
BCECPrivateKey privateKeySpec = (BCECPrivateKey) keyPair.getPrivate();
BCECPublicKey publicKeySpec = (BCECPublicKey) keyPair.getPublic();
BigInteger x = publicKeySpec.getQ().getX().toBigInteger();
BigInteger y = publicKeySpec.getQ().getY().toBigInteger();
BigInteger d = privateKeySpec.getD();
this.ecdsaPrivateKey = new ECDSAPrivateKey(d);
this.ecdsaPublicKey = new ECDSAPublicKey(signatureAlgorithm, x, y);
if (StringUtils.isNotBlank(dnName)) {
// Create certificate
GregorianCalendar startDate = new GregorianCalendar(); // time from which certificate is valid
GregorianCalendar expiryDate = new GregorianCalendar(); // time after which certificate is not valid
expiryDate.add(Calendar.YEAR, 1);
BigInteger serialNumber = new BigInteger(1024, new Random()); // serial number for certificate
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
X500Principal principal = new X500Principal(dnName);
certGen.setSerialNumber(serialNumber);
certGen.setIssuerDN(principal);
certGen.setNotBefore(startDate.getTime());
certGen.setNotAfter(expiryDate.getTime());
certGen.setSubjectDN(principal); // note: same as issuer
certGen.setPublicKey(keyPair.getPublic());
certGen.setSignatureAlgorithm("SHA256WITHECDSA");
X509Certificate x509Certificate = certGen.generate(privateKeySpec, "BC");
this.certificate = new Certificate(signatureAlgorithm, x509Certificate);
}
}
public Certificate generateV3Certificate(Date startDate, Date expirationDate, String dnName) throws CertificateEncodingException, InvalidKeyException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException {
// Create certificate
BigInteger serialNumber = new BigInteger(1024, new Random()); // serial number for certificate
X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
X500Principal principal = new X500Principal(dnName);
certGen.setSerialNumber(serialNumber);
certGen.setIssuerDN(principal);
certGen.setNotBefore(startDate);
certGen.setNotAfter(expirationDate);
certGen.setSubjectDN(principal); // note: same as issuer
certGen.setPublicKey(keyPair.getPublic());
certGen.setSignatureAlgorithm(signatureAlgorithm.getAlgorithm());
X509Certificate x509Certificate = certGen.generate(keyPair.getPrivate(), "BC");
return new Certificate(signatureAlgorithm, x509Certificate);
}
@Override
public ECDSAPrivateKey getPrivateKey() {
return ecdsaPrivateKey;
}
@Override
public ECDSAPublicKey getPublicKey() {
return ecdsaPublicKey;
}
@Override
public Certificate getCertificate() {
return certificate;
}
}