Index: java/net/deterlab/abac/GENIPrivCredential.java
===================================================================
--- java/net/deterlab/abac/GENIPrivCredential.java	(revision dd5d4d99a6f095d2f6cd56a52f81285c4517b0b3)
+++ java/net/deterlab/abac/GENIPrivCredential.java	(revision dd5d4d99a6f095d2f6cd56a52f81285c4517b0b3)
@@ -0,0 +1,239 @@
+package net.deterlab.abac;
+
+import java.io.*;
+import java.math.*;
+import java.text.*;
+
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+
+import javax.security.auth.x500.*;
+
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+
+import javax.xml.crypto.*;
+import javax.xml.crypto.dsig.*;
+import javax.xml.crypto.dsig.dom.*;
+import javax.xml.crypto.dsig.keyinfo.*;
+import javax.xml.crypto.dsig.spec.*;
+
+import org.xml.sax.*;
+import org.w3c.dom.*;
+
+import org.bouncycastle.asn1.*;
+import org.bouncycastle.asn1.x509.*;
+import org.bouncycastle.x509.*;
+import org.bouncycastle.x509.util.*;
+import org.bouncycastle.openssl.*;
+
+/**
+ * An ABAC credential formatted as an abac-type GENI credential.
+ * @author <a href="http://abac.deterlab.net">ISI ABAC team</a>
+ * @version 1.4
+ */
+public class GENIPrivCredential extends GENICredential {
+    /**
+     * Create an empty Credential.
+     */
+    public GENIPrivCredential() {
+	m_head = m_tail = null;
+	doc = null;
+	id = null;
+    }
+    /**
+     * Create a credential from a head and tail role.  This credential has no
+     * underlying certificate, and cannot be exported or used in real proofs.
+     * make_cert can create a certificate for a credential initialized this
+     * way.
+     * @param head the Role at the head of the credential
+     * @param tail the Role at the tail of the credential
+     */
+    public GENIPrivCredential(Role head, Role tail, Document d, Identity i) {
+        m_head = head;
+        m_tail = tail;
+	doc = null; 
+	id = null;
+    }
+
+    /**
+     * Create a certificate from this credential issued by the given identity.
+     * This is the signed XML ABAC credential.
+     * @param i the Identity that will issue the certificate
+     * @throws ABACException if xml creation fails
+     * @throws MissingIssuerException if the issuer is bad
+     * @throws BadSignatureException if the signature creation fails
+     */
+    public void make_cert(Identity i) 
+	    throws ABACException {
+	throw new ABACException("Cannot generate a GENIPrivCredential");
+    }
+
+    static public class GENIPrivSpecialization 
+	    extends CredentialFactorySpecialization {
+
+	protected Identity nodeToIdentity(Node n) {
+	    String certStr = null;
+
+	    if ( ( certStr = n.getTextContent()) == null ) return null;
+	    try {
+		certStr = "-----BEGIN CERTIFICATE-----\n" + 
+		    certStr + 
+		"\n-----END CERTIFICATE-----";
+		return new Identity(new StringReader(certStr));
+	    } 
+	    catch (Exception e) {
+		return null;
+	    }
+	}
+	protected Credential[] make_creds(Document d, Identity issuer) 
+		throws ABACException {
+	    Node root = null;
+	    Node credential = null;
+	    Node owner_gid = null;
+	    Node target_gid = null;
+	    Node privileges = null;
+	    Node priv = null;
+	    Identity owner = null;
+	    Identity target = null;
+	    ArrayList<GENIPrivCredential> rv = 
+		new ArrayList<GENIPrivCredential>();
+
+
+	    if ( (root = getChildByName(d, "signed-credential")) == null)
+		throw new CertInvalidException("No signed-credential element");
+	    if ( (credential = getChildByName(root, "credential")) == null )
+		throw new CertInvalidException("No credential element");
+	    if ( (owner_gid = getChildByName(credential, "owner_gid")) == null )
+		throw new CertInvalidException("No owner_gid element");
+	    if ((target_gid = getChildByName(credential,"target_gid")) == null )
+		throw new CertInvalidException("No target_gid element");
+	    if ((privileges = getChildByName(credential,"privileges")) == null )
+		throw new CertInvalidException("No privileges element");
+
+	    if ( (owner = nodeToIdentity(owner_gid)) == null) 
+		throw new CertInvalidException("Bad owner_gid element");
+	    if ( (target = nodeToIdentity(target_gid)) == null) 
+		throw new CertInvalidException("Bad target_gid element");
+
+	    for (Node n = privileges.getFirstChild(); n != null; 
+		    n = n.getNextSibling()) {
+		if (n.getNodeType() != Node.ELEMENT_NODE ||
+			!"privilege".equals(n.getNodeName()))
+		    throw new CertInvalidException(
+			    "Child of privileges not privilege?");
+		Node name = null;
+		Node can_delegate = null;
+		boolean cd = false;
+		String cds = null;
+		String pname = null;
+
+		if ( (name = getChildByName(n, "name")) == null)
+		    throw new CertInvalidException("No privilege name");
+
+		if ((can_delegate = getChildByName(n, "can_delegate")) == null)
+		    throw new CertInvalidException("No privilege delegate");
+
+		if ( (pname = name.getTextContent()) == null)
+		    throw new CertInvalidException("No privilege name text");
+		if ((cds = name.getTextContent()) == null)
+		    throw new CertInvalidException("No delegate text");
+		cd = cds.equals("1") || cds.equals("true");
+
+		if ( rv.isEmpty() ) {
+		    rv.add(new GENIPrivCredential(
+				new Role(issuer.getKeyID() + ".speaks_for_" +
+				    owner.getKeyID()),
+				new Role(owner.getKeyID()), d, issuer));
+		    rv.add(new GENIPrivCredential(
+				new Role(issuer.getKeyID() + ".speaks_for_" +
+				    owner.getKeyID()),
+				new Role(owner.getKeyID() + ".speaks_for_" +
+				    owner.getKeyID()), d, issuer));
+		}
+		rv.add(new GENIPrivCredential(
+			    new Role(issuer.getKeyID() + "." + pname + "_" +
+				target.getKeyID()),
+			    new Role(issuer.getKeyID() + ".speaks_for_" +
+				owner.getKeyID()), d, issuer));
+		if (cd ) {
+		    rv.add(new GENIPrivCredential(
+				new Role(issuer.getKeyID() + "." + pname + 
+				    "_" + target.getKeyID()),
+				new Role(issuer.getKeyID() + ".can_delegate_" 
+				    + pname + "_" + target.getKeyID() + 
+				    "." + pname + "_" + target.getKeyID()), 
+				d, issuer));
+		    rv.add(new GENIPrivCredential(
+				new Role(issuer.getKeyID() + 
+				    ".can_delegate_" + pname),
+				new Role(owner.getKeyID()), d, issuer));
+		}
+	    }
+	    return rv.toArray(new Credential[rv.size()]);
+	}
+
+	public Credential[] parseCredential(InputStream is, 
+		Collection<Identity> ids) throws ABACException {
+	    try {
+		Document d = read_certificate(is);
+		XMLSignatureFactory fac = 
+		    XMLSignatureFactory.getInstance("DOM");
+		NodeList nl = d.getElementsByTagNameNS(XMLSignature.XMLNS, 
+			"Signature");
+		DOMValidateContext valContext = null;
+		XMLSignature signature = null;
+		Identity lid = null;
+
+
+		if (nl.getLength() == 0) 
+		    throw new CertInvalidException(
+			    "Cannot find Signature element");
+
+		setIDAttrs(d);
+		valContext = new DOMValidateContext(new X509KeySelector(),
+			nl.item(0));
+		if ( valContext == null )
+		    throw new ABACException("No validation context!?");
+
+		signature = fac.unmarshalXMLSignature(valContext);
+		if (signature == null) 
+		    throw new BadSignatureException(
+			    "Cannot unmarshal signature");
+
+		if (!signature.validate(valContext))
+		    throw new BadSignatureException("bad signature");
+
+		lid = getIdentity(nl.item(0));
+
+		if ( !ids.contains(lid) ) ids.add(lid);
+
+	    }
+	    catch (ABACException ae) {
+		throw ae;
+	    }
+	    catch (Exception e) {
+		throw new BadSignatureException(e.getMessage(), e);
+	    }
+	    return null;
+	}
+
+	public Credential generateCredential(Role head, Role tail) {
+	    return null;
+	}
+    };
+
+    /**
+     * Return a CredentialCredentialFactorySpecialization for GENICredentials.
+     * Used by the CredentialFactory to parse and generate these kind of
+     * credentials.  It basically wraps constuctor calls.
+     * @return a CredentialFactorySpecialization for this kind of credential.
+     */
+    static public CredentialFactorySpecialization 
+	    getCredentialFactorySpecialization() {
+	return new GENIPrivSpecialization();
+    }
+}
