Home » openjdk-7 » javax » crypto » [javadoc | source]

    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   }

Home » openjdk-7 » javax » crypto » [javadoc | source]