package org.cagrid.dorian.service.ca;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
import org.bouncycastle.asn1.x509.X509Name;
import org.cagrid.core.common.FaultHelper;
import org.cagrid.dorian.common.Lifetime;
import org.cagrid.dorian.service.CertificateSignatureAlgorithm;
import org.cagrid.dorian.service.util.Utils;
import org.cagrid.gaards.pki.CRLEntry;
import org.cagrid.gaards.pki.CertUtil;
import org.cagrid.gaards.pki.KeyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author <A href="mailto:langella@bmi.osu.edu">Stephen Langella </A>
* @author <A href="mailto:oster@bmi.osu.edu">Scott Oster </A>
* @author <A href="mailto:hastings@bmi.osu.edu">Shannon Hastings </A>
* @version $Id: ArgumentManagerTable.java,v 1.2 2004/10/15 16:35:16 langella
* Exp $
*/
public abstract class CertificateAuthority {
private final static Logger logger = LoggerFactory.getLogger(CertificateAuthority.class);
private boolean initialized = false;
private CertificateAuthorityProperties properties;
public CertificateAuthority(CertificateAuthorityProperties properties) {
this.properties = properties;
}
public abstract String getUserCredentialsProvider();
public abstract String getCACredentialsProvider();
public abstract String getSignatureAlgorithm(CertificateSignatureAlgorithm alg) throws CertificateAuthorityException;
public abstract boolean hasCACredentials() throws CertificateAuthorityException;
public abstract void setCACredentials(X509Certificate cert, PrivateKey key, String password) throws CertificateAuthorityException;
public abstract void deleteCACredentials() throws CertificateAuthorityException;
public abstract PrivateKey getPrivateKey(String password) throws CertificateAuthorityException, NoCACredentialsException;
protected abstract java.security.cert.X509Certificate getCertificate() throws CertificateAuthorityException;
public void clearCertificateAuthority() throws CertificateAuthorityException {
deleteCACredentials();
this.initialized = false;
}
private synchronized void init() throws CertificateAuthorityException {
try {
if (!initialized) {
if (!hasCACredentials()) {
if (properties.isAutoCreateCAEnabled()) {
Lifetime lifetime = properties.getCreationPolicy().getLifetime();
this.createCertifcateAuthorityCredentials(properties.getCreationPolicy().getSubject(), Utils.getExpiredDate(lifetime), properties.getCreationPolicy().getKeySize());
}
}
initialized = true;
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Unexpected Error, could not initialize the Dorian Certificate Authority.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
private void createCertifcateAuthorityCredentials(String dn, Date expirationDate, int keySize) throws CertificateAuthorityException, NoCACredentialsException {
try {
KeyPair pair = KeyUtil.generateRSAKeyPair(getCACredentialsProvider(), keySize);
X509Certificate cacert = CertUtil.generateCACertificate(getCACredentialsProvider(), new X509Name(dn), new Date(), expirationDate, pair, CertUtil.SHA2_SIGNATURE_ALGORITHM);
deleteCACredentials();
this.setCACredentials(cacert, pair.getPrivate(), properties.getCertificateAuthorityPassword());
} catch (Exception e) {
logger.error(e.getMessage(), e);
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Unexpected Error, could not create the CA credentials.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
public java.security.cert.X509Certificate getCACertificate() throws CertificateAuthorityException, NoCACredentialsException {
return getCACertificate(true);
}
private java.security.cert.X509Certificate getCACertificate(boolean errorOnExpiredCredentials) throws CertificateAuthorityException, NoCACredentialsException {
X509Certificate cert = null;
init();
try {
if (!hasCACredentials()) {
NoCACredentialsException fault = FaultHelper.createFaultException(NoCACredentialsException.class, "No certificate exists for the CA.");
throw fault;
} else {
cert = getCertificate();
}
} catch (NoCACredentialsException f) {
throw f;
} catch (Exception e) {
logger.error(e.getMessage(), e);
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Unexpected Error, Error obtaining the CA private key.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
if (errorOnExpiredCredentials) {
Date now = new Date();
if (now.before(cert.getNotBefore()) || (now.after(cert.getNotAfter()))) {
if (properties.isAutoRenewCAEnabled()) {
Lifetime lifetime = properties.getRenewalLifetime();
return renewCertifcateAuthorityCredentials(Utils.getExpiredDate(lifetime));
} else {
NoCACredentialsException fault = FaultHelper.createFaultException(NoCACredentialsException.class, "The CA certificate had expired or is not valid at this time.");
throw fault;
}
}
}
return cert;
}
public synchronized X509Certificate signCertificate(String subject, PublicKey publicKey, Date start, Date expiration, CertificateSignatureAlgorithm signatureAlgorithm)
throws CertificateAuthorityException, NoCACredentialsException {
init();
X509Certificate cacert = getCACertificate();
Date caDate = cacert.getNotAfter();
if (start.after(caDate)) {
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Certificate start date is after the CA certificates expiration date.");
throw fault;
}
if (expiration.after(caDate)) {
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Certificate expiration date is after the CA certificates expiration date.");
throw fault;
}
try {
// VALIDATE DN
String caSubject = cacert.getSubjectDN().getName();
int caindex = caSubject.lastIndexOf(",");
String caPreSub = caSubject.substring(0, caindex);
if (!subject.startsWith(caPreSub)) {
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Invalid certificate subject, the subject must start with, " + caPreSub);
throw fault;
}
X509Certificate cert = CertUtil.generateCertificate(getCACredentialsProvider(), new X509Name(subject), start, expiration, publicKey, cacert, getPrivateKey(),
getSignatureAlgorithm(signatureAlgorithm), properties.getPolicyOID());
return cert;
} catch (CertificateAuthorityException e) {
throw e;
} catch (Exception e) {
logger.error(e.getMessage(), e);
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Unexpected Error, could not sign certificate.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
public synchronized X509Certificate signHostCertificate(String host, PublicKey publicKey, Date start, Date expiration, CertificateSignatureAlgorithm signatureAlgorithm)
throws CertificateAuthorityException, NoCACredentialsException {
init();
X509Certificate cacert = getCACertificate();
try {
String subject = Utils.getHostCertificateSubject(cacert, host);
return signCertificate(subject, publicKey, start, expiration, signatureAlgorithm);
} catch (Exception e) {
logger.error(e.getMessage(), e);
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Unexpected Error, could not sign host certificate.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
public synchronized X509Certificate renewCertifcateAuthorityCredentials(Date expirationDate) throws CertificateAuthorityException, NoCACredentialsException {
init();
try {
X509Certificate oldcert = getCACertificate(false);
int size = ((RSAPublicKey) oldcert.getPublicKey()).getModulus().bitLength();
KeyPair pair = KeyUtil.generateRSAKeyPair(getCACredentialsProvider(), size);
X509Certificate cacert = CertUtil.generateCACertificate(getCACredentialsProvider(), new X509Name(oldcert.getSubjectDN().getName()), new Date(), expirationDate, pair,
CertUtil.SHA2_SIGNATURE_ALGORITHM);
deleteCACredentials();
this.setCACredentials(cacert, pair.getPrivate(), properties.getCertificateAuthorityPassword());
return cacert;
} catch (Exception e) {
logger.error(e.getMessage(), e);
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Unexpected Error, could renew the CA credentials.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
public X509CRL getCRL(CRLEntry[] entries, CertificateSignatureAlgorithm signatureAlgorithm) throws CertificateAuthorityException, NoCACredentialsException {
try {
init();
return CertUtil.createCRL(getCACredentialsProvider(), getCACertificate(), getPrivateKey(), entries, getCACertificate().getNotAfter(), getSignatureAlgorithm(signatureAlgorithm));
} catch (Exception e) {
logger.error(e.getMessage(), e);
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Unexpected Error, could not create the CRL.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
public PrivateKey getPrivateKey() throws CertificateAuthorityException, NoCACredentialsException {
init();
try {
if (!hasCACredentials()) {
NoCACredentialsException fault = FaultHelper.createFaultException(NoCACredentialsException.class, "No Private Key exists for the CA.");
throw fault;
} else {
return getPrivateKey(properties.getCertificateAuthorityPassword());
}
} catch (NoCACredentialsException f) {
throw f;
} catch (Exception e) {
logger.error(e.getMessage(), e);
CertificateAuthorityException fault = FaultHelper.createFaultException(CertificateAuthorityException.class, "Unexpected Error, Error obtaining the CA private key.");
FaultHelper.addMessage(fault, e.getMessage());
throw fault;
}
}
public CertificateAuthorityProperties getProperties() {
return properties;
}
}