View Javadoc
1   /*
2    * Copyright (c) 1999, 2012, 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.security.*;
29  import java.security.spec.AlgorithmParameterSpec;
30  import java.io.Serializable;
31  import java.util.Enumeration;
32  import java.util.Vector;
33  
34  import javax.crypto.spec.*;
35  
36  /**
37   * The CryptoPermission class extends the
38   * java.security.Permission class. A
39   * CryptoPermission object is used to represent
40   * the ability of an application/applet to use certain
41   * algorithms with certain key sizes and other
42   * restrictions in certain environments. <p>
43   *
44   * @see java.security.Permission
45   *
46   * @author Jan Luehe
47   * @author Sharon Liu
48   * @since 1.4
49   */
50  class CryptoPermission extends java.security.Permission {
51  
52      private static final long serialVersionUID = 8987399626114087514L;
53  
54      private String alg;
55      private int maxKeySize = Integer.MAX_VALUE; // no restriction on maxKeySize
56      private String exemptionMechanism = null;
57      private AlgorithmParameterSpec algParamSpec = null;
58      private boolean checkParam = false; // no restriction on param
59  
60      static final String ALG_NAME_WILDCARD = "*";
61  
62      /**
63       * Constructor that takes an algorithm name.
64       *
65       * This constructor implies that the given algorithm can be
66       * used without any restrictions.
67       *
68       * @param alg the algorithm name.
69       */
70      CryptoPermission(String alg) {
71          super(null);
72          this.alg = alg;
73      }
74  
75      /**
76       * Constructor that takes an algorithm name and a maximum
77       * key size.
78       *
79       * This constructor implies that the given algorithm can be
80       * used with a key size up to <code>maxKeySize</code>.
81       *
82       * @param alg the algorithm name.
83       *
84       * @param maxKeySize the maximum allowable key size,
85       * specified in number of bits.
86       */
87      CryptoPermission(String alg, int maxKeySize) {
88          super(null);
89          this.alg = alg;
90          this.maxKeySize = maxKeySize;
91      }
92  
93      /**
94       * Constructor that takes an algorithm name, a maximum
95       * key size, and an AlgorithmParameterSpec object.
96       *
97       * This constructor implies that the given algorithm can be
98       * used with a key size up to <code>maxKeySize</code>, and
99       * algorithm
100      * parameters up to the limits set in <code>algParamSpec</code>.
101      *
102      * @param alg the algorithm name.
103      *
104      * @param maxKeySize the maximum allowable key size,
105      * specified in number of bits.
106      *
107      * @param algParamSpec the limits for allowable algorithm
108      * parameters.
109      */
110     CryptoPermission(String alg,
111                      int maxKeySize,
112                      AlgorithmParameterSpec algParamSpec) {
113         super(null);
114         this.alg = alg;
115         this.maxKeySize = maxKeySize;
116         this.checkParam = true;
117         this.algParamSpec = algParamSpec;
118     }
119 
120     /**
121      * Constructor that takes an algorithm name and the name of
122      * an exemption mechanism.
123      *
124      * This constructor implies that the given algorithm can be
125      * used without any key size or algorithm parameter restrictions
126      * provided that the specified exemption mechanism is enforced.
127      *
128      * @param alg the algorithm name.
129      *
130      * @param exemptionMechanism the name of the exemption mechanism.
131      */
132     CryptoPermission(String alg,
133                      String exemptionMechanism) {
134         super(null);
135         this.alg = alg;
136         this.exemptionMechanism = exemptionMechanism;
137     }
138 
139     /**
140      * Constructor that takes an algorithm name, a maximum key
141      * size, and the name of an exemption mechanism.
142      *
143      * This constructor implies that the given algorithm can be
144      * used with a key size up to <code>maxKeySize</code>
145      * provided that the
146      * specified exemption mechanism is enforced.
147      *
148      * @param alg the algorithm name.
149      * @param maxKeySize the maximum allowable key size,
150      * specified in number of bits.
151      * @param exemptionMechanism the name of the exemption
152      * mechanism.
153      */
154     CryptoPermission(String alg,
155                      int maxKeySize,
156                      String exemptionMechanism) {
157         super(null);
158         this.alg = alg;
159         this.exemptionMechanism = exemptionMechanism;
160         this.maxKeySize = maxKeySize;
161     }
162 
163     /**
164      * Constructor that takes an algorithm name, a maximum key
165      * size, the name of an exemption mechanism, and an
166      * AlgorithmParameterSpec object.
167      *
168      * This constructor implies that the given algorithm can be
169      * used with a key size up to <code>maxKeySize</code>
170      * and algorithm
171      * parameters up to the limits set in <code>algParamSpec</code>
172      * provided that
173      * the specified exemption mechanism is enforced.
174      *
175      * @param alg the algorithm name.
176      * @param maxKeySize the maximum allowable key size,
177      * specified in number of bits.
178      * @param algParamSpec the limit for allowable algorithm
179      *  parameter spec.
180      * @param exemptionMechanism the name of the exemption
181      * mechanism.
182      */
183     CryptoPermission(String alg,
184                      int maxKeySize,
185                      AlgorithmParameterSpec algParamSpec,
186                      String exemptionMechanism) {
187         super(null);
188         this.alg = alg;
189         this.exemptionMechanism = exemptionMechanism;
190         this.maxKeySize = maxKeySize;
191         this.checkParam = true;
192         this.algParamSpec = algParamSpec;
193     }
194 
195     /**
196      * Checks if the specified permission is "implied" by
197      * this object.
198      * <p>
199      * More specifically, this method returns true if:<p>
200      * <ul>
201      * <li> <i>p</i> is an instance of CryptoPermission, and<p>
202      * <li> <i>p</i>'s algorithm name equals or (in the case of wildcards)
203      *       is implied by this permission's algorithm name, and<p>
204      * <li> <i>p</i>'s maximum allowable key size is less or
205      *       equal to this permission's maximum allowable key size, and<p>
206      * <li> <i>p</i>'s algorithm parameter spec equals or is
207      *        implied by this permission's algorithm parameter spec, and<p>
208      * <li> <i>p</i>'s exemptionMechanism equals or
209      *        is implied by this permission's
210      *        exemptionMechanism (a <code>null</code> exemption mechanism
211      *        implies any other exemption mechanism).
212      * </ul>
213      *
214      * @param p the permission to check against.
215      *
216      * @return true if the specified permission is equal to or
217      * implied by this permission, false otherwise.
218      */
219     public boolean implies(Permission p) {
220         if (!(p instanceof CryptoPermission))
221             return false;
222 
223         CryptoPermission cp = (CryptoPermission)p;
224 
225         if ((!alg.equalsIgnoreCase(cp.alg)) &&
226             (!alg.equalsIgnoreCase(ALG_NAME_WILDCARD))) {
227             return false;
228         }
229 
230         // alg is the same as cp's alg or
231         // alg is a wildcard.
232         if (cp.maxKeySize <= this.maxKeySize) {
233             // check algParamSpec.
234             if (!impliesParameterSpec(cp.checkParam, cp.algParamSpec)) {
235                 return false;
236             }
237 
238             // check exemptionMechanism.
239             if (impliesExemptionMechanism(cp.exemptionMechanism)) {
240                 return true;
241             }
242         }
243 
244         return false;
245     }
246 
247     /**
248      * Checks two CryptoPermission objects for equality. Checks that
249      * <code>obj</code> is a CryptoPermission, and has the same
250      * algorithm name,
251      * exemption mechanism name, maximum allowable key size and
252      * algorithm parameter spec
253      * as this object.
254      * <P>
255      * @param obj the object to test for equality with this object.
256      * @return true if <code>obj</code> is equal to this object.
257      */
258     public boolean equals(Object obj) {
259         if (obj == this)
260             return true;
261 
262         if (!(obj instanceof CryptoPermission))
263             return false;
264 
265         CryptoPermission that = (CryptoPermission) obj;
266 
267         if (!(alg.equalsIgnoreCase(that.alg)) ||
268             (maxKeySize != that.maxKeySize)) {
269             return false;
270         }
271         if (this.checkParam != that.checkParam) {
272             return false;
273         }
274         return (equalObjects(this.exemptionMechanism,
275                              that.exemptionMechanism) &&
276                 equalObjects(this.algParamSpec,
277                              that.algParamSpec));
278     }
279 
280     /**
281      * Returns the hash code value for this object.
282      *
283      * @return a hash code value for this object.
284      */
285 
286     public int hashCode() {
287         int retval = alg.hashCode();
288         retval ^= maxKeySize;
289         if (exemptionMechanism != null) {
290             retval ^= exemptionMechanism.hashCode();
291         }
292         if (checkParam) retval ^= 100;
293         if (algParamSpec != null) {
294             retval ^= algParamSpec.hashCode();
295         }
296         return retval;
297     }
298 
299     /**
300      * There is no action defined for a CryptoPermission
301      * onject.
302      */
303     public String getActions()
304     {
305         return null;
306     }
307 
308     /**
309      * Returns a new PermissionCollection object for storing
310      * CryptoPermission objects.
311      *
312      * @return a new PermissionCollection object suitable for storing
313      * CryptoPermissions.
314      */
315 
316     public PermissionCollection newPermissionCollection() {
317         return new CryptoPermissionCollection();
318     }
319 
320     /**
321      * Returns the algorithm name associated with
322      * this CryptoPermission object.
323      */
324     final String getAlgorithm() {
325         return alg;
326     }
327 
328     /**
329      * Returns the exemption mechanism name
330      * associated with this CryptoPermission
331      * object.
332      */
333     final String getExemptionMechanism() {
334         return exemptionMechanism;
335     }
336 
337     /**
338      * Returns the maximum allowable key size associated
339      * with this CryptoPermission object.
340      */
341     final int getMaxKeySize() {
342         return maxKeySize;
343     }
344 
345     /**
346      * Returns true if there is a limitation on the
347      * AlgorithmParameterSpec associated with this
348      * CryptoPermission object and false if otherwise.
349      */
350     final boolean getCheckParam() {
351         return checkParam;
352     }
353 
354     /**
355      * Returns the AlgorithmParameterSpec
356      * associated with this CryptoPermission
357      * object.
358      */
359     final AlgorithmParameterSpec getAlgorithmParameterSpec() {
360         return algParamSpec;
361     }
362 
363     /**
364      * Returns a string describing this CryptoPermission.  The convention is to
365      * specify the class name, the algorithm name, the maximum allowable
366      * key size, and the name of the exemption mechanism, in the following
367      * format: '("ClassName" "algorithm" "keysize" "exemption_mechanism")'.
368      *
369      * @return information about this CryptoPermission.
370      */
371     public String toString() {
372         StringBuilder buf = new StringBuilder(100);
373         buf.append("(CryptoPermission " + alg + " " + maxKeySize);
374         if (algParamSpec != null) {
375             if (algParamSpec instanceof RC2ParameterSpec) {
376                 buf.append(" , effective " +
377                     ((RC2ParameterSpec)algParamSpec).getEffectiveKeyBits());
378             } else if (algParamSpec instanceof RC5ParameterSpec) {
379                 buf.append(" , rounds " +
380                     ((RC5ParameterSpec)algParamSpec).getRounds());
381             }
382         }
383         if (exemptionMechanism != null) { // OPTIONAL
384             buf.append(" " + exemptionMechanism);
385         }
386         buf.append(")");
387         return buf.toString();
388     }
389 
390     private boolean impliesExemptionMechanism(String exemptionMechanism) {
391         if (this.exemptionMechanism == null) {
392             return true;
393         }
394 
395         if (exemptionMechanism == null) {
396             return false;
397         }
398 
399         if (this.exemptionMechanism.equals(exemptionMechanism)) {
400             return true;
401         }
402 
403         return false;
404     }
405 
406     private boolean impliesParameterSpec(boolean checkParam,
407                                          AlgorithmParameterSpec algParamSpec) {
408         if ((this.checkParam) && checkParam) {
409             if (algParamSpec == null) {
410                 return true;
411             } else if (this.algParamSpec == null) {
412                 return false;
413             }
414 
415             if (this.algParamSpec.getClass() != algParamSpec.getClass()) {
416                 return false;
417             }
418 
419             if (algParamSpec instanceof RC2ParameterSpec) {
420                 if (((RC2ParameterSpec)algParamSpec).getEffectiveKeyBits() <=
421                     ((RC2ParameterSpec)
422                      (this.algParamSpec)).getEffectiveKeyBits()) {
423                     return true;
424                 }
425             }
426 
427             if (algParamSpec instanceof RC5ParameterSpec) {
428                 if (((RC5ParameterSpec)algParamSpec).getRounds() <=
429                     ((RC5ParameterSpec)this.algParamSpec).getRounds()) {
430                     return true;
431                 }
432             }
433 
434             if (algParamSpec instanceof PBEParameterSpec) {
435                 if (((PBEParameterSpec)algParamSpec).getIterationCount() <=
436                     ((PBEParameterSpec)this.algParamSpec).getIterationCount()) {
437                     return true;
438                 }
439             }
440 
441             // For classes we don't know, the following
442             // may be the best try.
443             if (this.algParamSpec.equals(algParamSpec)) {
444                 return true;
445             }
446             return false;
447         } else if (this.checkParam) {
448             return false;
449         } else {
450             return true;
451         }
452     }
453 
454     private boolean equalObjects(Object obj1, Object obj2) {
455         if (obj1 == null) {
456             return (obj2 == null ? true : false);
457         }
458 
459         return obj1.equals(obj2);
460     }
461 }
462 
463 /**
464  * A CryptoPermissionCollection stores a set of CryptoPermission
465  * permissions.
466  *
467  * @see java.security.Permission
468  * @see java.security.Permissions
469  * @see java.security.PermissionCollection
470  *
471  * @author Sharon Liu
472  */
473 final class CryptoPermissionCollection extends PermissionCollection
474     implements Serializable
475 {
476     private static final long serialVersionUID = -511215555898802763L;
477 
478     private Vector<Permission> permissions;
479 
480     /**
481      * Creates an empty CryptoPermissionCollection
482      * object.
483      */
484     CryptoPermissionCollection() {
485         permissions = new Vector<Permission>(3);
486     }
487 
488     /**
489      * Adds a permission to the CryptoPermissionCollection.
490      *
491      * @param permission the Permission object to add.
492      *
493      * @exception SecurityException - if this CryptoPermissionCollection
494      * object has been marked <i>readOnly</i>.
495      */
496     public void add(Permission permission) {
497         if (isReadOnly())
498             throw new SecurityException("attempt to add a Permission " +
499                                         "to a readonly PermissionCollection");
500 
501         if (!(permission instanceof CryptoPermission))
502             return;
503 
504         permissions.addElement(permission);
505     }
506 
507     /**
508      * Check and see if this CryptoPermission object implies
509      * the given Permission object.
510      *
511      * @param permission the Permission object to compare
512      *
513      * @return true if the given permission  is implied by this
514      * CryptoPermissionCollection, false if not.
515      */
516     public boolean implies(Permission permission) {
517         if (!(permission instanceof CryptoPermission))
518             return false;
519 
520         CryptoPermission cp = (CryptoPermission)permission;
521 
522         Enumeration<Permission> e = permissions.elements();
523 
524         while (e.hasMoreElements()) {
525             CryptoPermission x = (CryptoPermission) e.nextElement();
526             if (x.implies(cp)) {
527                 return true;
528             }
529         }
530         return false;
531     }
532 
533     /**
534      * Returns an enumeration of all the CryptoPermission objects
535      * in the container.
536      *
537      * @return an enumeration of all the CryptoPermission objects.
538      */
539 
540     public Enumeration<Permission> elements() {
541         return permissions.elements();
542     }
543 }