Skip to Content.
Sympa Menu

perfsonar-dev - perfsonar: r3973 - in branches/saslca/src/edu/psu/sasl_ca: . apps/client apps/server certdb certdb/provider util

Subject: perfsonar development work

List archive

perfsonar: r3973 - in branches/saslca/src/edu/psu/sasl_ca: . apps/client apps/server certdb certdb/provider util


Chronological Thread 
  • From:
  • To:
  • Subject: perfsonar: r3973 - in branches/saslca/src/edu/psu/sasl_ca: . apps/client apps/server certdb certdb/provider util
  • Date: Sun, 8 Jun 2008 04:42:38 -0400

Author: rodriguez
Date: 2008-06-08 04:42:37 -0400 (Sun, 08 Jun 2008)
New Revision: 3973

Added:
branches/saslca/src/edu/psu/sasl_ca/NewClientProtocolHandler.java
Modified:
branches/saslca/src/edu/psu/sasl_ca/CertificateEngine.java
branches/saslca/src/edu/psu/sasl_ca/ClientProtocolHandler.java
branches/saslca/src/edu/psu/sasl_ca/ServerProtocolHandler.java
branches/saslca/src/edu/psu/sasl_ca/apps/client/CSRSigner.java
branches/saslca/src/edu/psu/sasl_ca/apps/client/ClientConfiguration.java
branches/saslca/src/edu/psu/sasl_ca/apps/client/EduGAINClient.java

branches/saslca/src/edu/psu/sasl_ca/apps/client/PeerServerCertGenerator.java
branches/saslca/src/edu/psu/sasl_ca/apps/client/StressTest.java
branches/saslca/src/edu/psu/sasl_ca/apps/client/sasl_ca_client.java
branches/saslca/src/edu/psu/sasl_ca/apps/server/ServerShutdown.java
branches/saslca/src/edu/psu/sasl_ca/apps/server/sasl_ca_server.java
branches/saslca/src/edu/psu/sasl_ca/certdb/CertDB.java
branches/saslca/src/edu/psu/sasl_ca/certdb/provider/BerkeleyCertDB.java
branches/saslca/src/edu/psu/sasl_ca/certdb/provider/RawCertDB.java
branches/saslca/src/edu/psu/sasl_ca/certdb/provider/TextSummaryCertDB.java
branches/saslca/src/edu/psu/sasl_ca/util/OptionalPropertyNames.java
branches/saslca/src/edu/psu/sasl_ca/util/Util.java
Log:
- Adding SASL CA 1.0 for eduGAIN
+ Fixes all stuff around component IDs

Modified: branches/saslca/src/edu/psu/sasl_ca/CertificateEngine.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/CertificateEngine.java 2008-06-06
21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/CertificateEngine.java 2008-06-08
08:42:37 UTC (rev 3973)
@@ -68,6 +68,7 @@
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
@@ -106,7 +107,6 @@
import
edu.internet2.middleware.shibboleth.aa.attrresolv.ResolverAttributeSet;
import edu.internet2.middleware.shibboleth.common.LocalPrincipal;

-import edu.psu.sasl_ca.apps.client.subject.UserID;
import edu.psu.sasl_ca.asn1.ExtendedKeyUsageException;
import edu.psu.sasl_ca.asn1.IssuerAltNameGenerator;
import edu.psu.sasl_ca.asn1.KeyIdentifier;
@@ -227,10 +227,15 @@

private int edugainCertLifetime; // number of seconds an eduGAIN cert
is valid

+ /** prefix of the eduGIAN sujectaltname prefix. */
private String edugainDNPrefix;
-
- private String edugainSubjectPrefix;

+ /** the name of the edugain federation. */
+ private String edugainFederation;
+
+ /** the name of the interface we're listening on. */
+ private String hostname;
+
/** The Certificate Policies OID. */
private ASN1ObjectIdentifier policyOID;

@@ -267,7 +272,7 @@
private static final int defaultMaxCryptoOps = 10;

private static final Logger logger = Logger
- .getLogger(CertificateEngine.class);
+ .getLogger(CertificateEngine.class);

