source: java/net/deterlab/abac/X509Credential.java @ 0100d7b

abac0-leakabac0-meimei-idmei-rt0-nmei_rt0tvf-new-xml
Last change on this file since 0100d7b was 675770e, checked in by Ted Faber <faber@…>, 12 years ago

Allow users to set validity periods.

  • Property mode set to 100644
File size: 12.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.4
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    /** The certificate representing this credential */
31    protected X509V2AttributeCertificate ac;
32
33    /** Make sure BouncyCastle is loaded */
34    static { Context.loadBouncyCastle(); } 
35
36    /**
37     * Create an empty Credential.
38     */
39    public X509Credential() {
40        super();
41        ac = null;
42    }
43    /**
44     * Create a credential from a head and tail role.  This credential has no
45     * underlying certificate, and cannot be exported or used in real proofs.
46     * make_cert can create a certificate for a credential initialized this
47     * way.
48     * @param head the Role at the head of the credential
49     * @param tail the Role at the tail of the credential
50     */
51    public X509Credential(Role head, Role tail) {
52        super(head, tail);
53        ac = null; 
54    }
55
56    /**
57     * Do the credential extraction from an input stream.  This parses the
58     * certificate from the input stream and saves it. The contents must be
59     * validated and parsed later.
60     * @param stream the InputStream to read the certificate from.
61     * @throws IOException if the stream is unparsable
62     */
63    protected void read_certificate(InputStream stream) 
64            throws IOException {
65        try { 
66            ac = new X509V2AttributeCertificate(stream);
67        }
68        catch (Exception e) {
69            throw new IOException(e.getMessage(), e);
70        }
71    }
72
73    /**
74     * Initialize a credential from parsed certificate.  Validiate it against
75     * the given identities and parse out the roles.  Note that catching
76     * java.security.GeneralSecurityException catches most of the exceptions
77     * this throws.
78     * @param ids a Collection of Identities to use in validating the cert
79     * @throws CertInvalidException if the stream is unparsable
80     * @throws MissingIssuerException if none of the Identities can validate the
81     *                              certificate
82     * @throws BadSignatureException if the signature check fails
83     */
84    protected void init(Collection<Identity> ids) 
85            throws ABACException {
86        for (Identity i: ids) {
87            try {
88                ac.verify(i.getCertificate().getPublicKey(), "BC");
89                id = i;
90                break;
91            }
92            catch (GeneralSecurityException e) { }
93        }
94        if (id == null) throw new MissingIssuerException("Unknown identity");
95
96        m_expiration = ac.getNotAfter();
97        load_roles();
98
99        if (!id.getKeyID().equals(m_head.principal()))
100            throw new MissingIssuerException("Unknown identity");
101    }
102
103    /**
104     * Parse a credential from an InputStream and initialize the role from it.
105     * Combine read_credential(stream) and init(ids).  Note that catching
106     * java.security.GeneralSecurityException catches most of the exceptions
107     * this throws.
108     * @param stream the InputStream to read the certificate from.
109     * @param ids a Collection of Identities to use in validating the cert
110     * @throws CertInvalidException if the stream is unparsable
111     * @throws MissingIssuerException if none of the Identities can validate the
112     *                              certificate
113     * @throws BadSignatureException if the signature check fails
114     */
115    protected void init(InputStream stream, Collection<Identity> ids) 
116            throws ABACException {
117        try {
118            read_certificate(stream);
119        }
120        catch (IOException e) {
121            throw new CertInvalidException(e.getMessage(), e);
122        }
123        if (ac == null) throw new CertInvalidException("Unknown Format");
124        init(ids);
125    }
126
127    /**
128     * Create a credential from an attribute cert in a file. Throws an
129     * exception if the cert file can't be opened or if there's a format
130     * problem with the cert.  Note that catching
131     * java.security.GeneralSecurityException catches most of the exceptions
132     * this throws.
133     * @param filename a String containing the filename to read
134     * @param ids a Collection of Identities to use in validating the cert
135     * @throws CertInvalidException if the stream is unparsable
136     * @throws MissingIssuerException if none of the Identities can validate the
137     *                              certificate
138     * @throws BadSignatureException if the signature check fails
139     */
140    X509Credential(String filename, Collection<Identity> ids) 
141        throws ABACException { 
142        try {
143            init(new FileInputStream(filename), ids); 
144        }
145        catch (FileNotFoundException e) {
146            throw new CertInvalidException("Bad filename", e);
147        }
148    }
149
150    /**
151     * Create a credential from an attribute cert in a file. Throws an
152     * exception if the cert file can't be opened or if there's a format
153     * problem with the cert.  Note that catching
154     * java.security.GeneralSecurityException catches most of the exceptions
155     * this throws.
156     * @param file the File to read
157     * @param ids a Collection of Identities to use in validating the cert
158     * @throws CertInvalidException if the stream is unparsable
159     * @throws MissingIssuerException if none of the Identities can validate the
160     *                              certificate
161     * @throws BadSignatureException if the signature check fails
162     */
163    X509Credential(File file, Collection<Identity> ids) 
164            throws ABACException {
165        try {
166            init(new FileInputStream(file), ids);
167        }
168        catch (FileNotFoundException e) {
169            throw new CertInvalidException("Bad filename", e);
170        }
171    }
172
173    /**
174     * Create a credential from an InputStream.  Throws an exception if the
175     * stream can't be parsed or if there's a format problem with the cert.
176     * Note that catching java.security.GeneralSecurityException catches most
177     * of the exceptions this throws.
178     * @param s the InputStream to read
179     * @param ids a Collection of Identities to use in validating the cert
180     * @throws CertInvalidException if the stream is unparsable
181     * @throws MissingIssuerException if none of the Identities can validate the
182     *                              certificate
183     * @throws BadSignatureException if the signature check fails
184     */
185    X509Credential(InputStream s, Collection<Identity> ids) 
186            throws ABACException { init(s, ids); }
187
188    /**
189     * Create a credential from an X509V2AttributeCertificate object.  Throws
190     * an exception if the certificate doesn't parse into an ABAC credential,
191     * or cannot be validated.  Note that catching
192     * java.security.GeneralSecurityException catches most of the exceptions
193     * this throws.
194     * @param c the X509V2AttributeCertificate to create from
195     * @param ids a Collection of Identities to use in validating the cert
196     * @throws CertInvalidException if the stream is unparsable
197     * @throws MissingIssuerException if none of the Identities can validate the
198     *                              certificate
199     * @throws BadSignatureException if the signature check fails
200     */
201    X509Credential(X509V2AttributeCertificate c, 
202            Collection<Identity> ids) 
203            throws ABACException {
204        ac = c;
205        init(ids);
206    }
207
208
209    /**
210     * Create a certificate from this credential issued by the given identity
211     * valid for the given time.
212     * @param i the Identity that will issue the certificate
213     * @param validity a long holding the number of seconds that the credential
214     * is valid for.
215     * @throws ABACException if xml creation fails
216     * @throws MissingIssuerException if the issuer is bad
217     * @throws BadSignatureException if the signature creation fails
218     */
219    public void make_cert(Identity i, long validity) 
220            throws ABACException {
221        PrivateKey key = i.getKeyPair().getPrivate();
222        SubjectPublicKeyInfo pki = Context.extractSubjectPublicKeyInfo(
223                i.getKeyPair().getPublic());
224        X509V2AttributeCertificateGenerator gen = 
225            new X509V2AttributeCertificateGenerator();
226
227        try {
228            gen.setIssuer(new AttributeCertificateIssuer(
229                        new X500Principal("CN="+m_head.principal())));
230            gen.setHolder(new AttributeCertificateHolder(
231                        new X500Principal("CN="+m_head.principal())));
232            m_expiration = new Date(System.currentTimeMillis() 
233                    + (1000L * validity));
234            gen.setNotAfter(m_expiration);
235            gen.setNotBefore(new Date(System.currentTimeMillis()));
236            gen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
237            gen.addAttribute(new X509Attribute(attrOID, 
238                        new DERSequence(
239                            new DERSequence(
240                                new DERUTF8String(toString())))));
241            gen.setSignatureAlgorithm("SHA256WithRSAEncryption");
242
243            // Creddy expects an authority key identifier.
244            gen.addExtension(authKeyOID, false, 
245                    new AuthorityKeyIdentifier(pki));
246            ac = (X509V2AttributeCertificate) gen.generate(key, "BC");
247        }
248        catch (Exception e) {
249            throw new ABACException("Cannot encode cert", e);
250        }
251        // Create the cert.
252        id = i;
253    }
254
255    /**
256     * Create a certificate from this credential issued by the given identity
257     * valid for the default validity.
258     * @param i the Identity that will issue the certificate
259     * @throws ABACException if xml creation fails
260     * @throws MissingIssuerException if the issuer is bad
261     * @throws BadSignatureException if the signature creation fails
262     */
263    public void make_cert(Identity i) throws ABACException {
264        make_cert(i, defaultValidity);
265    }
266
267    /**
268     * Load the roles off the attribute cert.
269     * @throws CertInvalidException if the certificate is badly formatted
270     */
271    private void load_roles() throws CertInvalidException {
272        String roles = null;
273        try {
274            X509Attribute attr = ac.getAttributes()[0];
275
276            DERSequence    t1     = (DERSequence)attr.getValues()[0];
277            DERSequence    t2  = (DERSequence)t1.getObjectAt(0);
278            DERUTF8String  t3    = (DERUTF8String)t2.getObjectAt(0);
279
280            roles = t3.getString();
281        }
282        catch (Exception e) {
283            throw new CertInvalidException("Badly formatted certificate");
284        }
285
286        String[] parts = roles.split("\\s*<--?\\s*");
287        if (parts.length != 2)
288            throw new CertInvalidException("Invalid attribute: " + roles);
289
290        m_head = new Role(parts[0]);
291        m_tail = new Role(parts[1]);
292    }
293
294    /**
295     * Output the DER formatted attribute certificate associated with this
296     * Credential to the OutputStream.
297     * @param s the OutputStream on which to write
298     * @throws IOException if there is an error writing.
299     */
300    public void write(OutputStream s) throws IOException {
301        if (ac != null ) 
302            s.write(ac.getEncoded());
303        s.flush();
304    }
305
306    /**
307     * Output the DER formatted attribute certificate associated with this
308     * Credential to the filename given.
309     * @param fn a String containing the output filename
310     * @throws IOException if there is an error writing.
311     */
312    public void write(String fn) throws IOException, FileNotFoundException {
313        write(new FileOutputStream(fn));
314    }
315
316    /**
317     * Return true if this Credential has a certificate associated.  A jabac
318     * extension.
319     * @return true if this Credential has a certificate associated.
320     */
321    public boolean hasCertificate() { return ac != null; }
322
323    /**
324     * Return a CredentialFactorySpecialization for X509Credentials.  Used by
325     * the CredentialFactory to parse and generate these kind of credentials.
326     * It is basically a wrapper around constuctor calls.
327     * @return a CredentialParser for this kind of credential.
328     */
329    static public CredentialFactorySpecialization
330            getCredentialFactorySpecialization() {
331        return new CredentialFactorySpecialization() {
332            public Credential[] parseCredential(InputStream is, 
333                    Collection<Identity> ids) throws ABACException {
334                return new Credential[] { new X509Credential(is, ids) }; 
335            }
336            public Credential generateCredential(Role head, Role tail) {
337                return new X509Credential(head, tail);
338            }
339        };
340    }
341
342
343}
Note: See TracBrowser for help on using the repository browser.