source: java/net/deterlab/abac/X509Credential.java @ 797bebe

abac0-leakabac0-meimei-idmei-rt0-nmei_rt0tvf-new-xml
Last change on this file since 797bebe was 3797bbe, checked in by Ted Faber <faber@…>, 12 years ago

checkpoint

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