source: java/net/deterlab/abac/X509Credential.java @ 44896b5

abac0-leakabac0-meimei-idmei-rt0-nmei_rt0tvf-new-xml
Last change on this file since 44896b5 was 44896b5, checked in by Ted Faber <faber@…>, 11 years ago

Collapse Exception handling to something reasonable - first pass

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