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.security; 29 import java.util.Enumeration; 30 import java.util.Hashtable; 31 import java.util.Vector; 32 import java.util.NoSuchElementException; 33 import java.io.Serializable; 34 import java.io.InputStream; 35 import java.io.InputStreamReader; 36 import java.io.BufferedReader; 37 import java.io.IOException; 38 39 /** 40 * This class contains CryptoPermission objects, organized into 41 * PermissionCollections according to algorithm names. 42 * 43 * <p>When the <code>add</code> method is called to add a 44 * CryptoPermission, the CryptoPermission is stored in the 45 * appropriate PermissionCollection. If no such 46 * collection exists yet, the algorithm name associated with 47 * the CryptoPermission object is 48 * determined and the <code>newPermissionCollection</code> method 49 * is called on the CryptoPermission or CryptoAllPermission class to 50 * create the PermissionCollection and add it to the Permissions object. 51 * 52 * @see javax.crypto.CryptoPermission 53 * @see java.security.PermissionCollection 54 * @see java.security.Permissions 55 * 56 * @author Sharon Liu 57 * @since 1.4 58 */ 59 final class CryptoPermissions extends PermissionCollection 60 implements Serializable { 61 62 private static final long serialVersionUID = 4946547168093391015L; 63 64 // This class is similar to java.security.Permissions 65 private Hashtable perms; 66 67 /** 68 * Creates a new CryptoPermissions object containing 69 * no CryptoPermissionCollections. 70 */ 71 CryptoPermissions() { 72 perms = new Hashtable(7); 73 } 74 75 /** 76 * Populates the crypto policy from the specified 77 * InputStream into this CryptoPermissions object. 78 * 79 * @param in the InputStream to load from. 80 * 81 * @exception SecurityException if cannot load 82 * successfully. 83 */ 84 void load(InputStream in) 85 throws IOException, CryptoPolicyParser.ParsingException { 86 CryptoPolicyParser parser = new CryptoPolicyParser(); 87 parser.read(new BufferedReader(new InputStreamReader(in, "UTF-8"))); 88 89 CryptoPermission[] parsingResult = parser.getPermissions(); 90 for (int i = 0; i < parsingResult.length; i++) { 91 this.add(parsingResult[i]); 92 } 93 } 94 95 /** 96 * Returns true if this CryptoPermissions object doesn't 97 * contain any CryptoPermission objects; otherwise, returns 98 * false. 99 */ 100 boolean isEmpty() { 101 return perms.isEmpty(); 102 } 103 104 /** 105 * Adds a permission object to the PermissionCollection for the 106 * algorithm returned by 107 * <code>(CryptoPermission)permission.getAlgorithm()</code>. 108 * 109 * This method creates 110 * a new PermissionCollection object (and adds the permission to it) 111 * if an appropriate collection does not yet exist. <p> 112 * 113 * @param permission the Permission object to add. 114 * 115 * @exception SecurityException if this CryptoPermissions object is 116 * marked as readonly. 117 * 118 * @see isReadOnly 119 */ 120 public void add(Permission permission) { 121 122 if (isReadOnly()) 123 throw new SecurityException("Attempt to add a Permission " + 124 "to a readonly CryptoPermissions " + 125 "object"); 126 127 if (!(permission instanceof CryptoPermission)) 128 return; 129 130 CryptoPermission cryptoPerm = (CryptoPermission)permission; 131 PermissionCollection pc = 132 getPermissionCollection(cryptoPerm); 133 pc.add(cryptoPerm); 134 String alg = cryptoPerm.getAlgorithm(); 135 if (!perms.containsKey(alg)) { 136 perms.put(alg, pc); 137 } 138 } 139 140 /** 141 * Checks if this object's PermissionCollection for permissons 142 * of the specified permission's algorithm implies the specified 143 * permission. Returns true if the checking succeeded. 144 * 145 * @param permission the Permission object to check. 146 * 147 * @return true if "permission" is implied by the permissions 148 * in the PermissionCollection it belongs to, false if not. 149 * 150 */ 151 public boolean implies(Permission permission) { 152 if (!(permission instanceof CryptoPermission)) { 153 return false; 154 } 155 156 CryptoPermission cryptoPerm = (CryptoPermission)permission; 157 158 PermissionCollection pc = 159 getPermissionCollection(cryptoPerm.getAlgorithm()); 160 return pc.implies(cryptoPerm); 161 } 162 163 /** 164 * Returns an enumeration of all the Permission objects in all the 165 * PermissionCollections in this CryptoPermissions object. 166 * 167 * @return an enumeration of all the Permissions. 168 */ 169 public Enumeration elements() { 170 // go through each Permissions in the hash table 171 // and call their elements() function. 172 return new PermissionsEnumerator(perms.elements()); 173 } 174 175 /** 176 * Returns a CryptoPermissions object which 177 * represents the minimum of the specified 178 * CryptoPermissions object and this 179 * CryptoPermissions object. 180 * 181 * @param other the CryptoPermission 182 * object to compare with this object. 183 */ 184 CryptoPermissions getMinimum(CryptoPermissions other) { 185 if (other == null) { 186 return null; 187 } 188 189 if (this.perms.containsKey(CryptoAllPermission.ALG_NAME)) { 190 return other; 191 } 192 193 if (other.perms.containsKey(CryptoAllPermission.ALG_NAME)) { 194 return this; 195 } 196 197 CryptoPermissions ret = new CryptoPermissions(); 198 199 200 PermissionCollection thatWildcard = 201 (PermissionCollection)other.perms.get( 202 CryptoPermission.ALG_NAME_WILDCARD); 203 int maxKeySize = 0; 204 if (thatWildcard != null) { 205 maxKeySize = ((CryptoPermission) 206 thatWildcard.elements().nextElement()).getMaxKeySize(); 207 } 208 // For each algorithm in this CryptoPermissions, 209 // find out if there is anything we should add into 210 // ret. 211 Enumeration thisKeys = this.perms.keys(); 212 while (thisKeys.hasMoreElements()) { 213 String alg = (String)thisKeys.nextElement(); 214 215 PermissionCollection thisPc = 216 (PermissionCollection)this.perms.get(alg); 217 PermissionCollection thatPc = 218 (PermissionCollection)other.perms.get(alg); 219 220 CryptoPermission[] partialResult; 221 222 if (thatPc == null) { 223 if (thatWildcard == null) { 224 // The other CryptoPermissions 225 // doesn't allow this given 226 // algorithm at all. Just skip this 227 // algorithm. 228 continue; 229 } 230 partialResult = getMinimum(maxKeySize, thisPc); 231 } else { 232 partialResult = getMinimum(thisPc, thatPc); 233 } 234 235 for (int i = 0; i < partialResult.length; i++) { 236 ret.add(partialResult[i]); 237 } 238 } 239 240 PermissionCollection thisWildcard = 241 (PermissionCollection)this.perms.get( 242 CryptoPermission.ALG_NAME_WILDCARD); 243 244 // If this CryptoPermissions doesn't 245 // have a wildcard, we are done. 246 if (thisWildcard == null) { 247 return ret; 248 } 249 250 // Deal with the algorithms only appear 251 // in the other CryptoPermissions. 252 maxKeySize = 253 ((CryptoPermission) 254 thisWildcard.elements().nextElement()).getMaxKeySize(); 255 Enumeration thatKeys = other.perms.keys(); 256 while (thatKeys.hasMoreElements()) { 257 String alg = (String)thatKeys.nextElement(); 258 259 if (this.perms.containsKey(alg)) { 260 continue; 261 } 262 263 PermissionCollection thatPc = 264 (PermissionCollection)other.perms.get(alg); 265 266 CryptoPermission[] partialResult; 267 268 partialResult = getMinimum(maxKeySize, thatPc); 269 270 for (int i = 0; i < partialResult.length; i++) { 271 ret.add(partialResult[i]); 272 } 273 } 274 return ret; 275 } 276 277 /** 278 * Get the minimum of the two given PermissionCollection 279 * <code>thisPc</code> and <code>thatPc</code>. 280 * 281 * @param thisPc the first given PermissionColloection 282 * object. 283 * 284 * @param thatPc the second given PermissionCollection 285 * object. 286 */ 287 private CryptoPermission[] getMinimum(PermissionCollection thisPc, 288 PermissionCollection thatPc) { 289 Vector permVector = new Vector(2); 290 291 Enumeration thisPcPermissions = thisPc.elements(); 292 293 // For each CryptoPermission in 294 // thisPc object, do the following: 295 // 1) if this CryptoPermission is implied 296 // by thatPc, this CryptoPermission 297 // should be returned, and we can 298 // move on to check the next 299 // CryptoPermission in thisPc. 300 // 2) otherwise, we should return 301 // all CryptoPermissions in thatPc 302 // which 303 // are implied by this CryptoPermission. 304 // Then we can move on to the 305 // next CryptoPermission in thisPc. 306 while (thisPcPermissions.hasMoreElements()) { 307 CryptoPermission thisCp = 308 (CryptoPermission)thisPcPermissions.nextElement(); 309 310 Enumeration thatPcPermissions = thatPc.elements(); 311 while (thatPcPermissions.hasMoreElements()) { 312 CryptoPermission thatCp = 313 (CryptoPermission)thatPcPermissions.nextElement(); 314 315 if (thatCp.implies(thisCp)) { 316 permVector.addElement(thisCp); 317 break; 318 } 319 if (thisCp.implies(thatCp)) { 320 permVector.addElement(thatCp); 321 } 322 } 323 } 324 325 CryptoPermission[] ret = new CryptoPermission[permVector.size()]; 326 permVector.copyInto(ret); 327 return ret; 328 } 329 330 /** 331 * Returns all the CryptoPermission objects in the given 332 * PermissionCollection object 333 * whose maximum keysize no greater than <code>maxKeySize</code>. 334 * For all CryptoPermission objects with a maximum keysize greater 335 * than <code>maxKeySize</code>, this method constructs a 336 * corresponding CryptoPermission object whose maximum keysize is 337 * set to <code>maxKeySize</code>, and includes that in the result. 338 * 339 * @param maxKeySize the given maximum key size. 340 * 341 * @param pc the given PermissionCollection object. 342 */ 343 private CryptoPermission[] getMinimum(int maxKeySize, 344 PermissionCollection pc) { 345 Vector permVector = new Vector(1); 346 347 Enumeration enum_ = pc.elements(); 348 349 while (enum_.hasMoreElements()) { 350 CryptoPermission cp = 351 (CryptoPermission)enum_.nextElement(); 352 if (cp.getMaxKeySize() <= maxKeySize) { 353 permVector.addElement(cp); 354 } else { 355 if (cp.getCheckParam()) { 356 permVector.addElement( 357 new CryptoPermission(cp.getAlgorithm(), 358 maxKeySize, 359 cp.getAlgorithmParameterSpec(), 360 cp.getExemptionMechanism())); 361 } else { 362 permVector.addElement( 363 new CryptoPermission(cp.getAlgorithm(), 364 maxKeySize, 365 cp.getExemptionMechanism())); 366 } 367 } 368 } 369 370 CryptoPermission[] ret = new CryptoPermission[permVector.size()]; 371 permVector.copyInto(ret); 372 return ret; 373 } 374 375 /** 376 * Returns the PermissionCollection for the 377 * specified algorithm. Returns null if there 378 * isn't such a PermissionCollection. 379 * 380 * @param alg the algorithm name. 381 */ 382 PermissionCollection getPermissionCollection(String alg) { 383 // If this CryptoPermissions includes CryptoAllPermission, 384 // we should return CryptoAllPermission. 385 if (perms.containsKey(CryptoAllPermission.ALG_NAME)) { 386 return 387 (PermissionCollection)(perms.get(CryptoAllPermission.ALG_NAME)); 388 } 389 390 PermissionCollection pc = (PermissionCollection)perms.get(alg); 391 392 // If there isn't a PermissionCollection for 393 // the given algorithm,we should return the 394 // PermissionCollection for the wildcard 395 // if there is one. 396 if (pc == null) { 397 pc = (PermissionCollection)perms.get( 398 CryptoPermission.ALG_NAME_WILDCARD); 399 } 400 return pc; 401 } 402 403 /** 404 * Returns the PermissionCollection for the algorithm 405 * associated with the specified CryptoPermission 406 * object. Creates such a PermissionCollection 407 * if such a PermissionCollection does not 408 * exist yet. 409 * 410 * @param cryptoPerm the CryptoPermission object. 411 */ 412 private PermissionCollection getPermissionCollection( 413 CryptoPermission cryptoPerm) { 414 415 String alg = cryptoPerm.getAlgorithm(); 416 417 PermissionCollection pc = (PermissionCollection)perms.get(alg); 418 419 if (pc == null) { 420 pc = cryptoPerm.newPermissionCollection(); 421 } 422 return pc; 423 } 424 } 425 426 final class PermissionsEnumerator implements Enumeration { 427 428 // all the perms 429 private Enumeration perms; 430 // the current set 431 private Enumeration permset; 432 433 PermissionsEnumerator(Enumeration e) { 434 perms = e; 435 permset = getNextEnumWithMore(); 436 } 437 438 public synchronized boolean hasMoreElements() { 439 // if we enter with permissionimpl null, we know 440 // there are no more left. 441 442 if (permset == null) 443 return false; 444 445 // try to see if there are any left in the current one 446 447 if (permset.hasMoreElements()) 448 return true; 449 450 // get the next one that has something in it... 451 permset = getNextEnumWithMore(); 452 453 // if it is null, we are done! 454 return (permset != null); 455 } 456 457 public synchronized Object nextElement() { 458 // hasMoreElements will update permset to the next permset 459 // with something in it... 460 461 if (hasMoreElements()) { 462 return permset.nextElement(); 463 } else { 464 throw new NoSuchElementException("PermissionsEnumerator"); 465 } 466 467 } 468 469 private Enumeration getNextEnumWithMore() { 470 while (perms.hasMoreElements()) { 471 PermissionCollection pc = 472 (PermissionCollection) perms.nextElement(); 473 Enumeration next = pc.elements(); 474 if (next.hasMoreElements()) 475 return next; 476 } 477 return null; 478 } 479 }