source: java/net/deterlab/abac/Identity.java @ 718a51f1

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

Hide the ugly Identity constructor and tweak the doc

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