package net.deterlab.abac; import java.io.*; import java.util.*; import java.security.*; import java.security.cert.*; import net.deterlab.abac.Identity; import org.bouncycastle.asn1.*; import org.bouncycastle.x509.*; import org.bouncycastle.jce.provider.X509AttrCertParser; import org.bouncycastle.jce.provider.X509CertificateObject; import org.bouncycastle.openssl.PEMReader; public class Credential { protected static Vector s_ids = new Vector(); /** * A dummy credential. */ public Credential() { m_head = m_tail = null; m_ac = null; m_id = null; } /** * Create a credential from a head and tail role. This is only for testing. * In a real implementation the Credential must be loaded from an X.509 * attribute cert. */ public Credential(Role head, Role tail) { m_head = head; m_tail = tail; m_ac = null; m_id = null; } /** * Do the credential initialization from a filename. */ protected void init(InputStream stream) throws Exception { X509AttrCertParser parser = new X509AttrCertParser(); parser.engineInit(stream); m_ac = (X509V2AttributeCertificate)parser.engineRead(); m_id = null; for (Identity id: s_ids) { try { m_ac.verify(id.getCertificate().getPublicKey(), "BC"); m_id = id; break; } catch (InvalidKeyException e) { } } if (m_id == null) throw new InvalidKeyException("Unknown identity"); load_roles(); } /** * Create a credential from an attribute cert. Throws an exception if the * cert file can't be opened or if there's a format problem with the cert. */ public Credential(String filename) throws Exception { init(new FileInputStream(filename)); } /** * Create a credential from an attribute cert. Throws an exception if the * cert file can't be opened or if there's a format problem with the cert. */ public Credential(File file) throws Exception { init(new FileInputStream(file)); } /** * Create a credential from an InputStream. */ public Credential(InputStream s) throws Exception { init(s); } /** * Load the roles off the attribute cert. Throws a RuntimeException if * there's something wrong with the cert. */ private void load_roles() throws RuntimeException { String roles = null; try { X509Attribute attr = m_ac.getAttributes()[0]; DERSequence java = (DERSequence)attr.getValues()[0]; DERSequence fucking = (DERSequence)java.getObjectAt(0); DERUTF8String sucks = (DERUTF8String)fucking.getObjectAt(0); roles = sucks.getString(); } catch (Exception e) { throw new RuntimeException("Your attribute certificate is funky and I'm not gonna debug it", e); } String[] parts = roles.split("\\s*<--?\\s*"); if (parts.length != 2) throw new RuntimeException("Invalid attribute: " + roles); m_head = new Role(parts[0]); m_tail = new Role(parts[1]); } /** * Get the head role from the credential. */ public Role head() { return m_head; } /** * Get the tail role from the credential */ public Role tail() { return m_tail; } /** * Gets the cert associated with this credential (if any). */ public X509V2AttributeCertificate cert() { return m_ac; } /** * Turn the credential into string form. The format is head <- tail. For * example: A.r1 <- B.r2.r3. */ public String toString() { return m_head + " <- " + m_tail; } public String simpleString() { return m_head.simpleString() + " <- " + m_tail.simpleString(); } public void write(OutputStream s) throws IOException { s.write(m_ac.getEncoded()); } public void write(String fn) throws IOException, FileNotFoundException { write(new FileOutputStream(fn)); } public boolean hasCertificate() { return m_ac != null; } private Role m_head, m_tail; private X509V2AttributeCertificate m_ac; private Identity m_id; public static void addIdentity(Identity id) { s_ids.add(id); if (id.getName() != null && id.getKeyID() != null) Role.add_mapping(id.getName(), id.getKeyID()); } public static Collection identities() { return s_ids; } }