source: java/net/deterlab/abac/GENICredentialv1_1.java @ 120b7d8

abac0-leakabac0-meitvf-new-xml
Last change on this file since 120b7d8 was 120b7d8, checked in by Ted Faber <faber@…>, 11 years ago

More name mapping

  • Property mode set to 100644
File size: 13.3 KB
Line 
1package net.deterlab.abac;
2
3import java.io.*;
4import java.math.*;
5import java.text.*;
6
7import java.util.*;
8
9import java.security.*;
10import java.security.cert.*;
11
12import javax.xml.parsers.*;
13import javax.xml.transform.*;
14import javax.xml.transform.dom.*;
15import javax.xml.transform.stream.*;
16
17import javax.xml.crypto.*;
18import javax.xml.crypto.dsig.*;
19import javax.xml.crypto.dsig.dom.*;
20import javax.xml.crypto.dsig.keyinfo.*;
21import javax.xml.crypto.dsig.spec.*;
22
23import org.xml.sax.*;
24import org.w3c.dom.*;
25
26/**
27 * An ABAC credential formatted as an abac-type GENI credential, version 1.1.
28 * @author <a href="http://abac.deterlab.net">ISI ABAC team</a>
29 * @version 1.4
30 */
31public class GENICredentialv1_1 extends GENICredential
32    implements Comparable, MapsKeyIDs {
33
34    protected KeyIDMap keyMap;
35    /**
36     * Create an empty Credential.
37     */
38    public GENICredentialv1_1() {
39        super();
40        keyMap = new KeyIDMap();
41    }
42    /**
43     * Create a credential from a head and tail role.  This credential has no
44     * underlying certificate, and cannot be exported or used in real proofs.
45     * make_cert can create a certificate for a credential initialized this
46     * way.
47     * @param head the Role at the head of the credential
48     * @param tail the Role at the tail of the credential
49     */
50    public GENICredentialv1_1(Role head, Role tail) {
51        super(head, tail);
52        keyMap = new KeyIDMap();
53    }
54    /**
55     * Create a credential from an attribute cert in a file. Throws an
56     * exception if the cert file can't be opened or if there's a format
57     * problem with the cert.  Note that catching
58     * java.security.GeneralSecurityException catches most of the exceptions
59     * this throws.
60     * @param filename a String containing the filename to read
61     * @param ids a Collection of Identities to use in validating the cert
62     * @throws CertInvalidException if the stream is unparsable
63     * @throws MissingIssuerException if none of the Identities can validate the
64     *                              certificate
65     * @throws BadSignatureException if the signature check fails
66     */
67    GENICredentialv1_1(String filename, Collection<Identity> ids) 
68        throws ABACException { 
69        super(filename, ids);
70        /* Parsers should create a keyMap in load_roles(), but create one here
71         * if not */
72        if ( keyMap == null ) keyMap = new KeyIDMap();
73    }
74
75    /**
76     * Create a credential from an attribute cert in a file. Throws an
77     * exception if the cert file can't be opened or if there's a format
78     * problem with the cert.  Note that catching
79     * java.security.GeneralSecurityException catches most of the exceptions
80     * this throws.
81     * @param file the File to read
82     * @param ids a Collection of Identities to use in validating the cert
83     * @throws CertInvalidException if the stream is unparsable
84     * @throws MissingIssuerException if none of the Identities can validate the
85     *                              certificate
86     * @throws BadSignatureException if the signature check fails
87     */
88    GENICredentialv1_1(File file, Collection<Identity> ids) 
89            throws ABACException {
90        super(file, ids);
91        /* Parsers should create a keyMap in load_roles(), but create one here
92         * if not */
93        if ( keyMap == null ) keyMap = new KeyIDMap();
94    }
95
96    /**
97     * Create a credential from an InputStream.  Throws an exception if the
98     * stream can't be parsed or if there's a format problem with the cert.
99     * Note that catching java.security.GeneralSecurityException catches most
100     * of the exceptions this throws.
101     * @param s the InputStream to read
102     * @param ids a Collection of Identities to use in validating the cert
103     * @throws CertInvalidException if the stream is unparsable
104     * @throws MissingIssuerException if none of the Identities can validate the
105     *                              certificate
106     * @throws BadSignatureException if the signature check fails
107     */
108    GENICredentialv1_1(InputStream s, Collection<Identity> ids) 
109            throws ABACException { 
110        super(s, ids);
111        /* Parsers should create a keyMap in load_roles(), but create one here
112         * if not */
113        if ( keyMap == null ) keyMap = new KeyIDMap();
114    }
115
116    protected String makeTestMnemonic(String k) {
117        String rv = keyMap.keyToNickname(k);
118        int i = 0;
119
120        if ( rv != null ) return rv;
121        else return keyMap.addNickname(k, "name");
122    }
123
124
125    protected void add_structured_role(Role r, Node top) {
126        if ( r.is_principal()) {
127            Element p = doc.createElement("ABACprincipal");
128            Element k = doc.createElement("keyid");
129            Element m = doc.createElement("mnemonic");
130
131            k.appendChild(doc.createTextNode(r.principal()));
132            m.appendChild(doc.createTextNode(makeTestMnemonic(r.principal())));
133            p.appendChild(k);
134            p.appendChild(m);
135            top.appendChild(p);
136        } else if ( r.is_role() ) {
137            Element p = doc.createElement("ABACprincipal");
138            Element k = doc.createElement("keyid");
139            Element m = doc.createElement("mnemonic");
140            Element rr = doc.createElement("role");
141
142            k.appendChild(doc.createTextNode(r.principal()));
143            m.appendChild(doc.createTextNode(makeTestMnemonic(r.principal())));
144            rr.appendChild(doc.createTextNode(r.role_name()));
145            p.appendChild(k);
146            p.appendChild(m);
147            top.appendChild(p);
148            top.appendChild(rr);
149        } else {
150            Element p = doc.createElement("ABACprincipal");
151            Element k = doc.createElement("keyid");
152            Element m = doc.createElement("mnemonic");
153            Element rr = doc.createElement("role");
154            Element lr = doc.createElement("linking_role");
155
156            k.appendChild(doc.createTextNode(r.principal()));
157            m.appendChild(doc.createTextNode(makeTestMnemonic(r.principal())));
158            rr.appendChild(doc.createTextNode(r.role_name()));
159            lr.appendChild(doc.createTextNode(r.linking_role()));
160            p.appendChild(k);
161            p.appendChild(m);
162            top.appendChild(p);
163            top.appendChild(rr);
164            top.appendChild(lr);
165        }
166    }
167
168    protected Node make_structured_rt0() {
169        Element a = doc.createElement("rt0");
170        Element v = doc.createElement("version");
171        Element n = doc.createElement("head");
172        Role[] tailRoles = null;
173
174        v.appendChild(doc.createTextNode("1.1"));
175        a.appendChild(v);
176        add_structured_role(head(), n);
177        a.appendChild(n);
178       
179        if (tail().is_intersection()) {
180            try { 
181                tailRoles = tail().prereqs();
182            } catch (ABACException ignored ) { }
183        } else {
184            tailRoles = new Role[] { tail() };
185        }
186
187        for ( Role tr: tailRoles ) {
188            n = doc.createElement("tail");
189            add_structured_role(tr, n);
190            a.appendChild(n);
191        }
192        return a;
193    }
194
195    /**
196     * Encode the abac credential's XML and set the validity.  This is straight
197     * line code that directly builds the credential.
198     * @param validity a long holding the number of seconds that the credential
199     * is valid for.
200     * @return a Node, the place to attach signatures
201     * @throws ABACException if any of the XML construction fails
202     */
203    protected Node make_rt0_content(long validity) throws ABACException {
204        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
205        DocumentBuilder db = null;
206        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
207        StringBuffer expBuf = new StringBuffer();
208
209        /* This is a weirdness to cope with the GENI format.  They have a naked
210         * xml:id specifier without any namespace declarations in the
211         * credential.  Notice that this is the opposite of the setting used in
212         * init to read a credential. */
213        dbf.setNamespaceAware(false);
214
215        if ( dbf == null ) 
216            throw new ABACException("Cannot get DocumentBuilderFactory!?");
217
218        try {
219            db = dbf.newDocumentBuilder();
220        }
221        catch (ParserConfigurationException pe) {
222            throw new ABACException("Cannot get DocumentBuilder!?" + 
223                    pe.getMessage(), pe);
224        }
225
226        doc = db.newDocument();
227        if ( doc == null ) 
228            throw new ABACException("No Document");
229
230        Element root = doc.createElement("signed-credential"); 
231        Element cred = doc.createElement("credential");
232        Element serial = doc.createElement("serial");
233        Element owner_gid = doc.createElement("owner_gid");
234        Element target_gid = doc.createElement("target_gid");
235        Element uuid = doc.createElement("uuid");
236        Element sig = doc.createElement("signatures");
237        Element e = doc.createElement("type");
238        Node text = doc.createTextNode("abac");
239
240        doc.appendChild(root);
241
242        cred.setAttribute("xml:id", "ref0");
243        /* So that the signing code can find the section to sign */
244        cred.setIdAttribute("xml:id", true);
245
246        root.appendChild(cred);
247        e.appendChild(text);
248        for (Element ele : new Element[] 
249                {serial, owner_gid, target_gid, uuid, sig, e })
250            cred.appendChild(ele);
251
252        m_expiration = new Date(System.currentTimeMillis() + 
253                (1000L * validity ));
254        df.setTimeZone(new SimpleTimeZone(0, "Z"));
255        df.format(m_expiration, expBuf, new FieldPosition(0));
256        e = doc.createElement("expires");
257        text = doc.createTextNode(expBuf.toString());
258        e.appendChild(text);
259        cred.appendChild(e);
260
261        e = doc.createElement("abac");
262        e.appendChild(make_structured_rt0());
263        cred.appendChild(e);
264
265        root.appendChild(sig);
266        return sig;
267    }
268
269    protected Role parse_structured_rt0(Node srt)  throws CertInvalidException {
270        Node p = getChildByName(srt, "ABACprincipal");
271        Node k = null;
272        Node mn = null;
273        Node r = getChildByName(srt, "role");
274        Node lr = getChildByName(srt, "linking_role");
275        String ks = null;
276        String mns = null;
277        String rs = ( r != null ) ? r.getTextContent() : null;
278        String lrs = ( lr!= null ) ? lr.getTextContent() : null;
279        Role rv = null;
280
281        if (p == null ) 
282            throw new CertInvalidException("No principal!?");
283
284        if ( (k = getChildByName(p, "keyid")) == null ) 
285            throw new CertInvalidException("Principal w/o keyid");
286
287        if ( (ks = k.getTextContent()) == null ) 
288            throw new CertInvalidException("Empty keyid");
289
290        if ( (mn = getChildByName(p, "mnemonic")) != null )
291            mns = mn.getTextContent();
292
293        if ( lrs != null ) {
294            if ( rs == null ) {
295                throw new CertInvalidException("Linking role without role");
296            }
297            rv = new Role(ks + "." + lrs + "." + rs);
298        } else if ( rs == null ) {
299            rv = new Role(ks);
300        } else {
301            rv = new Role(ks + "." + rs);
302        }
303        if ( mns != null ) keyMap.addNickname(ks, mns);
304        return rv;
305    }
306
307    /**
308     * Load the roles off the attribute cert.
309     * @throws CertInvalidException if the certificate is badly formatted
310     */
311    protected void load_roles() throws CertInvalidException {
312        if ( doc == null ) 
313            throw new CertInvalidException("No credential");
314
315        if ( keyMap == null ) keyMap = new KeyIDMap();
316
317        NodeList nodes = doc.getElementsByTagName("credential");
318        Node node = null;
319        Node type = null;
320        Node rt0 = null;
321        Node v = null;
322        String vs = null;
323
324        if (nodes == null || nodes.getLength() != 1) 
325            throw new CertInvalidException("More than one credential?");
326
327        node = nodes.item(0);
328        if ( node == null ) 
329            throw new CertInvalidException("bad credential element?");
330
331        if ( (type = getChildByName(node, "type")) == null ) {
332            throw new CertInvalidException("No Type field");
333        }
334
335        if ( !"abac".equals(type.getTextContent()) ) 
336            throw new CertInvalidException("Not an abac type credential");
337
338        // Walk down to the abac and rt0 field using the rt0 variable.
339        if ( (rt0 = getChildByName(node, "abac")) == null ) {
340            throw new CertInvalidException("No abac field");
341        }
342        if ( (rt0 = getChildByName(rt0, "rt0")) == null ) {
343            throw new CertInvalidException("No rt0 field");
344        }
345
346        if ( (v = getChildByName(rt0, "version")) == null ) {
347            throw new CertInvalidException("No version field");
348        }
349        if ( (vs = v.getTextContent()) == null) {
350            throw new CertInvalidException("empty version field");
351        }
352        if ( ! vs.trim().equals("1.1")) {
353            throw new CertInvalidException("bad version: expected 1.1 got "+vs);
354        }
355
356        m_head = null;
357        m_tail = null;
358
359        for (Node n = rt0.getFirstChild(); n != null; n = n.getNextSibling()) {
360            String nname = null;
361
362            if ( n.getNodeType() != Node.ELEMENT_NODE) continue;
363            nname = n.getNodeName();
364            if (nname == null ) continue;
365
366            if (nname.equals("head")) {
367                if ( m_head != null ) 
368                    throw new CertInvalidException("2 head elements");
369                try {
370                    m_head = parse_structured_rt0(n);
371                } catch (CertInvalidException ce) {
372                    throw new CertInvalidException("Error parsing head: " + 
373                            ce.getMessage());
374                }
375            } else if (nname.equals("tail")) {
376                Role t = null;
377
378                try {
379                    t = parse_structured_rt0(n);
380                } catch (CertInvalidException ce) {
381                    throw new CertInvalidException("Error parsing tail: " + 
382                            ce.getMessage());
383                }
384                // This is a little wasteful in processing terms, but simply
385                // appends the new tail entry to a new intersection role.
386                if ( m_tail != null ) 
387                    m_tail = new Role(m_tail.toString()  + " & " + 
388                            t.toString());
389                else m_tail = t;
390            }
391        }
392    }
393    /**
394     * Return the keymap.
395     * @return a KeyIDMap, this class's keymap
396     */
397    public KeyIDMap getMapping() { return keyMap; }
398    /**
399     * Return a CredentialCredentialFactorySpecialization for
400     * GENICredentialsv1_1.  Used by the CredentialFactory to parse and generate
401     * these kind of credentials.  It basically wraps constuctor calls.
402     * @return a CredentialFactorySpecialization for this kind of credential.
403     */
404    static public CredentialFactorySpecialization
405            getCredentialFactorySpecialization() {
406        return new CredentialFactorySpecialization() {
407            public Credential[] parseCredential(InputStream is, 
408                    Collection<Identity> ids) throws ABACException {
409                return new Credential[] { new GENICredentialv1_1(is, ids) }; 
410            }
411            public Credential generateCredential(Role head, Role tail) {
412                return new GENICredentialv1_1(head, tail);
413            }
414        };
415    }
416}
Note: See TracBrowser for help on using the repository browser.