Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/crypto/CryptoPermissions.java
38829 views
/*1* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.crypto;2627import java.security.*;28import java.util.Enumeration;29import java.util.Hashtable;30import java.util.Vector;31import java.util.NoSuchElementException;32import java.util.concurrent.ConcurrentHashMap;33import java.io.Serializable;34import java.io.InputStream;35import java.io.InputStreamReader;36import java.io.BufferedReader;37import java.io.ObjectStreamField;38import java.io.ObjectInputStream;39import java.io.ObjectInputStream.GetField;40import java.io.ObjectOutputStream;41import java.io.ObjectOutputStream.PutField;42import java.io.IOException;4344/**45* This class contains CryptoPermission objects, organized into46* PermissionCollections according to algorithm names.47*48* <p>When the <code>add</code> method is called to add a49* CryptoPermission, the CryptoPermission is stored in the50* appropriate PermissionCollection. If no such51* collection exists yet, the algorithm name associated with52* the CryptoPermission object is53* determined and the <code>newPermissionCollection</code> method54* is called on the CryptoPermission or CryptoAllPermission class to55* create the PermissionCollection and add it to the Permissions object.56*57* @see javax.crypto.CryptoPermission58* @see java.security.PermissionCollection59* @see java.security.Permissions60*61* @author Sharon Liu62* @since 1.463*/64final class CryptoPermissions extends PermissionCollection65implements Serializable {6667private static final long serialVersionUID = 4946547168093391015L;6869/**70* @serialField perms java.util.Hashtable71*/72private static final ObjectStreamField[] serialPersistentFields = {73new ObjectStreamField("perms", Hashtable.class),74};7576// Switched from Hashtable to ConcurrentHashMap to improve scalability.77// To maintain serialization compatibility, this field is made transient78// and custom readObject/writeObject methods are used.79private transient ConcurrentHashMap<String,PermissionCollection> perms;8081/**82* Creates a new CryptoPermissions object containing83* no CryptoPermissionCollections.84*/85CryptoPermissions() {86perms = new ConcurrentHashMap<>(7);87}8889/**90* Populates the crypto policy from the specified91* InputStream into this CryptoPermissions object.92*93* @param in the InputStream to load from.94*95* @exception SecurityException if cannot load96* successfully.97*/98void load(InputStream in)99throws IOException, CryptoPolicyParser.ParsingException {100CryptoPolicyParser parser = new CryptoPolicyParser();101parser.read(new BufferedReader(new InputStreamReader(in, "UTF-8")));102103CryptoPermission[] parsingResult = parser.getPermissions();104for (int i = 0; i < parsingResult.length; i++) {105this.add(parsingResult[i]);106}107}108109/**110* Returns true if this CryptoPermissions object doesn't111* contain any CryptoPermission objects; otherwise, returns112* false.113*/114boolean isEmpty() {115return perms.isEmpty();116}117118/**119* Adds a permission object to the PermissionCollection for the120* algorithm returned by121* <code>(CryptoPermission)permission.getAlgorithm()</code>.122*123* This method creates124* a new PermissionCollection object (and adds the permission to it)125* if an appropriate collection does not yet exist. <p>126*127* @param permission the Permission object to add.128*129* @exception SecurityException if this CryptoPermissions object is130* marked as readonly.131*132* @see isReadOnly133*/134public void add(Permission permission) {135136if (isReadOnly())137throw new SecurityException("Attempt to add a Permission " +138"to a readonly CryptoPermissions " +139"object");140141if (!(permission instanceof CryptoPermission))142return;143144CryptoPermission cryptoPerm = (CryptoPermission)permission;145PermissionCollection pc =146getPermissionCollection(cryptoPerm);147pc.add(cryptoPerm);148String alg = cryptoPerm.getAlgorithm();149perms.putIfAbsent(alg, pc);150}151152/**153* Checks if this object's PermissionCollection for permissons154* of the specified permission's algorithm implies the specified155* permission. Returns true if the checking succeeded.156*157* @param permission the Permission object to check.158*159* @return true if "permission" is implied by the permissions160* in the PermissionCollection it belongs to, false if not.161*162*/163public boolean implies(Permission permission) {164if (!(permission instanceof CryptoPermission)) {165return false;166}167168CryptoPermission cryptoPerm = (CryptoPermission)permission;169170PermissionCollection pc =171getPermissionCollection(cryptoPerm.getAlgorithm());172return pc.implies(cryptoPerm);173}174175/**176* Returns an enumeration of all the Permission objects in all the177* PermissionCollections in this CryptoPermissions object.178*179* @return an enumeration of all the Permissions.180*/181public Enumeration<Permission> elements() {182// go through each Permissions in the hash table183// and call their elements() function.184return new PermissionsEnumerator(perms.elements());185}186187/**188* Returns a CryptoPermissions object which189* represents the minimum of the specified190* CryptoPermissions object and this191* CryptoPermissions object.192*193* @param other the CryptoPermission194* object to compare with this object.195*/196CryptoPermissions getMinimum(CryptoPermissions other) {197if (other == null) {198return null;199}200201if (this.perms.containsKey(CryptoAllPermission.ALG_NAME)) {202return other;203}204205if (other.perms.containsKey(CryptoAllPermission.ALG_NAME)) {206return this;207}208209CryptoPermissions ret = new CryptoPermissions();210211212PermissionCollection thatWildcard =213other.perms.get(CryptoPermission.ALG_NAME_WILDCARD);214int maxKeySize = 0;215if (thatWildcard != null) {216maxKeySize = ((CryptoPermission)217thatWildcard.elements().nextElement()).getMaxKeySize();218}219// For each algorithm in this CryptoPermissions,220// find out if there is anything we should add into221// ret.222Enumeration<String> thisKeys = this.perms.keys();223while (thisKeys.hasMoreElements()) {224String alg = thisKeys.nextElement();225226PermissionCollection thisPc = this.perms.get(alg);227PermissionCollection thatPc = other.perms.get(alg);228229CryptoPermission[] partialResult;230231if (thatPc == null) {232if (thatWildcard == null) {233// The other CryptoPermissions234// doesn't allow this given235// algorithm at all. Just skip this236// algorithm.237continue;238}239partialResult = getMinimum(maxKeySize, thisPc);240} else {241partialResult = getMinimum(thisPc, thatPc);242}243244for (int i = 0; i < partialResult.length; i++) {245ret.add(partialResult[i]);246}247}248249PermissionCollection thisWildcard =250this.perms.get(CryptoPermission.ALG_NAME_WILDCARD);251252// If this CryptoPermissions doesn't253// have a wildcard, we are done.254if (thisWildcard == null) {255return ret;256}257258// Deal with the algorithms only appear259// in the other CryptoPermissions.260maxKeySize =261((CryptoPermission)262thisWildcard.elements().nextElement()).getMaxKeySize();263Enumeration<String> thatKeys = other.perms.keys();264while (thatKeys.hasMoreElements()) {265String alg = thatKeys.nextElement();266267if (this.perms.containsKey(alg)) {268continue;269}270271PermissionCollection thatPc = other.perms.get(alg);272273CryptoPermission[] partialResult;274275partialResult = getMinimum(maxKeySize, thatPc);276277for (int i = 0; i < partialResult.length; i++) {278ret.add(partialResult[i]);279}280}281return ret;282}283284/**285* Get the minimum of the two given PermissionCollection286* <code>thisPc</code> and <code>thatPc</code>.287*288* @param thisPc the first given PermissionColloection289* object.290*291* @param thatPc the second given PermissionCollection292* object.293*/294private CryptoPermission[] getMinimum(PermissionCollection thisPc,295PermissionCollection thatPc) {296Vector<CryptoPermission> permVector = new Vector<>(2);297298Enumeration<Permission> thisPcPermissions = thisPc.elements();299300// For each CryptoPermission in301// thisPc object, do the following:302// 1) if this CryptoPermission is implied303// by thatPc, this CryptoPermission304// should be returned, and we can305// move on to check the next306// CryptoPermission in thisPc.307// 2) otherwise, we should return308// all CryptoPermissions in thatPc309// which310// are implied by this CryptoPermission.311// Then we can move on to the312// next CryptoPermission in thisPc.313while (thisPcPermissions.hasMoreElements()) {314CryptoPermission thisCp =315(CryptoPermission)thisPcPermissions.nextElement();316317Enumeration<Permission> thatPcPermissions = thatPc.elements();318while (thatPcPermissions.hasMoreElements()) {319CryptoPermission thatCp =320(CryptoPermission)thatPcPermissions.nextElement();321322if (thatCp.implies(thisCp)) {323permVector.addElement(thisCp);324break;325}326if (thisCp.implies(thatCp)) {327permVector.addElement(thatCp);328}329}330}331332CryptoPermission[] ret = new CryptoPermission[permVector.size()];333permVector.copyInto(ret);334return ret;335}336337/**338* Returns all the CryptoPermission objects in the given339* PermissionCollection object340* whose maximum keysize no greater than <code>maxKeySize</code>.341* For all CryptoPermission objects with a maximum keysize greater342* than <code>maxKeySize</code>, this method constructs a343* corresponding CryptoPermission object whose maximum keysize is344* set to <code>maxKeySize</code>, and includes that in the result.345*346* @param maxKeySize the given maximum key size.347*348* @param pc the given PermissionCollection object.349*/350private CryptoPermission[] getMinimum(int maxKeySize,351PermissionCollection pc) {352Vector<CryptoPermission> permVector = new Vector<>(1);353354Enumeration<Permission> enum_ = pc.elements();355356while (enum_.hasMoreElements()) {357CryptoPermission cp =358(CryptoPermission)enum_.nextElement();359if (cp.getMaxKeySize() <= maxKeySize) {360permVector.addElement(cp);361} else {362if (cp.getCheckParam()) {363permVector.addElement(364new CryptoPermission(cp.getAlgorithm(),365maxKeySize,366cp.getAlgorithmParameterSpec(),367cp.getExemptionMechanism()));368} else {369permVector.addElement(370new CryptoPermission(cp.getAlgorithm(),371maxKeySize,372cp.getExemptionMechanism()));373}374}375}376377CryptoPermission[] ret = new CryptoPermission[permVector.size()];378permVector.copyInto(ret);379return ret;380}381382/**383* Returns the PermissionCollection for the384* specified algorithm. Returns null if there385* isn't such a PermissionCollection.386*387* @param alg the algorithm name.388*/389PermissionCollection getPermissionCollection(String alg) {390// If this CryptoPermissions includes CryptoAllPermission,391// we should return CryptoAllPermission.392PermissionCollection pc = perms.get(CryptoAllPermission.ALG_NAME);393if (pc == null) {394pc = perms.get(alg);395396// If there isn't a PermissionCollection for397// the given algorithm,we should return the398// PermissionCollection for the wildcard399// if there is one.400if (pc == null) {401pc = perms.get(CryptoPermission.ALG_NAME_WILDCARD);402}403}404return pc;405}406407/**408* Returns the PermissionCollection for the algorithm409* associated with the specified CryptoPermission410* object. Creates such a PermissionCollection411* if such a PermissionCollection does not412* exist yet.413*414* @param cryptoPerm the CryptoPermission object.415*/416private PermissionCollection getPermissionCollection(417CryptoPermission cryptoPerm) {418419String alg = cryptoPerm.getAlgorithm();420421PermissionCollection pc = perms.get(alg);422423if (pc == null) {424pc = cryptoPerm.newPermissionCollection();425}426return pc;427}428429private void readObject(ObjectInputStream s)430throws IOException, ClassNotFoundException {431ObjectInputStream.GetField fields = s.readFields();432@SuppressWarnings("unchecked")433Hashtable<String,PermissionCollection> permTable =434(Hashtable<String,PermissionCollection>)435(fields.get("perms", null));436if (permTable != null) {437perms = new ConcurrentHashMap<>(permTable);438} else {439perms = new ConcurrentHashMap<>();440}441}442443private void writeObject(ObjectOutputStream s) throws IOException {444Hashtable<String,PermissionCollection> permTable =445new Hashtable<>(perms);446ObjectOutputStream.PutField fields = s.putFields();447fields.put("perms", permTable);448s.writeFields();449}450}451452final class PermissionsEnumerator implements Enumeration<Permission> {453454// all the perms455private Enumeration<PermissionCollection> perms;456// the current set457private Enumeration<Permission> permset;458459PermissionsEnumerator(Enumeration<PermissionCollection> e) {460perms = e;461permset = getNextEnumWithMore();462}463464public synchronized boolean hasMoreElements() {465// if we enter with permissionimpl null, we know466// there are no more left.467468if (permset == null)469return false;470471// try to see if there are any left in the current one472473if (permset.hasMoreElements())474return true;475476// get the next one that has something in it...477permset = getNextEnumWithMore();478479// if it is null, we are done!480return (permset != null);481}482483public synchronized Permission nextElement() {484// hasMoreElements will update permset to the next permset485// with something in it...486487if (hasMoreElements()) {488return permset.nextElement();489} else {490throw new NoSuchElementException("PermissionsEnumerator");491}492}493494private Enumeration<Permission> getNextEnumWithMore() {495while (perms.hasMoreElements()) {496PermissionCollection pc = perms.nextElement();497Enumeration<Permission> next = pc.elements();498if (next.hasMoreElements())499return next;500}501return null;502}503}504505506