/**
* Create a new CertificateEngine.
@@ -285,7 +290,7 @@
final List<CertPolicy> csrPolicy,
final CryptoShibHandle handleGenerator,
final SerialNumberGenerator sng, final CertDB certdb)
- throws CertificateEngineException,
IllegalArgumentException {
+ throws CertificateEngineException, IllegalArgumentException {

if (props == null) {
throw new IllegalArgumentException("props is null");
@@ -297,17 +302,17 @@

if (handleGenerator == null) {
throw new IllegalArgumentException(
- "Must provider a CryptoShibHandle
generator");
+ "Must provider a CryptoShibHandle generator");
}

if (sng == null) {
throw new IllegalArgumentException(
- "Must provider a
SerialNumberGenerator");
+ "Must provider a SerialNumberGenerator");
}

if (certdb == null) {
throw new IllegalArgumentException(
- "Must provide a CertDB for logging");
+ "Must provide a CertDB for logging");
}

this.policyList = csrPolicy;
@@ -327,16 +332,16 @@
// we don't have to check if any of these are null
b/c they're mandatory properties

this.certSigningAlgorithm = props
-
.get(MandatoryPropertyNames.CRYPTO_CERT_SIGNING_ALGORITHM);
+
.get(MandatoryPropertyNames.CRYPTO_CERT_SIGNING_ALGORITHM);
this.certSigningAlgId = new AlgorithmIdentifier(
certSigningAlgorithm);

String keyStoreType = props
-
.get(MandatoryPropertyNames.KEYSTORE_TYPE);
+ .get(MandatoryPropertyNames.KEYSTORE_TYPE);
String keystoreFileName = props
-
.get(MandatoryPropertyNames.KEYSTORE_FILE);
+ .get(MandatoryPropertyNames.KEYSTORE_FILE);
String saslcaKeyStoreAlias = props
-
.get(MandatoryPropertyNames.KEYSTORE_SIGNING_ALIAS);
+ .get(MandatoryPropertyNames.KEYSTORE_SIGNING_ALIAS);
char keyStorePassword[] = props.get(

MandatoryPropertyNames.KEYSTORE_PASSWORD).toCharArray();
char keyStorePrivateKeyPassword[] = props.get(
@@ -344,34 +349,34 @@
.toCharArray();

String opaqueCertLifetimeString = props
-
.get(MandatoryPropertyNames.CERT_OPAQUE_LIFETIME);
+ .get(MandatoryPropertyNames.CERT_OPAQUE_LIFETIME);
this.opaqueCertLifetime = Integer
- .parseInt(opaqueCertLifetimeString);
+ .parseInt(opaqueCertLifetimeString);

String identityCertLifetimeString = props
-
.get(MandatoryPropertyNames.CERT_IDENTITY_LIFETIME);
+ .get(MandatoryPropertyNames.CERT_IDENTITY_LIFETIME);
this.identityCertLifetime = Integer
- .parseInt(identityCertLifetimeString);
+ .parseInt(identityCertLifetimeString);

String peerserverCertLifetimeString = props
-
.get(MandatoryPropertyNames.CERT_PEERSERVER_LIFETIME);
+ .get(MandatoryPropertyNames.CERT_PEERSERVER_LIFETIME);
this.peerserverCertLifetime = Integer
-
.parseInt(peerserverCertLifetimeString);
+ .parseInt(peerserverCertLifetimeString);

// try to load the edugain lifetime
String edugainCertLifetimeString = props
-
.get(OptionalPropertyNames.CERT_EDUGAIN_LIFETIME);
+ .get(OptionalPropertyNames.CERT_EDUGAIN_LIFETIME);
if (edugainCertLifetimeString != null
&&
edugainCertLifetimeString.trim().length() > 0) {
this.edugainCertLifetime = Integer
-
.parseInt(edugainCertLifetimeString);
+ .parseInt(edugainCertLifetimeString);
} else {
this.edugainCertLifetime = 0;
}

// try to load edugain DN prefix
String edugainDNPrefixString = props
-
.get(OptionalPropertyNames.CERT_EDUGAIN_COMPONENT_PREFIX);
+
.get(OptionalPropertyNames.CERT_EDUGAIN_COMPONENT_PREFIX);
if (edugainDNPrefixString != null
&&
edugainDNPrefixString.trim().length() > 0) {
this.edugainDNPrefix =
edugainDNPrefixString.trim();
@@ -379,16 +384,19 @@
this.edugainDNPrefix = "";
}

- // try to load edugain Subject prefix
- String edugainSubjectPrefixString = props
-
.get(OptionalPropertyNames.CERT_EDUGAIN_SUBJECT_PREFIX);
- if (edugainSubjectPrefixString != null
- &&
edugainSubjectPrefixString.trim().length() > 0) {
- this.edugainSubjectPrefix =
edugainSubjectPrefixString.trim();
+ // try to get the edugain federation name.
+ String edugainFedTemp = props
+
.get(OptionalPropertyNames.CERT_EDUGAIN_FEDERATION_NAME);
+ if (edugainFedTemp != null &&
edugainFedTemp.trim().length() > 0) {
+ this.edugainFederation = edugainFedTemp;
} else {
- this.edugainSubjectPrefix = "";
+ this.edugainFederation = "";
}

+ // edugain needs to know the hostname we're listening
on. This is a mandatory property.
+ this.hostname =
props.get(MandatoryPropertyNames.SASLCA_HOSTNAME)
+ .trim();
+
// if edugain support is enabled, create a
SubjectAltNameGenerator for eduGAIN.
// we have to use a seperate one for edugain, since
it may be configured differently
// from the regular one.
@@ -400,7 +408,7 @@
}

String skewString = props
-
.get(OptionalPropertyNames.SASLCA_SKEW_SECONDS);
+ .get(OptionalPropertyNames.SASLCA_SKEW_SECONDS);
try {
this.certSkewSeconds =
Integer.parseInt(skewString);
} catch (NumberFormatException numEx) {
@@ -411,12 +419,12 @@
}

String resolverConfigFileString = props
-
.get(MandatoryPropertyNames.DIRECTORY_RESOLVER_FILE);
+ .get(MandatoryPropertyNames.DIRECTORY_RESOLVER_FILE);
File configFile = new File(resolverConfigFileString);
this.resolver = new
AttributeResolver(configFile.toURI().toString());

String maxCryptoOps = props
-
.get(OptionalPropertyNames.CRYPTO_MAX_OPS);
+ .get(OptionalPropertyNames.CRYPTO_MAX_OPS);
try {
this.cryptoSemaphore = new Semaphore(Integer
.parseInt(maxCryptoOps));
@@ -428,7 +436,7 @@
}

String cpsOIDString = props
-
.get(OptionalPropertyNames.SASLCA_POLICY_OID);
+ .get(OptionalPropertyNames.SASLCA_POLICY_OID);
if (cpsOIDString != null &&
cpsOIDString.trim().length() > 0) {
this.policyOID = new
ASN1ObjectIdentifier(cpsOIDString.trim());
} else {
@@ -436,7 +444,7 @@
}

String CPRURLString = props
-
.get(OptionalPropertyNames.SASLCA_CPS_URL);
+ .get(OptionalPropertyNames.SASLCA_CPS_URL);
if (CPRURLString != null &&
CPRURLString.trim().length() > 0) {
this.cps = new
ASN1IA5String(CPRURLString.trim());
} else {
@@ -472,7 +480,7 @@
// try to just get a single cert. failing that, abort.
try {
Certificate[] chain = ks
-
.getCertificateChain(saslcaKeyStoreAlias);
+ .getCertificateChain(saslcaKeyStoreAlias);
this.signingCertChain = new
X509Certificate[chain.length];
for (int i = 0; i < chain.length; i++) {
this.signingCertChain[i] =
(X509Certificate) chain[i];
@@ -492,13 +500,13 @@
Object o =
ks.getCertificate(saslcaKeyStoreAlias);
if (o == null) {
logger
- .fatal("alias "
- +
saslcaKeyStoreAlias
- + "
in KeyStore "
- +
keystoreFileName
- + "
does not contain a certificate or a certificate chain. Unable to get signing
certificate.");
+ .fatal("alias "
+ + saslcaKeyStoreAlias
+ + " in KeyStore "
+ + keystoreFileName
+ + " does not contain
a certificate or a certificate chain. Unable to get signing certificate.");
throw new KeyStoreException(
- "KeyStore does not
contian a certificate chain or a single signing certificate.");
+ "KeyStore does not contian a
certificate chain or a single signing certificate.");
}
this.signingCert =
(java.security.cert.X509Certificate) o;

@@ -525,7 +533,7 @@
boolean validChain =
Util.verifyCertChain(this.signingCertChain);
if (!validChain) {
throw new CertificateException(
- "signing certificate chain is
not valid");
+ "signing certificate chain is not valid");
}

// check that every cert in the signing cert chain is
still valid.
@@ -536,7 +544,7 @@
/* EVENTUALLY UNCOMMENT THIS TO MAKE SURE WE
SIGN WITH A VALID CERT
but since we're using keytool to make the certs, and
keytool
can't set the cA bit, we ignore it for now.
-
+
int pathLen = signingCert.getBasicConstraints();
if (pathLen < 0) {
// the cA bit is not set
@@ -597,47 +605,47 @@
// load which attribues we need to resolve
this.fetchCattribute = ("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_COUNTRY)) ? true
- : false);
+ : false);
this.fetchSTattribute = ("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_STATE)) ? true
- : false);
+ : false);
this.fetchLattribute = ("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_CITY)) ? true : false);
this.fetchOattribute = ("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_ORGANIZATION)) ? true
- : false);
+ : false);
this.fetchOUattribute = ("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_DEPARTMENT)) ? true
- : false);
+ : false);
this.fetchCNattribute = ("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_COMMON_NAME)) ? true
- : false);
+ : false);
this.fetchMailattribute = ("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_MAIL)) ? true : false);
this.fetchURLattribute = ("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_URL)) ? true : false);
this.fetchPrincipalattribute =
("attribute".equals(props

.get(MandatoryPropertyNames.DIRECTORY_PRINCIPAL)) ? true
- : false);
+ : false);

this.Cvalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_COUNTRY_VALUE);
+ .get(MandatoryPropertyNames.DIRECTORY_COUNTRY_VALUE);
this.STvalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_STATE_VALUE);
+ .get(MandatoryPropertyNames.DIRECTORY_STATE_VALUE);
this.Lvalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_CITY_VALUE);
+ .get(MandatoryPropertyNames.DIRECTORY_CITY_VALUE);
this.Ovalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_ORGANIZATION_VALUE);
+
.get(MandatoryPropertyNames.DIRECTORY_ORGANIZATION_VALUE);
this.OUvalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_DEPARTMENT_VALUE);
+
.get(MandatoryPropertyNames.DIRECTORY_DEPARTMENT_VALUE);
this.CNvalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_COMMON_NAME_VALUE);
+
.get(MandatoryPropertyNames.DIRECTORY_COMMON_NAME_VALUE);
this.Mailvalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_MAIL_VALUE);
+ .get(MandatoryPropertyNames.DIRECTORY_MAIL_VALUE);
this.URLvalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_URL_VALUE);
+ .get(MandatoryPropertyNames.DIRECTORY_URL_VALUE);
this.Principalvalue = props
-
.get(MandatoryPropertyNames.DIRECTORY_PRINCIPAL_VALUE);
+
.get(MandatoryPropertyNames.DIRECTORY_PRINCIPAL_VALUE);

ResolverAttribute[] attributesToFetch =
this.getAttributesToFetch();

@@ -648,13 +656,13 @@
if
(!attributePlugins.contains(attribute.getName())) {
throw new MissingPluginException(
"Missing an attribute
definition for "
- +
attribute.getName());
+ +
attribute.getName());
}
}

// process any mandatory attributes
String s = props
-
.get(OptionalPropertyNames.SASLCA_MANDATORY_ATTRIBUTES);
+
.get(OptionalPropertyNames.SASLCA_MANDATORY_ATTRIBUTES);
if (s != null) {
String[] attrs = s.trim().split(" ");
for (String attr : attrs) {
@@ -676,7 +684,7 @@
// get the issuerAltName extension
try {
this.issuerAltNameExtension =
IssuerAltNameGenerator
-
.convertSubjectAltName(this.signingCert);
+ .convertSubjectAltName(this.signingCert);
} catch (Exception ex) {
this.issuerAltNameExtension = null;
}
@@ -685,7 +693,6 @@
this.akiExt = makeAuthorityKey(this.signingCert);

} catch (Exception ex) {
- ex.printStackTrace();
logger.fatal("Fatal error setting up
CertificateEngine class", ex);

this.dispose();
@@ -744,9 +751,9 @@
cert.addExtension(ku.getExtension());
} catch (KeyUsageException ex) {
logger
- .error(
- "Error
creating KeyUsage Extension for edugain certificate",
- ex);
+ .error(
+ "Error creating KeyUsage
Extension for edugain certificate",
+ ex);
throw new ExtendedKeyUsageException(ex);
}
}
@@ -801,9 +808,9 @@
* @throws InterruptedException If the method is interrupted while
waiting for the signing semaphore
*/
private void signCert(final codec.x509.X509Certificate cert)
- throws CertificateException, IllegalArgumentException,
- InterruptedException, InvalidKeyException,
- NoSuchAlgorithmException, SignatureException {
+ throws CertificateException, IllegalArgumentException,
+ InterruptedException, InvalidKeyException,
+ NoSuchAlgorithmException, SignatureException {

if (cert == null) {
throw new IllegalArgumentException("cert is null");
@@ -899,8 +906,8 @@

Principal princ = new
LocalPrincipal(username);
String encryptedHandle = "CN="
- +
this.handleGenerator.getCryptoHandle(princ,
- currentDate);
+ +
this.handleGenerator.getCryptoHandle(princ,
+ currentDate);
X500Principal subjectDN = new
X500Principal(encryptedHandle);
cert.setSubjectDN(subjectDN);
logger.info("SubjectDN = " + subjectDN);
@@ -917,7 +924,7 @@

// a hash of attribute name:value pairs
Map<String, String[]> resolvedAttributes =
this
- .fetchAttributes(princ,
certType);
+ .fetchAttributes(princ, certType);
String DN = this.makeDN(resolvedAttributes);
X500Principal subjectDN = new
X500Principal(DN);
cert.setSubjectDN(subjectDN);
@@ -959,28 +966,28 @@
// check if edugain certs are enabled
if (this.edugainCertLifetime <= 0) {
throw new
CertPolicyAuthorizationException(
- "edugain certificates
are not enabled.");
+ "edugain certificates are not
enabled.");
}

logger.info("making an eduGAIN cert for: " +
username);

-// Principal princ = new
LocalPrincipal(username);
- UUID uuid = UUIDGenerator.getInstance()
-
.generateRandomBasedUUID(Util.prngFactory.get());
-
- String DN =
"CN="+uuid.toString()+","+this.edugainSubjectPrefix;
- X500Principal subjectDN = new
X500Principal(DN);
- cert.setSubjectDN(new UserID(DN));
- logger.info("SubjectDN = " +
subjectDN.getName());
-
- String temp = this.edugainDNPrefix + ":" +
uuid.toString();
+ Principal princ = new
LocalPrincipal(username);
+// UUID uuid = UUIDGenerator.getInstance()
+//
.generateRandomBasedUUID(Util.prngFactory.get());
+ String temp = this.edugainDNPrefix + ":"
+ + this.edugainFederation + ":user:" +
username;
String eduGainDN =
"https://registry.edugain.org/resolver?urn=";
- + URLEncoder.encode(temp,
"UTF-8");
+ + URLEncoder.encode(temp, "UTF-8");

Map<String, String[]> resolvedAttributes =
new HashMap<String, String[]>();
resolvedAttributes.put("uri", new String[] {
eduGainDN });

cert.addExtension(this.edugainSanGenerator.getSubjectAltName(
null, resolvedAttributes,
null, null, true));
+
+ Principal subjectDN = new
X500Principal("O=saslca, OU="
+ + this.edugainFederation + ",
CN=" + username);
+ logger.info("SubjectDN = " + subjectDN);
+ cert.setSubjectDN(subjectDN);
}

// common cert building steps.
@@ -1027,9 +1034,8 @@
signedCertArray[0] = cert;
System.arraycopy(this.signingCertChain, 0,
signedCertArray, 1,
this.signingCertChain.length);
- logger.info("Subject DN Issuer:
"+signedCertArray[1].getSubjectDN().getName());

- this.certDB.log(cert, username, (ipAddrs == null ?
null
+ this.certDB.log(signedCertArray, username, (ipAddrs
== null ? null
: ipAddrs[0]), certType);

return signedCertArray;
@@ -1064,8 +1070,8 @@
final java.security.cert.X509Certificate oldCert,
final CertificationRequest newCSR, final CertType
certType,
final InetAddress[] ipAddrs, final String[] hostnames)
- throws IllegalArgumentException,
CertificateEngineException,
- CertificateExpiredException,
CertificateNotYetValidException {
+ throws IllegalArgumentException, CertificateEngineException,
+ CertificateExpiredException, CertificateNotYetValidException {

if (oldCert == null) {
throw new IllegalArgumentException("oldCert is null");
@@ -1112,7 +1118,7 @@
boolean validSig = sig.verify(newCSR.getSignature());
if (!validSig) {
throw new CertificateEngineException(
- "New CSR does not have a
proper signature.");
+ "New CSR does not have a proper signature.");
}

} catch (NoSuchAlgorithmException ex) {
@@ -1200,14 +1206,14 @@

// set NotAfter
GregorianCalendar notAfterCal = (GregorianCalendar)
notBeforeCal
- .clone();
+ .clone();
switch (certType) {

case opaque:
notAfterCal.add(GregorianCalendar.SECOND,
this.opaqueCertLifetime);
case identity:
notAfterCal
- .add(GregorianCalendar.SECOND,
this.identityCertLifetime);
+ .add(GregorianCalendar.SECOND,
this.identityCertLifetime);
case peerserver:
notAfterCal.add(GregorianCalendar.SECOND,
this.peerserverCertLifetime);
@@ -1245,7 +1251,7 @@
resolver.resolveAttributes(princ, "SASL-CA",
"SASL-CA", attrSet);

ResolverAttributeSet.ResolverAttributeIterator
setIterator = attrSet
- .resolverAttributeIterator();
+ .resolverAttributeIterator();

// loop through the returned attributes.
// for every attribute, extract any String values and
put them in resolvedAttributes
@@ -1256,7 +1262,7 @@
while (setIterator.hasNext()) {

ResolverAttribute attribute =
(ResolverAttribute) setIterator
-
.nextResolverAttribute();
+ .nextResolverAttribute();

List<String> attributeValues = new
ArrayList<String>();

@@ -1285,8 +1291,8 @@
if (attributeValues.size() >
0) {

resolvedAttributes.put(attribute.getName(),

(String[]) attributeValues
-
.toArray(new String[attributeValues
-
.size()]));
+
.toArray(new String[attributeValues
+
.size()]));
}
}
}
@@ -1308,7 +1314,7 @@

if (!foundAll) {
throw new CertificateEngineException(
- "Unable to retrieve
all identity cert attributes. Aborting.");
+ "Unable to retrieve all identity cert
attributes. Aborting.");
}
}
}
@@ -1532,7 +1538,7 @@
}

return (AAAttribute[]) attributesToFetch
- .toArray(new
AAAttribute[attributesToFetch.size()]);
+ .toArray(new AAAttribute[attributesToFetch.size()]);
}

/**

Modified: branches/saslca/src/edu/psu/sasl_ca/ClientProtocolHandler.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/ClientProtocolHandler.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/ClientProtocolHandler.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -86,6 +86,7 @@

import edu.psu.sasl_ca.apps.client.ClientConfiguration;

+
/**
* This is used for the client-side of communication with the SASL-CA.
* The ClientProtocolHandler will handle all communication with the SASL-CA.
@@ -131,1035 +132,965 @@
* @version 0.4
* @author Derek Morr
()
*/
-public class ClientProtocolHandler extends ProtocolHandler implements
- PrivilegedExceptionAction<Map<CertificationRequest,
X509Certificate[]>> {
+public class ClientProtocolHandler extends ProtocolHandler
+ implements PrivilegedExceptionAction<Map<CertificationRequest,
X509Certificate[]>> {
+
+ /* timeout value for socket operations */
+ private int timeout = 30 * 1000;
+
+ /** The SaslClient */
+ private SaslClient saslclient;
+
+ private String hostname;
+ private int port;
+
+ /** The list of CSRs to process */
+ private Collection<CertificationRequest> csrList = new
ArrayList<CertificationRequest>();
+
+ /** A CertificateFactory to convert encoded certificates into Java
objects */
+ private CertificateFactory certFactory;
+
+ /** Security layer properties for the
{@link
SaslClientWrapper} */
+ private Map<String, ?> saslProperties;
+
+ /** store how long each CSR took to fetch. Used for profiling. */
+ private long[] timings;
+
+ /** should we profile the SASL-CA (i.e., use timings[] ?) */
+ private boolean profile = false;
+
+ /** should cert chains be verified? */
+ private boolean verifyCerts = true;
+
+ private static final Logger logger =
Logger.getLogger(ClientProtocolHandler.class);
+
+ /** A set of SASL client mechanism names that don't protect against
plaintext sniffing. */
+ private static final Set<String> insecureSaslMechanisms;

- /* timeout value for socket operations */
- private int timeout = 30 * 1000;
+ static {

- /** The SaslClient */
- private SaslClient saslclient;
+ // make a list of SASL mechanisms that transmit data in the clear.
+
+ Map<String, String> props = new HashMap<String, String>();
+ Set<String> allSaslMechanisms =
ProtocolHandler.filterSaslClientMechanisms(props);
+
+ props.put(Sasl.POLICY_NOPLAINTEXT, "true");
+ Set<String> secureSaslMechanisms =
ProtocolHandler.filterSaslClientMechanisms(props);
+
+ allSaslMechanisms.removeAll(secureSaslMechanisms);
+
+ insecureSaslMechanisms = allSaslMechanisms;
+ }

- private String hostname;
-
- private int port;
-
- /** The list of CSRs to process */
- private Collection<CertificationRequest> csrList = new
ArrayList<CertificationRequest>();
-
- /** A CertificateFactory to convert encoded certificates into Java
objects */
- private CertificateFactory certFactory;
-
- /** Security layer properties for the
{@link
SaslClientWrapper} */
- private Map<String, ?> saslProperties;
-
- /** store how long each CSR took to fetch. Used for profiling. */
- private long[] timings;
-
- /** should we profile the SASL-CA (i.e., use timings[] ?) */
- private boolean profile = false;
-
- /** should cert chains be verified? */
- private boolean verifyCerts = true;
-
- private static final Logger logger = Logger
- .getLogger(ClientProtocolHandler.class);
-
- /** A set of SASL client mechanism names that don't protect against
plaintext sniffing. */
- private static final Set<String> insecureSaslMechanisms;
-
- static {
-
- // make a list of SASL mechanisms that transmit data in the
clear.
-
- Map<String, String> props = new HashMap<String, String>();
- Set<String> allSaslMechanisms = ProtocolHandler
- .filterSaslClientMechanisms(props);
-
- props.put(Sasl.POLICY_NOPLAINTEXT, "true");
- Set<String> secureSaslMechanisms = ProtocolHandler
- .filterSaslClientMechanisms(props);
-
- allSaslMechanisms.removeAll(secureSaslMechanisms);
-
- insecureSaslMechanisms = allSaslMechanisms;
+
+ /**
+ * Creates a new ClientProtocolHandler object.
+ *
+ * @param clientConfig A
{@link
ClientConfiguration} wrapper object.
+ */
+ public ClientProtocolHandler(final ClientConfiguration clientConfig)
throws IOException,
+ IllegalArgumentException, ClientProtocolHandlerException,
CertificateException {
+
+ this(clientConfig.getServerName(), clientConfig.getServerPort(),
+ clientConfig.getCallbackHandler(),
clientConfig.getSaslProperties());
+
+ String[] protocols = clientConfig.getTLSProtocols();
+ if (protocols != null) {
+ super.setStartTLSProtocols(protocols);
+ }
+
+ String[] cipherSuites = clientConfig.getTLSCipherSuites();
+ if (cipherSuites != null) {
+ super.setStartTLSCipherSuites(cipherSuites);
+ }
+
+ }
+
+
+ /**
+ * Creates a new ClientProtocolHandler object.
+ *
+ * @param hostname The hostname or IP address of the SASL-CA
+ * @param port The port on the SASL-CA
+ * @param cbh A
{@link
javax.security.auth.callback.CallbackHandler} for JAAS login
+ * @param saslProperties A
{@link
Map} of SASL properties
+ *
+ * @throws IllegalArgumentException If any arguments (aside from
<code>saslProperties</code>) are <code>null</code> or 0.
+ * @throws ClientProtocolHandlerException on any other error
+ * @throws CertificateException If an X.509
{@link
CertificateFactory} implementation cannot be found;
+ */
+ public ClientProtocolHandler(final String hostname, int port, final
CallbackHandler cbh,
+ final Map<String, ?> saslProperties)
+ throws IOException, IllegalArgumentException,
ClientProtocolHandlerException, CertificateException {
+
+ super(null, cbh);
+
+ if (hostname == null) {
+ throw new IllegalArgumentException("Hostname is null");
}
+
+ if ((port < 1) || (port > 65535)) {
+ throw new IllegalArgumentException("Invalid port specified");
+ }
+
+ this.hostname = hostname;
+ this.port = port;
+ this.saslProperties = saslProperties;
+
+ this.certFactory = CertificateFactory.getInstance("X.509");
+
+ super.debuggingSendPrefix = "C: ";
+ super.debuggingReadPrefix = "S: ";
+ }
+
+
+ /**
+ * Connect to the SASL-CA.
+ *
+ * @throws UnknownHostException If this.hostname can't be resolved.
+ * @throws IOException If the socket can't be created.
+ * @throws SecurityException If the security manager won't let
+ */
+ public void connect() throws UnknownHostException, IOException,
SecurityException {
+
+ logger.info("Connecting to " + this.hostname + ":" + this.port);
+ super.socket = new Socket(this.hostname, this.port);
+ super.socket.setSoTimeout(timeout);
+ super.in = super.socket.getInputStream();
+ super.out = super.socket.getOutputStream();
+ }
+
+
+ /**
+ * Disconnect from the SASL-CA.
+ */
+ public void disconnect() {
+ try {
+ logger.info("closing client socket");
+ super.socket.close();
+ } catch(Exception ex) {
+ logger.error("Error while closing socket", ex);
+ }
+ }
+
+
+ /**
+ * Set the
{@link
Socket} timeout value.
+ *
+ * You shouldn't need to set this normally.
+ *
+ * @param timeout The number of milliseconds to wait before timing out a
{@link
Socket} connection. A value of 0 disables timeout.
+ *
+ * @see java.net.Socket#setSoTimeout
+ */
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+
+ /**
+ * Set if the class should record timing information for each CSR
request. Used for debugging.
+ *
+ * @param profiling Set to <code>true</code> if timing should be
enabled. It defaults to <code>false</code>.
+ */
+ public void setProfiling(boolean profiling) {
+ this.profile = profiling;
+ }
+
+
+ /**
+ * Set if the class should verify certificate chainsn from the server.
+ *
+ * @param verify Set to <code>false</code> if verification should not be
performed. It defaults to <code>true</code>.
+ */
+ public void setVerifyChains(boolean verify) {
+ this.verifyCerts = verify;
+ }
+
+ /**
+ * Add a
{@link
CertificationRequest} to be processed.
+ *
+ * @param csr The
{@link
CertificationRequest} to be signed by the SASL-CA.
+ */
+ public void addCSR(final CertificationRequest csr) {
+
+ if (csr != null) {
+ this.csrList.add(csr);
+ }
+ }
+
+
+ /**
+ * Add a list of
{@link
CertificationRequest} to be processed.
+ *
+ * @param csrList The list of
{@link
CertificationRequest} to be signed by the SASL-CA.
+ */
+ public void addCSRs(final Collection<CertificationRequest> csrList) {
+
+ for (CertificationRequest csr : csrList) {
+ if (csr != null) {
+ this.csrList.add(csr);
+ }
+ }
+ }

- /**
- * Creates a new ClientProtocolHandler object.
- *
- * @param clientConfig A
{@link
ClientConfiguration} wrapper object.
- */
- public ClientProtocolHandler(final ClientConfiguration clientConfig)
- throws IOException, IllegalArgumentException,
- ClientProtocolHandlerException, CertificateException {
+
+ /**
+ * Add a DER-encoded CSR to be processed.
+ *
+ * @param csrBytes A <code>byte[]</code> containing a DER-encoded CSR
+ *
+ * @throws ASN1Exception if csrBytes is invalid.
+ */
+ public void addCSR(final byte[] csrBytes) throws ASN1Exception {

- this(clientConfig.getServerName(),
clientConfig.getServerPort(),
- clientConfig.getCallbackHandler(),
clientConfig
- .getSaslProperties());
+ if (csrBytes != null) {
+ this.csrList.add(new CertificationRequest(csrBytes));
+ }
+ }
+
+
+ /**
+ * Authenticate the user to the SASL-CA.
+ *
+ * @throws IOException on any I/O errors
+ * @throws KeyManagementException If STARTTLS is requested, but invalid
keying material is present.
+ * @throws NoSuchAlgorithmException If STARTTLS is requested, but an
invalid algorithm is selected.
+ * @throws ClientProtocolHandler on any other error.
+ */
+ public void authenticateUser() throws IOException,
KeyManagementException, NoSuchAlgorithmException,
ClientProtocolHandlerException {
+
+ try {
+
+ String inString;
+ String outString;
+ String[] mechlist;
+
+ this.doInitialConnect();
+
+ // get the list of SASL mechanisms supported by the server
+ mechlist = this.getServerSaslMechanisms();
+
+ logger.debug("saslprops: " + this.saslProperties);
+
+ // we can now create a SaslClient
+ // (which will pick the best supported mechanism)
+ try {
+ this.saslclient = Sasl.createSaslClient(mechlist, null,
+ ProtocolHandler.protocolName, this.hostname,
this.saslProperties, super.cbh);
+ super.saslWrapper = new SaslClientWrapper(this.saslclient);
+ } catch(SaslException saslEx) {
+ // send client error message
+ super.sendMsg(ProtocolHandler.A11 + " Unable to initialize
SASL");
+
+ throw new ClientProtocolHandlerException("Unable to
initialize SASL", saslEx);
+ }
+
+ // if we're using an insecure mechanism, try to setup an ssl
tunnel
+ String mechanism = this.saslclient.getMechanismName();
+ if (insecureSaslMechanisms.contains(mechanism)) {

- String[] protocols = clientConfig.getTLSProtocols();
- if (protocols != null) {
- super.setStartTLSProtocols(protocols);
- }
+ super.sendMsg(ProtocolHandler.STARTTLS_REQUEST);
+ inString = super.readMsg();
+ if (inString.equals(ProtocolHandler.STARTTLS_DENIED)) {
+ logger.error("Server does not support STARTTLS, but the
client mandates it for mechanism "
+ + this.saslclient.getMechanismName());
+ throw new ClientProtocolHandlerException("Server denied
STARTTLS request");
+ } else if
(!inString.equals(ProtocolHandler.STARTTLS_GRANTED)) {
+ throw new ClientProtocolHandlerException("Unparsable
message received during STARTTLS exchange");
+ }

- String[] cipherSuites = clientConfig.getTLSCipherSuites();
- if (cipherSuites != null) {
- super.setStartTLSCipherSuites(cipherSuites);
+ super.enableStartTLS(true);
+ }
+
+ this.startAuthenticationLoop();
+
+ // the authentication loop:
+ // We exchange messages with the server until we receive
+ // an AUTHENTICATION_OK or an AUTHENTICATION_DENIED message,
+
+ boolean receivedOkMessage = false; // did we receive an A06
message
+ logger.debug("entering authN loop");
+ do {
+
+ inString = super.readMsg();
+
+ // check if the server sent a success message
+ if (inString.startsWith(ProtocolHandler.A06)) {
+
+ receivedOkMessage = true;
+
+ // the server may have sent a final response with the
success message
+ // if so, we just call evaluateChallenge() with it and
don't return
+ // anything to the server, per the SASL spec.
+ if (!this.saslclient.isComplete()) {
+
+ logger.debug("SASL exchange is complete; parsing last
token");
+
+ String argument;
+ byte[] response;
+
+ try {
+ argument = inString.substring(A06.length());
+ response =
this.saslclient.evaluateChallenge(Base64.decode(argument));
+ } catch (CorruptedCodeException ccEx) {
+ throw new ClientProtocolHandlerException("Error
decoding server response", ccEx);
+ }
+ }
}
-
- }
-
- /**
- * Creates a new ClientProtocolHandler object.
- *
- * @param hostname The hostname or IP address of the SASL-CA
- * @param port The port on the SASL-CA
- * @param cbh A
{@link
javax.security.auth.callback.CallbackHandler} for JAAS login
- * @param saslProperties A
{@link
Map} of SASL properties
- *
- * @throws IllegalArgumentException If any arguments (aside from
<code>saslProperties</code>) are <code>null</code> or 0.
- * @throws ClientProtocolHandlerException on any other error
- * @throws CertificateException If an X.509
{@link
CertificateFactory} implementation cannot be found;
- */
- public ClientProtocolHandler(final String hostname, int port,
- final CallbackHandler cbh, final Map<String, ?>
saslProperties)
- throws IOException, IllegalArgumentException,
- ClientProtocolHandlerException, CertificateException {
-
- super(null, cbh);
-
- if (hostname == null) {
- throw new IllegalArgumentException("Hostname is
null");
+ // check for a server error
+ else if (inString.startsWith(ProtocolHandler.A10)) {
+ throw new ClientProtocolHandlerException("Received an
error message from server: " + inString);
}
-
- if ((port < 1) || (port > 65535)) {
- throw new IllegalArgumentException("Invalid port
specified");
+ // check if the authN was denied
+ else if (inString.startsWith(ProtocolHandler.A07)) {
+ throw new ClientProtocolHandlerException("Server refused
authentication: " + inString);
}
-
- this.hostname = hostname;
- this.port = port;
- this.saslProperties = saslProperties;
-
- this.certFactory = CertificateFactory.getInstance("X.509");
-
- super.debuggingSendPrefix = "C: ";
- super.debuggingReadPrefix = "S: ";
+ // check if we have to send more authN data
+ else if (inString.startsWith(ProtocolHandler.A08)) {
+
+ byte[] nextResponse = null;
+
+ // this is an ugly hack.
+ // the server might be sending back a zero-length byte
array
+ // which is encoded as, well, nothing.
+
+ // check if there's nothing more in inString
+ if (A08.equals(inString)) {
+ nextResponse = this.saslclient.evaluateChallenge(new
byte[0]);
+ } else {
+
+ // ok, so the server sent a "real" response
+
+ try {
+ String argument =
inString.substring(A08.length());
+ byte[] arg_binary = Base64.decode(argument);
+ nextResponse =
this.saslclient.evaluateChallenge(arg_binary);
+ } catch (CorruptedCodeException ex) {
+ throw new ClientProtocolHandlerException("Error
decoding server response", ex);
+ } catch (SaslException ex) {
+ // there was a SASL error. Abort the connection.
+ super.sendMsg(ProtocolHandler.A11 + " SASL error
during authentication loop");
+ throw new ClientProtocolHandlerException("SASL
error during authentication loop,", ex);
+ }
+ }
+
+ outString = ProtocolHandler.A09;
+
+ if (nextResponse != null) {
+ outString += " " + Base64.encode(nextResponse);
+ }
+
+ sendMsg(outString);
+ }
+ // this shouldn't happen
+ else {
+ logger.error("received unknown message: " + inString);
+ throw new ClientProtocolHandlerException("unknown message
received: " + inString);
+ }
+
+ } while (!receivedOkMessage);
+ logger.debug("out of authN loop");
+
+ // check if SASL negotiated a security layer,
+ // and if so, adjust buffer sizes accordingly.
+ super.checkForSecurityLayer();
+
+ } catch (IllegalArgumentException ex) {
+ // this should never happen because I'm always passing non-null
arguments to methods.
+ throw new ClientProtocolHandlerException("An internal method was
passed an bad argument", ex);
}
-
- /**
- * Connect to the SASL-CA.
- *
- * @throws UnknownHostException If this.hostname can't be resolved.
- * @throws IOException If the socket can't be created.
- * @throws SecurityException If the security manager won't let
- */
- public void connect() throws UnknownHostException, IOException,
- SecurityException {
-
- logger.info("Connecting to " + this.hostname + ":" +
this.port);
- super.socket = new Socket(this.hostname, this.port);
- super.socket.setSoTimeout(timeout);
- super.in = super.socket.getInputStream();
- super.out = super.socket.getOutputStream();
+ }
+
+
+ /**
+ * Initiate the SASL-CA protocol by connecting to the SASL-CA with
version 1 of the protocol.
+ *
+ * @throws IOException on I/O Errors
+ * @throws ClientProtocolHandlerException on SASL-CA protocol errors.
+ */
+ private void doInitialConnect() throws IOException,
ClientProtocolHandlerException, IllegalArgumentException {
+
+ String inString;
+
+ // connect with protocol version 1 to the server
+ super.sendMsg(ProtocolHandler.A01);
+ inString = super.readMsg();
+ if (!(inString.equals(ProtocolHandler.A02))) {
+ throw new ClientProtocolHandlerException("Server does not support
protocol version 1");
}
-
- /**
- * Disconnect from the SASL-CA.
- */
- public void disconnect() {
- try {
- logger.info("closing client socket");
- super.socket.close();
- } catch (Exception ex) {
- logger.error("Error while closing socket", ex);
- }
+ }
+
+
+ /**
+ * Get the SASL mechanisms supported by the server.
+ *
+ * If the server returns an error message or an invalid response,
+ * we shut down the connection with the server (we send an error
message, we don't close the socket).
+ *
+ * @return A String array of SASL mechanisms supported by the server.
+ *
+ * @throws IOException on I/O errors
+ * @throws ClientProtocolHandlerExcetpion on protocol-releated errors.
+ */
+ private String[] getServerSaslMechanisms() throws
IllegalArgumentException, IOException, ClientProtocolHandlerException {
+
+ String inString;
+ String[] mechlist;
+
+ // get the SASL mechanisms supported by the server.
+ super.sendMsg(ProtocolHandler.A03);
+ inString = super.readMsg();
+
+ // check for an error from the server
+ if (inString.equals(ProtocolHandler.A10)) {
+ // strip off the protocol header and return the error message
+ String errorString =
inString.substring(ProtocolHandler.A10.length());
+ throw new ClientProtocolHandlerException("Received error message
from server: " + errorString);
}
-
- /**
- * Set the
{@link
Socket} timeout value.
- *
- * You shouldn't need to set this normally.
- *
- * @param timeout The number of milliseconds to wait before timing
out a
{@link
Socket} connection. A value of 0 disables timeout.
- *
- * @see java.net.Socket#setSoTimeout
- */
- public void setTimeout(int timeout) {
- this.timeout = timeout;
+
+ // the server should have sent us a space-seperated
+ // list of SASL mechanisms in an A04 message
+ if (inString.startsWith(ProtocolHandler.A04)) {
+
+ // parse the mechanism list from the server
+ String mech_string =
inString.substring(ProtocolHandler.A04.length(), inString.length()).trim();
+ mechlist = mech_string.split(" ");
+
+ // do a quick check on mechlist's contents:
+ // RFC 2222 (SASL) says that mechanism names should be strings of
1-20
+ // uppercase chars, digits and the underscore.
+ // Pattern pat = Pattern.compile("[A-Z0-9_]{1,20}");
+ // for (int i = 0; i < mechlist.length; i++) {
+ // Matcher match = pat.matcher(mechlist[i]);
+ // if (!match.matches()) {
+ // throw new ClientProtocolHandlerException("received
invalid SASL mechanism name ("
+ // + mechlist[i] + ")");
+ // }
+ // }
+ } else {
+ super.sendMsg(ProtocolHandler.A11 + " Unparsable message
received"); // send client error message
+ throw new ClientProtocolHandlerException("unparsable message
received: " + inString);
}
-
- /**
- * Set if the class should record timing information for each CSR
request. Used for debugging.
- *
- * @param profiling Set to <code>true</code> if timing should be
enabled. It defaults to <code>false</code>.
- */
- public void setProfiling(boolean profiling) {
- this.profile = profiling;
+
+ return mechlist;
+ }
+
+
+ /**
+ * Start the authentication loop with the SASL-CA.
+ *
+ * This method can only be called after a SASL mechanism has been
selected.
+ *
+ * @throws IOException on I/O errors.
+ * @throws ClientProtocolHandlerException on protocol-related errors.
+ */
+ private void startAuthenticationLoop() throws IllegalArgumentException,
IllegalStateException, ClientProtocolHandlerException, IOException {
+
+ String outString;
+
+ // inform the server of what mechanism we picked,
+ // and start the authentication loop.
+ super.saslMechanism = this.saslclient.getMechanismName();
+ logger.info("chose SASL mechanism: " +
this.saslclient.getMechanismName());
+ outString = ProtocolHandler.A05 + super.saslMechanism;
+
+ // check for an initial response
+ try {
+ if (this.saslclient.hasInitialResponse()) {
+ // pass byte[0] to evaluateChallenge()
+ // to get the initial response
+ byte[] initialResponse =
+ this.saslclient.evaluateChallenge(new byte[0]);
+ String encodedResponse = Base64.encode(initialResponse);
+ outString += " " + encodedResponse;
+ }
+ } catch(SaslException saslEx) {
+ super.sendMsg(ProtocolHandler.A11 + " Unable to initialize SASL");
+ throw new ClientProtocolHandlerException("Unable to initialize
SASL", saslEx);
}
-
- /**
- * Set if the class should verify certificate chainsn from the server.
- *
- * @param verify Set to <code>false</code> if verification should not
be performed. It defaults to <code>true</code>.
- */
- public void setVerifyChains(boolean verify) {
- this.verifyCerts = verify;
+
+ super.sendMsg(outString);
+ }
+
+
+ /**
+ * Converts a CSR into a Certificate.
+ *
+ * @param req The
{@link
CertificationRequest} to be signed by the SASL-CA.
+ *
+ * @return A certificate chain, ordered with the user's certificate
first and the root ca's certificate last,
+ * or <code>null</code> if there was an error getting a
certificate for this CSR.
+ *
+ * @throws ClientProtocolHandlerException for regular errors
+ * @throws IOException for I/O errors
+ * @throws CertificateException for certificate-related errors
+ */
+ public X509Certificate[] getCertificate(final CertificationRequest req) {
+ //throws CertificateException, ClientProtocolHandlerException,
IOException {
+
+ if (req == null) {
+ return null;
}
-
- /**
- * Add a
{@link
CertificationRequest} to be processed.
- *
- * @param csr The
{@link
CertificationRequest} to be signed by the SASL-CA.
- */
- public void addCSR(final CertificationRequest csr) {
-
- if (csr != null) {
- this.csrList.add(csr);
+
+ try {
+
+ // convert the CSR into a base64-encoded byte array
+ String encodedRequest;
+
+ try {
+ encodedRequest = codec.Base64.encode(req.getEncoded());
+ } catch (ASN1Exception asn1Ex) {
+ logger.error("error decoding CSR", asn1Ex);
+ return null;
+ }
+
+ String inString;
+
+ // send the C01
+ super.sendMsg(ProtocolHandler.C01 + encodedRequest);
+
+ // read the reply
+ inString = super.readMsg();
+
+ // check for errors
+ if (inString == null) {
+ logger.error("Error reading data from SASL-CA: null input
received.");
+ return null;
+ } else if (ProtocolHandler.C05.equals(inString)) {
+ logger.error("SASL-CA: Generic server error.");
+ return null;
+ } else if (inString.startsWith(ProtocolHandler.C03)) {
+ String reason =
inString.substring(ProtocolHandler.C03.length());
+ logger.error("Certification request was denied: " + reason);
+ return null;
+ } else if (!inString.startsWith(ProtocolHandler.C02)) {
+ logger.error("Malformed response from SASL-CA");
+ return null;
+ }
+
+ // extract the Base64-encoded certificate chain
+ List<X509Certificate> certChain = new
ArrayList<X509Certificate>();
+ try {
+ String encodedCertChainString =
inString.substring(ProtocolHandler.C02.length());
+ for (String encodedCert : encodedCertChainString.split(" ")) {
+
+ // decode the cert.
+ byte[] decodedCert = Base64.decode(encodedCert);
+
+ try {
+ java.io.FileOutputStream fos = new
java.io.FileOutputStream("/tmp/foo");
+ fos.write(decodedCert);
+ fos.close();
+ } catch (Exception ex) {
+ logger.error("Error writing cert bytes to /tmp/foo");
+ }
+
+ X509Certificate tempCert =
(X509Certificate)this.certFactory.generateCertificate(new
ByteArrayInputStream(decodedCert));
+
+ if (this.verifyCerts) {
+ tempCert.checkValidity();
+ }
+
+ boolean result = certChain.add(tempCert);
+ if (!result) {
+ logger.error("Unable to add decoded cert to internal
buffer");
+ return null;
+ }
}
+ } catch(CorruptedCodeException ccEx) {
+ logger.error("Error Base64-decoding returned certificate
chain", ccEx);
+ return null;
+ } catch(CertificateExpiredException ex) {
+ logger.error("Certificiate has expired", ex);
+ return null;
+ } catch (CertificateNotYetValidException ex) {
+ logger.error("Certificate is not yet valid", ex);
+ return null;
+ } catch (CertificateException ex) {
+ logger.error("Error decoding returned certificate", ex);
+ return null;
+ }
+
+ X509Certificate[] certArray = new
X509Certificate[certChain.size()];
+
+ return certChain.toArray(certArray);
+
+ } catch (IllegalArgumentException ex) {
+ logger.error("an internal method was passed an invalid argument",
ex);
+ return null;
+ } catch (IOException ex) {
+ logger.error("I/O error to the SASL-CA", ex);
+ return null;
}
-
- /**
- * Add a list of
{@link
CertificationRequest} to be processed.
- *
- * @param csrList The list of
{@link
CertificationRequest} to be signed by the SASL-CA.
- */
- public void addCSRs(final Collection<CertificationRequest> csrList) {
-
- for (CertificationRequest csr : csrList) {
- if (csr != null) {
- this.csrList.add(csr);
- }
- }
+ }
+
+
+ /**
+ * End the connection to the SASL-CA.
+ *
+ * @throws IOException If unable to send a message to the SASL-CA.
+ */
+ public void endCertification() throws IOException {
+ try {
+ super.sendMsg(ProtocolHandler.C04);
+ } catch (IllegalArgumentException ex) {
+ // this won't ever happen because I'm passing a non-null argument
+ throw new IOException("an invalid argument was passed to
sendMsg:" + ex.toString());
}
+ }
+
+
+ /**
+ * "Refresh" a certificate - gets a new cert on the basis of an existing
cert.
+ *
+ * @param oldCert The user's existing
{@link
X509Certificate}
+ * @param csrType The type (identity, opaque, etc) of the new CSR to
build.
+ * @param oldPrivateKey The user's existing
{@link
java.security.PrivateKey}
+ * @param newPublicKey The new
{@link
PublicKey}
+ * @param signingAlgorithm The signature algorithm to use to sign the CSR
+ *
+ * @return An array of
{@link
X509Certificate} objects forming a cert chain
+ *
+ * @throws IllegalArgumentExceptin If any argument is <code>null</code>
+ * @throws ClientProtocolHandlerException On any other error.
+ */
+ public synchronized X509Certificate[] refreshCertificate(final
X509Certificate oldCert, final String csrType,
+ final PrivateKey oldPrivateKey, final PublicKey newPublicKey,
final String signingAlgorithm) throws ClientProtocolHandlerException {
+
+ if (oldCert == null) {
+ throw new IllegalArgumentException("must specify an old
certificate");
+ }
+
+ if (csrType == null) {
+ throw new IllegalArgumentException("must specify a csr type");
+ }
+
+ if (oldPrivateKey == null) {
+ throw new IllegalArgumentException("must specify an old private
key");
+ }
+
+ if (newPublicKey == null) {
+ throw new IllegalArgumentException("must specify a new private
key");
+ }
+
+ if (signingAlgorithm == null) {
+ throw new IllegalArgumentException("must specify a signing
algorithm");
+ }
+
+
+ try {

- /**
- * Add a DER-encoded CSR to be processed.
- *
- * @param csrBytes A <code>byte[]</code> containing a DER-encoded CSR
- *
- * @throws ASN1Exception if csrBytes is invalid.
- */
- public void addCSR(final byte[] csrBytes) throws ASN1Exception {
-
- if (csrBytes != null) {
- this.csrList.add(new CertificationRequest(csrBytes));
+ CertificationRequest csr =
ClientProtocolHandler.generateCSR(csrType, newPublicKey, oldPrivateKey,
signingAlgorithm);
+
+ this.connect();
+
+ // the data read from the server
+ String inString;
+
+ // connect with protocol version 1 to the server
+ super.sendMsg(ProtocolHandler.A01);
+ inString = super.readMsg();
+ if (!inString.equals(ProtocolHandler.A02)) {
+ throw new ClientProtocolHandlerException("Server does not
support protocol version 1");
+ }
+
+ super.sendMsg(ProtocolHandler.C06 +
Base64.encode(oldCert.getEncoded()) + " " + Base64.encode(csr.getEncoded()));
+
+ inString = super.readMsg();
+
+ // check for errors
+ if (inString == null) {
+ logger.error("Error reading data from SASL-CA: null input
received.");
+ throw new ClientProtocolHandlerException("Error reading data
from SASL-CA: null input received");
+ } else if (ProtocolHandler.C05.equals(inString)) {
+ logger.error("SASL-CA: Generic server error.");
+ throw new ClientProtocolHandlerException("SASL-CA: Generic
server error");
+ } else if (ProtocolHandler.C03.equals(inString)) {
+ String reason =
inString.substring(ProtocolHandler.C03.length());
+ logger.error("Certification request was denied: " + reason);
+ throw new ClientProtocolHandlerException("Certification
request was denied: " + reason);
+ } else if (!inString.startsWith(ProtocolHandler.C02)) {
+ logger.error("Malformed response from SASL-CA");
+ throw new ClientProtocolHandlerException("Malformed response
from SASL-CA");
+ }
+
+ // extract the Base64-encoded certificate chain
+ ArrayList<X509Certificate> certChain = new
ArrayList<X509Certificate>();
+ try {
+ String encodedCertChainString =
inString.substring(ProtocolHandler.C02.length());
+ for (String encodedCert : encodedCertChainString.split(" ")) {
+
+ // decode the cert.
+ byte[] decodedCert = Base64.decode(encodedCert);
+ X509Certificate tempCert = (X509Certificate)
this.certFactory.generateCertificate(new ByteArrayInputStream(decodedCert));
+
+ boolean result = certChain.add(tempCert);
+ if (!result) {
+ logger.error("Unable to add decoded cert to internal
buffer");
+ throw new ClientProtocolHandlerException("Unable to
add decoded cert to internal buffer");
+ }
}
- }
-
- /**
- * Authenticate the user to the SASL-CA.
- *
- * @throws IOException on any I/O errors
- * @throws KeyManagementException If STARTTLS is requested, but
invalid keying material is present.
- * @throws NoSuchAlgorithmException If STARTTLS is requested, but an
invalid algorithm is selected.
- * @throws ClientProtocolHandler on any other error.
- */
- public void authenticateUser() throws IOException,
KeyManagementException,
- NoSuchAlgorithmException,
ClientProtocolHandlerException {
-
- try {
-
- String inString;
- String outString;
- String[] mechlist;
-
- this.doInitialConnect();
-
- // get the list of SASL mechanisms supported by the
server
- mechlist = this.getServerSaslMechanisms();
-
- logger.debug("saslprops: " + this.saslProperties);
-
- // we can now create a SaslClient
- // (which will pick the best supported mechanism)
- try {
- logger.debug("Sasl.createSaslClient(...)");
- this.saslclient =
Sasl.createSaslClient(mechlist, null,
- ProtocolHandler.protocolName,
this.hostname,
- this.saslProperties,
super.cbh);
- logger.debug("new SaslClientWrapper(...)");
- super.saslWrapper = new
SaslClientWrapper(this.saslclient);
- } catch (SaslException saslEx) {
- // send client error message
- super.sendMsg(ProtocolHandler.A11
- + " Unable to initialize
SASL");
-
- throw new ClientProtocolHandlerException(
- "Unable to initialize SASL",
saslEx);
- }
-
- logger.debug("if we're using an insecure mechanism,
try to setup an ssl tunnel");
- // if we're using an insecure mechanism, try to setup
an ssl tunnel
- String mechanism = this.saslclient.getMechanismName();
- if (insecureSaslMechanisms.contains(mechanism)) {
-
-
super.sendMsg(ProtocolHandler.STARTTLS_REQUEST);
- inString = super.readMsg();
- if
(inString.equals(ProtocolHandler.STARTTLS_DENIED)) {
- logger
- .error("Server does
not support STARTTLS, but the client mandates it for mechanism "
- +
this.saslclient.getMechanismName());
- throw new
ClientProtocolHandlerException(
- "Server denied
STARTTLS request");
- } else if
(!inString.equals(ProtocolHandler.STARTTLS_GRANTED)) {
- throw new
ClientProtocolHandlerException(
- "Unparsable message
received during STARTTLS exchange");
- }
-
- super.enableStartTLS(true);
- }
-
- logger.debug("this.startAuthenticationLoop();");
- this.startAuthenticationLoop();
-
- logger.debug("// the authentication loop:");
- // the authentication loop:
- // We exchange messages with the server until we
receive
- // an AUTHENTICATION_OK or an AUTHENTICATION_DENIED
message,
-
- boolean receivedOkMessage = false; // did we receive
an A06 message
- logger.debug("entering authN loop");
- do {
-
- inString = super.readMsg();
-
- // check if the server sent a success message
- if (inString.startsWith(ProtocolHandler.A06))
{
-
- receivedOkMessage = true;
-
- // the server may have sent a final
response with the success message
- // if so, we just call
evaluateChallenge() with it and don't return
- // anything to the server, per the
SASL spec.
- if (!this.saslclient.isComplete()) {
-
- logger
- .debug("SASL
exchange is complete; parsing last token");
-
- String argument;
- byte[] response;
-
- try {
- argument =
inString.substring(A06.length());
- response =
this.saslclient.evaluateChallenge(Base64
-
.decode(argument));
- } catch
(CorruptedCodeException ccEx) {
- throw new
ClientProtocolHandlerException(
-
"Error decoding server response", ccEx);
- }
- }
- }
- // check for a server error
- else if
(inString.startsWith(ProtocolHandler.A10)) {
- throw new
ClientProtocolHandlerException(
- "Received an error
message from server: "
- +
inString);
- }
- // check if the authN was denied
- else if
(inString.startsWith(ProtocolHandler.A07)) {
- throw new
ClientProtocolHandlerException(
- "Server refused
authentication: " + inString);
- }
- // check if we have to send more authN data
- else if
(inString.startsWith(ProtocolHandler.A08)) {
-
- byte[] nextResponse = null;
-
- // this is an ugly hack.
- // the server might be sending back a
zero-length byte array
- // which is encoded as, well, nothing.
-
- // check if there's nothing more in
inString
- if (A08.equals(inString)) {
- nextResponse = this.saslclient
-
.evaluateChallenge(new byte[0]);
- } else {
-
- // ok, so the server sent a
"real" response
-
- try {
- String argument =
inString.substring(A08.length());
- byte[] arg_binary =
Base64.decode(argument);
- nextResponse =
this.saslclient
-
.evaluateChallenge(arg_binary);
- } catch
(CorruptedCodeException ex) {
- throw new
ClientProtocolHandlerException(
-
"Error decoding server response", ex);
- } catch (SaslException ex) {
- // there was a SASL
error. Abort the connection.
-
super.sendMsg(ProtocolHandler.A11
- + "
SASL error during authentication loop");
- throw new
ClientProtocolHandlerException(
- "SASL
error during authentication loop,",
- ex);
- }
- }
-
- outString = ProtocolHandler.A09;
-
- if (nextResponse != null) {
- outString += " " +
Base64.encode(nextResponse);
- }
-
- sendMsg(outString);
- }
- // this shouldn't happen
- else {
- logger.error("received unknown
message: " + inString);
- throw new
ClientProtocolHandlerException(
- "unknown message
received: " + inString);
- }
-
- } while (!receivedOkMessage);
- logger.debug("out of authN loop");
-
- // check if SASL negotiated a security layer,
- // and if so, adjust buffer sizes accordingly.
- super.checkForSecurityLayer();
-
- } catch (IllegalArgumentException ex) {
- // this should never happen because I'm always
passing non-null arguments to methods.
- throw new ClientProtocolHandlerException(
- "An internal method was passed an bad
argument", ex);
+
+ } catch(CorruptedCodeException ex) {
+ logger.error("Base64-decoding returned invalid certificate
chain", ex);
+ throw new ClientProtocolHandlerException("Base64-decoding
returned invalid certificate chain", ex);
+ }
+
+
+ // check the cert chain's validity
+ if (this.verifyCerts) {
+ for (X509Certificate cert : certChain) {
+ cert.checkValidity();
}
+ }
+
+ X509Certificate[] certArray = new
X509Certificate[certChain.size()];
+
+ return certChain.toArray(certArray);
+
+
+ } catch (NoSuchAlgorithmException ex) {
+ throw new ClientProtocolHandlerException("Unable to find provider
for SHA1withRSA", ex);
+ } catch (UnknownHostException ex) {
+ throw new ClientProtocolHandlerException("Unable to connect to
the SASL-CA", ex);
+ } catch (IOException ex) {
+ throw new ClientProtocolHandlerException("Unable to connect to
the SASL-CA", ex);
+ } catch (Exception ex) {
+ throw new ClientProtocolHandlerException("Error refreshing cert",
ex);
+ } finally {
+ try {
+ this.endCertification();
+ this.disconnect();
+ } catch (Exception ex) {
+ }
}
-
- /**
- * Initiate the SASL-CA protocol by connecting to the SASL-CA with
version 1 of the protocol.
- *
- * @throws IOException on I/O Errors
- * @throws ClientProtocolHandlerException on SASL-CA protocol errors.
- */
- private void doInitialConnect() throws IOException,
- ClientProtocolHandlerException,
IllegalArgumentException {
-
- String inString;
-
- // connect with protocol version 1 to the server
- super.sendMsg(ProtocolHandler.A01);
- inString = super.readMsg();
- if (!(inString.equals(ProtocolHandler.A02))) {
- throw new ClientProtocolHandlerException(
- "Server does not support protocol
version 1");
- }
+ }
+
+
+ /**
+ * Connect to the SASL-CA and obtain certificates.
+ *
+ * This will authenticate the user to the SASL-CA, and attempt to have
the CSRs signed by the SASL-CA.
+ *
+ * If an exception if thrown, you should not try to read the
certificates.
+ *
+ * Note - CSRs are processed in the list they were added to the
ClientProtocolHandler.
+ * If a CSR in the queue caused a fatal error from the server,
subsequent CSRs will not be processed.
+ * Clients should be prepared for a null cert chain in the returned Map.
+ *
+ * @return This method returns a
{@link
Map} mapping
{@link
CertificationRequest}s to
{@link
X509Certificate}[]s.
+ * The certificate chains are ordered with the end-entity cert
first and the root CAs cert last. If there
+ * was an error obtaining a certificate chain for a given CSR,
the value for that CSR will be <code>null</code>.
+ * If no CSRs were specified, this method returns
<code>null</code>
+ *
+ * @throws IOException On I/O errors.
+ * @throws KeyManagementException If STARTTLS is requested, but invalid
keying material is present.
+ * @throws NoSuchAlgorithmException If STARTTLS is requested, but no JCE
provider for the requested algorithm can be found.
+ * @throws ClientProtocolHandlerException On all other errors.
+ */
+ public Map<CertificationRequest, X509Certificate[]> run() throws
IOException, KeyManagementException, NoSuchAlgorithmException,
ClientProtocolHandlerException {
+
+ /** The set of signed certificates (with chains), keyed by the CSR
that generated them. */
+ Map<CertificationRequest, X509Certificate[]> signedCertificates =
+ new HashMap<CertificationRequest, X509Certificate[]>();
+
+ boolean authenticated = false;
+
+ if (this.csrList.isEmpty()) {
+ logger.error("No CSRs specified. Aborting.");
+ return null;
}

- /**
- * Get the SASL mechanisms supported by the server.
- *
- * If the server returns an error message or an invalid response,
- * we shut down the connection with the server (we send an error
message, we don't close the socket).
- *
- * @return A String array of SASL mechanisms supported by the server.
- *
- * @throws IOException on I/O errors
- * @throws ClientProtocolHandlerExcetpion on protocol-releated errors.
- */
- private String[] getServerSaslMechanisms() throws
IllegalArgumentException,
- IOException, ClientProtocolHandlerException {
-
- String inString;
- String[] mechlist;
-
- // get the SASL mechanisms supported by the server.
- super.sendMsg(ProtocolHandler.A03);
- inString = super.readMsg();
-
- // check for an error from the server
- if (inString.equals(ProtocolHandler.A10)) {
- // strip off the protocol header and return the error
message
- String errorString =
inString.substring(ProtocolHandler.A10
- .length());
- throw new ClientProtocolHandlerException(
- "Received error message from server:
" + errorString);
- }
-
- // the server should have sent us a space-seperated
- // list of SASL mechanisms in an A04 message
- if (inString.startsWith(ProtocolHandler.A04)) {
-
- // parse the mechanism list from the server
- String mech_string = inString.substring(
- ProtocolHandler.A04.length(),
inString.length()).trim();
- mechlist = mech_string.split(" ");
-
- // do a quick check on mechlist's contents:
- // RFC 2222 (SASL) says that mechanism names should
be strings of 1-20
- // uppercase chars, digits and the underscore.
- // Pattern pat =
Pattern.compile("[A-Z0-9_]{1,20}");
- // for (int i = 0; i < mechlist.length; i++) {
- // Matcher match = pat.matcher(mechlist[i]);
- // if (!match.matches()) {
- // throw new
ClientProtocolHandlerException("received invalid SASL mechanism name ("
- // + mechlist[i] + ")");
- // }
- // }
- } else {
- super.sendMsg(ProtocolHandler.A11 + " Unparsable
message received"); // send client error message
- throw new ClientProtocolHandlerException(
- "unparsable message received: " +
inString);
- }
-
- return mechlist;
+ this.connect();
+
+ if (this.profile) {
+ this.timings = new long[this.csrList.size()];
}
-
- /**
- * Start the authentication loop with the SASL-CA.
- *
- * This method can only be called after a SASL mechanism has been
selected.
- *
- * @throws IOException on I/O errors.
- * @throws ClientProtocolHandlerException on protocol-related errors.
- */
- private void startAuthenticationLoop() throws
IllegalArgumentException,
- IllegalStateException,
ClientProtocolHandlerException, IOException {
-
- String outString;
-
- // inform the server of what mechanism we picked,
- // and start the authentication loop.
- super.saslMechanism = this.saslclient.getMechanismName();
- logger.info("chose SASL mechanism: "
- + this.saslclient.getMechanismName());
- outString = ProtocolHandler.A05 + super.saslMechanism;
-
- // check for an initial response
- try {
- if (this.saslclient.hasInitialResponse()) {
- // pass byte[0] to evaluateChallenge()
- // to get the initial response
- byte[] initialResponse = this.saslclient
- .evaluateChallenge(new
byte[0]);
- String encodedResponse =
Base64.encode(initialResponse);
- outString += " " + encodedResponse;
- }
- } catch (SaslException saslEx) {
- super.sendMsg(ProtocolHandler.A11 + " Unable to
initialize SASL");
- throw new ClientProtocolHandlerException(
- "Unable to initialize SASL", saslEx);
+
+ try {
+
+ this.authenticateUser();
+ authenticated = true;
+
+ long startTime = 0;
+ int i = 0;
+
+ for (CertificationRequest csr : this.csrList) {
+
+ if (this.profile) {
+ startTime = System.currentTimeMillis();
}
-
- super.sendMsg(outString);
- }
-
- /**
- * Converts a CSR into a Certificate.
- *
- * @param req The
{@link
CertificationRequest} to be signed by the SASL-CA.
- *
- * @return A certificate chain, ordered with the user's certificate
first and the root ca's certificate last,
- * or <code>null</code> if there was an error getting a
certificate for this CSR.
- *
- * @throws ClientProtocolHandlerException for regular errors
- * @throws IOException for I/O errors
- * @throws CertificateException for certificate-related errors
- */
- public X509Certificate[] getCertificate(final CertificationRequest
req) {
- //throws CertificateException,
ClientProtocolHandlerException, IOException {
-
- if (req == null) {
- return null;
+
+ signedCertificates.put(csr, this.getCertificate(csr));
+
+ if (this.profile) {
+ this.timings[i++] = System.currentTimeMillis() -
startTime;
}
-
- try {
-
- // convert the CSR into a base64-encoded byte array
- String encodedRequest;
-
- try {
- encodedRequest =
codec.Base64.encode(req.getEncoded());
- } catch (ASN1Exception asn1Ex) {
- logger.error("error decoding CSR", asn1Ex);
- return null;
- }
-
- String inString;
-
- // send the C01
- super.sendMsg(ProtocolHandler.C01 + encodedRequest);
-
- // read the reply
- inString = super.readMsg();
-
- // check for errors
- if (inString == null) {
- logger
- .error("Error reading data
from SASL-CA: null input received.");
- return null;
- } else if (ProtocolHandler.C05.equals(inString)) {
- logger.error("SASL-CA: Generic server
error.");
- return null;
- } else if (inString.startsWith(ProtocolHandler.C03)) {
- String reason = inString
-
.substring(ProtocolHandler.C03.length());
- logger.error("Certification request was
denied: " + reason);
- return null;
- } else if (!inString.startsWith(ProtocolHandler.C02))
{
- logger.error("Malformed response from
SASL-CA");
- return null;
- }
-
- // extract the Base64-encoded certificate chain
- List<X509Certificate> certChain = new
ArrayList<X509Certificate>();
- try {
- String encodedCertChainString = inString
-
.substring(ProtocolHandler.C02.length());
- for (String encodedCert :
encodedCertChainString.split(" ")) {
-
- // decode the cert.
- byte[] decodedCert =
Base64.decode(encodedCert);
-
-/* try {
- java.io.FileOutputStream fos
= new java.io.FileOutputStream(
- "/tmp/foo");
- fos.write(decodedCert);
- fos.close();
- } catch (Exception ex) {
- logger.error("Error writing
cert bytes to /tmp/foo");
- } */
-
- X509Certificate tempCert =
(X509Certificate) this.certFactory
-
.generateCertificate(new ByteArrayInputStream(
-
decodedCert));
-
- if (this.verifyCerts) {
- tempCert.checkValidity();
- }
-
- boolean result =
certChain.add(tempCert);
- if (!result) {
- logger
-
.error("Unable to add decoded cert to internal buffer");
- return null;
- }
- }
- } catch (CorruptedCodeException ccEx) {
- logger.error(
- "Error Base64-decoding
returned certificate chain",
- ccEx);
- return null;
- } catch (CertificateExpiredException ex) {
- logger.error("Certificiate has expired", ex);
- return null;
- } catch (CertificateNotYetValidException ex) {
- logger.error("Certificate is not yet valid",
ex);
- return null;
- } catch (CertificateException ex) {
- logger.error("Error decoding returned
certificate", ex);
- return null;
- }
-
- X509Certificate[] certArray = new
X509Certificate[certChain.size()];
-
- return certChain.toArray(certArray);
-
- } catch (IllegalArgumentException ex) {
- logger.error("an internal method was passed an
invalid argument",
- ex);
- return null;
- } catch (IOException ex) {
- logger.error("I/O error to the SASL-CA", ex);
- return null;
- }
+ }
+ } catch (IllegalArgumentException ex) {
+ // this won't ever happen because I'm passing non-null arguments
+ throw new ClientProtocolHandlerException("an internal method was
passed an invalid argument", ex);
+ } finally {
+
+ // if we're past the authN phase of the protocol, we should send
a C04 message to clean up.
+ if (authenticated) {
+ this.endCertification();
+ }
+
+ this.disconnect();
+
+ // clean up after SASL
+ this.dispose();
}
-
- /**
- * End the connection to the SASL-CA.
- *
- * @throws IOException If unable to send a message to the SASL-CA.
- */
- public void endCertification() throws IOException {
- try {
- super.sendMsg(ProtocolHandler.C04);
- } catch (IllegalArgumentException ex) {
- // this won't ever happen because I'm passing a
non-null argument
- throw new IOException("an invalid argument was passed
to sendMsg:"
- + ex.toString());
- }
+
+ return signedCertificates;
+ }
+
+
+ /**
+ * Generates a PKCS#10 Certificate Signing Request.
+ *
+ * To generate an identity CSR, use "CN=identity" for
<code>dnString</code>.
+ * To generate an opaque CSR, use "CN=opaque" for <code>dnString</code>.
+ *
+ * @param dnString The X.500 DN for the CSR's Subject field
+ * @param keyPair The
{@link
KeyPair} used to build the CSR.
+ * @param signatureAlgorithm The signature algorithm to use to sign the
CSR.
+ *
+ * @throws ClientProtocolHandlerException on error
+ * @throws IllegalArgumentException if any arguments are
<code>null</code>
+ * @throws NoSuchAlgorithmException if signatureAlgorithm isn't
supported by the JVM
+ */
+ public static CertificationRequest generateCSR(final String dnString,
final KeyPair keyPair,
+ final String signatureAlgorithm) throws
ClientProtocolHandlerException, IllegalArgumentException,
NoSuchAlgorithmException {
+
+ return generateCSR(dnString, keyPair.getPublic(),
keyPair.getPrivate(), signatureAlgorithm);
+ }
+
+
+
+ /**
+ * Generates a PKCS#10 Certificate Signing Request.
+ *
+ * This variant of the method lets you specify a custom
{@link
PrivateKey} for signing the CSR. Normally, you would not do this.
+ * It is only used for the certificate refresh methods of the SASL-CA.
+ *
+ * To generate an identity CSR, use "CN=identity" for
<code>dnString</code>.
+ * To generate an opaque CSR, use "CN=opaque" for <code>dnString</code>.
+ *
+ * @param dnString The X.500 DN for the CSR's Subject field
+ * @param pubKey The
{@link
PublicKey} used to build the CSR.
+ * @param signingKey The
{@link
PrivateKey} with which to sign the CSR.
+ * @param signatureAlgorithm The signature algorithm to use to sign the
CSR.
+ *
+ * @throws ClientProtocolHandlerException on error
+ * @throws IllegalArgumentException if any arguments are null
+ * @throws NoSuchAlgorithmException if signatureAlgorithm isn't
supported by the JVM
+ */
+ public static CertificationRequest generateCSR(final String dnString,
final PublicKey pubKey,
+ final PrivateKey signingKey, final String signatureAlgorithm)
throws ClientProtocolHandlerException, IllegalArgumentException,
NoSuchAlgorithmException {
+
+ Name dn;
+ CertificationRequest req;
+
+
+ // validate the arguments
+
+ if (pubKey == null) {
+ throw new IllegalArgumentException("KeyPair's public key is
null");
}
-
- /**
- * "Refresh" a certificate - gets a new cert on the basis of an
existing cert.
- *
- * @param oldCert The user's existing
{@link
X509Certificate}
- * @param csrType The type (identity, opaque, etc) of the new CSR to
build.
- * @param oldPrivateKey The user's existing
{@link
java.security.PrivateKey}
- * @param newPublicKey The new
{@link
PublicKey}
- * @param signingAlgorithm The signature algorithm to use to sign the
CSR
- *
- * @return An array of
{@link
X509Certificate} objects forming a cert chain
- *
- * @throws IllegalArgumentExceptin If any argument is
<code>null</code>
- * @throws ClientProtocolHandlerException On any other error.
- */
- public synchronized X509Certificate[] refreshCertificate(
- final X509Certificate oldCert, final String csrType,
- final PrivateKey oldPrivateKey, final PublicKey
newPublicKey,
- final String signingAlgorithm)
- throws ClientProtocolHandlerException {
-
- if (oldCert == null) {
- throw new IllegalArgumentException(
- "must specify an old certificate");
- }
-
- if (csrType == null) {
- throw new IllegalArgumentException("must specify a
csr type");
- }
-
- if (oldPrivateKey == null) {
- throw new IllegalArgumentException(
- "must specify an old private key");
- }
-
- if (newPublicKey == null) {
- throw new IllegalArgumentException("must specify a
new private key");
- }
-
- if (signingAlgorithm == null) {
- throw new IllegalArgumentException(
- "must specify a signing algorithm");
- }
-
- try {
-
- CertificationRequest csr =
ClientProtocolHandler.generateCSR(
- csrType, newPublicKey, oldPrivateKey,
signingAlgorithm);
-
- this.connect();
-
- // the data read from the server
- String inString;
-
- // connect with protocol version 1 to the server
- super.sendMsg(ProtocolHandler.A01);
- inString = super.readMsg();
- if (!inString.equals(ProtocolHandler.A02)) {
- throw new ClientProtocolHandlerException(
- "Server does not support
protocol version 1");
- }
-
- super.sendMsg(ProtocolHandler.C06
- + Base64.encode(oldCert.getEncoded())
+ " "
- + Base64.encode(csr.getEncoded()));
-
- inString = super.readMsg();
-
- // check for errors
- if (inString == null) {
- logger
- .error("Error reading data
from SASL-CA: null input received.");
- throw new ClientProtocolHandlerException(
- "Error reading data from
SASL-CA: null input received");
- } else if (ProtocolHandler.C05.equals(inString)) {
- logger.error("SASL-CA: Generic server
error.");
- throw new ClientProtocolHandlerException(
- "SASL-CA: Generic server
error");
- } else if (ProtocolHandler.C03.equals(inString)) {
- String reason = inString
-
.substring(ProtocolHandler.C03.length());
- logger.error("Certification request was
denied: " + reason);
- throw new ClientProtocolHandlerException(
- "Certification request was
denied: " + reason);
- } else if (!inString.startsWith(ProtocolHandler.C02))
{
- logger.error("Malformed response from
SASL-CA");
- throw new ClientProtocolHandlerException(
- "Malformed response from
SASL-CA");
- }
-
- // extract the Base64-encoded certificate chain
- ArrayList<X509Certificate> certChain = new
ArrayList<X509Certificate>();
- try {
- String encodedCertChainString = inString
-
.substring(ProtocolHandler.C02.length());
- for (String encodedCert :
encodedCertChainString.split(" ")) {
-
- // decode the cert.
- byte[] decodedCert =
Base64.decode(encodedCert);
- X509Certificate tempCert =
(X509Certificate) this.certFactory
-
.generateCertificate(new ByteArrayInputStream(
-
decodedCert));
-
- boolean result =
certChain.add(tempCert);
- if (!result) {
- logger
-
.error("Unable to add decoded cert to internal buffer");
- throw new
ClientProtocolHandlerException(
- "Unable to
add decoded cert to internal buffer");
- }
- }
-
- } catch (CorruptedCodeException ex) {
- logger.error(
- "Base64-decoding returned
invalid certificate chain",
- ex);
- throw new ClientProtocolHandlerException(
- "Base64-decoding returned
invalid certificate chain",
- ex);
- }
-
- // check the cert chain's validity
- if (this.verifyCerts) {
- for (X509Certificate cert : certChain) {
- cert.checkValidity();
- }
- }
-
- X509Certificate[] certArray = new
X509Certificate[certChain.size()];
-
- return certChain.toArray(certArray);
-
- } catch (NoSuchAlgorithmException ex) {
- throw new ClientProtocolHandlerException(
- "Unable to find provider for
SHA1withRSA", ex);
- } catch (UnknownHostException ex) {
- throw new ClientProtocolHandlerException(
- "Unable to connect to the SASL-CA",
ex);
- } catch (IOException ex) {
- throw new ClientProtocolHandlerException(
- "Unable to connect to the SASL-CA",
ex);
- } catch (Exception ex) {
- throw new ClientProtocolHandlerException("Error
refreshing cert",
- ex);
- } finally {
- try {
- this.endCertification();
- this.disconnect();
- } catch (Exception ex) {
- }
- }
+
+ if (signingKey == null) {
+ throw new IllegalArgumentException("Signing key is null");
}
-
- /**
- * Connect to the SASL-CA and obtain certificates.
- *
- * This will authenticate the user to the SASL-CA, and attempt to
have the CSRs signed by the SASL-CA.
- *
- * If an exception if thrown, you should not try to read the
certificates.
- *
- * Note - CSRs are processed in the list they were added to the
ClientProtocolHandler.
- * If a CSR in the queue caused a fatal error from the server,
subsequent CSRs will not be processed.
- * Clients should be prepared for a null cert chain in the returned
Map.
- *
- * @return This method returns a
{@link
Map} mapping
{@link
CertificationRequest}s to
{@link
X509Certificate}[]s.
- * The certificate chains are ordered with the end-entity
cert first and the root CAs cert last. If there
- * was an error obtaining a certificate chain for a given
CSR, the value for that CSR will be <code>null</code>.
- * If no CSRs were specified, this method returns
<code>null</code>
- *
- * @throws IOException On I/O errors.
- * @throws KeyManagementException If STARTTLS is requested, but
invalid keying material is present.
- * @throws NoSuchAlgorithmException If STARTTLS is requested, but no
JCE provider for the requested algorithm can be found.
- * @throws ClientProtocolHandlerException On all other errors.
- */
- public Map<CertificationRequest, X509Certificate[]> run()
- throws IOException, KeyManagementException,
- NoSuchAlgorithmException,
ClientProtocolHandlerException {
-
- /** The set of signed certificates (with chains), keyed by
the CSR that generated them. */
- Map<CertificationRequest, X509Certificate[]>
signedCertificates = new HashMap<CertificationRequest, X509Certificate[]>();
-
- boolean authenticated = false;
-
- if (this.csrList.isEmpty()) {
- logger.error("No CSRs specified. Aborting.");
- return null;
- }
-
- this.connect();
-
- if (this.profile) {
- this.timings = new long[this.csrList.size()];
- }
-
- try {
-
- this.authenticateUser();
- authenticated = true;
-
- long startTime = 0;
- int i = 0;
-
- for (CertificationRequest csr : this.csrList) {
-
- if (this.profile) {
- startTime =
System.currentTimeMillis();
- }
-
- signedCertificates.put(csr,
this.getCertificate(csr));
-
- if (this.profile) {
- this.timings[i++] =
System.currentTimeMillis() - startTime;
- }
- }
- } catch (IllegalArgumentException ex) {
- // this won't ever happen because I'm passing
non-null arguments
- throw new ClientProtocolHandlerException(
- "an internal method was passed an
invalid argument", ex);
- } finally {
-
- // if we're past the authN phase of the protocol, we
should send a C04 message to clean up.
- if (authenticated) {
- this.endCertification();
- }
-
- this.disconnect();
-
- // clean up after SASL
- this.dispose();
- }
-
- return signedCertificates;
+
+ if (dnString == null) {
+ throw new IllegalArgumentException("DN string is null");
}
-
- /**
- * Generates a PKCS#10 Certificate Signing Request.
- *
- * To generate an identity CSR, use "CN=identity" for
<code>dnString</code>.
- * To generate an opaque CSR, use "CN=opaque" for
<code>dnString</code>.
- *
- * @param dnString The X.500 DN for the CSR's Subject field
- * @param keyPair The
{@link
KeyPair} used to build the CSR.
- * @param signatureAlgorithm The signature algorithm to use to sign
the CSR.
- *
- * @throws ClientProtocolHandlerException on error
- * @throws IllegalArgumentException if any arguments are
<code>null</code>
- * @throws NoSuchAlgorithmException if signatureAlgorithm isn't
supported by the JVM
- */
- public static CertificationRequest generateCSR(final String dnString,
- final KeyPair keyPair, final String
signatureAlgorithm)
- throws ClientProtocolHandlerException,
IllegalArgumentException,
- NoSuchAlgorithmException {
-
- return generateCSR(dnString, keyPair.getPublic(),
keyPair.getPrivate(),
- signatureAlgorithm);
+
+ try {
+ dn = new Name(dnString);
+ } catch (BadNameException ex) {
+ throw new IllegalArgumentException("malformed DN", ex);
}
-
- /**
- * Generates a PKCS#10 Certificate Signing Request.
- *
- * This variant of the method lets you specify a custom
{@link
PrivateKey} for signing the CSR. Normally, you would not do this.
- * It is only used for the certificate refresh methods of the SASL-CA.
- *
- * To generate an identity CSR, use "CN=identity" for
<code>dnString</code>.
- * To generate an opaque CSR, use "CN=opaque" for
<code>dnString</code>.
- *
- * @param dnString The X.500 DN for the CSR's Subject field
- * @param pubKey The
{@link
PublicKey} used to build the CSR.
- * @param signingKey The
{@link
PrivateKey} with which to sign the CSR.
- * @param signatureAlgorithm The signature algorithm to use to sign
the CSR.
- *
- * @throws ClientProtocolHandlerException on error
- * @throws IllegalArgumentException if any arguments are null
- * @throws NoSuchAlgorithmException if signatureAlgorithm isn't
supported by the JVM
- */
- public static CertificationRequest generateCSR(final String dnString,
- final PublicKey pubKey, final PrivateKey signingKey,
- final String signatureAlgorithm)
- throws ClientProtocolHandlerException,
IllegalArgumentException,
- NoSuchAlgorithmException {
-
- Name dn;
- CertificationRequest req;
-
- // validate the arguments
-
- if (pubKey == null) {
- throw new IllegalArgumentException("KeyPair's public
key is null");
- }
-
- if (signingKey == null) {
- throw new IllegalArgumentException("Signing key is
null");
- }
-
- if (dnString == null) {
- throw new IllegalArgumentException("DN stringe is
null");
- }
-
- try {
- dn = new Name(dnString);
- } catch (BadNameException ex) {
- throw new IllegalArgumentException("malformed DN",
ex);
- }
-
- try {
- req = new CertificationRequest(pubKey, dn);
- } catch (ASN1Exception asn1Ex) {
- throw new ClientProtocolHandlerException(
- "ASN.1 error while building CSR",
asn1Ex);
- } catch (InvalidKeyException ikEx) {
- throw new ClientProtocolHandlerException(
- "Key is invalid while building CSR",
ikEx);
- }
-
- /* get a copy of req's bytestream, sign it, and insert the
signature */
- byte[] req_bytestream;
- try {
- req_bytestream = req.getTBS();
- } catch (CorruptedCodeException ccEx) {
- throw new ClientProtocolHandlerException(
- "ASN1 error while parsing CSR", ccEx);
- }
-
- try {
- Signature sig =
Signature.getInstance(signatureAlgorithm);
- sig.initSign(signingKey);
- sig.update(req_bytestream);
-
- byte sig_bytestream[];
-
- AlgorithmIdentifier alg = new AlgorithmIdentifier(
- signatureAlgorithm);
- sig_bytestream = sig.sign();
- req.setSignature(sig_bytestream, alg);
- } catch (Exception ex) {
- throw new ClientProtocolHandlerException("Error while
signing CSR",
- ex);
- }
-
- return req;
+
+
+ try {
+ req = new CertificationRequest(pubKey, dn);
+ } catch (ASN1Exception asn1Ex) {
+ throw new ClientProtocolHandlerException("ASN.1 error while
building CSR", asn1Ex);
+ } catch (InvalidKeyException ikEx) {
+ throw new ClientProtocolHandlerException("Key is invalid while
building CSR", ikEx);
}
-
- /**
- * Get the timing information.
- *
- * @return A <code>long[]</code> containing timing for how long each
CSR took to fetch.
- * If profiling wasn't enabled via
{@link
#setProfiling}, this method returns <code>null</code>.
- */
- public long[] getTiming() {
- return this.timings;
+
+ /* get a copy of req's bytestream, sign it, and insert the signature
*/
+ byte[] req_bytestream;
+ try {
+ req_bytestream = req.getTBS();
+ } catch (CorruptedCodeException ccEx) {
+ throw new ClientProtocolHandlerException("ASN1 error while
parsing CSR", ccEx);
}
-
- /**
- * Disposes of any objects the ClientProtocolHandler used internally.
- *
- * After calling this method, the ClientProtocolHandler will be
unusable for obtaining new certificates.
- * But any certificates/keys already obtained will still be
accessible.
- *
- * You should not need to call this function. It is called by
<code>run()</code>.
- *
- */
- public void dispose() {
-
- logger.debug("in dispose()");
-
- try {
- if (this.saslclient != null) {
- this.saslclient.dispose();
- }
- } catch (SaslException ex) {
- logger.error("Error while disposing of SASL client",
ex);
- }
-
- this.saslclient = null;
-
- // reset parent class data, so subsequent calls to
this.refreshCertificate() will work
- super.readBuffer = new byte[65535];
- super.writeBuffer = new byte[65535];
- super.wrapData = false;
- super.saslWrapper = null;
- super.saslMechanism = null;
- super.usingTLS = false;
- super.socket = null;
+
+ try {
+ Signature sig = Signature.getInstance(signatureAlgorithm);
+ sig.initSign(signingKey);
+ sig.update(req_bytestream);
+
+ byte sig_bytestream[];
+
+ AlgorithmIdentifier alg = new
AlgorithmIdentifier(signatureAlgorithm);
+ sig_bytestream = sig.sign();
+ req.setSignature(sig_bytestream, alg);
+ } catch (Exception ex) {
+ throw new ClientProtocolHandlerException("Error while signing
CSR", ex);
}
+
+ return req;
+ }
+
+
+ /**
+ * Get the timing information.
+ *
+ * @return A <code>long[]</code> containing timing for how long each CSR
took to fetch.
+ * If profiling wasn't enabled via
{@link
#setProfiling}, this method returns <code>null</code>.
+ */
+ public long[] getTiming() {
+ return this.timings;
+ }
+
+
+ /**
+ * Disposes of any objects the ClientProtocolHandler used internally.
+ *
+ * After calling this method, the ClientProtocolHandler will be unusable
for obtaining new certificates.
+ * But any certificates/keys already obtained will still be accessible.
+ *
+ * You should not need to call this function. It is called by
<code>run()</code>.
+ *
+ */
+ public void dispose() {
+
+ logger.debug("in dispose()");
+
+ try {
+ if (this.saslclient != null) {
+ this.saslclient.dispose();
+ }
+ } catch (SaslException ex) {
+ logger.error("Error while disposing of SASL client", ex);
+ }
+
+ this.saslclient = null;
+
+ // reset parent class data, so subsequent calls to
this.refreshCertificate() will work
+ super.readBuffer = new byte[65535];
+ super.writeBuffer = new byte[65535];
+ super.wrapData = false;
+ super.saslWrapper = null;
+ super.saslMechanism = null;
+ super.usingTLS = false;
+ super.socket = null;
+ }
}

Added: branches/saslca/src/edu/psu/sasl_ca/NewClientProtocolHandler.java

Modified: branches/saslca/src/edu/psu/sasl_ca/ServerProtocolHandler.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/ServerProtocolHandler.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/ServerProtocolHandler.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -49,6 +49,8 @@
import codec.CorruptedCodeException;
import codec.asn1.ASN1Exception;
import codec.pkcs10.CertificationRequest;
+import codec.x501.BadNameException;
+import codec.x501.Name;

import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -119,7 +121,24 @@

private static final Logger logger =
Logger.getLogger(ServerProtocolHandler.class);

+ /** Names for the DN mapper. */
+ private static Name opaqueName;
+ private static Name identifyName;
+ private static Name peerserverName;
+ private static Name edugainName;

+ static {
+ try {
+ opaqueName = new Name(StringConstants.opaqueCertIdentifier);
+ identifyName = new Name(StringConstants.identityCertIdentifier);
+ peerserverName = new
Name(StringConstants.peerserverCertIdentifier);
+ edugainName = new Name(StringConstants.edugainCertIdentifier);
+ } catch (BadNameException ex) {
+ logger.error("Error initializing CSR name comparision
constants", ex);
+ }
+ }
+
+
/**
* Build a new ServerProtocolHandler.
*
@@ -666,14 +685,33 @@

CertType type;

- String csrDN = csr.getSubjectDN().toString();
- if (csrDN.equals(StringConstants.opaqueCertIdentifier)) {
+ Name csrDN = csr.getSubjectDN();
+ if (csrDN == null) {
+ logger.error("null CSR DN");
+ return null;
+ }
+
+// if (csrDN.equals(StringConstants.opaqueCertIdentifier)) {
+// type = CertType.opaque;
+// } else if (csrDN.equals(StringConstants.identityCertIdentifier)) {
+// type = CertType.identity;
+// } else if
(csrDN.startsWith(StringConstants.peerserverCertIdentifier)) {
+// type = CertType.peerserver;
+// } else if
(csrDN.startsWith(StringConstants.edugainCertIdentifier)) {
+// type = CertType.edugain;
+// } else {
+// logger.error("user has requested an unknown certificate type:
" + csrDN);
+// type = null;
+// }
+
+
+ if (csrDN.equals(opaqueName)) {
type = CertType.opaque;
- } else if (csrDN.equals(StringConstants.identityCertIdentifier)) {
+ } else if (csrDN.equals(identifyName)) {
type = CertType.identity;
- } else if
(csrDN.startsWith(StringConstants.peerserverCertIdentifier)) {
+ } else if (csrDN.equals(peerserverName)) {
type = CertType.peerserver;
- } else if (csrDN.startsWith(StringConstants.edugainCertIdentifier)) {
+ } else if (csrDN.equals(edugainName)) {
type = CertType.edugain;
} else {
logger.error("user has requested an unknown certificate type: "
+ csrDN);

Modified: branches/saslca/src/edu/psu/sasl_ca/apps/client/CSRSigner.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/apps/client/CSRSigner.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/apps/client/CSRSigner.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -58,7 +58,7 @@
import codec.pkcs10.CertificationRequest;
import codec.x501.Name;

-import edu.psu.sasl_ca.ClientProtocolHandler;
+import edu.psu.sasl_ca.NewClientProtocolHandler;
import edu.psu.sasl_ca.util.StringConstants;
import edu.psu.sasl_ca.util.Util;

@@ -75,7 +75,7 @@
*/
public class CSRSigner {

- private static ClientProtocolHandler cph;
+ private static NewClientProtocolHandler cph;
private static Subject subj;

private static final Logger logger = Logger.getLogger(CSRSigner.class);
@@ -93,7 +93,7 @@
CallbackHandler cbh = config.getCallbackHandler();

subj = Util.jaasLogin(cbh);
- cph = new ClientProtocolHandler(config);
+ cph = new NewClientProtocolHandler(config);

String csrFilename = System.getProperty("csrFilename");
CertificationRequest csr = Util.loadCSRFromFile(csrFilename);

Modified:
branches/saslca/src/edu/psu/sasl_ca/apps/client/ClientConfiguration.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/apps/client/ClientConfiguration.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/apps/client/ClientConfiguration.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -56,7 +56,6 @@

import com.sun.security.auth.callback.TextCallbackHandler;

-import edu.psu.sasl_ca.apps.client.subject.MyOwnCallbackHandler;
import edu.psu.sasl_ca.util.MissingPropertyException;
import edu.psu.sasl_ca.util.OptionalPropertyNames;
import edu.psu.sasl_ca.util.StringConstants;
@@ -191,7 +190,7 @@
}

if (this.cbh == null) {
- this.cbh = new MyOwnCallbackHandler("kan","1mth3fuck1ngon3");
+ this.cbh = new TextCallbackHandler();
}
}


Modified: branches/saslca/src/edu/psu/sasl_ca/apps/client/EduGAINClient.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/apps/client/EduGAINClient.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/apps/client/EduGAINClient.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -58,8 +58,7 @@

import codec.pkcs10.CertificationRequest;

-import edu.psu.sasl_ca.ClientProtocolHandler;
-import edu.psu.sasl_ca.apps.client.subject.UserID;
+import edu.psu.sasl_ca.NewClientProtocolHandler;
import edu.psu.sasl_ca.util.StringConstants;
import edu.psu.sasl_ca.util.Util;

@@ -74,103 +73,96 @@
* attempts to renew the eduGAIN certificate.
*/
public class EduGAINClient {
+
+ /** primary class for interacting with a SASL-CA server. */
+ private static NewClientProtocolHandler cph;
+
+ /** JAAS Subject. Contains credentials for authentication to the SASL-CA
server. */
+ private static Subject subj;
+
+ private static String keyAlgorithm;
+ private static int keySize;
+
+ private static final Logger logger =
Logger.getLogger(sasl_ca_client.class);
+
+
+ public static void main(final String args[]) throws Exception {
+
+ // this is needed since the standard java JCE's don't handle
+ // oid 1.2.840.113549.1.1.1 (RSA)
+ Security.addProvider(new CDCStandardProvider());
+
+ // load the client configuration options from the
+ // system properties, or from a config file. */
+ ClientConfiguration config = new ClientConfiguration();
+ cph = new NewClientProtocolHandler(config);

- /** primary class for interacting with a SASL-CA server. */
- private static ClientProtocolHandler cph;
+ keyAlgorithm = config.getKeyAlgorithm();
+ keySize = config.getKeySize();
+ CallbackHandler handler = config.getCallbackHandler();

- /** JAAS Subject. Contains credentials for authentication to the
SASL-CA server. */
- private static Subject subj;
+ // obtain login credentials for the user.
+ subj = Util.jaasLogin(handler);
+ logger.debug(subj);
+
+ // generate the keypair and create a CSR.
+ KeyPair eduGainKeyPair = Util.generateKeyPair(keyAlgorithm, keySize);
+ CertificationRequest edugainCSR =
+ cph.generateCSR(StringConstants.edugainCertIdentifier,
eduGainKeyPair, "SHA1withRSA");
+ cph.addCSR(edugainCSR);

- private static String keyAlgorithm;
+ // actually get the certs
+ Map<CertificationRequest, X509Certificate[]> certMap =
+ (Map<CertificationRequest,
X509Certificate[]>)Subject.doAs(subj, cph);
+
+
+ // verify that the cert chain from the SASL-CA is valid.
+ X509Certificate[] certChain = certMap.get(edugainCSR);
+ boolean valid = Util.verifyCertChain(certChain);
+ logger.info("Identity cert chain is valid: " + valid);

- private static int keySize;
-
- private static final Logger logger =
Logger.getLogger(sasl_ca_client.class);
-
- public static void main(final String args[]) throws Exception {
-
- // this is needed since the standard java JCE's don't handle
- // oid 1.2.840.113549.1.1.1 (RSA)
- Security.addProvider(new CDCStandardProvider());
-
- logger.info("load the client configuration options from the
system properties, or from a config file.");
- // load the client configuration options from the
- // system properties, or from a config file. */
- ClientConfiguration config = new ClientConfiguration();
- cph = new ClientProtocolHandler(config);
-
- keyAlgorithm = config.getKeyAlgorithm();
- keySize = config.getKeySize();
- CallbackHandler handler = config.getCallbackHandler();
-
- logger.info("obtain login credentials for the user.");
- // obtain login credentials for the user.
- subj = new Subject();
- subj.getPrincipals().add(new UserID("kan"));
- logger.debug(subj);
-
- logger.info("generate the keypair and create a CSR.");
- // generate the keypair and create a CSR.
- KeyPair eduGainKeyPair = Util.generateKeyPair(keyAlgorithm,
keySize);
- CertificationRequest edugainCSR = cph.generateCSR(
- StringConstants.edugainCertIdentifier,
eduGainKeyPair,
- "SHA1withRSA");
- cph.addCSR(edugainCSR);
-
- logger.info("actually get the certs.");
- // actually get the certs
- Map<CertificationRequest, X509Certificate[]> certMap =
(Map<CertificationRequest, X509Certificate[]>) Subject
- .doAs(subj, cph);
-
- logger.info("verify that the cert chain from the SASL-CA is
valid.");
- // verify that the cert chain from the SASL-CA is valid.
- X509Certificate[] certChain = certMap.get(edugainCSR);
- boolean valid = Util.verifyCertChain(certChain);
- logger.info("Identity cert chain is valid: " + valid);
-
- logger.info("write the cert chain out to a series of
DER-encoded files.");
- // write the cert chain out to a series of DER-encoded files.
- FileOutputStream out;
- int i = 0;
- if (certChain != null) {
- for (X509Certificate cert : certMap.get(edugainCSR)) {
- out = new FileOutputStream("identity.cert." +
i++);
- System.out.println("writing cert for "
- +
cert.getSubjectX500Principal().getName());
- out.write(cert.getEncoded());
- out.close();
- }
-
- out = new FileOutputStream("identity.key");
- out.write(eduGainKeyPair.getPrivate().getEncoded());
- out.close();
- } else {
- logger.error("Error obtaining identity cert");
- }
-
- /* // try to refresh the edugain cert
- X509Certificate oldEdugainCert = certChain[0];
- PrivateKey oldPrivateKey = eduGainKeyPair.getPrivate();
- KeyPair newKeyPair = Util.generateKeyPair(keyAlgorithm,
keySize);
-
- X509Certificate[] newCertChain =
cph.refreshCertificate(oldEdugainCert,
- StringConstants.identityCertIdentifier, oldPrivateKey,
- newKeyPair.getPublic(), "SHA1withRSA");
-
- valid = Util.verifyCertChain(newCertChain);
- logger.info("refreshed identity cert chain is valid: " +
valid);
-
- i=0;
- for (X509Certificate cert : newCertChain) {
- out = new FileOutputStream("refreshed.identiy.cert." + i++);
- System.out.println("writing cert for " +
cert.getSubjectX500Principal().getName());
- out.write(cert.getEncoded());
- out.close();
- }
-
- out = new FileOutputStream("refreshed.identity.key");
- out.write(newKeyPair.getPrivate().getEncoded());
- out.close();
- */
+ // write the cert chain out to a series of DER-encoded files.
+ FileOutputStream out;
+ int i=0;
+ if (certChain != null) {
+ for (X509Certificate cert : certMap.get(edugainCSR)) {
+ out = new FileOutputStream("identity.cert." + i++);
+ System.out.println("writing cert for " +
cert.getSubjectX500Principal().getName());
+ out.write(cert.getEncoded());
+ out.close();
+ }
+
+ out = new FileOutputStream("identity.key");
+ out.write(eduGainKeyPair.getPrivate().getEncoded());
+ out.close();
+ } else {
+ logger.error("Error obtaining identity cert");
}
+
+
+ // try to refresh the edugain cert
+ X509Certificate oldEdugainCert = certChain[0];
+ PrivateKey oldPrivateKey = eduGainKeyPair.getPrivate();
+ KeyPair newKeyPair = Util.generateKeyPair(keyAlgorithm, keySize);
+
+ X509Certificate[] newCertChain =
cph.refreshCertificate(oldEdugainCert,
+ StringConstants.identityCertIdentifier, oldPrivateKey,
+ newKeyPair.getPublic(), "SHA1withRSA");
+
+ valid = Util.verifyCertChain(newCertChain);
+ logger.info("refreshed identity cert chain is valid: " + valid);
+
+ i=0;
+ for (X509Certificate cert : newCertChain) {
+ out = new FileOutputStream("refreshed.identiy.cert." + i++);
+ System.out.println("writing cert for " +
cert.getSubjectX500Principal().getName());
+ out.write(cert.getEncoded());
+ out.close();
+ }
+
+ out = new FileOutputStream("refreshed.identity.key");
+ out.write(newKeyPair.getPrivate().getEncoded());
+ out.close();
+
+ }
}

Modified:
branches/saslca/src/edu/psu/sasl_ca/apps/client/PeerServerCertGenerator.java
===================================================================
---
branches/saslca/src/edu/psu/sasl_ca/apps/client/PeerServerCertGenerator.java
2008-06-06 21:45:48 UTC (rev 3972)
+++
branches/saslca/src/edu/psu/sasl_ca/apps/client/PeerServerCertGenerator.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -57,7 +57,7 @@

import codec.pkcs10.CertificationRequest;

-import edu.psu.sasl_ca.ClientProtocolHandler;
+import edu.psu.sasl_ca.NewClientProtocolHandler;
import edu.psu.sasl_ca.util.Util;
import edu.psu.sasl_ca.util.StringConstants;

@@ -65,7 +65,7 @@

public class PeerServerCertGenerator {

- private static ClientProtocolHandler cph;
+ private static NewClientProtocolHandler cph;
private static Subject subj;

private static final Logger logger =
Logger.getLogger(PeerServerCertGenerator.class);
@@ -87,7 +87,7 @@
}

subj = Util.jaasLogin(config.getCallbackHandler());
- cph = new ClientProtocolHandler(config);
+ cph = new NewClientProtocolHandler(config);

String peerServerHostname =
System.getProperty("lionshare.PeerServerHostname");
String peerServerKeyStoreName =
System.getProperty("lionshare.PeerServerKeyStore");

Modified: branches/saslca/src/edu/psu/sasl_ca/apps/client/StressTest.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/apps/client/StressTest.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/apps/client/StressTest.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -61,7 +61,7 @@

import codec.pkcs10.CertificationRequest;

-import edu.psu.sasl_ca.ClientProtocolHandler;
+import edu.psu.sasl_ca.NewClientProtocolHandler;
import edu.psu.sasl_ca.util.StringConstants;
import edu.psu.sasl_ca.util.Util;

@@ -104,7 +104,7 @@
/** per-run offset into timings */
private int run;

- private ClientProtocolHandler cph;
+ private NewClientProtocolHandler cph;


/**
@@ -117,7 +117,7 @@
ctx.login();
this.subj = ctx.getSubject();

- this.cph = new ClientProtocolHandler(clientConfig);
+ this.cph = new NewClientProtocolHandler(clientConfig);
this.cph.setProfiling(true);

for (CertificationRequest csr : csrs) {
@@ -250,7 +250,7 @@
for (int i=0; i<numberOfRequests; i++) {
KeyPair kp =
Util.generateKeyPair(clientConfig.getKeyAlgorithm(),
clientConfig.getKeySize(), prng);
- csrs[i] =
ClientProtocolHandler.generateCSR(StringConstants.opaqueCertIdentifier, kp,
"SHA1withRSA");
+ csrs[i] =
NewClientProtocolHandler.generateCSR(StringConstants.opaqueCertIdentifier,
kp, "SHA1withRSA");
}
}


Modified: branches/saslca/src/edu/psu/sasl_ca/apps/client/sasl_ca_client.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/apps/client/sasl_ca_client.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/apps/client/sasl_ca_client.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -58,149 +58,146 @@

import codec.pkcs10.CertificationRequest;

-import edu.psu.sasl_ca.ClientProtocolHandler;
+import edu.psu.sasl_ca.NewClientProtocolHandler;
import edu.psu.sasl_ca.util.StringConstants;
import edu.psu.sasl_ca.util.Util;

import org.apache.log4j.Logger;

+
public class sasl_ca_client {
+
+ private static NewClientProtocolHandler cph;
+ private static Subject subj;
+
+ private static String keyAlgorithm;
+ private static int keySize;
+
+ private static final Logger logger =
Logger.getLogger(sasl_ca_client.class);
+
+
+ public static void main(final String args[]) throws Exception {
+
+ // this is needed since the standard java JCE's don't handle
+ // oid 1.2.840.113549.1.1.1 (RSA)
+ Security.addProvider(new CDCStandardProvider());
+
+ ClientConfiguration config = new ClientConfiguration();
+ cph = new NewClientProtocolHandler(config);

- private static ClientProtocolHandler cph;
+ keyAlgorithm = config.getKeyAlgorithm();
+ keySize = config.getKeySize();
+ CallbackHandler handler = config.getCallbackHandler();

- private static Subject subj;
-
- private static String keyAlgorithm;
-
- private static int keySize;
-
- private static final Logger logger =
Logger.getLogger(sasl_ca_client.class);
-
- public static void main(final String args[]) throws Exception {
-
- // this is needed since the standard java JCE's don't handle
- // oid 1.2.840.113549.1.1.1 (RSA)
- Security.addProvider(new CDCStandardProvider());
-
- ClientConfiguration config = new ClientConfiguration();
- cph = new ClientProtocolHandler(config);
-
- keyAlgorithm = config.getKeyAlgorithm();
- keySize = config.getKeySize();
- CallbackHandler handler = config.getCallbackHandler();
-
- subj = Util.jaasLogin(handler);
- logger.debug(subj);
-
- KeyPair identityKeyPair = Util.generateKeyPair(keyAlgorithm,
keySize);
- KeyPair opaqueKeyPair = Util.generateKeyPair(keyAlgorithm,
keySize);
-
- CertificationRequest identityCSR = cph.generateCSR(
- StringConstants.identityCertIdentifier,
identityKeyPair,
- "SHA1withRSA");
- CertificationRequest opaqueCSR = cph.generateCSR(
- StringConstants.opaqueCertIdentifier,
opaqueKeyPair,
- "SHA1withRSA");
- cph.addCSR(identityCSR);
- cph.addCSR(opaqueCSR);
-
- // actually get the certs
- Map<CertificationRequest, X509Certificate[]> certMap =
(Map<CertificationRequest, X509Certificate[]>) Subject
- .doAs(subj, cph);
-
- FileOutputStream out;
-
- X509Certificate[] certChain = certMap.get(identityCSR);
- boolean valid = Util.verifyCertChain(certChain);
- logger.info("Identity cert chain is valid: " + valid);
-
- int i = 0;
- if (certChain != null) {
- for (X509Certificate cert : certMap.get(identityCSR))
{
- out = new FileOutputStream("identity.cert." +
i++);
- System.out.println("writing cert for "
- +
cert.getSubjectX500Principal().getName());
- out.write(cert.getEncoded());
- out.close();
- }
-
- out = new FileOutputStream("identity.key");
- out.write(identityKeyPair.getPrivate().getEncoded());
- out.close();
- } else {
- logger.error("Error obtaining identity cert");
- }
-
- certChain = certMap.get(opaqueCSR);
- valid = Util.verifyCertChain(certChain);
- logger.info("Opaque cert chain is valid: " + valid);
-
- if (certChain != null) {
- i = 0;
- for (X509Certificate cert : certMap.get(opaqueCSR)) {
- out = new FileOutputStream("opaque.cert." +
i++);
- System.out.println("writing cert for "
- +
cert.getSubjectX500Principal().getName());
- out.write(cert.getEncoded());
- out.close();
- }
-
- out = new FileOutputStream("opaque.key");
- out.write(opaqueKeyPair.getPrivate().getEncoded());
- out.close();
- } else {
- logger.error("Error obtaining opaque cert");
- }
-
-/* // try to refresh the opaque cert
- X509Certificate oldOpaqueCert = certMap.get(opaqueCSR)[0];
- PrivateKey oldPrivateKey = opaqueKeyPair.getPrivate();
- KeyPair newKeyPair = Util.generateKeyPair(keyAlgorithm,
keySize);
-
- X509Certificate[] newCertChain =
cph.refreshCertificate(oldOpaqueCert,
- StringConstants.opaqueCertIdentifier,
oldPrivateKey, newKeyPair
- .getPublic(), "SHA1withRSA");
-
- valid = Util.verifyCertChain(newCertChain);
- logger.info("refreshed opaque cert chain is valid: " + valid);
-
- i = 0;
- for (X509Certificate cert : newCertChain) {
- out = new FileOutputStream("refreshed.opaque.cert." +
i++);
- System.out.println("writing cert for "
- +
cert.getSubjectX500Principal().getName());
- out.write(cert.getEncoded());
- out.close();
- }
-
- out = new FileOutputStream("refreshed.opaque.key");
- out.write(newKeyPair.getPrivate().getEncoded());
+ subj = Util.jaasLogin(handler);
+ logger.debug(subj);
+
+ KeyPair identityKeyPair = Util.generateKeyPair(keyAlgorithm, keySize);
+ KeyPair opaqueKeyPair = Util.generateKeyPair(keyAlgorithm, keySize);
+
+ CertificationRequest identityCSR =
+ cph.generateCSR(StringConstants.identityCertIdentifier,
identityKeyPair, "SHA1withRSA");
+ CertificationRequest opaqueCSR =
+ cph.generateCSR(StringConstants.opaqueCertIdentifier,
opaqueKeyPair, "SHA1withRSA");
+ cph.addCSR(identityCSR);
+ cph.addCSR(opaqueCSR);
+
+ // actually get the certs
+ Map<CertificationRequest, X509Certificate[]> certMap =
+ (Map<CertificationRequest,
X509Certificate[]>)Subject.doAs(subj, cph);
+
+ FileOutputStream out;
+
+ X509Certificate[] certChain = certMap.get(identityCSR);
+ boolean valid = Util.verifyCertChain(certChain);
+ logger.info("Identity cert chain is valid: " + valid);
+
+ int i=0;
+ if (certChain != null) {
+ for (X509Certificate cert : certMap.get(identityCSR)) {
+ out = new FileOutputStream("identity.cert." + i++);
+ System.out.println("writing cert for " +
cert.getSubjectX500Principal().getName());
+ out.write(cert.getEncoded());
out.close();
-
- // now try to refresh the identify cert
- X509Certificate oldIdentityCert = certMap.get(identityCSR)[0];
- oldPrivateKey = identityKeyPair.getPrivate();
- newKeyPair = Util.generateKeyPair(keyAlgorithm, keySize);
-
- newCertChain = cph.refreshCertificate(oldIdentityCert,
- StringConstants.identityCertIdentifier,
oldPrivateKey,
- newKeyPair.getPublic(), "SHA1withRSA");
-
- valid = Util.verifyCertChain(newCertChain);
- logger.info("refreshed identity cert chain is valid: " +
valid);
-
- i = 0;
- for (X509Certificate cert : newCertChain) {
- out = new FileOutputStream("refreshed.identiy.cert."
+ i++);
- System.out.println("writing cert for "
- +
cert.getSubjectX500Principal().getName());
- out.write(cert.getEncoded());
- out.close();
- }
-
- out = new FileOutputStream("refreshed.identity.key");
- out.write(newKeyPair.getPrivate().getEncoded());
- out.close(); */
-
+ }
+
+ out = new FileOutputStream("identity.key");
+ out.write(identityKeyPair.getPrivate().getEncoded());
+ out.close();
+ } else {
+ logger.error("Error obtaining identity cert");
}
+
+
+ certChain = certMap.get(opaqueCSR);
+ valid = Util.verifyCertChain(certChain);
+ logger.info("Opaque cert chain is valid: " + valid);
+
+ if (certChain != null) {
+ i=0;
+ for (X509Certificate cert : certMap.get(opaqueCSR)) {
+ out = new FileOutputStream("opaque.cert." + i++);
+ System.out.println("writing cert for " +
cert.getSubjectX500Principal().getName());
+ out.write(cert.getEncoded());
+ out.close();
+ }
+
+ out = new FileOutputStream("opaque.key");
+ out.write(opaqueKeyPair.getPrivate().getEncoded());
+ out.close();
+ } else {
+ logger.error("Error obtaining opaque cert");
+ }
+
+
+ // try to refresh the opaque cert
+ X509Certificate oldOpaqueCert = certMap.get(opaqueCSR)[0];
+ PrivateKey oldPrivateKey = opaqueKeyPair.getPrivate();
+ KeyPair newKeyPair = Util.generateKeyPair(keyAlgorithm, keySize);
+
+ X509Certificate[] newCertChain =
cph.refreshCertificate(oldOpaqueCert,
+ StringConstants.opaqueCertIdentifier, oldPrivateKey,
+ newKeyPair.getPublic(), "SHA1withRSA");
+
+ valid = Util.verifyCertChain(newCertChain);
+ logger.info("refreshed opaque cert chain is valid: " + valid);
+
+ i=0;
+ for (X509Certificate cert : newCertChain) {
+ out = new FileOutputStream("refreshed.opaque.cert." + i++);
+ System.out.println("writing cert for " +
cert.getSubjectX500Principal().getName());
+ out.write(cert.getEncoded());
+ out.close();
+ }
+
+ out = new FileOutputStream("refreshed.opaque.key");
+ out.write(newKeyPair.getPrivate().getEncoded());
+ out.close();
+
+
+ // now try to refresh the identify cert
+ X509Certificate oldIdentityCert = certMap.get(identityCSR)[0];
+ oldPrivateKey = identityKeyPair.getPrivate();
+ newKeyPair = Util.generateKeyPair(keyAlgorithm, keySize);
+
+ newCertChain = cph.refreshCertificate(oldIdentityCert,
+ StringConstants.identityCertIdentifier, oldPrivateKey,
+ newKeyPair.getPublic(), "SHA1withRSA");
+
+ valid = Util.verifyCertChain(newCertChain);
+ logger.info("refreshed identity cert chain is valid: " + valid);
+
+ i=0;
+ for (X509Certificate cert : newCertChain) {
+ out = new FileOutputStream("refreshed.identiy.cert." + i++);
+ System.out.println("writing cert for " +
cert.getSubjectX500Principal().getName());
+ out.write(cert.getEncoded());
+ out.close();
+ }
+
+ out = new FileOutputStream("refreshed.identity.key");
+ out.write(newKeyPair.getPrivate().getEncoded());
+ out.close();
+
+ }
}

Modified: branches/saslca/src/edu/psu/sasl_ca/apps/server/ServerShutdown.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/apps/server/ServerShutdown.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/apps/server/ServerShutdown.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -67,7 +67,7 @@

byte[] SHUTDOWN_MSG = "KILL_SASL_CA\n".getBytes("US-ASCII");

- InetAddress localhost = InetAddress.getByAddress(Util.LOCALHOST);
+ InetAddress localhost = InetAddress.getLocalHost();
Socket sock = new Socket(localhost, 8804);

OutputStream out = sock.getOutputStream();

Modified: branches/saslca/src/edu/psu/sasl_ca/apps/server/sasl_ca_server.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/apps/server/sasl_ca_server.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/apps/server/sasl_ca_server.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -57,7 +57,6 @@
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
-import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
@@ -87,12 +86,11 @@
import javax.security.sasl.SaslServerFactory;
import javax.security.sasl.SaslException;

-import cdc.standard.CDCStandardProvider;
import codec.pkcs10.CertificationRequest;

import edu.psu.sasl_ca.CertType;
import edu.psu.sasl_ca.CertificateEngine;
-import edu.psu.sasl_ca.ClientProtocolHandler;
+import edu.psu.sasl_ca.NewClientProtocolHandler;
import edu.psu.sasl_ca.CryptoShibHandle;
import edu.psu.sasl_ca.ServerConnectionHandler;
import edu.psu.sasl_ca.StartTLSConfig;
@@ -116,6 +114,7 @@
import org.apache.log4j.Logger;

import com.sun.security.auth.callback.TextCallbackHandler;
+import javax.security.auth.callback.CallbackHandler;


/**
@@ -173,9 +172,13 @@
/** The thread timeout time in seconds. */
private int threadTimeOut = 60;

- /** The
{@link
ServerSocket} used to accept connections. */
- private ServerSocket serverSocket;
+ /** A list of
{@link
Thread}s used to accept connections. */
+ private List<Thread> listeningThreads;

+ /** A List of runnables for the listening threads. */
+ private List<ListenerThreadRunnable> listeningRunnables;
+
+
/**
* Small internal wrapper class for command-line arguments.
*
@@ -199,22 +202,108 @@
}


+ /**
+ * Listener thread. The thread will create a
{@link
ServerSocket}
+ * listening on address in its start() method.
+ */
+ class ListenerThreadRunnable implements Runnable {
+
+ private InetAddress serverAddress;
+ private int serverPort;
+ private ServerSocket serverSocket;
+ private volatile boolean stillRunning = false;
+ private CallbackHandler cbh;
+ private Subject subj;
+ private boolean startedOK = false;
+
+ /**
+ * Create a new Listener Thread.
+ *
+ * @param address The address on which to listen.
+ */
+ public ListenerThreadRunnable(final InetAddress address, int port,
+ final CallbackHandler handler, final Subject s ) {
+
+ if (address == null || handler == null || s == null) {
+ return;
+ }
+
+ serverAddress = address;
+ serverPort = port;
+ cbh = handler;
+ subj = s;
+ }
+
+
+ /**
+ * Start the listener thread and create the server socket.
+ */
+ public void run() {
+
+ try {
+ serverSocket = new ServerSocket();
+ serverSocket.bind(new InetSocketAddress(serverAddress,
serverPort));
+ logger.info("listening on: " + serverAddress.getHostAddress()
+ ", port " + serverPort);
+ startedOK = true;
+ stillRunning = true;
+ } catch (IOException ex) {
+ logger.error("Error creating server socket for " +
serverAddress.getHostAddress(), ex);
+ return;
+ }
+
+ // loop, accepting connections
+ while (stillRunning) {
+
+ try {
+ Socket connection = serverSocket.accept();
+ ServerConnectionHandler sch = new
ServerConnectionHandler(connection, subj, cbh,
+ hostName, mechanisms, certEngine, principalMappers,
+ tlsConfig, saslSecLayerProperties);
+ threadpool.execute(sch);
+ } catch (Exception ex) {
+ logger.error("Error accepting and enqueueing connection",
ex);
+ }
+ }
+
+ }
+
+
+ /**
+ * Stop accepting incoming connections.
+ * This will stop enqueing new connections.
+ * The ServerSocket will be left open.
+ */
+ public void stopAcceptingConnections() {
+ stillRunning = false;
+ logger.info("No longer accepting connections on " +
serverAddress.getHostAddress());
+ }
+
+ /**
+ * Close the
{@link
ServerSocket}.
+ *
+ * If this method is called before calling stopAccetingConnections(),
+ * that method will be called.
+ */
+ public void closeServerSocket() throws IOException {
+
+ if (stillRunning) {
+ stopAcceptingConnections();
+ }
+
+ if (startedOK) {
+ serverSocket.close();
+ }
+ }
+ }
+
public static void main(final String[] args) throws Exception {

sasl_ca_server server = new sasl_ca_server();
ArgumentWrapper argWrapper = new ArgumentWrapper(args);

server.init(argWrapper);
- if (args.length==5&&args[0].equals("newkey")) {
- String keystorefile=args[1];
- String keystorepass=args[2];
- String alias=args[3];
- String hostname=args[4];
-
server.makeClientStartTLSCert(alias,keystorefile,hostname,keystorepass.toCharArray());
- }
- else {
- server.start();
- }
+ server.start();
+
}


@@ -243,7 +332,7 @@
this.certDB = this.setupCertDB();
this.certEngine = new CertificateEngine(this.properties,
this.csrPolicyList, this.handleGenerator, this.sng, this.certDB);
this.saslSecLayerProperties = this.setupSaslSecurityLayer();
- this.tlsConfig = this.setupTLS();
+ this.tlsConfig = this.setupTLS();
}


@@ -255,33 +344,38 @@
* @see org.apache.commons.daemon.Demon#start()
*/
public void start() throws Exception {
-
- logger.info("listening on: " + hostName + ":" + hostPort);
-
+
logger.info("Obtaining credentials...");
TextCallbackHandler cbh = new TextCallbackHandler();
Subject subj = Util.jaasLogin(cbh);
logger.info("got credentials.");
logger.debug(subj);
+
+ // listen on all addresses for which we're configured
+ InetAddress[] listeningAddresses =
InetAddress.getAllByName(this.hostName);
+ if (listeningAddresses == null || listeningAddresses.length == 0) {
+ logger.fatal("Unable to resolve IP addresses for " +
this.hostName);
+ throw new Exception("Unable to resolve IP addresses for " +
this.hostName);
+ }
+
+ // Allocate one thread per IP address on which we'll listen.
+ this.listeningThreads = new
ArrayList<Thread>(listeningAddresses.length);
+ this.listeningRunnables = new
ArrayList<ListenerThreadRunnable>(listeningAddresses.length);
+
+ for (InetAddress address : listeningAddresses) {
+
+ ListenerThreadRunnable r = new ListenerThreadRunnable(address,
this.hostPort, cbh, subj);
+ listeningRunnables.add(r);
+
+ Thread t = new Thread(r, "listener thread for " +
address.getHostAddress());
+ listeningThreads.add(t);
+ t.start();
+ }

// create a new thread for the shutdown socket's accept loop
Thread shutdownThread = new Thread(new ShutdownThreadRunner(),
"shutdownsocket listener");
shutdownThread.setDaemon(true);
shutdownThread.start();
-
- this.serverSocket = new ServerSocket();
- serverSocket.bind(new InetSocketAddress(this.hostName,
this.hostPort));
- Socket connection;
-
- // loop, accepting connections
- while (true) {
-
- connection = this.serverSocket.accept();
- ServerConnectionHandler sch = new
ServerConnectionHandler(connection, subj, cbh,
- this.hostName, this.mechanisms, this.certEngine,
this.principalMappers,
- this.tlsConfig, this.saslSecLayerProperties);
- this.threadpool.execute(sch);
- }
}


@@ -289,9 +383,7 @@
* Dummy constructor used by reflection
*/
public sasl_ca_server() {
- // this is needed since the standard java JCE's don't handle
- // oid 1.2.840.113549.1.1.1 (RSA)
- Security.addProvider(new CDCStandardProvider());
+
}


@@ -302,7 +394,11 @@
*/
public synchronized void stop() throws Exception {

- this.serverSocket.close();
+ // stop accepting connections on all serversockets.
+ for (ListenerThreadRunnable r : listeningRunnables) {
+ r.stopAcceptingConnections();
+ }
+
this.threadpool.shutdown();
logger.info("waiting up to 30 seconds to for queued requests to
finish processing.");
this.threadpool.awaitTermination(30, TimeUnit.SECONDS);
@@ -318,6 +414,14 @@

// cleanly shutdown internal resources

+ for (ListenerThreadRunnable r : listeningRunnables) {
+ try {
+ r.closeServerSocket();
+ } catch (IOException ex) {
+ logger.error("Error shutting down a listener thread", ex);
+ }
+ }
+
this.certDB.dispose();
this.certEngine.dispose();
this.sng.dispose();
@@ -419,9 +523,7 @@
}
}

- System.out.println("cipherKeyAlias: "+cipherKeyAlias+"
ks.containsAlias: "+ks.containsAlias(cipherKeyAlias)+ " cipherKeyPassword:
"+cipherKeyPassword);
- Key k=ks.getKey(cipherKeyAlias, cipherKeyPassword.toCharArray());
- SecretKey cipherKey = (SecretKey)k;
+ SecretKey cipherKey = (SecretKey)ks.getKey(cipherKeyAlias,
cipherKeyPassword.toCharArray());
SecretKey macKey = (SecretKey)ks.getKey(macKeyAlias,
macKeyPassword.toCharArray());

return new CryptoShibHandle(cipherAlgorithm, cipherProvider,
cipherKey,
@@ -970,7 +1072,7 @@

String hostname =
properties.get(MandatoryPropertyNames.SASLCA_HOSTNAME);

- CertificationRequest csr =
ClientProtocolHandler.generateCSR(StringConstants.peerserverCertIdentifier
+ CertificationRequest csr =
NewClientProtocolHandler.generateCSR(StringConstants.peerserverCertIdentifier
+ hostname, kp, StringConstants.starttlsSignatureAlgorithm);

ArrayList<String> altNames = new ArrayList<String>();
@@ -1002,59 +1104,7 @@
return cred;
}

- /**
- * Make a new cert for clients
- *
- * @param keystore The SASL-CA keystore
- * @param keystoreFile Backing file for keystore
- * @param keyStorePassword Password for keystoreFile
- *
- */
- private void makeClientStartTLSCert(String alias,String
keystoreName,String hostname,char[] keyStorePassword) throws Exception {
-
- FileInputStream file_is = new FileInputStream(keystoreName);
-
- KeyStore keyStore = KeyStore.getInstance("JCEKS");
-
- keyStore.load(file_is, keyStorePassword);
-
- file_is.close();

- KeyPair kp =
Util.generateKeyPair(StringConstants.starttlsKeyAlgorithm,
- StringConstants.starttlsKeySize);
-
- X509Credential cred = new X509Credential();
- cred.key = kp.getPrivate();
-
- CertificationRequest csr =
ClientProtocolHandler.generateCSR(StringConstants.peerserverCertIdentifier
- + hostname, kp, StringConstants.starttlsSignatureAlgorithm);
-
- ArrayList<String> altNames = new ArrayList<String>();
- altNames.add(hostname);
- String s = properties.get(OptionalPropertyNames.STARTTLS_ALTNAMES);
- if (s != null) {
- altNames.addAll(Arrays.asList(s.trim().split(" ")));
- }
-
- X509Certificate[] certChain = this.certEngine.createCertificate(csr,
CertType.peerserver,
- "sasl-ca-starttls", new InetAddress[] {
InetAddress.getLocalHost() },
- altNames.toArray(new String[altNames.size()]));
-
- cred.certChain = certChain;
-
- logger.info("generated new STARTTLS cert");
-
- // store the newly made cert into the master (on-disk) keystore
- keyStore.setKeyEntry(alias, cred.key, alias.toCharArray(), certChain);
-
- FileOutputStream fos = new FileOutputStream(keystoreName);
- try {
- keyStore.store(fos, keyStorePassword);
- } finally {
- fos.close();
- }
- }
-
/**
* Extract the signing cert from the keystore
*
@@ -1141,7 +1191,7 @@

public ShutdownThreadRunner() throws IOException,
UnknownHostException {

- InetAddress localhost = InetAddress.getByAddress(Util.LOCALHOST);
+ InetAddress localhost = InetAddress.getLocalHost();
SocketAddress addr = new InetSocketAddress(localhost, 8804);

ServerSocket shutdownSocket = new ServerSocket();

Modified: branches/saslca/src/edu/psu/sasl_ca/certdb/CertDB.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/certdb/CertDB.java 2008-06-06
21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/certdb/CertDB.java 2008-06-08
08:42:37 UTC (rev 3973)
@@ -77,14 +77,14 @@
/**
* Log that a cert was issued.
*
- * @param cert The cert that was issued.
+ * @param certChain The cert chain that was issued. The first element in
the array should be the end-entity cert.
* @param username The username to whom the cert was issues
* @param addr The IP address/hostname from where the CSR came.
* @param type The cert type.
*
* @throws CertDBException On any error.
*/
- public void log(final X509Certificate cert, final String username,
+ public void log(final X509Certificate[] cert, final String username,
final InetAddress addr, final CertType type) throws
CertDBException;



Modified:
branches/saslca/src/edu/psu/sasl_ca/certdb/provider/BerkeleyCertDB.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/certdb/provider/BerkeleyCertDB.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/certdb/provider/BerkeleyCertDB.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -46,8 +46,6 @@
package edu.psu.sasl_ca.certdb.provider;


-import com.sleepycat.je.CursorConfig;
-import edu.psu.sasl_ca.certdb.DatabaseRecord;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
@@ -66,6 +64,7 @@
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;
import com.sleepycat.je.Cursor;
+import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
@@ -365,12 +364,14 @@
*
* @throws CertDBException On any error.
*/
- public void log(final X509Certificate cert, final String username, final
InetAddress addr, final CertType type) throws CertDBException {
+ public void log(final X509Certificate[] certChain, final String
username, final InetAddress addr, final CertType type) throws CertDBException
{

- if (cert == null) {
+ if (certChain == null || certChain.length == 0) {
return;
}

+ X509Certificate cert = certChain[0];
+
Transaction tx = null;
DatabaseRecord record = null;


Modified: branches/saslca/src/edu/psu/sasl_ca/certdb/provider/RawCertDB.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/certdb/provider/RawCertDB.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/certdb/provider/RawCertDB.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -135,19 +135,21 @@
/**
* Log that a cert was issued.
*
- * @param cert The cert that was issued.
+ * @param certChain The cert chain that was issued.
* @param username The username to whom the cert was issued
* @param addr The IP address/hostname from where the CSR came.
* @param type The Cert Type (identity, opaque, etc)
*
* @throws CertDBException On any error.
*/
- public void log(final X509Certificate cert, final String username, final
InetAddress addr, final CertType type) throws CertDBException {
+ public void log(final X509Certificate[] certChain, final String
username, final InetAddress addr, final CertType type) throws CertDBException
{

- if (cert == null) {
+ if (certChain == null || certChain.length == 0) {
return;
}

+ X509Certificate cert = certChain[0];
+
logger.info("Logging record of certificate number " +
cert.getSerialNumber());

String path = this.loggingPath + File.separatorChar +
cert.getSerialNumber();

Modified:
branches/saslca/src/edu/psu/sasl_ca/certdb/provider/TextSummaryCertDB.java
===================================================================
---
branches/saslca/src/edu/psu/sasl_ca/certdb/provider/TextSummaryCertDB.java
2008-06-06 21:45:48 UTC (rev 3972)
+++
branches/saslca/src/edu/psu/sasl_ca/certdb/provider/TextSummaryCertDB.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -118,9 +118,15 @@
return new DatabaseRecord[0];
}

-
- public void log(final X509Certificate cert, final String username, final
InetAddress addr, final CertType type) {
+ /** @{inheritDoc} */
+ public void log(final X509Certificate[] certChain, final String
username, final InetAddress addr, final CertType type) {

+ if (certChain == null || certChain.length == 0) {
+ return;
+ }
+
+ X509Certificate cert = certChain[0];
+
String dateString = cert.getNotBefore().toString();
String typeString = type.name();
String addrString = (addr == null ? "" : addr.toString());

Modified: branches/saslca/src/edu/psu/sasl_ca/util/OptionalPropertyNames.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/util/OptionalPropertyNames.java
2008-06-06 21:45:48 UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/util/OptionalPropertyNames.java
2008-06-08 08:42:37 UTC (rev 3973)
@@ -129,7 +129,7 @@
/** The prefix for eduGAIN cert DNs. */
public static final String CERT_EDUGAIN_COMPONENT_PREFIX =
EDUGAIN_PREFIX + "ComponentPrefix";

- /** */
- public static final String CERT_EDUGAIN_SUBJECT_PREFIX = EDUGAIN_PREFIX
+ "SubjectPrefix";
+ /** The name of the eduGAIN federation. */
+ public static final String CERT_EDUGAIN_FEDERATION_NAME = EDUGAIN_PREFIX
+ "Federation";

}

Modified: branches/saslca/src/edu/psu/sasl_ca/util/Util.java
===================================================================
--- branches/saslca/src/edu/psu/sasl_ca/util/Util.java 2008-06-06 21:45:48
UTC (rev 3972)
+++ branches/saslca/src/edu/psu/sasl_ca/util/Util.java 2008-06-08 08:42:37
UTC (rev 3973)
@@ -68,11 +68,14 @@
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;
+
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginContext;
+
import codec.Base64;
import codec.pkcs10.CertificationRequest;
+
import org.apache.log4j.Logger;

/**
@@ -92,10 +95,6 @@
private static String PrngProvider = null;
private static String PrngAlgorithm = null;

- // localhost
- public static final byte[] LOCALHOST = new byte[]{127, 0, 0, 1};
-
-
/** Don't instantiate this class. All of its method are static. */
private Util() {
}



  • perfsonar: r3973 - in branches/saslca/src/edu/psu/sasl_ca: . apps/client apps/server certdb certdb/provider util, svnlog, 06/08/2008

Archive powered by MHonArc 2.6.16.

Top of Page