source: java/net/deterlab/abac/X509Credential.java @ 8375d4f

abac0-leakabac0-meimei-idmei-rt0-nmei_rt0tvf-new-xml
Last change on this file since 8375d4f 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
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>
[4560b65]23 * @version 1.4
[3797bbe]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() {
[7f614c1]40        super();
[3797bbe]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) {
[7f614c1]52        super(head, tail);
[3797bbe]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 {
[3612811]65        try { 
66            ac = new X509V2AttributeCertificate(stream);
67        }
68        catch (Exception e) {
69            throw new IOException(e.getMessage(), e);
70        }
[3797bbe]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
[44896b5]79     * @throws CertInvalidException if the stream is unparsable
80     * @throws MissingIssuerException if none of the Identities can validate the
[3797bbe]81     *                              certificate
[44896b5]82     * @throws BadSignatureException if the signature check fails
[3797bbe]83     */
84    protected void init(Collection<Identity> ids) 
[44896b5]85            throws ABACException {
[3797bbe]86        for (Identity i: ids) {
87            try {
88                ac.verify(i.getCertificate().getPublicKey(), "BC");
89                id = i;
90                break;
91            }
[44896b5]92            catch (GeneralSecurityException e) { }
[3797bbe]93        }
[44896b5]94        if (id == null) throw new MissingIssuerException("Unknown identity");
[3797bbe]95
[7f614c1]96        m_expiration = ac.getNotAfter();
[3797bbe]97        load_roles();
98
99        if (!id.getKeyID().equals(m_head.principal()))
[44896b5]100            throw new MissingIssuerException("Unknown identity");
[3797bbe]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
[44896b5]110     * @throws CertInvalidException if the stream is unparsable
111     * @throws MissingIssuerException if none of the Identities can validate the
[3797bbe]112     *                              certificate
[44896b5]113     * @throws BadSignatureException if the signature check fails
[3797bbe]114     */
115    protected void init(InputStream stream, Collection<Identity> ids) 
[44896b5]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");
[3797bbe]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
[44896b5]135     * @throws CertInvalidException if the stream is unparsable
136     * @throws MissingIssuerException if none of the Identities can validate the
[3797bbe]137     *                              certificate
[44896b5]138     * @throws BadSignatureException if the signature check fails
[3797bbe]139     */
[4d5f56d]140    X509Credential(String filename, Collection<Identity> ids) 
[44896b5]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    }
[3797bbe]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
[44896b5]158     * @throws CertInvalidException if the stream is unparsable
159     * @throws MissingIssuerException if none of the Identities can validate the
[3797bbe]160     *                              certificate
[44896b5]161     * @throws BadSignatureException if the signature check fails
[3797bbe]162     */
[4d5f56d]163    X509Credential(File file, Collection<Identity> ids) 
[44896b5]164            throws ABACException {
165        try {
166            init(new FileInputStream(file), ids);
167        }
168        catch (FileNotFoundException e) {
169            throw new CertInvalidException("Bad filename", e);
170        }
[3797bbe]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
[44896b5]180     * @throws CertInvalidException if the stream is unparsable
181     * @throws MissingIssuerException if none of the Identities can validate the
[3797bbe]182     *                              certificate
[44896b5]183     * @throws BadSignatureException if the signature check fails
[3797bbe]184     */
[4d5f56d]185    X509Credential(InputStream s, Collection<Identity> ids) 
[44896b5]186            throws ABACException { init(s, ids); }
[3797bbe]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
[44896b5]196     * @throws CertInvalidException if the stream is unparsable
197     * @throws MissingIssuerException if none of the Identities can validate the
[3797bbe]198     *                              certificate
[44896b5]199     * @throws BadSignatureException if the signature check fails
[3797bbe]200     */
[4d5f56d]201    X509Credential(X509V2AttributeCertificate c, 
[44896b5]202            Collection<Identity> ids) 
203            throws ABACException {
[3797bbe]204        ac = c;
205        init(ids);
206    }
207
208
209    /**
[675770e]210     * Create a certificate from this credential issued by the given identity
211     * valid for the given time.
[3797bbe]212     * @param i the Identity that will issue the certificate
[675770e]213     * @param validity a long holding the number of seconds that the credential
214     * is valid for.
[44896b5]215     * @throws ABACException if xml creation fails
216     * @throws MissingIssuerException if the issuer is bad
217     * @throws BadSignatureException if the signature creation fails
[3797bbe]218     */
[675770e]219    public void make_cert(Identity i, long validity) 
[44896b5]220            throws ABACException {
[3797bbe]221        PrivateKey key = i.getKeyPair().getPrivate();
222        SubjectPublicKeyInfo pki = Context.extractSubjectPublicKeyInfo(
223                i.getKeyPair().getPublic());
224        X509V2AttributeCertificateGenerator gen = 
225            new X509V2AttributeCertificateGenerator();
226
[44896b5]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())));
[675770e]232            m_expiration = new Date(System.currentTimeMillis() 
233                    + (1000L * validity));
234            gen.setNotAfter(m_expiration);
[44896b5]235            gen.setNotBefore(new Date(System.currentTimeMillis()));
236            gen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
237            gen.addAttribute(new X509Attribute(attrOID, 
[3797bbe]238                        new DERSequence(
[44896b5]239                            new DERSequence(
240                                new DERUTF8String(toString())))));
241            gen.setSignatureAlgorithm("SHA256WithRSAEncryption");
[3797bbe]242
[44896b5]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        }
[3797bbe]251        // Create the cert.
252        id = i;
253    }
254
[675770e]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
[3797bbe]267    /**
[44896b5]268     * Load the roles off the attribute cert.
269     * @throws CertInvalidException if the certificate is badly formatted
[3797bbe]270     */
[44896b5]271    private void load_roles() throws CertInvalidException {
[3797bbe]272        String roles = null;
273        try {
274            X509Attribute attr = ac.getAttributes()[0];
275
[7b33c9b]276            DERSequence    t1     = (DERSequence)attr.getValues()[0];
277            DERSequence    t2  = (DERSequence)t1.getObjectAt(0);
278            DERUTF8String  t3    = (DERUTF8String)t2.getObjectAt(0);
[3797bbe]279
[7b33c9b]280            roles = t3.getString();
[3797bbe]281        }
282        catch (Exception e) {
[44896b5]283            throw new CertInvalidException("Badly formatted certificate");
[3797bbe]284        }
285
286        String[] parts = roles.split("\\s*<--?\\s*");
287        if (parts.length != 2)
[44896b5]288            throw new CertInvalidException("Invalid attribute: " + roles);
[3797bbe]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
[f84d71e]323    /**
[aaadefd]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.
[f84d71e]327     * @return a CredentialParser for this kind of credential.
328     */
[aaadefd]329    static public CredentialFactorySpecialization
330            getCredentialFactorySpecialization() {
331        return new CredentialFactorySpecialization() {
[f84d71e]332            public Credential[] parseCredential(InputStream is, 
333                    Collection<Identity> ids) throws ABACException {
334                return new Credential[] { new X509Credential(is, ids) }; 
335            }
[aaadefd]336            public Credential generateCredential(Role head, Role tail) {
337                return new X509Credential(head, tail);
338            }
[f84d71e]339        };
340    }
341
[3797bbe]342
343}
Note: See TracBrowser for help on using the repository browser.