History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/crypto/CryptoPolicyParser.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/crypto/CryptoPolicyParser.java+707−0
@@ -0,0 +1,707 @@
1+/*
2+ * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package javax.crypto;
27+
28+import java.io.*;
29+import java.util.Enumeration;
30+import java.util.Hashtable;
31+import java.util.Vector;
32+import java.util.StringTokenizer;
33+import static java.util.Locale.ENGLISH;
34+
35+import java.security.GeneralSecurityException;
36+import java.security.spec.AlgorithmParameterSpec;
37+import java.lang.reflect.*;
38+
39+/**
40+ * JCE has two pairs of jurisdiction policy files: one represents U.S. export
41+ * laws, and the other represents the local laws of the country where the
42+ * JCE will be used.
43+ *
44+ * The jurisdiction policy file has the same syntax as JDK policy files except
45+ * that JCE has new permission classes called javax.crypto.CryptoPermission
46+ * and javax.crypto.CryptoAllPermission.
47+ *
48+ * The format of a permission entry in the jurisdiction policy file is:
49+ *
50+ * permission <crypto permission class name>[, <algorithm name>
51+ * [[, <exemption mechanism name>][, <maxKeySize>
52+ * [, <AlgrithomParameterSpec class name>, <parameters
53+ * for constructing an AlgrithomParameterSpec object>]]]];
54+ *
55+ * @author Sharon Liu
56+ *
57+ * @see java.security.Permissions
58+ * @see java.security.spec.AlgrithomParameterSpec
59+ * @see javax.crypto.CryptoPermission
60+ * @see javax.crypto.CryptoAllPermission
61+ * @see javax.crypto.CryptoPermissions
62+ * @since 1.4
63+ */
64+
65+final class CryptoPolicyParser {
66+
67+ private Vector grantEntries;
68+
69+ // Convenience variables for parsing
70+ private StreamTokenizer st;
71+ private int lookahead;
72+
73+ /**
74+ * Creates a CryptoPolicyParser object.
75+ */
76+ CryptoPolicyParser() {
77+ grantEntries = new Vector();
78+ }
79+
80+ /**
81+ * Reads a policy configuration using a Reader object. <p>
82+ *
83+ * @param policy the policy Reader object.
84+ *
85+ * @exception ParsingException if the policy configuration
86+ * contains a syntax error.
87+ *
88+ * @exception IOException if an error occurs while reading
89+ * the policy configuration.
90+ */
91+
92+ void read(Reader policy)
93+ throws ParsingException, IOException
94+ {
95+ if (!(policy instanceof BufferedReader)) {
96+ policy = new BufferedReader(policy);
97+ }
98+
99+ /*
100+ * Configure the stream tokenizer:
101+ * Recognize strings between "..."
102+ * Don't convert words to lowercase
103+ * Recognize both C-style and C++-style comments
104+ * Treat end-of-line as white space, not as a token
105+ */
106+ st = new StreamTokenizer(policy);
107+
108+ st.resetSyntax();
109+ st.wordChars('a', 'z');
110+ st.wordChars('A', 'Z');
111+ st.wordChars('.', '.');
112+ st.wordChars('0', '9');
113+ st.wordChars('_', '_');
114+ st.wordChars('$', '$');
115+ st.wordChars(128 + 32, 255);
116+ st.whitespaceChars(0, ' ');
117+ st.commentChar('/');
118+ st.quoteChar('\'');
119+ st.quoteChar('"');
120+ st.lowerCaseMode(false);
121+ st.ordinaryChar('/');
122+ st.slashSlashComments(true);
123+ st.slashStarComments(true);
124+ st.parseNumbers();
125+
126+ /*
127+ * The crypto jurisdiction policy must be consistent. The
128+ * following hashtable is used for checking consistency.
129+ */
130+ Hashtable processedPermissions = null;
131+
132+ /*
133+ * The main parsing loop. The loop is executed once for each entry
134+ * in the policy file. The entries are delimited by semicolons. Once
135+ * we've read in the information for an entry, go ahead and try to
136+ * add it to the grantEntries.
137+ */
138+ lookahead = st.nextToken();
139+ while (lookahead != StreamTokenizer.TT_EOF) {
140+ if (peek("grant")) {
141+ GrantEntry ge = parseGrantEntry(processedPermissions);
142+ if (ge != null)
143+ grantEntries.addElement(ge);
144+ } else {
145+ throw new ParsingException(st.lineno(), "expected grant " +
146+ "statement");
147+ }
148+ match(";");
149+ }
150+ }
151+
152+ /**
153+ * parse a Grant entry
154+ */
155+ private GrantEntry parseGrantEntry(Hashtable processedPermissions)
156+ throws ParsingException, IOException
157+ {
158+ GrantEntry e = new GrantEntry();
159+
160+ match("grant");
161+ match("{");
162+
163+ while(!peek("}")) {
164+ if (peek("Permission")) {
165+ CryptoPermissionEntry pe =
166+ parsePermissionEntry(processedPermissions);
167+ e.add(pe);
168+ match(";");
169+ } else {
170+ throw new
171+ ParsingException(st.lineno(), "expected permission entry");
172+ }
173+ }
174+ match("}");
175+
176+ return e;
177+ }
178+
179+ /**
180+ * parse a CryptoPermission entry
181+ */
182+ private CryptoPermissionEntry parsePermissionEntry(
183+ Hashtable processedPermissions)
184+ throws ParsingException, IOException
185+ {
186+ CryptoPermissionEntry e = new CryptoPermissionEntry();
187+
188+ match("Permission");
189+ e.cryptoPermission = match("permission type");
190+
191+ if (e.cryptoPermission.equals("javax.crypto.CryptoAllPermission")) {
192+ // Done with the CryptoAllPermission entry.
193+ e.alg = CryptoAllPermission.ALG_NAME;
194+ e.maxKeySize = Integer.MAX_VALUE;
195+ return e;
196+ }
197+
198+ // Should see the algorithm name.
199+ if (peek("\"")) {
200+ // Algorithm name - always convert to upper case after parsing.
201+ e.alg = match("quoted string").toUpperCase(ENGLISH);
202+ } else {
203+ // The algorithm name can be a wildcard.
204+ if (peek("*")) {
205+ match("*");
206+ e.alg = CryptoPermission.ALG_NAME_WILDCARD;
207+ } else {
208+ throw new ParsingException(st.lineno(),
209+ "Missing the algorithm name");
210+ }
211+ }
212+
213+ peekAndMatch(",");
214+
215+ // May see the exemption mechanism name.
216+ if (peek("\"")) {
217+ // Exemption mechanism name - convert to upper case too.
218+ e.exemptionMechanism = match("quoted string").toUpperCase(ENGLISH);
219+ }
220+
221+ peekAndMatch(",");
222+
223+ // Check whether this entry is consistent with other permission entries
224+ // that have been read.
225+ if (!isConsistent(e.alg, e.exemptionMechanism, processedPermissions)) {
226+ throw new ParsingException(st.lineno(), "Inconsistent policy");
227+ }
228+
229+ // Should see the maxKeySize if not at the end of this entry yet.
230+ if (peek("number")) {
231+ e.maxKeySize = match();
232+ } else {
233+ if (peek("*")) {
234+ match("*");
235+ e.maxKeySize = Integer.MAX_VALUE;
236+ } else {
237+ if (!peek(";")) {
238+ throw new ParsingException(st.lineno(),
239+ "Missing the maximum " +
240+ "allowable key size");
241+ } else {
242+ // At the end of this permission entry
243+ e.maxKeySize = Integer.MAX_VALUE;
244+ }
245+ }
246+ }
247+
248+ peekAndMatch(",");
249+
250+ // May see an AlgorithmParameterSpec class name.
251+ if (peek("\"")) {
252+ // AlgorithmParameterSpec class name.
253+ String algParamSpecClassName = match("quoted string");
254+
255+ Vector paramsV = new Vector(1);
256+ while (peek(",")) {
257+ match(",");
258+ if (peek("number")) {
259+ paramsV.addElement(new Integer(match()));
260+ } else {
261+ if (peek("*")) {
262+ match("*");
263+ paramsV.addElement(new Integer(Integer.MAX_VALUE));
264+ } else {
265+ throw new ParsingException(st.lineno(),
266+ "Expecting an integer");
267+ }
268+ }
269+ }
270+
271+ Integer[] params = new Integer[paramsV.size()];
272+ paramsV.copyInto(params);
273+
274+ e.checkParam = true;
275+ e.algParamSpec = getInstance(algParamSpecClassName, params);
276+ }
277+
278+ return e;
279+ }
280+
281+ private static final AlgorithmParameterSpec getInstance(String type,
282+ Integer[] params)
283+ throws ParsingException
284+ {
285+ AlgorithmParameterSpec ret = null;
286+
287+ try {
288+ Class apsClass = Class.forName(type);
289+ Class[] paramClasses = new Class[params.length];
290+
291+ for (int i = 0; i < params.length; i++) {
292+ paramClasses[i] = int.class;
293+ }
294+
295+ Constructor c = apsClass.getConstructor(paramClasses);
296+ ret = (AlgorithmParameterSpec) c.newInstance((Object[]) params);
297+ } catch (Exception e) {
298+ throw new ParsingException("Cannot call the constructor of " +
299+ type + e);
300+ }
301+ return ret;
302+ }
303+
304+
305+ private boolean peekAndMatch(String expect)
306+ throws ParsingException, IOException
307+ {
308+ if (peek(expect)) {
309+ match(expect);
310+ return true;
311+ }
312+ return false;
313+ }
314+
315+ private boolean peek(String expect) {
316+ boolean found = false;
317+
318+ switch (lookahead) {
319+
320+ case StreamTokenizer.TT_WORD:
321+ if (expect.equalsIgnoreCase(st.sval))
322+ found = true;
323+ break;
324+ case StreamTokenizer.TT_NUMBER:
325+ if (expect.equalsIgnoreCase("number")) {
326+ found = true;
327+ }
328+ break;
329+ case ',':
330+ if (expect.equals(","))
331+ found = true;
332+ break;
333+ case '{':
334+ if (expect.equals("{"))
335+ found = true;
336+ break;
337+ case '}':
338+ if (expect.equals("}"))
339+ found = true;
340+ break;
341+ case '"':
342+ if (expect.equals("\""))
343+ found = true;
344+ break;
345+ case '*':
346+ if (expect.equals("*"))
347+ found = true;
348+ break;
349+ case ';':
350+ if (expect.equals(";"))
351+ found = true;
352+ break;
353+ default:
354+ break;
355+ }
356+ return found;
357+ }
358+
359+ /**
360+ * Excepts to match a non-negative number.
361+ */
362+ private int match()
363+ throws ParsingException, IOException
364+ {
365+ int value = -1;
366+ int lineno = st.lineno();
367+ String sValue = null;
368+
369+ switch (lookahead) {
370+ case StreamTokenizer.TT_NUMBER:
371+ value = (int)st.nval;
372+ if (value < 0) {
373+ sValue = String.valueOf(st.nval);
374+ }
375+ lookahead = st.nextToken();
376+ break;
377+ default:
378+ sValue = st.sval;
379+ break;
380+ }
381+ if (value <= 0) {
382+ throw new ParsingException(lineno, "a non-negative number",
383+ sValue);
384+ }
385+ return value;
386+ }
387+
388+ private String match(String expect)
389+ throws ParsingException, IOException
390+ {
391+ String value = null;
392+
393+ switch (lookahead) {
394+ case StreamTokenizer.TT_NUMBER:
395+ throw new ParsingException(st.lineno(), expect,
396+ "number "+String.valueOf(st.nval));
397+ case StreamTokenizer.TT_EOF:
398+ throw new ParsingException("expected "+expect+", read end of file");
399+ case StreamTokenizer.TT_WORD:
400+ if (expect.equalsIgnoreCase(st.sval)) {
401+ lookahead = st.nextToken();
402+ }
403+ else if (expect.equalsIgnoreCase("permission type")) {
404+ value = st.sval;
405+ lookahead = st.nextToken();
406+ }
407+ else
408+ throw new ParsingException(st.lineno(), expect, st.sval);
409+ break;
410+ case '"':
411+ if (expect.equalsIgnoreCase("quoted string")) {
412+ value = st.sval;
413+ lookahead = st.nextToken();
414+ } else if (expect.equalsIgnoreCase("permission type")) {
415+ value = st.sval;
416+ lookahead = st.nextToken();
417+ }
418+ else
419+ throw new ParsingException(st.lineno(), expect, st.sval);
420+ break;
421+ case ',':
422+ if (expect.equals(","))
423+ lookahead = st.nextToken();
424+ else
425+ throw new ParsingException(st.lineno(), expect, ",");
426+ break;
427+ case '{':
428+ if (expect.equals("{"))
429+ lookahead = st.nextToken();
430+ else
431+ throw new ParsingException(st.lineno(), expect, "{");
432+ break;
433+ case '}':
434+ if (expect.equals("}"))
435+ lookahead = st.nextToken();
436+ else
437+ throw new ParsingException(st.lineno(), expect, "}");
438+ break;
439+ case ';':
440+ if (expect.equals(";"))
441+ lookahead = st.nextToken();
442+ else
443+ throw new ParsingException(st.lineno(), expect, ";");
444+ break;
445+ case '*':
446+ if (expect.equals("*"))
447+ lookahead = st.nextToken();
448+ else
449+ throw new ParsingException(st.lineno(), expect, "*");
450+ break;
451+ default:
452+ throw new ParsingException(st.lineno(), expect,
453+ new String(new char[] {(char)lookahead}));
454+ }
455+ return value;
456+ }
457+
458+ CryptoPermission[] getPermissions() {
459+ Vector result = new Vector();
460+
461+ Enumeration grantEnum = grantEntries.elements();
462+ while (grantEnum.hasMoreElements()) {
463+ GrantEntry ge = (GrantEntry)grantEnum.nextElement();
464+ Enumeration permEnum = ge.permissionElements();
465+ while (permEnum.hasMoreElements()) {
466+ CryptoPermissionEntry pe =
467+ (CryptoPermissionEntry)permEnum.nextElement();
468+ if (pe.cryptoPermission.equals(
469+ "javax.crypto.CryptoAllPermission")) {
470+ result.addElement(CryptoAllPermission.INSTANCE);
471+ } else {
472+ if (pe.checkParam) {
473+ result.addElement(new CryptoPermission(
474+ pe.alg,
475+ pe.maxKeySize,
476+ pe.algParamSpec,
477+ pe.exemptionMechanism));
478+ } else {
479+ result.addElement(new CryptoPermission(
480+ pe.alg,
481+ pe.maxKeySize,
482+ pe.exemptionMechanism));
483+ }
484+ }
485+ }
486+ }
487+
488+ CryptoPermission[] ret = new CryptoPermission[result.size()];
489+ result.copyInto(ret);
490+
491+ return ret;
492+ }
493+
494+ private boolean isConsistent(String alg,
495+ String exemptionMechanism,
496+ Hashtable processedPermissions) {
497+ String thisExemptionMechanism =
498+ exemptionMechanism == null ? "none" : exemptionMechanism;
499+
500+ if (processedPermissions == null) {
501+ processedPermissions = new Hashtable();
502+ Vector exemptionMechanisms = new Vector(1);
503+ exemptionMechanisms.addElement(thisExemptionMechanism);
504+ processedPermissions.put(alg, exemptionMechanisms);
505+ return true;
506+ }
507+
508+ if (processedPermissions.containsKey(CryptoAllPermission.ALG_NAME)) {
509+ return false;
510+ }
511+
512+ Vector exemptionMechanisms;
513+
514+ if (processedPermissions.containsKey(alg)) {
515+ exemptionMechanisms = (Vector)processedPermissions.get(alg);
516+ if (exemptionMechanisms.contains(thisExemptionMechanism)) {
517+ return false;
518+ }
519+ } else {
520+ exemptionMechanisms = new Vector(1);
521+ }
522+
523+ exemptionMechanisms.addElement(thisExemptionMechanism);
524+ processedPermissions.put(alg, exemptionMechanisms);
525+ return true;
526+ }
527+
528+ /**
529+ * Each grant entry in the policy configuration file is represented by a
530+ * GrantEntry object. <p>
531+ *
532+ * <p>
533+ * For example, the entry
534+ * <pre>
535+ * grant {
536+ * permission javax.crypto.CryptoPermission "DES", 56;
537+ * };
538+ *
539+ * </pre>
540+ * is represented internally
541+ * <pre>
542+ *
543+ * pe = new CryptoPermissionEntry("javax.crypto.CryptoPermission",
544+ * "DES", 56);
545+ *
546+ * ge = new GrantEntry();
547+ *
548+ * ge.add(pe);
549+ *
550+ * </pre>
551+ *
552+ * @see java.security.Permission
553+ * @see javax.crypto.CryptoPermission
554+ * @see javax.crypto.CryptoPermissions
555+ */
556+
557+ private static class GrantEntry {
558+
559+ private Vector permissionEntries;
560+
561+ GrantEntry() {
562+ permissionEntries = new Vector();
563+ }
564+
565+ void add(CryptoPermissionEntry pe)
566+ {
567+ permissionEntries.addElement(pe);
568+ }
569+
570+ boolean remove(CryptoPermissionEntry pe)
571+ {
572+ return permissionEntries.removeElement(pe);
573+ }
574+
575+ boolean contains(CryptoPermissionEntry pe)
576+ {
577+ return permissionEntries.contains(pe);
578+ }
579+
580+ /**
581+ * Enumerate all the permission entries in this GrantEntry.
582+ */
583+ Enumeration permissionElements(){
584+ return permissionEntries.elements();
585+ }
586+
587+ }
588+
589+ /**
590+ * Each crypto permission entry in the policy configuration file is
591+ * represented by a CryptoPermissionEntry object. <p>
592+ *
593+ * <p>
594+ * For example, the entry
595+ * <pre>
596+ * permission javax.crypto.CryptoPermission "DES", 56;
597+ * </pre>
598+ * is represented internally
599+ * <pre>
600+ *
601+ * pe = new CryptoPermissionEntry("javax.crypto.cryptoPermission",
602+ * "DES", 56);
603+ * </pre>
604+ *
605+ * @see java.security.Permissions
606+ * @see javax.crypto.CryptoPermission
607+ * @see javax.crypto.CryptoAllPermission
608+ */
609+
610+ private static class CryptoPermissionEntry {
611+
612+ String cryptoPermission;
613+ String alg;
614+ String exemptionMechanism;
615+ int maxKeySize;
616+ boolean checkParam;
617+ AlgorithmParameterSpec algParamSpec;
618+
619+ CryptoPermissionEntry() {
620+ // Set default values.
621+ maxKeySize = 0;
622+ alg = null;
623+ exemptionMechanism = null;
624+ checkParam = false;
625+ algParamSpec = null;
626+ }
627+
628+ /**
629+ * Calculates a hash code value for the object. Objects
630+ * which are equal will also have the same hashcode.
631+ */
632+ public int hashCode() {
633+ int retval = cryptoPermission.hashCode();
634+ if (alg != null) retval ^= alg.hashCode();
635+ if (exemptionMechanism != null) {
636+ retval ^= exemptionMechanism.hashCode();
637+ }
638+ retval ^= maxKeySize;
639+ if (checkParam) retval ^= 100;
640+ if (algParamSpec != null) {
641+ retval ^= algParamSpec.hashCode();
642+ }
643+ return retval;
644+ }
645+
646+ public boolean equals(Object obj) {
647+ if (obj == this)
648+ return true;
649+
650+ if (!(obj instanceof CryptoPermissionEntry))
651+ return false;
652+
653+ CryptoPermissionEntry that = (CryptoPermissionEntry) obj;
654+
655+ if (this.cryptoPermission == null) {
656+ if (that.cryptoPermission != null) return false;
657+ } else {
658+ if (!this.cryptoPermission.equals(
659+ that.cryptoPermission))
660+ return false;
661+ }
662+
663+ if (this.alg == null) {
664+ if (that.alg != null) return false;
665+ } else {
666+ if (!this.alg.equalsIgnoreCase(that.alg))
667+ return false;
668+ }
669+
670+ if (!(this.maxKeySize == that.maxKeySize)) return false;
671+
672+ if (this.checkParam != that.checkParam) return false;
673+
674+ if (this.algParamSpec == null) {
675+ if (that.algParamSpec != null) return false;
676+ } else {
677+ if (!this.algParamSpec.equals(that.algParamSpec))
678+ return false;
679+ }
680+
681+ // everything matched -- the 2 objects are equal
682+ return true;
683+ }
684+ }
685+
686+ static final class ParsingException extends GeneralSecurityException {
687+
688+ private static final long serialVersionUID = 7147241245566588374L;
689+
690+ /**
691+ * Constructs a ParsingException with the specified
692+ * detail message.
693+ * @param msg the detail message.
694+ */
695+ ParsingException(String msg) {
696+ super(msg);
697+ }
698+
699+ ParsingException(int line, String msg) {
700+ super("line " + line + ": " + msg);
701+ }
702+
703+ ParsingException(int line, String expect, String actual) {
704+ super("line "+line+": expected '"+expect+"', found '"+actual+"'");
705+ }
706+ }
707+}