package net.deterlab.abac; import java.io.*; import java.math.*; import java.util.*; import java.util.zip.*; import java.security.*; import java.security.cert.*; import net.deterlab.abac.Identity; import org.bouncycastle.asn1.*; import org.bouncycastle.asn1.x509.*; import org.bouncycastle.x509.*; import org.bouncycastle.jce.X509Principal; import org.bouncycastle.jce.provider.X509AttrCertParser; import org.bouncycastle.jce.provider.X509CertificateObject; import org.bouncycastle.openssl.PEMReader; import java.security.PrivateKey; public class Credential implements Comparable { protected static Vector s_ids = new Vector(); protected static String attrOID = "1.3.6.1.5.5.7.10.4"; protected static String authKeyOID = "2.5.29.35"; /** * 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 read_certificate(InputStream stream) throws Exception { X509AttrCertParser parser = new X509AttrCertParser(); parser.engineInit(stream); m_ac = (X509V2AttributeCertificate)parser.engineRead(); } protected void init(InputStream stream, Collection ids) throws Exception { read_certificate(stream); if (m_ac == null) throw new IOException("Unknown Format"); init(ids); } protected void init(Collection ids) throws CertificateException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException,SignatureException { for (Identity id: 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(); if (!m_id.getKeyID().equals(m_head.issuer_part())) throw new InvalidKeyException("Unknown identity"); } /** * 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, Collection ids) throws Exception { init(new FileInputStream(filename), ids); } /** * 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, Collection ids) throws Exception { init(new FileInputStream(file), ids); } /** * Create a credential from an InputStream. */ public Credential(InputStream s, Collection ids) throws Exception { init(s, ids); } public Credential(X509V2AttributeCertificate c, Collection ids) throws Exception { m_ac = c; init(ids); } /** * Create a certificate from this credential issued by the given identity. * This is just grungy credential generation work. */ public void make_cert(Identity i) { PrivateKey key = i.getKeyPair().getPrivate(); SubjectPublicKeyInfo pki = Identity.extractSubjectPublicKeyInfo( i.getKeyPair().getPublic()); X509V2AttributeCertificateGenerator gen = new X509V2AttributeCertificateGenerator(); gen.setIssuer(new AttributeCertificateIssuer( new X509Principal("CN="+m_head.issuer_part()))); gen.setHolder(new AttributeCertificateHolder( new X509Principal("CN="+m_head.issuer_part()))); gen.setNotAfter(new Date(System.currentTimeMillis() + 3600 * 1000 * 24 * 365)); 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"); try { // Creddy expects an authority key identifier. gen.addExtension(authKeyOID, false, new AuthorityKeyIdentifier(pki)); // Create the cert. m_ac = (X509V2AttributeCertificate) gen.generate(key, "BC"); } catch (Exception e) { System.err.println(e); } } /** * 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]); } /** * Two credentials are the same if their roles are the same. */ public boolean equals(Object o) { if ( o instanceof Credential ) { Credential c = (Credential) o; if (m_head == null || m_tail == null ) return false; else return (m_head.equals(c.head()) && m_tail.equals(c.tail())); } else return false; } public int compareTo(Object o) { if (o instanceof Credential) { Credential c = (Credential) o; if (head().equals(c.head())) return tail().compareTo(c.tail()); else return head().compareTo(c.head()); } else return 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(Context c) { return m_head.simpleString(c) + " <- " + m_tail.simpleString(c); } public void write(OutputStream s) throws IOException { s.write(m_ac.getEncoded()); s.flush(); } public void write(String fn) throws IOException, FileNotFoundException { write(new FileOutputStream(fn)); } public boolean hasCertificate() { return m_ac != null; } public Identity getID() { return m_id; } private Role m_head, m_tail; private X509V2AttributeCertificate m_ac; private Identity m_id; }