Index: java/net/deterlab/abac/GENICredential.java
===================================================================
--- java/net/deterlab/abac/GENICredential.java	(revision 7f16578c6fae234708054ac88d5bccdf57800f14)
+++ java/net/deterlab/abac/GENICredential.java	(revision 797bebe2efe124193658b4872505d50276554e78)
@@ -48,4 +48,51 @@
     protected Identity id;
 
+
+    /**
+     * Keyselector implementation from the web
+     */
+    protected class X509KeySelector extends KeySelector {
+	public KeySelectorResult select(KeyInfo keyInfo,
+					KeySelector.Purpose purpose,
+					AlgorithmMethod method,
+					XMLCryptoContext context)
+	    throws KeySelectorException {
+	    Iterator ki = keyInfo.getContent().iterator();
+	    while (ki.hasNext()) {
+		XMLStructure info = (XMLStructure) ki.next();
+		if (!(info instanceof X509Data))
+		    continue;
+		X509Data x509Data = (X509Data) info;
+		Iterator xi = x509Data.getContent().iterator();
+		while (xi.hasNext()) {
+		    Object o = xi.next();
+		    if (!(o instanceof X509Certificate))
+			continue;
+		    final PublicKey key = ((X509Certificate)o).getPublicKey();
+		    // Make sure the algorithm is compatible
+		    // with the method.
+		    if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
+			return new KeySelectorResult() {
+			    public Key getKey() { return key; }
+			};
+		    }
+		}
+	    }
+	    throw new KeySelectorException("No key found!");
+	}
+
+	boolean algEquals(String algURI, String algName) {
+	    if ((algName.equalsIgnoreCase("DSA") &&
+		algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) ||
+		(algName.equalsIgnoreCase("RSA") &&
+
+		algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1))) {
+		return true;
+	    } else {
+		return false;
+	    }
+	}
+    }
+
     /**
      * Create an empty Credential.
@@ -86,7 +133,9 @@
 	    throw new IOException("Cannot get DocumentBuilderFactory!?");
 	try {
+	    dbf.setNamespaceAware(true);
 	    if ( (db = dbf.newDocumentBuilder()) == null ) 
 		throw new IOException("Cannot get DocumentBuilder!?");
 	    doc = db.parse(stream);
+	    doc.normalizeDocument();
 	}
 	catch (IllegalArgumentException ie) {
@@ -100,4 +149,75 @@
 	}
 
+    }
+
+    /**
+     * Walk the document and set all instances of an xml:id attribute to be ID
+     * attributes in terms of the java libraries.  This is needed for the
+     * signature code to find signed subsections.  The "xml:id" is treated as
+     * both a namespace free ID with a colon and as an "id" identifier in the
+     * "xml" namespace so we don't miss it.
+     * @param n the root of the document to mark
+     */
+    static protected void setIDAttrs(Node n) {
+	if ( n.getNodeType() == Node.ELEMENT_NODE) {
+	    Element e = (Element) n;
+	    String id = e.getAttribute("xml:id");
+
+	    if ( id != null && id.length() > 0 )
+		e.setIdAttribute("xml:id", true);
+
+	    id = e.getAttributeNS("xml", "id");
+	    if ( id != null && id.length() > 0 )
+		e.setIdAttributeNS("xml", "id", true);
+	}
+
+	for (Node nn = n.getFirstChild(); nn != null; nn = nn.getNextSibling())
+	    setIDAttrs(nn);
+    }
+
+    /**
+     * Return the child of Node n  that has the given name, if there is one.
+     * @param n a Node to search
+     * @param name the name to search for
+     * @return a Node with the name, may be null
+     */
+    static protected Node getChildByName(Node n, String name) {
+	if (name == null ) return null;
+
+	for (Node nn = n.getFirstChild(); nn != null; nn = nn.getNextSibling())
+	    if ( nn.getNodeType() == Node.ELEMENT_NODE && 
+		    name.equals(nn.getNodeName())) return nn;
+	return null;
+    }
+
+    /**
+     * Find the X509Certificate in the Signature element and convert it to an
+     * ABAC identity.  This assumes a KeyInfo in that section holding an
+     * X509Data section containing the certificate in an X509Certificate
+     * section.  Any of that not being found will cause a failure.  If the
+     * Identity cannot be created a Gignature exception is thrown.
+     * @param n a Node pointing to a Signature section
+     * @return an Identity constructed frm the X509 Certificate
+     * @throws SignatureException if the Identity cannot be created from the
+     * certificate.
+     */
+    static protected Identity getIdentity(Node n) throws SignatureException {
+	Identity rv = null;
+	Node nn = getChildByName(n, "KeyInfo");
+	String certStr = null;
+
+	if ( nn == null ) return null;
+	if ( ( nn = getChildByName(nn, "X509Data")) == null ) return null;
+	if ( ( nn = getChildByName(nn, "X509Certificate")) == null ) return null;
+	if ( ( certStr = nn.getTextContent()) == null ) return null;
+	try {
+	    certStr = "-----BEGIN CERTIFICATE-----\n" + 
+		certStr + 
+		"\n-----END CERTIFICATE-----";
+	    return new Identity(new StringReader(certStr));
+	} 
+	catch (Exception e) {
+	    throw new SignatureException(e.getMessage());
+	}
     }
 
