source: java/net/deterlab/abac/Credential.java @ 1b88de8

abac0-leakabac0-meicompt_changesgec13mei-idmei-rt0-nmei_rt0mei_rt2mei_rt2_fix_1meiyap-rt1meiyap1rt2tvf-new-xml
Last change on this file since 1b88de8 was e36ea1d, checked in by Ted Faber <faber@…>, 14 years ago

Initial javadocs

  • Property mode set to 100644
File size: 16.2 KB
Line 
1package net.deterlab.abac;
2
3import java.io.*;
4import java.math.*;
5
6import java.util.*;
7import java.security.*;
8import java.security.cert.*;
9
10import javax.security.auth.x500.*;
11
12import org.bouncycastle.asn1.*;
13import org.bouncycastle.asn1.x509.*;
14import org.bouncycastle.x509.*;
15import org.bouncycastle.x509.util.*;
16import org.bouncycastle.openssl.*;
17
18/**
19 * An ABAC credential, with or without an underlying certificate that
20 * represents it.  These are edges in proof garphs and can be constructed from
21 * their constituent Roles.
22 * @author <a href="http://abac.deterlab.net">ISI ABAC team</a>
23 * @version 1.3
24 */
25public class Credential implements Comparable {
26    /** The ASN1 OID for an IETF attribute. */
27    protected static String attrOID = "1.3.6.1.5.5.7.10.4";
28    /** The ASN1 OID for AuthorityKeyIdentifier. */
29    protected static String authKeyOID = "2.5.29.35";
30
31    /** The role at the head */
32    protected Role m_head
33    /** The role at the tail */;
34    protected Role m_tail;
35    /** The certificate representing this credential */
36    protected X509V2AttributeCertificate ac;
37    /** The identity that issued the certificate */
38    protected Identity id;
39
40    /**
41     * Create an empty Credential.
42     */
43    public Credential() {
44        m_head = m_tail = null;
45        ac = null;
46        id = null;
47    }
48    /**
49     * Create a credential from a head and tail role.  This credential has no
50     * underlying certificate, and cannot be exported or used in real proofs.
51     * make_cert can create a certificate for a credential initialized this
52     * way.
53     * @param head the Role at the head of the credential
54     * @param tail the Role at the tail of the credential
55     */
56    public Credential(Role head, Role tail) {
57        m_head = head;
58        m_tail = tail;
59        ac = null; 
60        id = null;
61    }
62
63    /**
64     * Do the credential extraction from an input stream.  This parses the
65     * certificate from the input stream and saves it. The contents must be
66     * validated and parsed later.
67     * @param stream the InputStream to read the certificate from.
68     * @throws IOException if the stream is unparsable
69     */
70    protected void read_certificate(InputStream stream) 
71            throws IOException {
72        ac = new X509V2AttributeCertificate(stream);
73    }
74
75    /**
76     * Initialize a credential from parsed certificate.  Validiate it against
77     * the given identities and parse out the roles.  Note that catching
78     * java.security.GeneralSecurityException catches most of the exceptions
79     * this throws.
80     * @param ids a Collection of Identities to use in validating the cert
81     * @throws CertificateException if the certificate is badly formatted
82     * @throws InvalidKeyException if none of the Identities can validate the
83     *                              certificate
84     * @throws NoSuchAlgorithmException if the credential uses an unknown
85     *                              signature algorithm
86     * @throws NoSuchProviderException if the provider of the signature
87     *                              algorithm is unavailable
88     * @throws SignatureException if the signature check fails
89     */
90    protected void init(Collection<Identity> ids) 
91            throws CertificateException, InvalidKeyException, 
92                NoSuchAlgorithmException, NoSuchProviderException,
93                SignatureException {
94        for (Identity i: ids) {
95            try {
96                ac.verify(i.getCertificate().getPublicKey(), "BC");
97                id = i;
98                break;
99            }
100            catch (InvalidKeyException e) { }
101        }
102        if (id == null) throw new InvalidKeyException("Unknown identity");
103
104        load_roles();
105
106        if (!id.getKeyID().equals(m_head.principal()))
107            throw new InvalidKeyException("Unknown identity");
108    }
109
110    /**
111     * Parse a credential from an InputStream and initialize the role from it.
112     * Combine read_credential(stream) and init(ids).  Note that catching
113     * java.security.GeneralSecurityException catches most of the exceptions
114     * this throws.
115     * @param stream the InputStream to read the certificate from.
116     * @param ids a Collection of Identities to use in validating the cert
117     * @throws CertificateException if the certificate is badly formatted
118     * @throws InvalidKeyException if none of the Identities can validate the
119     *                              certificate
120     * @throws NoSuchAlgorithmException if the credential uses an unknown
121     *                              signature algorithm
122     * @throws NoSuchProviderException if the provider of the signature
123     *                              algorithm is unavailable
124     * @throws SignatureException if the signature check fails
125     * @throws IOException if the certificate is unparsable.
126     */
127    protected void init(InputStream stream, Collection<Identity> ids) 
128            throws CertificateException, InvalidKeyException, 
129                NoSuchAlgorithmException, NoSuchProviderException,
130                SignatureException, IOException {
131        read_certificate(stream);
132        if (ac == null) throw new IOException("Unknown Format");
133        init(ids);
134    }
135
136    /**
137     * Create a credential from an attribute cert in a file. Throws an
138     * exception if the cert file can't be opened or if there's a format
139     * problem with the cert.  Note that catching
140     * java.security.GeneralSecurityException catches most of the exceptions
141     * this throws.
142     * @param filename a String containing the filename to read
143     * @param ids a Collection of Identities to use in validating the cert
144     * @throws StreamParsingException if the stream is unparsable
145     * @throws CertificateException if the certificate is badly formatted
146     * @throws InvalidKeyException if none of the Identities can validate the
147     *                              certificate
148     * @throws NoSuchAlgorithmException if the credential uses an unknown
149     *                              signature algorithm
150     * @throws NoSuchProviderException if the provider of the signature
151     *                              algorithm is unavailable
152     * @throws SignatureException if the signature check fails
153     * @throws IOException if the certificate is unparsable.
154     */
155    public Credential(String filename, Collection<Identity> ids) 
156        throws Exception { init(new FileInputStream(filename), ids); }
157
158    /**
159     * Create a credential from an attribute cert in a file. Throws an
160     * exception if the cert file can't be opened or if there's a format
161     * problem with the cert.  Note that catching
162     * java.security.GeneralSecurityException catches most of the exceptions
163     * this throws.
164     * @param file the File to read
165     * @param ids a Collection of Identities to use in validating the cert
166     * @throws StreamParsingException if the stream is unparsable
167     * @throws CertificateException if the certificate is badly formatted
168     * @throws InvalidKeyException if none of the Identities can validate the
169     *                              certificate
170     * @throws NoSuchAlgorithmException if the credential uses an unknown
171     *                              signature algorithm
172     * @throws NoSuchProviderException if the provider of the signature
173     *                              algorithm is unavailable
174     * @throws SignatureException if the signature check fails
175     * @throws IOException if the certificate is unparsable.
176     */
177    public Credential(File file, Collection<Identity> ids) 
178            throws CertificateException, InvalidKeyException, 
179                NoSuchAlgorithmException, NoSuchProviderException,
180                SignatureException, StreamParsingException, IOException {
181        init(new FileInputStream(file), ids);
182    }
183
184    /**
185     * Create a credential from an InputStream.  Throws an exception if the
186     * stream can't be parsed or if there's a format problem with the cert.
187     * Note that catching java.security.GeneralSecurityException catches most
188     * of the exceptions this throws.
189     * @param s the InputStream to read
190     * @param ids a Collection of Identities to use in validating the cert
191     * @throws StreamParsingException if the stream is unparsable
192     * @throws CertificateException if the certificate is badly formatted
193     * @throws InvalidKeyException if none of the Identities can validate the
194     *                              certificate
195     * @throws NoSuchAlgorithmException if the credential uses an unknown
196     *                              signature algorithm
197     * @throws NoSuchProviderException if the provider of the signature
198     *                              algorithm is unavailable
199     * @throws SignatureException if the signature check fails
200     * @throws IOException if the certificate is unparsable.
201     */
202    public Credential(InputStream s, Collection<Identity> ids) 
203            throws CertificateException, InvalidKeyException, 
204                NoSuchAlgorithmException, NoSuchProviderException,
205                SignatureException, StreamParsingException, IOException {
206        init(s, ids);
207    }
208
209    /**
210     * Create a credential from an X509V2AttributeCertificate object.  Throws
211     * an exception if the certificate doesn't parse into an ABAC credential,
212     * or cannot be validated.  Note that catching
213     * java.security.GeneralSecurityException catches most of the exceptions
214     * this throws.
215     * @param c the X509V2AttributeCertificate to create from
216     * @param ids a Collection of Identities to use in validating the cert
217     * @throws CertificateException if the certificate is badly formatted
218     * @throws InvalidKeyException if none of the Identities can validate the
219     *                              certificate
220     * @throws NoSuchAlgorithmException if the credential uses an unknown
221     *                              signature algorithm
222     * @throws NoSuchProviderException if the provider of the signature
223     *                              algorithm is unavailable
224     * @throws SignatureException if the signature check fails
225     * @throws IOException if the certificate is unparsable.
226     */
227    public Credential(X509V2AttributeCertificate c, Collection<Identity> ids) 
228            throws CertificateException, InvalidKeyException, 
229                NoSuchAlgorithmException, NoSuchProviderException,
230                SignatureException, IOException {
231        ac = c;
232        init(ids);
233    }
234
235
236    /**
237     * Create a certificate from this credential issued by the given identity.
238     * Note that catching java.security.GeneralSecurityException catches most
239     * of the exceptions this throws.
240     * @param i the Identity that will issue the certificate
241     * @throws IOException reading or writing problems
242     * @throws CertificateEncodingException Problem creating certificate
243     * @throws InvalidKeyException if none of the Identities can sign the
244     *                              certificate
245     * @throws NoSuchAlgorithmException if the credential uses an unknown
246     *                              signature algorithm
247     * @throws NoSuchProviderException if the provider of the signature
248     *                              algorithm is unavailable
249     * @throws SignatureException if the signature creation fails
250     */
251    public void make_cert(Identity i) 
252            throws IOException, CertificateEncodingException,
253               NoSuchProviderException, NoSuchAlgorithmException,
254               SignatureException, InvalidKeyException {
255        PrivateKey key = i.getKeyPair().getPrivate();
256        SubjectPublicKeyInfo pki = Context.extractSubjectPublicKeyInfo(
257                i.getKeyPair().getPublic());
258        X509V2AttributeCertificateGenerator gen = 
259            new X509V2AttributeCertificateGenerator();
260
261        gen.setIssuer(new AttributeCertificateIssuer(
262                    new X500Principal("CN="+m_head.principal())));
263        gen.setHolder(new AttributeCertificateHolder(
264                    new X500Principal("CN="+m_head.principal())));
265        gen.setNotAfter(new Date(System.currentTimeMillis() 
266                    + 3600 * 1000 * 24 * 365));
267        gen.setNotBefore(new Date(System.currentTimeMillis()));
268        gen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
269        gen.addAttribute(new X509Attribute(attrOID, 
270                    new DERSequence(
271                        new DERSequence(
272                            new DERUTF8String(toString())))));
273        gen.setSignatureAlgorithm("SHA256WithRSAEncryption");
274
275        // Creddy expects an authority key identifier.
276        gen.addExtension(authKeyOID, false, 
277                new AuthorityKeyIdentifier(pki));
278        // Create the cert.
279        ac = (X509V2AttributeCertificate) gen.generate(key, "BC");
280    }
281
282    /**
283     * Load the roles off the attribute cert. Throws a RuntimeException if
284     * there's something wrong with the cert.
285     */
286    private void load_roles() {
287        String roles = null;
288        try {
289            X509Attribute attr = ac.getAttributes()[0];
290
291            DERSequence    java     = (DERSequence)attr.getValues()[0];
292            DERSequence    fucking  = (DERSequence)java.getObjectAt(0);
293            DERUTF8String  sucks    = (DERUTF8String)fucking.getObjectAt(0);
294
295            roles = sucks.getString();
296        }
297        catch (Exception e) {
298            throw new RuntimeException("Badly formatted certificate");
299        }
300
301        String[] parts = roles.split("\\s*<--?\\s*");
302        if (parts.length != 2)
303            throw new RuntimeException("Invalid attribute: " + roles);
304
305        m_head = new Role(parts[0]);
306        m_tail = new Role(parts[1]);
307    }
308
309    /**
310     * Two credentials are the same if their roles are the same.
311     * @param o an Object to compare
312     * @return true if the Credentials have the Roles
313     */
314    public boolean equals(Object o) {
315        if ( o instanceof Credential ) {
316            Credential c = (Credential) o;
317
318            if (m_head == null || m_tail == null ) return false;
319            else return (m_head.equals(c.head()) && m_tail.equals(c.tail()));
320        }
321        else return false;
322    }
323
324    /**
325     * Allow credentials to be compared.  They are ordered by their Roles, head
326     * then tail.
327     * @param o an Object to compare
328     * @return -1 if this Credential is before, 0 if they are the same, and 1
329     *              if this Credential is after the given object.
330     */
331    public int compareTo(Object o) {
332        if (o instanceof Credential) {
333            Credential c = (Credential) o;
334
335            if (head().equals(c.head())) return tail().compareTo(c.tail());
336            else return head().compareTo(c.head());
337        }
338        else return 1;
339    }
340
341
342    /**
343     * Get the head role from the credential.
344     * @return the Role in the head
345     */
346    public Role head() { return m_head; }
347
348    /**
349     * Get the tail role from the credential
350     * @return the Role in the tail
351     */
352    public Role tail() { return m_tail; }
353
354    /**
355     * Gets the cert associated with this credential (if any).
356     * @return the attribute cert associated with this credential (if any).
357     */
358    public X509V2AttributeCertificate cert() { return ac; }
359
360    /**
361     * Turn the credential into string form. The format is head &lt;- tail. For
362     * example: A.r1 &lt;- B.r2.r3.  Principal names are key identifiers.
363     * @return the string form
364     */
365    public String toString() {
366        return m_head + " <- " + m_tail;
367    }
368
369    /**
370     * Turn the credential into string form. The format is head &lt;- tail. For
371     * example: A.r1 &lt;- B.r2.r3.  Principal names are shortened to menmonics
372     * if the Context knows the identity.
373     * @param c the Context to translate names in
374     * @return the string form
375     */
376    public String simpleString(Context c) {
377        return m_head.simpleString(c) + " <- " + m_tail.simpleString(c);
378    }
379
380    /**
381     * Output the DER formatted attribute certificate associated with this
382     * Credential to the OutputStream.
383     * @param s the OutputStream on which to write
384     * @throws IOException if there is an error writing.
385     */
386    public void write(OutputStream s) throws IOException {
387        if (ac != null ) 
388            s.write(ac.getEncoded());
389        s.flush();
390    }
391
392    /**
393     * Output the DER formatted attribute certificate associated with this
394     * Credential to the filename given.
395     * @param fn a String containing the output filename
396     * @throws IOException if there is an error writing.
397     */
398    public void write(String fn) throws IOException, FileNotFoundException {
399        write(new FileOutputStream(fn));
400    }
401
402    /**
403     * Return true if this Credential has a certificate associated.  A jabac
404     * extension.
405     * @return true if this Credential has a certificate associated.
406     */
407    public boolean hasCertificate() { return ac != null; }
408
409    /**
410     * Return the Identity that issued the underlying certificate.  A jabac
411     * extension.
412     * @return the Identity that issued the underlying certificate.
413     */
414    public Identity issuer() { return id; }
415    /**
416     * Return the X509Certificate that issued the underlying certificate.
417     * @return the X509Certificate that issued the underlying certificate.
418     */
419    public X509Certificate issuerCert() { return id.getCertificate(); }
420    /**
421     * Return the X509V2AttributeCertificate that underlys the Credential
422     * @return the X509V2AttributeCertificate that underlys the Credential.
423     */
424    public X509V2AttributeCertificate attributeCert() { return ac; }
425
426
427}
Note: See TracBrowser for help on using the repository browser.