source: java/net/deterlab/abac/Identity.java @ b89cfd8

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

Expirations for identities, too.

  • Property mode set to 100644
File size: 14.7 KB
RevLine 
[9725efb]1package net.deterlab.abac;
2
3import java.io.*;
4
5import java.util.*;
6import java.security.*;
7import java.security.cert.*;
[3a52bed]8import javax.security.auth.x500.*;
[9725efb]9
[3a52bed]10import java.math.BigInteger;
[9725efb]11
12import org.bouncycastle.asn1.*;
13import org.bouncycastle.asn1.util.*;
14import org.bouncycastle.asn1.x509.*;
15import org.bouncycastle.x509.*;
[238717d]16import org.bouncycastle.openssl.*;
17
[9725efb]18
[e36ea1d]19/**
20 * An ABAC identity.  An X509 Certificate-encoded public key.  The key
21 * identifier is used as the name of the Identity.  This whole class is
22 * something of a jabac extension.
23 * @author <a href="http://abac.deterlab.net">ISI ABAC team</a>
[4560b65]24 * @version 1.4
[e36ea1d]25 */
[5cf72cc]26public class Identity implements Comparable {
[3f928b0]27    /** Default validity period (in seconds) */
28    static public long defaultValidity = 3600L * 24L * 365L;
[e36ea1d]29    /** The underlying X509 certificate. */
30    protected X509Certificate cert;
31    /** The public key id used as this principal's name */
32    protected String keyid;
33    /** The common name in the certificate, used as a mnemonic */
34    protected String cn;
35    /** The keypair, if any, used to sign for this Identity */
36    protected KeyPair kp;
[3f928b0]37    /** The expiration for this Identity */
38    protected Date expiration;
[9725efb]39
[238717d]40    /** Make sure BouncyCastle is loaded */
41    static { Context.loadBouncyCastle(); } 
42
[1a7e6d3]43    /**
[e36ea1d]44     * Initialize from PEM cert in a reader.  Use a PEMReader to get
45     * the certificate, and call init(cert) on it.
46     * @param r a Reader containing the certificate
47     * @throws CertificateException if the certificate is badly formatted
48     * @throws InvalidKeyException if none of the Identities can validate the
49     *                              certificate
50     * @throws NoSuchAlgorithmException if the credential uses an unknown
51     *                              signature algorithm
52     * @throws NoSuchProviderException if the provider of the signature
53     *                              algorithm is unavailable
54     * @throws SignatureException if the signature check fails
55     * @throws IOException if the certificate is unparsable.
[1a7e6d3]56     */
[8a14e37]57    protected void init(Reader r) throws 
[42ca4b8]58            CertificateException, NoSuchAlgorithmException,InvalidKeyException,
59            NoSuchProviderException, SignatureException, IOException {
60        PEMReader pr = new PEMReader(r);
61        Object c = null;
62
63        while ( ( c= pr.readObject()) != null ){
64
[84f0e7a]65            if (c instanceof X509Certificate) {
[0595372]66                if ( cn == null ) 
[84f0e7a]67                    init((X509Certificate)c);
[42ca4b8]68                else
69                    throw new CertificateException("Two certs in one file");
70            }
71            else if (c instanceof KeyPair) setKeyPair((KeyPair)c);
[8a14e37]72            else 
[42ca4b8]73                throw new CertificateException(
74                        "Not an identity certificate");
75        }
[f31432f]76        // If there's nothing for the PEM reader to parse, the cert is invalid.
77        if (cn == null) 
78            throw new CertificateException(
79                    "Not an identity certificate");
[8a14e37]80    }
81
82    /**
[e36ea1d]83     * Initialize internals from cert.  Confirm it is self signed,  and then
84     * the keyid and common name.  There's some work to get this stuff, but
85     * it's all an incantation of getting the right classes to get the right
86     * data.  Looks more complex than it is.
87     * @param c an X509Certificate to init from
88     * @throws CertificateException if the certificate is badly formatted
89     * @throws InvalidKeyException if none of the Identities can validate the
90     *                              certificate
91     * @throws NoSuchAlgorithmException if the credential uses an unknown
92     *                              signature algorithm
93     * @throws NoSuchProviderException if the provider of the signature
94     *                              algorithm is unavailable
95     * @throws SignatureException if the signature check fails
96     * @throws IOException if the certificate is unparsable.
[8a14e37]97     */
[84f0e7a]98    protected void init(X509Certificate c) throws
[8a14e37]99        CertificateException, NoSuchAlgorithmException,InvalidKeyException,
100        NoSuchProviderException, SignatureException, IOException {
[0595372]101            cert = (X509Certificate) c;
102            cert.verify(cert.getPublicKey());
[8a14e37]103            // Cert is valid, fill in the CN and keyid
[0595372]104            keyid = Context.extractKeyID(cert.getPublicKey());
105            cn = cert.getSubjectDN().getName();
[3f928b0]106            expiration = cert.getNotAfter();
[8a14e37]107            /// XXX: better parse
[0595372]108            if (cn.startsWith("CN=")) cn = cn.substring(3);
[9725efb]109    }
110
[1a7e6d3]111    /**
[e36ea1d]112     * Construct from a string, used as a CN.  Keys are generated.
113     * @param cn a String containing the menomnic name
[3f928b0]114     * @param validity a long containing the validity period (in seconds)
[e36ea1d]115     * @throws IOException reading or writing problems
116     * @throws CertificateEncodingException Problem creating certificate
117     * @throws InvalidKeyException if none of the Identities can sign the
118     *                              certificate
119     * @throws NoSuchAlgorithmException if the credential uses an unknown
120     *                              signature algorithm
121     * @throws NoSuchProviderException if the provider of the signature
122     *                              algorithm is unavailable
123     * @throws SignatureException if the signature creation fails
[1a7e6d3]124     */
[3f928b0]125    public Identity(String cn, long validity) throws
[3a52bed]126            CertificateException, NoSuchAlgorithmException,InvalidKeyException,
127            NoSuchProviderException, SignatureException, IOException {
128        X509V1CertificateGenerator gen = new X509V1CertificateGenerator();
[42ca4b8]129        kp = KeyPairGenerator.getInstance("RSA").genKeyPair();
[3a52bed]130
131        gen.setIssuerDN(new X500Principal("CN=" + cn));
132        gen.setSubjectDN(new X500Principal("CN=" + cn));
[3f928b0]133        gen.setNotAfter(new Date(System.currentTimeMillis() +
134                1000L * validity));
[3a52bed]135        gen.setNotBefore(new Date(System.currentTimeMillis()));
136        gen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
137        gen.setPublicKey(kp.getPublic());
138        gen.setSignatureAlgorithm("SHA256WithRSAEncryption");
[238717d]139        X509Certificate a = (X509Certificate) gen.generate(kp.getPrivate(), "BC");
[3a52bed]140        init(a);
141    }
142
[9725efb]143
[3f928b0]144    /**
145     * Construct from a string, used as a CN.  Keys are generated.
146     * @param cn a String containing the menomnic name
147     * @param validity a long containing the validity period (in seconds)
148     * @throws IOException reading or writing problems
149     * @throws CertificateEncodingException Problem creating certificate
150     * @throws InvalidKeyException if none of the Identities can sign the
151     *                              certificate
152     * @throws NoSuchAlgorithmException if the credential uses an unknown
153     *                              signature algorithm
154     * @throws NoSuchProviderException if the provider of the signature
155     *                              algorithm is unavailable
156     * @throws SignatureException if the signature creation fails
157     */
158    public Identity(String cn) throws
159            CertificateException, NoSuchAlgorithmException,InvalidKeyException,
160            NoSuchProviderException, SignatureException, IOException {
161        this(cn, defaultValidity);
162    }
[9725efb]163
[1a7e6d3]164    /**
[a7f73b5]165     * Construct from a file containing a self-signed PEM certificate.
[e36ea1d]166     * @param file the File to read
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.
[1a7e6d3]176     */
[9725efb]177    public Identity(File file) throws 
178        CertificateException, NoSuchAlgorithmException,InvalidKeyException,
179        NoSuchProviderException, SignatureException, FileNotFoundException,
[42ca4b8]180        IOException { 
181            kp = null;
182            init(new FileReader(file));
183        }
[1a7e6d3]184
185    /**
[e36ea1d]186     * Construct from a reader containing a self-signed PEM certificate.
187     * @param r the Reader containing the certificate
188     * @throws CertificateException if the certificate is badly formatted
189     * @throws InvalidKeyException if none of the Identities can validate the
190     *                              certificate
191     * @throws NoSuchAlgorithmException if the credential uses an unknown
192     *                              signature algorithm
193     * @throws NoSuchProviderException if the provider of the signature
194     *                              algorithm is unavailable
195     * @throws SignatureException if the signature check fails
196     * @throws IOException if the certificate is unparsable.
[1a7e6d3]197     */
198    public Identity(Reader r) throws 
199        CertificateException, NoSuchAlgorithmException,InvalidKeyException,
[42ca4b8]200        NoSuchProviderException, SignatureException, IOException {
201            kp = null;
202            init(r);
203        }
[1a7e6d3]204
205    /**
[e36ea1d]206     * Construct from an InputStream containing a self-signed PEM certificate.
207     * @param s the InputStream containing the certificate
208     * @throws CertificateException if the certificate is badly formatted
209     * @throws InvalidKeyException if none of the Identities can validate the
210     *                              certificate
211     * @throws NoSuchAlgorithmException if the credential uses an unknown
212     *                              signature algorithm
213     * @throws NoSuchProviderException if the provider of the signature
214     *                              algorithm is unavailable
215     * @throws SignatureException if the signature check fails
216     * @throws IOException if the certificate is unparsable.
[1a7e6d3]217     */
218    public Identity(InputStream s) throws 
219        CertificateException, NoSuchAlgorithmException,InvalidKeyException,
220        NoSuchProviderException, SignatureException, IOException { 
[42ca4b8]221            kp = null;
[1a7e6d3]222            init(new InputStreamReader(s));
223        }
224
[8a14e37]225    /**
[e36ea1d]226     * Construct from an X509Certificate
227     * @param cert an X509Certificate to init from
228     * @throws CertificateException if the certificate is badly formatted
229     * @throws InvalidKeyException if none of the Identities can validate the
230     *                              certificate
231     * @throws NoSuchAlgorithmException if the credential uses an unknown
232     *                              signature algorithm
233     * @throws NoSuchProviderException if the provider of the signature
234     *                              algorithm is unavailable
235     * @throws SignatureException if the signature check fails
236     * @throws IOException if the certificate is unparsable.
[8a14e37]237     */
[84f0e7a]238    public Identity(X509Certificate cert) throws 
[8a14e37]239        CertificateException, NoSuchAlgorithmException,InvalidKeyException,
240        NoSuchProviderException, SignatureException, FileNotFoundException,
[42ca4b8]241        IOException { 
242            kp = null;
243            init(cert);
244        }
[8a14e37]245
[8a93b41]246    /**
247     * Write the PEM key to the given writer.
[e36ea1d]248     * @param w the Writer
249     * @return true if the Identity had a keypair and wrote the key
250     * @throws IOException if writing fails
[8a93b41]251     */
252    public boolean writePrivateKey(Writer w) throws IOException {
253        if (kp != null ) {
254            PEMWriter pw = new PEMWriter(w);
255
256            pw.writeObject(kp.getPrivate());
257            pw.flush();
258            return true;
259        }
260        else return false;
261    }
262
263    /**
264     * Write the PEM key to a file with the given name.
265     */
266    public boolean writePrivateKey(String fn) 
267            throws IOException, FileNotFoundException {
268        return writePrivateKey(new FileWriter(fn));
269    }
270
271    /**
272     * Write the PEM key to the given file.
[e36ea1d]273     * @param fn a String with the output file name
274     * @return true if the Identity had a keypair and wrote the key
275     * @throws IOException if writing fails
[8a93b41]276     */
277    public boolean writePrivateKey(File fn) 
278            throws IOException, FileNotFoundException {
279        return writePrivateKey(new FileWriter(fn));
280    }
281
282    /**
283     * Write the PEM key to the given OutputStream.
[e36ea1d]284     * @param s an OutputStream to write on
285     * @return true if the Identity had a keypair and wrote the key
286     * @throws IOException if writing fails
[8a93b41]287     */
288    public boolean writePrivateKey(OutputStream s) 
289            throws IOException, FileNotFoundException {
290        return writePrivateKey(new OutputStreamWriter(s));
291    }
292
[1a7e6d3]293
294    /**
295     * Write the PEM cert to the given writer.
[e36ea1d]296     * @param w a Writer to write on
297     * @throws IOException if writing fails
[1a7e6d3]298     */
299    public void write(Writer w) throws IOException {
300        PEMWriter pw = new PEMWriter(w);
301
[0595372]302        pw.writeObject(cert);
[5cf72cc]303        pw.flush();
[1a7e6d3]304    }
305
306    /**
307     * Write the PEM cert to a file with the given name.
308     */
309    public void write(String fn) throws IOException, FileNotFoundException {
310        write(new FileWriter(fn));
311    }
312
313    /**
314     * Write the PEM cert to the given file.
[e36ea1d]315     * @param fn a String with the output file name
316     * @throws IOException if writing fails
[1a7e6d3]317     */
318    public void write(File fn) throws IOException, FileNotFoundException {
319        write(new FileWriter(fn));
320    }
321
322    /**
323     * Write the PEM cert to the given OutputStream.
[e36ea1d]324     * @param s an OutputStream to write on
325     * @throws IOException if writing fails
[1a7e6d3]326     */
327    public void write(OutputStream s) 
328        throws IOException, FileNotFoundException {
329        write(new OutputStreamWriter(s));
330    }
[9725efb]331
[e9360e2]332
[e36ea1d]333    /**
334     * Return the Identity's KeyID
335     * @return the Identity's KeyID
336     */
[0595372]337    public String getKeyID() { return keyid; }
[e36ea1d]338    /**
339     * Return the Identity's mnemonic name
340     * @return the Identity's mnemonic name
341     */
[0595372]342    public String getName() { return cn; }
[e36ea1d]343    /**
344     * Return the Identity's X509 Certificate
345     * @return the Identity's X509 Certificate
346     */
347    public X509Certificate getCertificate() { return cert; }
[3f928b0]348
349    /**
350     * Return the expiration time of the Identity
351     * @return a Date the expiration time of the Identity
352     */
353    public Date getExpiration(){ return expiration; }
354
[e36ea1d]355    /**
356     * Return a simple string rep of the Identity.
357     * @return a simple string rep of the Identity.
358     */
[42ca4b8]359    public String toString() { 
[0595372]360        String s = keyid + " (" + cn ;
[42ca4b8]361
[0595372]362        if (keyid != null ) s += " [keyed]";
[42ca4b8]363        s += ")";
364        return s;
365    }
366    /**
367     * Associate a keypair with this Identity.  If the ID has a certificate,
368     * make sure that the keypair matches it.  If not throw an
369     * IllegalArgumentException.
[e36ea1d]370     * @param k the KeyPair to connect
371     * @throws IllegalArgumentException if the keypair does not
372     *                              match the pubkey in the X509 certificate
[42ca4b8]373     */
374    public void setKeyPair(KeyPair k) {
[0595372]375        if (keyid != null) {
376            String kid = Context.extractKeyID(k.getPublic());
[42ca4b8]377
[0595372]378            if ( kid != null && kid.equals(keyid)) kp = k;
[42ca4b8]379            else 
380                throw new IllegalArgumentException(
381                        "Keypair does not match certificate");
382        }
383        else kp = k;
384    }
[e36ea1d]385
386    /**
387     * Return the keypair associated with this Identity (if any)
388     * @return the keypair associated with this Identity (if any)
389     */
[42ca4b8]390    public KeyPair getKeyPair() { return kp; }
[e36ea1d]391
392    /**
[a7f73b5]393     * Return true if the two identites refer to teh same key.  Two Identities
394     * are equal if their key ID's match.
[e36ea1d]395     * @return true if the two key ID's are equal.
396     */
[5cf72cc]397    public boolean equals(Object o) { 
398        if ( o == null ) return false;
399        else if ( ! (o instanceof Identity) ) return false;
400        else return getKeyID().equals(((Identity)o).getKeyID());
401    }
[e36ea1d]402    /**
[a7f73b5]403     * Order 2 identities for sorting.  They are ordered by their key ID's.
[e36ea1d]404     * @param o an Object to compare
405     * @return -1 if this Identity is before, 0 if they are the same, and 1
406     *              if this Identity is after the given object.
407     */
[5cf72cc]408    public int compareTo(Object o) { 
409        if ( ! (o instanceof Identity) ) return 1;
410        else return getKeyID().compareTo(((Identity)o).getKeyID());
411    }
[1a7e6d3]412
[9725efb]413};
Note: See TracBrowser for help on using the repository browser.