KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > crypto > CryptoPolicyParser


1 /*
2  * @(#)CryptoPolicyParser.java 1.11 04/01/06
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.crypto;
9
10 import java.io.*;
11 import java.util.Enumeration;
12 import java.util.Hashtable;
13 import java.util.Vector;
14 import java.util.StringTokenizer;
15
16 import java.security.GeneralSecurityException;
17 import java.security.spec.AlgorithmParameterSpec;
18 import java.lang.reflect.*;
19
20 /**
21  * JCE has two pairs of jurisdiction policy files: one represents U.S. export
22  * laws, and the other represents the local laws of the country where the
23  * JCE will be used.
24  *
25  * The jurisdiction policy file has the same syntax as JDK policy files except
26  * that JCE has new permission classes called javax.crypto.CryptoPermission
27  * and javax.crypto.CryptoAllPermission.
28  *
29  * The format of a permission entry in the jurisdiction policy file is:
30  *
31  * permission <crypto permission class name>[, <algorithm name>
32  * [[, <exemption mechanism name>][, <maxKeySize>
33  * [, <AlgrithomParameterSpec class name>, <parameters
34  * for constructing an AlgrithomParameterSpec object>]]]];
35  *
36  * @version 1.11, 01/06/04
37  * @author Sharon Liu
38  *
39  * @see java.security.Permissions
40  * @see java.security.spec.AlgrithomParameterSpec
41  * @see javax.crypto.CryptoPermission
42  * @see javax.crypto.CryptoAllPermission
43  * @see javax.crypto.CryptoPermissions
44  * @since 1.4
45  */