@@ -124,8 +244,7 @@
 	XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
 	NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, 
-		"Signature");
+	 	"Signature");
 	DOMValidateContext valContext = null;
 	XMLSignature signature = null;
-	boolean isValid = false;
 
 	try {
@@ -134,7 +253,7 @@
 		throw new SignatureException("Cannot find Signature element");
 
-	    // XXX: need a javax.xml.crypto.KeySelector  we'll probably have to
-	    // parse the certificate in teh sig and use singletonKeySelector
-	    valContext = new DOMValidateContext((KeySelector) null, nl.item(0));
+	    setIDAttrs(doc);
+	    valContext = new DOMValidateContext(new X509KeySelector(),
+		    nl.item(0));
 	    if ( valContext == null )
 		throw new SignatureException("No context");
@@ -145,7 +264,11 @@
 
 	    if (!signature.validate(valContext))
-		throw new SignatureException("bag signature");
+		throw new SignatureException("bad signature");
 
 	    load_roles();
+
+	    id = getIdentity(nl.item(0));
+
+	    if ( !ids.contains(id) ) ids.add(id);
 
 	    if (!id.getKeyID().equals(m_head.principal()))
@@ -294,5 +417,6 @@
 
 	    SignedInfo si = fac.newSignedInfo(
-		    fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
+		    fac.newCanonicalizationMethod(
+			CanonicalizationMethod.INCLUSIVE,
 			(C14NMethodParameterSpec) null),
 		    fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
@@ -319,18 +443,31 @@
 	    doc.appendChild(root);
 	    Element cred = doc.createElement("credential");
-	    Element sig = doc.createElement("credential");
+	    Element sig = doc.createElement("signatures");
+	    Element e = doc.createElement("type");
+	    Node text = doc.createTextNode("abac");
+
 	    cred.setAttributeNS("xml", "id", "ref0");
 	    root.appendChild(cred);
-	    cred.appendChild(doc.createElement("type").appendChild(
-			doc.createTextNode("abac")));
+	    e.appendChild(text);
+	    cred.appendChild(e);
+			
 	    df.format(new Date(System.currentTimeMillis() 
 			+ (3600L * 1000L * 24L * 365L)), expBuf, 
 		    new FieldPosition(0));
-	    cred.appendChild(doc.createElement("expires").appendChild(
-			doc.createTextNode(expBuf.toString())));
-	    cred.appendChild(doc.createElement("version").appendChild(
-			doc.createTextNode("1.0")));
-	    cred.appendChild(doc.createElement("rt0").appendChild(
-			doc.createTextNode(m_head + "<-" + m_tail)));
+	    e = doc.createElement("expires");
+	    text = doc.createTextNode(expBuf.toString());
+	    e.appendChild(text);
+	    cred.appendChild(e);
+
+	    e = doc.createElement("version");
+	    text = doc.createTextNode("1.0");
+	    e.appendChild(text);
+	    cred.appendChild(e);
+
+	    e = doc.createElement("rt0");
+	    text = doc.createTextNode(m_head + "<-" + m_tail);
+	    e.appendChild(text);
+	    cred.appendChild(e);
+
 	    root.appendChild(sig);
 
@@ -343,32 +480,4 @@
 	}
 
-	/*
-	PrivateKey key = i.getKeyPair().getPrivate();
-	SubjectPublicKeyInfo pki = Context.extractSubjectPublicKeyInfo(
-		i.getKeyPair().getPublic());
-	X509V2AttributeCertificateGenerator gen = 
-	    new X509V2AttributeCertificateGenerator();
-
-	gen.setIssuer(new AttributeCertificateIssuer(
-		    new X500Principal("CN="+m_head.principal())));
-	gen.setHolder(new AttributeCertificateHolder(
-		    new X500Principal("CN="+m_head.principal())));
-	gen.setNotAfter(new Date(System.currentTimeMillis() 
-		    + (3600L * 1000L * 24L * 365L)));
-	gen.setNotBefore(new Date(System.currentTimeMillis()));
-	gen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
-	gen.addAttribute(new X509Attribute(attrOID, 
-		    new DERSequence(
-			new DERSequence(
-			    new DERUTF8String(toString())))));
-	gen.setSignatureAlgorithm("SHA256WithRSAEncryption");
-
-	// Creddy expects an authority key identifier.
-	gen.addExtension(authKeyOID, false, 
-		new AuthorityKeyIdentifier(pki));
-	// Create the cert.
-	ac = (X509V2AttributeCertificate) gen.generate(key, "BC");
-	id = i;
-	*/
     }
 
