package org.cagrid.dorian.ca;
import java.io.ByteArrayInputStream;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import junit.framework.TestCase;
import org.bouncycastle.asn1.x509.X509Name;
import org.cagrid.dorian.common.Lifetime;
import org.cagrid.dorian.model.exceptions.DorianInternalException;
import org.cagrid.dorian.service.CertificateSignatureAlgorithm;
import org.cagrid.dorian.service.ca.CertificateAuthority;
import org.cagrid.dorian.service.ca.CertificateAuthorityCreationPolicy;
import org.cagrid.dorian.service.ca.CertificateAuthorityException;
import org.cagrid.dorian.service.ca.CertificateAuthorityProperties;
import org.cagrid.dorian.service.ca.CredentialsManager;
import org.cagrid.dorian.service.ca.DBCertificateAuthority;
import org.cagrid.dorian.service.ca.EracomCertificateAuthority;
import org.cagrid.dorian.service.ca.EracomCertificateAuthorityProperties;
import org.cagrid.dorian.service.ca.NoCACredentialsException;
import org.cagrid.dorian.service.ca.WrappedKey;
import org.cagrid.dorian.service.ca.WrappingCertificateAuthority;
import org.cagrid.gaards.dorian.test.Utils;
import org.cagrid.gaards.pki.CertUtil;
import org.cagrid.gaards.pki.KeyUtil;
import org.cagrid.tools.database.Database;
import org.globus.gsi.GlobusCredential;
/**
* @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 class TestCertificateAuthority extends TestCase {
private static final String TABLE = "test_dorian_ca";
private static final String SUBJECT_PREFIX = "O=Testing Organization,OU=ABC,OU=XYZ,CN=";
private Database db;
private int MAX_COUNT = 8;
private int TIME_MULTIPLIER = 2;
public void testWrappingCertificateAuthority() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoCreateAutoRenewalLong();
ca = getCertificateAuthority(conf);
if (ca instanceof WrappingCertificateAuthority) {
ca.clearCertificateAuthority();
createAndStoreCA(ca);
WrappingCertificateAuthority wca = (WrappingCertificateAuthority) ca;
KeyPair pair = KeyUtil.generateRSAKeyPair1024();
WrappedKey wk = wca.wrap(pair.getPrivate());
try {
KeyUtil.loadPrivateKey(new ByteArrayInputStream(wk.getWrappedKeyData()), null);
fail("Should not be able to unwrap key.");
} catch (Exception e) {
}
PrivateKey key = wca.unwrap(wk);
assertEquals(pair.getPrivate(), key);
}
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private CertificateAuthority getCertificateAuthority(CertificateAuthorityProperties conf) throws Exception {
Class type = Utils.getCA().getClass();
CertificateAuthorityProperties props = Utils.getCAProperties();
props.setAutoCreateCA(conf.isAutoCreateCAEnabled());
props.setAutoRenewCA(conf.isAutoRenewCAEnabled());
props.setCreationPolicy(conf.getCreationPolicy());
props.setRenewalLifetime(conf.getRenewalLifetime());
CertificateAuthority ca = null;
if (type.equals(DBCertificateAuthority.class)) {
ca = new DBCertificateAuthority("dorianca",db, props);
} else if (type.equals(DBCertificateAuthority.class)) {
ca = new EracomCertificateAuthority((EracomCertificateAuthorityProperties) props);
} else {
throw new Exception("The certificate authority " + type + " is not a valid ca for the test " + TestCertificateAuthority.class.getName() + ".");
}
ca.clearCertificateAuthority();
return ca;
}
private String identityToSubject(String identity) {
String s = identity.substring(1);
return s.replace('/', ',');
}
public void testRequestCertificateBadSubject() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoCreateAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
createAndStoreCA(ca);
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.DAY_OF_MONTH, 5);
Date end = cal.getTime();
submitCertificateRequest(ca, "O=OSU,OU=BMI,OU=MSCL,CN=foo", start, end);
assertTrue(false);
} catch (CertificateAuthorityException f) {
if (f.getMessage().indexOf("Invalid certificate subject") == -1) {
f.printStackTrace();
assertTrue(false);
}
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void testCreateCertificate() {
CertificateAuthority ca = null;
try {
int hours = 12;
CertificateAuthorityProperties conf = this.getDorianCAConfAutoCreateAutoRenewalLong();
String user = SUBJECT_PREFIX + "User";
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
Calendar c = new GregorianCalendar();
Date start = c.getTime();
c.add(Calendar.HOUR, hours);
KeyPair pair = KeyUtil.generateRSAKeyPair1024();
assertNotNull(pair);
PublicKey proxyPublicKey = pair.getPublic();
assertNotNull(proxyPublicKey);
X509Certificate cert = ca.signCertificate(user, pair.getPublic(), start, c.getTime(), CertificateSignatureAlgorithm.SHA2);
assertNotNull(cert);
GlobusCredential cred = new GlobusCredential(pair.getPrivate(), new X509Certificate[] { cert });
assertNotNull(cred);
long timeLeft = cred.getTimeLeft();
assertEquals(user, cert.getSubjectDN().getName());
assertEquals(user, identityToSubject(cred.getIdentity()));
assertEquals(cert.getIssuerDN(), ca.getCACertificate().getSubjectDN());
long okMax = hours * 60 * 60;
// Allow some Buffer
long okMin = okMax - 300;
// must have less time left than the maximum
assertTrue(timeLeft <= okMax);
// must have more time left than the minimum
assertTrue(timeLeft >= okMin);
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
}
}
public void testCertificateTimeToGreat() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoCreateAutoRenewalLong();
String user = SUBJECT_PREFIX + "User";
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
Calendar c = new GregorianCalendar();
Date start = c.getTime();
c.add(Calendar.YEAR, 10);
Date expiration = c.getTime();
KeyPair pair = KeyUtil.generateRSAKeyPair1024();
try {
ca.signCertificate(user, pair.getPublic(), start, expiration, CertificateSignatureAlgorithm.SHA2);
fail("Should not be able to sign a certificate that expires after the CA.");
} catch (CertificateAuthorityException f) {
}
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
}
}
public void testNoCACredentials() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfNoAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
try {
ca.getCACertificate();
assertTrue(false);
} catch (NoCACredentialsException f) {
}
assertEquals(0, db.getUsedConnectionCount());
try {
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.DAY_OF_MONTH, 5);
Date end = cal.getTime();
submitCertificateRequest(ca, SUBJECT_PREFIX, start, end);
assertEquals(0, db.getUsedConnectionCount());
assertTrue(false);
} catch (NoCACredentialsException f) {
}
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void testNoCACredentialsWithAutoRenew() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
try {
ca.getCACertificate();
assertTrue(false);
} catch (NoCACredentialsException f) {
}
try {
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.DAY_OF_MONTH, 5);
Date end = cal.getTime();
submitCertificateRequest(ca, SUBJECT_PREFIX, start, end);
assertTrue(false);
} catch (NoCACredentialsException f) {
}
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void testSetCACredentials() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
// ca.destroyTable();
createAndStoreCA(ca);
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void testAutoCreateCA() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoCreateAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
assertFalse(ca.hasCACredentials());
X509Certificate cert = ca.getCACertificate();
assertTrue(ca.hasCACredentials());
assertEquals(conf.getCreationPolicy().getSubject(), cert.getSubjectDN().getName());
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void testRequestCertificate() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
createAndStoreCA(ca);
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.DAY_OF_MONTH, 5);
Date end = cal.getTime();
submitCertificateRequest(ca, SUBJECT_PREFIX, start, end);
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void testRequestCertificateBadDate() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
createAndStoreCA(ca);
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.YEAR, 5);
Date end = cal.getTime();
submitCertificateRequest(ca, SUBJECT_PREFIX, start, end);
assertTrue(false);
} catch (CertificateAuthorityException f) {
if (f.getMessage().indexOf("Certificate expiration date is after the CA certificates expiration date") == -1) {
f.printStackTrace();
fail(f.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
fail(e.getMessage());
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void testExpiredCACredentialsWithRenewal() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = this.getDorianCAConfAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
// give a chance for others to run right before we enter timing
// sensitive code
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Thread.currentThread().yield();
X509Certificate origRoot = null;
boolean completed = false;
int count = 0;
int seconds = 5000;
while ((!completed) && (count < MAX_COUNT)) {
try {
origRoot = createAndStoreCAShort(ca, seconds);
completed = true;
} catch (Exception f) {
count = count + 1;
seconds = seconds * TIME_MULTIPLIER;
}
}
Thread.sleep(seconds + 500);
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.DAY_OF_MONTH, 5);
Date end = cal.getTime();
assertNotSame(origRoot, ca.getCACertificate());
submitCertificateRequest(ca, SUBJECT_PREFIX, start, end);
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void testExpiredCACredentialsNoRenewal() {
CertificateAuthority ca = null;
try {
CertificateAuthorityProperties conf = getDorianCAConfNoAutoRenewalLong();
ca = getCertificateAuthority(conf);
ca.clearCertificateAuthority();
// ca.destroyTable();
// give a chance for others to run right before we enter timing
// sensitive code
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
Thread.currentThread().yield();
boolean completed = false;
int count = 0;
int seconds = 5000;
while ((!completed) && (count < MAX_COUNT)) {
try {
createAndStoreCAShort(ca, seconds);
completed = true;
} catch (Exception f) {
count = count + 1;
seconds = seconds * TIME_MULTIPLIER;
}
}
Thread.sleep(seconds + 500);
try {
ca.getCACertificate();
assertTrue(false);
} catch (NoCACredentialsException f) {
}
try {
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.DAY_OF_MONTH, 5);
Date end = cal.getTime();
submitCertificateRequest(ca, SUBJECT_PREFIX, start, end);
} catch (NoCACredentialsException f) {
}
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
} finally {
try {
ca.clearCertificateAuthority();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private CertificateAuthorityProperties getDorianCAConfAutoRenewalLong() throws DorianInternalException {
Lifetime lifetime = new Lifetime();
lifetime.setYears(5);
lifetime.setMonths(0);
lifetime.setDays(0);
CertificateAuthorityCreationPolicy creation = new CertificateAuthorityCreationPolicy(SUBJECT_PREFIX + "Temp Certificate Authority", 2048, lifetime);
CertificateAuthorityProperties conf = new CertificateAuthorityProperties("password", null, 1024, false, null, true, lifetime);
return conf;
}
private CertificateAuthorityProperties getDorianCAConfAutoCreateAutoRenewalLong() throws DorianInternalException {
Lifetime lifetime = new Lifetime();
lifetime.setYears(5);
lifetime.setMonths(0);
lifetime.setDays(0);
CertificateAuthorityCreationPolicy creation = new CertificateAuthorityCreationPolicy(SUBJECT_PREFIX + "Temp Certificate Authority", 2048, lifetime);
CertificateAuthorityProperties conf = new CertificateAuthorityProperties("password", null, 1024, true, creation, true, lifetime);
return conf;
}
private CertificateAuthorityProperties getDorianCAConfNoAutoRenewalLong() throws DorianInternalException {
CertificateAuthorityProperties conf = new CertificateAuthorityProperties("password", 1024);
return conf;
}
private void createAndStoreCA(CertificateAuthority ca) throws Exception {
KeyPair rootPair = KeyUtil.generateRSAKeyPair1024(ca.getCACredentialsProvider());
assertNotNull(rootPair);
String rootSub = SUBJECT_PREFIX + "Temp Certificate Authority";
X509Name rootSubject = new X509Name(rootSub);
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.YEAR, 1);
Date end = cal.getTime();
X509Certificate root = CertUtil.generateCACertificate(ca.getCACredentialsProvider(), rootSubject, start, end, rootPair, CertUtil.SHA2_SIGNATURE_ALGORITHM);
assertNotNull(root);
ca.setCACredentials(root, rootPair.getPrivate(), null);
X509Certificate r = ca.getCACertificate();
assertNotNull(r);
assertEquals(r, root);
}
private X509Certificate createAndStoreCAShort(CertificateAuthority ca, int seconds) throws Exception {
KeyPair rootPair = KeyUtil.generateRSAKeyPair2048(ca.getCACredentialsProvider());
assertNotNull(rootPair);
String rootSub = SUBJECT_PREFIX + "Temp Certificate Authority";
X509Name rootSubject = new X509Name(rootSub);
GregorianCalendar cal = new GregorianCalendar();
Date start = cal.getTime();
cal.add(Calendar.SECOND, (seconds / 1000));
Date end = cal.getTime();
X509Certificate root = CertUtil.generateCACertificate(ca.getCACredentialsProvider(), rootSubject, start, end, rootPair, CertUtil.SHA2_SIGNATURE_ALGORITHM);
assertNotNull(root);
ca.setCACredentials(root, rootPair.getPrivate(), null);
X509Certificate r = ca.getCACertificate();
assertNotNull(r);
if (!r.equals(root)) {
throw new Exception("The CA certificate obtained was not expected");
}
return r;
}
private void submitCertificateRequest(CertificateAuthority ca, String prefix, Date start, Date end) throws Exception {
String cn = "User";
String subject = prefix + cn;
KeyPair pair = KeyUtil.generateRSAKeyPair1024();
X509Certificate cert = ca.signCertificate(subject, pair.getPublic(), start, end, CertificateSignatureAlgorithm.SHA2);
assertNotNull(cert);
assertEquals(cert.getSubjectDN().getName(), subject);
}
protected void setUp() throws Exception {
super.setUp();
try {
db = Utils.getDB();
assertEquals(0, db.getUsedConnectionCount());
CredentialsManager.CREDENTIALS_TABLE = TABLE;
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
}
}
protected void tearDown() throws Exception {
super.setUp();
try {
assertEquals(0, db.getUsedConnectionCount());
} catch (Exception e) {
e.printStackTrace();
assertTrue(false);
}
}
}