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