46
47 final class CryptoPolicyParser {
48
49     private Vector grantEntries;
50
51     // Convenience variables for parsing
52
private StreamTokenizer st;
53     private int lookahead;
54
55     /**
56      * Creates a CryptoPolicyParser object.
57      */

58     CryptoPolicyParser() {
59     grantEntries = new Vector();
60     }
61
62     /**
63      * Reads a policy configuration using a Reader object. <p>
64      *
65      * @param policy the policy Reader object.
66      *
67      * @exception ParsingException if the policy configuration
68      * contains a syntax error.
69      *
70      * @exception IOException if an error occurs while reading
71      * the policy configuration.
72      */

73
74     void read(Reader policy)
75     throws ParsingException, IOException
76     {
77     if (!(policy instanceof BufferedReader)) {
78         policy = new BufferedReader(policy);
79     }
80
81     /*
82      * Configure the stream tokenizer:
83      * Recognize strings between "..."
84      * Don't convert words to lowercase
85      * Recognize both C-style and C++-style comments
86      * Treat end-of-line as white space, not as a token
87      */

88     st = new StreamTokenizer(policy);
89
90     st.resetSyntax();
91     st.wordChars('a', 'z');
92     st.wordChars('A', 'Z');
93     st.wordChars('.', '.');
94     st.wordChars('0', '9');
95     st.wordChars('_', '_');
96     st.wordChars('$', '$');
97     st.wordChars(128 + 32, 255);
98     st.whitespaceChars(0, ' ');
99     st.commentChar('/');
100     st.quoteChar('\'');
101     st.quoteChar('"');
102     st.lowerCaseMode(false);
103     st.ordinaryChar('/');
104     st.slashSlashComments(true);
105     st.slashStarComments(true);
106         st.parseNumbers();
107
108     /*
109      * The crypto jurisdiction policy must be consistent. The
110      * following hashtable is used for checking consistency.
111      */

112     Hashtable processedPermissions = null;
113
114     /*
115      * The main parsing loop. The loop is executed once for each entry
116      * in the policy file. The entries are delimited by semicolons. Once
117      * we've read in the information for an entry, go ahead and try to
118      * add it to the grantEntries.
119      */

120     lookahead = st.nextToken();
121     while (lookahead != StreamTokenizer.TT_EOF) {
122         if (peek("grant")) {
123         GrantEntry ge = parseGrantEntry(processedPermissions);
124         if (ge != null)
125             grantEntries.addElement(ge);
126         } else {
127         throw new ParsingException(st.lineno(), "expected grant " +
128                        "statement");
129         }
130         match(";");
131     }
132     }
133
134     /**
135      * parse a Grant entry
136      */

137     private GrantEntry parseGrantEntry(Hashtable processedPermissions)
138     throws ParsingException, IOException
139     {
140     GrantEntry e = new GrantEntry();
141
142     match("grant");
143     match("{");
144
145     while(!peek("}")) {
146         if (peek("Permission")) {
147         CryptoPermissionEntry pe =
148             parsePermissionEntry(processedPermissions);
149         e.add(pe);
150         match(";");
151         } else {
152         throw new
153             ParsingException(st.lineno(), "expected permission entry");
154         }
155     }
156     match("}");
157
158     return e;
159     }
160
161     /**
162      * parse a CryptoPermission entry
163      */

164     private CryptoPermissionEntry parsePermissionEntry(
165                        Hashtable processedPermissions)
166     throws ParsingException, IOException
167         
168     {
169     CryptoPermissionEntry e = new CryptoPermissionEntry();
170
171     match("Permission");
172     e.cryptoPermission = match("permission type");
173     
174     if (e.cryptoPermission.equals("javax.crypto.CryptoAllPermission")) {
175         // Done with the CryptoAllPermission entry.
176
e.alg = CryptoAllPermission.ALG_NAME;
177         e.maxKeySize = Integer.MAX_VALUE;
178         return e;
179     }
180
181     // Should see the algorithm name.
182
if (peek("\"")) {
183         // Algorithm name - always convert to upper case after parsing.
184
e.alg = match("quoted string").toUpperCase();
185     } else {
186         // The algorithm name can be a wildcard.
187
if (peek("*")) {
188         match("*");
189         e.alg = CryptoPermission.ALG_NAME_WILDCARD;
190         } else {
191         throw new ParsingException(st.lineno(),
192                        "Missing the algorithm name");
193         }
194     }
195
196     peekAndMatch(",");
197
198     // May see the exemption mechanism name.
199
if (peek("\"")) {
200         // Exemption mechanism name - convert to upper case too.
201
e.exemptionMechanism = match("quoted string").toUpperCase();
202     }
203
204     peekAndMatch(",");
205     
206     // Check whether this entry is consistent with other permission entries
207
// that have been read.
208
if (!isConsistent(e.alg, e.exemptionMechanism, processedPermissions)) {
209         throw new ParsingException(st.lineno(), "Inconsistent policy");
210     }
211
212     // Should see the maxKeySize if not at the end of this entry yet.
213
if (peek("number")) {
214         e.maxKeySize = match();
215     } else {
216         if (peek("*")) {
217         match("*");
218         e.maxKeySize = Integer.MAX_VALUE;
219         } else {
220         if (!peek(";")) {
221             throw new ParsingException(st.lineno(),
222                            "Missing the maximum " +
223                            "allowable key size");
224         } else {
225             // At the end of this permission entry
226
e.maxKeySize = Integer.MAX_VALUE;
227         }
228         }
229     }
230     
231     peekAndMatch(",");
232
233     // May see an AlgorithmParameterSpec class name.
234
if (peek("\"")) {
235         // AlgorithmParameterSpec class name.
236
String algParamSpecClassName = match("quoted string");
237
238         Vector paramsV = new Vector(1);
239         while (peek(",")) {
240         match(",");
241         if (peek("number")) {
242             paramsV.addElement(new Integer(match()));
243         } else {
244             if (peek("*")) {
245             match("*");
246             paramsV.addElement(new Integer(Integer.MAX_VALUE));
247             } else {
248             throw new ParsingException(st.lineno(),
249                            "Expecting an integer");
250             }
251         }
252         }
253      
254         Integer[] params = new Integer[paramsV.size()];
255         paramsV.copyInto(params);
256         
257         e.checkParam = true;
258         e.algParamSpec = getInstance(algParamSpecClassName, params);
259     }
260
261     return e;
262     }
263
264     private static final AlgorithmParameterSpec getInstance(String type,
265                                 Integer[] params)
266     throws ParsingException
267     {
268     AlgorithmParameterSpec ret = null;
269
270     try {
271         Class apsClass = Class.forName(type);
272         Class[] paramClasses = new Class[params.length];
273
274         for (int i = 0; i < params.length; i++) {
275         paramClasses[i] = int.class;
276         }
277
278         Constructor c = apsClass.getConstructor(paramClasses);
279         ret = (AlgorithmParameterSpec) c.newInstance(params);
280     } catch (Exception e) {
281         throw new ParsingException("Cannot call the constructor of " +
282                        type + e);
283     }
284     return ret;
285     }
286                                 
287
288     private boolean peekAndMatch(String expect)
289     throws ParsingException, IOException
290     {
291     if (peek(expect)) {
292         match(expect);
293         return true;
294     }
295     return false;
296     }
297
298     private boolean peek(String expect) {
299     boolean found = false;
300
301     switch (lookahead) {
302
303     case StreamTokenizer.TT_WORD:
304         if (expect.equalsIgnoreCase(st.sval))
305         found = true;
306         break;
307     case StreamTokenizer.TT_NUMBER:
308         if (expect.equalsIgnoreCase("number")) {
309         found = true;
310         }
311         break;
312     case ',':
313         if (expect.equals(","))
314         found = true;
315         break;
316     case '{':
317         if (expect.equals("{"))
318         found = true;
319         break;
320     case '}':
321         if (expect.equals("}"))
322         found = true;
323         break;
324     case '"':
325         if (expect.equals("\""))
326         found = true;
327         break;
328     case '*':
329         if (expect.equals("*"))
330         found = true;
331         break;
332     case ';':
333         if (expect.equals(";"))
334         found = true;
335         break;
336     default:
337         break;
338     }
339     return found;
340     }
341
342     /**
343      * Excepts to match a non-negative number.
344      */

345     private int match()
346     throws ParsingException, IOException
347     {
348     int value = -1;
349     int lineno = st.lineno();
350     String sValue = null;
351
352     switch (lookahead) {
353     case StreamTokenizer.TT_NUMBER:
354         value = (int)st.nval;
355         if (value < 0) {
356         sValue = String.valueOf(st.nval);
357         }
358         lookahead = st.nextToken();
359         break;
360     default:
361         sValue = st.sval;
362         break;
363     }
364     if (value <= 0) {
365         throw new ParsingException(lineno, "a non-negative number",
366                        sValue);
367     }
368     return value;
369     }
370
371     private String match(String expect)
372     throws ParsingException, IOException
373     {
374     String value = null;
375
376     switch (lookahead) {
377     case StreamTokenizer.TT_NUMBER:
378         throw new ParsingException(st.lineno(), expect,
379                        "number "+String.valueOf(st.nval));
380     case StreamTokenizer.TT_EOF:
381        throw new ParsingException("expected "+expect+", read end of file");
382     case StreamTokenizer.TT_WORD:
383         if (expect.equalsIgnoreCase(st.sval)) {
384         lookahead = st.nextToken();
385         }
386         else if (expect.equalsIgnoreCase("permission type")) {
387         value = st.sval;
388         lookahead = st.nextToken();
389         }
390         else
391         throw new ParsingException(st.lineno(), expect, st.sval);
392         break;
393     case '"':
394         if (expect.equalsIgnoreCase("quoted string")) {
395         value = st.sval;
396         lookahead = st.nextToken();
397         } else if (expect.equalsIgnoreCase("permission type")) {
398         value = st.sval;
399         lookahead = st.nextToken();
400         }
401         else
402         throw new ParsingException(st.lineno(), expect, st.sval);
403         break;
404     case ',':
405         if (expect.equals(","))
406         lookahead = st.nextToken();
407         else
408         throw new ParsingException(st.lineno(), expect, ",");
409         break;
410     case '{':
411         if (expect.equals("{"))
412         lookahead = st.nextToken();
413         else
414         throw new ParsingException(st.lineno(), expect, "{");
415         break;
416     case '}':
417         if (expect.equals("}"))
418         lookahead = st.nextToken();
419         else
420         throw new ParsingException(st.lineno(), expect, "}");
421         break;
422     case ';':
423         if (expect.equals(";"))
424         lookahead = st.nextToken();
425         else
426         throw new ParsingException(st.lineno(), expect, ";");
427         break;
428     case '*':
429         if (expect.equals("*"))
430         lookahead = st.nextToken();
431         else
432         throw new ParsingException(st.lineno(), expect, "*");
433         break;
434     default:
435         throw new ParsingException(st.lineno(), expect,
436                    new String(new char[] {(char)lookahead}));
437     }
438     return value;
439     }
440
441     CryptoPermission[] getPermissions() {
442     Vector result = new Vector();
443
444     Enumeration grantEnum = grantEntries.elements();
445     while (grantEnum.hasMoreElements()) {
446         GrantEntry ge = (GrantEntry)grantEnum.nextElement();
447         Enumeration permEnum = ge.permissionElements();
448         while (permEnum.hasMoreElements()) {
449         CryptoPermissionEntry pe =
450             (CryptoPermissionEntry)permEnum.nextElement();
451         if (pe.cryptoPermission.equals(
452                     "javax.crypto.CryptoAllPermission")) {
453             result.addElement(CryptoAllPermission.INSTANCE);
454         } else {
455             if (pe.checkParam) {
456                 result.addElement(new CryptoPermission(
457                             pe.alg,
458                         pe.maxKeySize,
459                         pe.algParamSpec,
460                         pe.exemptionMechanism));
461             } else {
462             result.addElement(new CryptoPermission(
463                                                 pe.alg,
464                                                 pe.maxKeySize,
465                                                 pe.exemptionMechanism));
466             }
467         }
468         }
469     }
470
471     CryptoPermission[] ret = new CryptoPermission[result.size()];
472     result.copyInto(ret);
473
474     return ret;
475     }
476
477     private boolean isConsistent(String alg,
478                  String exemptionMechanism,
479                  Hashtable processedPermissions) {
480     String thisExemptionMechanism =
481         exemptionMechanism == null ? "none" : exemptionMechanism;
482
483     if (processedPermissions == null) {
484         processedPermissions = new Hashtable();
485         Vector exemptionMechanisms = new Vector(1);
486         exemptionMechanisms.addElement(thisExemptionMechanism);
487         processedPermissions.put(alg, exemptionMechanisms);
488         return true;
489     }
490
491     if (processedPermissions.containsKey(CryptoAllPermission.ALG_NAME)) {
492         return false;
493     }
494
495     Vector exemptionMechanisms;
496
497     if (processedPermissions.containsKey(alg)) {
498         exemptionMechanisms = (Vector)processedPermissions.get(alg);
499         if (exemptionMechanisms.contains(thisExemptionMechanism)) {
500         return false;
501         }
502     } else {
503         exemptionMechanisms = new Vector(1);
504     }
505
506     exemptionMechanisms.addElement(thisExemptionMechanism);
507     processedPermissions.put(alg, exemptionMechanisms);
508     return true;
509     }
510
511     /**
512      * Each grant entry in the policy configuration file is represented by a
513      * GrantEntry object. <p>
514      *
515      * <p>
516      * For example, the entry
517      * <pre>
518      * grant {
519      * permission javax.crypto.CryptoPermission "DES", 56;
520      * };
521      *
522      * </pre>
523      * is represented internally
524      * <pre>
525      *
526      * pe = new CryptoPermissionEntry("javax.crypto.CryptoPermission",
527      * "DES", 56);
528      *
529      * ge = new GrantEntry();
530      *
531      * ge.add(pe);
532      *
533      * </pre>
534      *
535      * @see java.security.Permission
536      * @see javax.crypto.CryptoPermission
537      * @see javax.crypto.CryptoPermissions
538      */

539
540     private static class GrantEntry {
541
542     private Vector permissionEntries;
543
544     GrantEntry() {
545         permissionEntries = new Vector();
546     }
547
548     void add(CryptoPermissionEntry pe)
549     {
550         permissionEntries.addElement(pe);
551     }
552
553     boolean remove(CryptoPermissionEntry pe)
554     {
555         return permissionEntries.removeElement(pe);
556     }
557
558     boolean contains(CryptoPermissionEntry pe)
559     {
560         return permissionEntries.contains(pe);
561     }
562
563     /**
564      * Enumerate all the permission entries in this GrantEntry.
565      */

566     Enumeration permissionElements(){
567         return permissionEntries.elements();
568     }
569
570     }
571
572     /**
573      * Each crypto permission entry in the policy configuration file is
574      * represented by a CryptoPermissionEntry object. <p>
575      *
576      * <p>
577      * For example, the entry
578      * <pre>
579      * permission javax.crypto.CryptoPermission "DES", 56;
580      * </pre>
581      * is represented internally
582      * <pre>
583      *
584      * pe = new CryptoPermissionEntry("javax.crypto.cryptoPermission",
585      * "DES", 56);
586      * </pre>
587      *
588      * @see java.security.Permissions
589      * @see javax.crypto.CryptoPermission
590      * @see javax.crypto.CryptoAllPermission
591      */

592
593     private static class CryptoPermissionEntry {
594
595     String cryptoPermission;
596     String alg;
597     String exemptionMechanism;
598     int maxKeySize;
599     boolean checkParam;
600     AlgorithmParameterSpec algParamSpec;
601
602     CryptoPermissionEntry() {
603         // Set default values.
604
maxKeySize = 0;
605         alg = null;
606         exemptionMechanism = null;
607         checkParam = false;
608         algParamSpec = null;
609     }
610
611     /**
612      * Calculates a hash code value for the object. Objects
613      * which are equal will also have the same hashcode.
614      */

615     public int hashCode() {
616         int retval = cryptoPermission.hashCode();
617         if (alg != null) retval ^= alg.hashCode();
618         if (exemptionMechanism != null) {
619         retval ^= exemptionMechanism.hashCode();
620         }
621         retval ^= maxKeySize;
622         if (checkParam) retval ^= 100;
623         if (algParamSpec != null) {
624         retval ^= algParamSpec.hashCode();
625         }
626         return retval;
627     }
628
629     public boolean equals(Object obj) {
630         if (obj == this)
631         return true;
632
633         if (!(obj instanceof CryptoPermissionEntry))
634         return false;
635
636         CryptoPermissionEntry that = (CryptoPermissionEntry) obj;
637
638         if (this.cryptoPermission == null) {
639         if (that.cryptoPermission != null) return false;
640         } else {
641         if (!this.cryptoPermission.equals(
642                          that.cryptoPermission))
643             return false;
644         }
645     
646         if (this.alg == null) {
647         if (that.alg != null) return false;
648         } else {
649         if (!this.alg.equalsIgnoreCase(that.alg))
650             return false;
651         }
652
653         if (!(this.maxKeySize == that.maxKeySize)) return false;
654
655         if (this.checkParam != that.checkParam) return false;
656
657         if (this.algParamSpec == null) {
658         if (that.algParamSpec != null) return false;
659         } else {
660         if (!this.algParamSpec.equals(that.algParamSpec))
661             return false;
662         }
663
664         // everything matched -- the 2 objects are equal
665
return true;
666     }
667     }
668
669     static final class ParsingException extends GeneralSecurityException {
670
671     private static final long serialVersionUID = 7147241245566588374L;
672
673     /**
674      * Constructs a ParsingException with the specified
675      * detail message.
676      * @param msg the detail message.
677      */

678     ParsingException(String msg) {
679         super(msg);
680     }
681
682     ParsingException(int line, String msg) {
683         super("line " + line + ": " + msg);
684     }
685
686     ParsingException(int line, String expect, String actual) {
687         super("line "+line+": expected '"+expect+"', found '"+actual+"'");
688     }
689     }
690 }
691
Popular Tags