Index: java/net/deterlab/abac/Credential.java
===================================================================
--- java/net/deterlab/abac/Credential.java	(revision f0ae3d832dd26f4cb484091adf33a82c29438008)
+++ java/net/deterlab/abac/Credential.java	(revision 42ca4b8b7c93afe5516430d6d6163a14567e97df)
@@ -229,5 +229,7 @@
 		throws IOException {
 	Vector<Credential> creds = new Vector<Credential>();
-	Vector<ZipEntry> derFiles = new Vector<ZipEntry>();
+	Vector<ZipEntry> derEntries = new Vector<ZipEntry>();
+	Map<String, Identity> ids = new TreeMap<String, Identity>();
+	Map<String, KeyPair> kps = new TreeMap<String, KeyPair>();
 
 	ZipFile z = new ZipFile(zf);
@@ -236,29 +238,42 @@
 		ze.hasMoreElements();) {
 	    ZipEntry  f = ze.nextElement();
-	    Object o = null;
 	    try {
-		o = new PEMReader(new InputStreamReader(
-			    z.getInputStream(f))).readObject();
-	    }
-	    catch (IOException e) { 
-		// PEMReader couldn't deal, so we assume it's a DER
-		derFiles.add(f);
-		continue;
-	    }
-	    try {
-		if ( o == null ) {
-		    // This shouldn't be, but assume it's a DER
-		    derFiles.add(f);
-		}
-		else if (o instanceof X509CertificateObject) {
-		    Credential.addIdentity(
-			    new Identity((X509CertificateObject)o));
-		}
-		else if (o instanceof KeyPair ) {
-		    if ( keys != null ) keys.add((KeyPair) o);
+		PEMReader r = new PEMReader(
+			new InputStreamReader(z.getInputStream(f)));
+		Object o = readPEM(r);
+
+		if ( o != null ) {
+		    if (o instanceof Identity) {
+			Identity i = (Identity) o;
+			String kid = i.getKeyID();
+
+			if (kps.containsKey(kid) ) {
+			    i.setKeyPair(kps.get(kid));
+			    kps.remove(kid);
+			}
+			else if (i.getKeyPair() == null ) 
+			    ids.put(i.getKeyID(), i);
+
+			Credential.addIdentity(i);
+		    }
+		    else if (o instanceof KeyPair ) {
+			KeyPair kp = (KeyPair) o;
+			String kid = Identity.extractKeyID(kp.getPublic());
+
+			if (ids.containsKey(kid)) {
+			    Identity i = ids.get(kid);
+
+			    i.setKeyPair(kp);
+			    ids.remove(kid);
+			}
+			else {
+			    kps.put(kid, kp);
+			}
+		    }
 		}
 		else {
-		    throw new IOException("Unexpected PEM object: " + 
-			    o.getClass().getName());
+		    // Not a PEM file
+		    derEntries.add(f);
+		    continue;
 		}
 	    }
@@ -268,5 +283,5 @@
 	}
 
-	for ( ZipEntry f : derFiles ) {
+	for ( ZipEntry f : derEntries ) {
 	    try {
 		creds.add(new Credential(z.getInputStream(f)));
@@ -292,4 +307,40 @@
     }
 
+    protected static Object readPEM(PEMReader r) throws IOException {
+	Identity i = null;
+	KeyPair keys = null;
+	Object o = null;
+
+	while ( (o = r.readObject()) != null ) {
+	    if (o instanceof X509CertificateObject) {
+		if ( i == null ) {
+		    try {
+			i = new Identity((X509CertificateObject)o);
+		    }
+		    catch (Exception e) {
+			// Translate Idenitiy exceptions to IOException
+			throw new IOException(e);
+		    }
+		    if (keys != null ) {
+			i.setKeyPair(keys);
+			keys = null;
+		    }
+		}
+		else throw new IOException("Two certificates");
+	    }
+	    else if (o instanceof KeyPair ) {
+		if ( i != null ) i.setKeyPair((KeyPair) o);
+		else keys = (KeyPair) o;
+	    }
+	    else {
+		throw new IOException("Unexpected PEM object: " + 
+			o.getClass().getName());
+	    }
+	}
+
+	if ( i != null ) return i;
+	else if ( keys != null) return keys;
+	else return null;
+    }
 
     /**
@@ -305,4 +356,6 @@
 	Vector<File> derFiles = new Vector<File>();
 	Collection<File> files = new Vector<File>();
+	Map<String, Identity> ids = new TreeMap<String, Identity>();
+	Map<String, KeyPair> kps = new TreeMap<String, KeyPair>();
 
 	if (d.isDirectory() ) 
@@ -312,28 +365,41 @@
 
 	for (File f: files ) {
-	    Object o = null;
 	    try {
-		o = new PEMReader(new FileReader(f)).readObject();
-	    }
-	    catch (IOException e) { 
-		// PEMReader couldn't deal, so we assume it's a DER
-		derFiles.add(f);
-		continue;
-	    }
-	    try {
-		if ( o == null ) {
-		    // This shouldn't be, but assume it's a DER
+		PEMReader r = new PEMReader(new FileReader(f));
+		Object o = readPEM(r);
+
+		if ( o != null ) {
+		    if (o instanceof Identity) {
+			Identity i = (Identity) o;
+			String kid = i.getKeyID();
+
+			if (kps.containsKey(kid) ) {
+			    i.setKeyPair(kps.get(kid));
+			    kps.remove(kid);
+			}
+			else if (i.getKeyPair() == null ) 
+			    ids.put(i.getKeyID(), i);
+
+			Credential.addIdentity(i);
+		    }
+		    else if (o instanceof KeyPair ) {
+			KeyPair kp = (KeyPair) o;
+			String kid = Identity.extractKeyID(kp.getPublic());
+
+			if (ids.containsKey(kid)) {
+			    Identity i = ids.get(kid);
+
+			    i.setKeyPair(kp);
+			    ids.remove(kid);
+			}
+			else {
+			    kps.put(kid, kp);
+			}
+		    }
+		}
+		else {
+		    // Not a PEM file
 		    derFiles.add(f);
-		}
-		else if (o instanceof X509CertificateObject) {
-		    Credential.addIdentity(
-			    new Identity((X509CertificateObject)o));
-		}
-		else if (o instanceof KeyPair ) {
-		    if ( keys != null ) keys.add((KeyPair) o);
-		}
-		else {
-		    throw new IOException("Unexpected PEM object: " + 
-			    o.getClass().getName());
+		    continue;
 		}
 	    }
Index: java/net/deterlab/abac/CredentialGraph.java
===================================================================
--- java/net/deterlab/abac/CredentialGraph.java	(revision f0ae3d832dd26f4cb484091adf33a82c29438008)
+++ java/net/deterlab/abac/CredentialGraph.java	(revision 42ca4b8b7c93afe5516430d6d6163a14567e97df)
@@ -39,25 +39,4 @@
 
     /**
-     * Add a role to the graph./
-     */
-    public void add_vertex(Role role) {
-        g.addVertex(role);
-    }
-
-    /**
-     * Remove a role from the grpah if it exists.
-     */
-    public void remove_vertex(Role role) {
-        g.removeVertex(role);
-    }
-
-    /**
-     * Get a list of all roles known to the graph.
-     */
-    public Collection<Role> roles() {
-        return g.getVertices();
-    }
-
-    /**
      * Add a credential to the graph.
      */
Index: java/net/deterlab/abac/Identity.java
===================================================================
--- java/net/deterlab/abac/Identity.java	(revision f0ae3d832dd26f4cb484091adf33a82c29438008)
+++ java/net/deterlab/abac/Identity.java	(revision 42ca4b8b7c93afe5516430d6d6163a14567e97df)
@@ -23,4 +23,5 @@
     private String m_keyid;
     private String m_cn;
+    private KeyPair kp;
 
     /**
@@ -29,13 +30,22 @@
      */
     protected void init(Reader r) throws 
-	CertificateException, NoSuchAlgorithmException,InvalidKeyException,
-	NoSuchProviderException, SignatureException, IOException {
-	    PEMReader pr = new PEMReader(r);
-	    Object c = pr.readObject();
-
-	    if (c instanceof X509CertificateObject) 
-		init((X509CertificateObject)c);
+	    CertificateException, NoSuchAlgorithmException,InvalidKeyException,
+	    NoSuchProviderException, SignatureException, IOException {
+	PEMReader pr = new PEMReader(r);
+	Object c = null;
+
+	while ( ( c= pr.readObject()) != null ){
+
+	    if (c instanceof X509CertificateObject) {
+		if ( m_cn == null ) 
+		    init((X509CertificateObject)c);
+		else
+		    throw new CertificateException("Two certs in one file");
+	    }
+	    else if (c instanceof KeyPair) setKeyPair((KeyPair)c);
 	    else 
-		throw new CertificateException("Not an identity certificate");
+		throw new CertificateException(
+			"Not an identity certificate");
+	}
     }
 
@@ -64,6 +74,6 @@
 	    CertificateException, NoSuchAlgorithmException,InvalidKeyException,
 	    NoSuchProviderException, SignatureException, IOException {
-	KeyPair kp = KeyPairGenerator.getInstance("RSA").genKeyPair();
 	X509V1CertificateGenerator gen = new X509V1CertificateGenerator();
+	kp = KeyPairGenerator.getInstance("RSA").genKeyPair();
 
 	gen.setIssuerDN(new X500Principal("CN=" + cn));
@@ -75,5 +85,6 @@
 	gen.setPublicKey(kp.getPublic());
 	gen.setSignatureAlgorithm("SHA256WithRSAEncryption");
-	X509CertificateObject a = (X509CertificateObject) gen.generate(kp.getPrivate());
+	X509CertificateObject a = 
+	    (X509CertificateObject) gen.generate(kp.getPrivate());
 	init(a);
     }
@@ -87,5 +98,8 @@
 	CertificateException, NoSuchAlgorithmException,InvalidKeyException,
 	NoSuchProviderException, SignatureException, FileNotFoundException,
-	IOException { init(new FileReader(file)); }
+	IOException { 
+	    kp = null;
+	    init(new FileReader(file));
+	}
 
     /**
@@ -94,5 +108,8 @@
     public Identity(Reader r) throws 
 	CertificateException, NoSuchAlgorithmException,InvalidKeyException,
-	NoSuchProviderException, SignatureException, IOException { init(r); }
+	NoSuchProviderException, SignatureException, IOException {
+	    kp = null;
+	    init(r);
+	}
 
     /**
@@ -102,4 +119,5 @@
 	CertificateException, NoSuchAlgorithmException,InvalidKeyException,
 	NoSuchProviderException, SignatureException, IOException { 
+	    kp = null;
 	    init(new InputStreamReader(s));
 	}
@@ -112,5 +130,8 @@
 	CertificateException, NoSuchAlgorithmException,InvalidKeyException,
 	NoSuchProviderException, SignatureException, FileNotFoundException,
-	IOException { init(cert); }
+	IOException { 
+	    kp = null;
+	    init(cert);
+	}
 
 
@@ -174,5 +195,28 @@
     public String getKeyID() { return m_keyid; }
     public String getName() { return m_cn; }
-    public String toString() { return m_keyid + " (" + m_cn + ")"; }
+    public String toString() { 
+	String s = m_keyid + " (" + m_cn ;
+
+	if (m_keyid != null ) s += " [keyed]";
+	s += ")";
+	return s;
+    }
+    /**
+     * Associate a keypair with this Identity.  If the ID has a certificate,
+     * make sure that the keypair matches it.  If not throw an
+     * IllegalArgumentException.
+     */
+    public void setKeyPair(KeyPair k) {
+	if (m_keyid != null) {
+	    String kid = extractKeyID(k.getPublic());
+
+	    if ( kid != null && kid.equals(m_keyid)) kp = k;
+	    else 
+		throw new IllegalArgumentException(
+			"Keypair does not match certificate");
+	}
+	else kp = k;
+    }
+    public KeyPair getKeyPair() { return kp; }
     public boolean equals(Object o) { 
 	if ( o == null ) return false;
