Path: blob/master/src/java.base/share/classes/javax/crypto/CryptoPermissions.java
41152 views
/*1* Copyright (c) 1999, 2019, 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.ObjectOutputStream;40import java.io.IOException;4142import static java.nio.charset.StandardCharsets.UTF_8;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 {6667@java.io.Serial68private static final long serialVersionUID = 4946547168093391015L;6970/**71* @serialField perms java.util.Hashtable72*/73@java.io.Serial74private static final ObjectStreamField[] serialPersistentFields = {75new ObjectStreamField("perms", Hashtable.class),76};7778// Switched from Hashtable to ConcurrentHashMap to improve scalability.79// To maintain serialization compatibility, this field is made transient80// and custom readObject/writeObject methods are used.81private transient ConcurrentHashMap<String,PermissionCollection> perms;8283/**84* Creates a new CryptoPermissions object containing85* no CryptoPermissionCollections.86*/87CryptoPermissions() {88perms = new ConcurrentHashMap<>(7);89}9091/**92* Populates the crypto policy from the specified93* InputStream into this CryptoPermissions object.94*95* @param in the InputStream to load from.96*97* @exception SecurityException if cannot load98* successfully.99*/100void load(InputStream in)101throws IOException, CryptoPolicyParser.ParsingException {102CryptoPolicyParser parser = new CryptoPolicyParser();103parser.read(new BufferedReader(new InputStreamReader(in, UTF_8)));104105CryptoPermission[] parsingResult = parser.getPermissions();106for (int i = 0; i < parsingResult.length; i++) {107this.add(parsingResult[i]);108}109}110111/**112* Returns true if this CryptoPermissions object doesn't113* contain any CryptoPermission objects; otherwise, returns114* false.115*/116boolean isEmpty() {117return perms.isEmpty();118}119120/**121* Adds a permission object to the PermissionCollection for the122* algorithm returned by123* <code>(CryptoPermission)permission.getAlgorithm()</code>.124*125* This method creates126* a new PermissionCollection object (and adds the permission to it)127* if an appropriate collection does not yet exist. <p>128*129* @param permission the Permission object to add.130*131* @exception SecurityException if this CryptoPermissions object is132* marked as readonly.133*134* @see isReadOnly135*/136@Override137public void add(Permission permission) {138139if (isReadOnly()) {140throw new SecurityException("Attempt to add a Permission " +141"to a readonly CryptoPermissions " +142"object");143}144145if (!(permission instanceof CryptoPermission)) {146return;147}148149CryptoPermission cryptoPerm = (CryptoPermission)permission;150PermissionCollection pc =151getPermissionCollection(cryptoPerm);152pc.add(cryptoPerm);153String alg = cryptoPerm.getAlgorithm();154perms.putIfAbsent(alg, pc);155}156157/**158* Checks if this object's PermissionCollection for permissons159* of the specified permission's algorithm implies the specified160* permission. Returns true if the checking succeeded.161*162* @param permission the Permission object to check.163*164* @return true if "permission" is implied by the permissions165* in the PermissionCollection it belongs to, false if not.166*167*/168@Override169public boolean implies(Permission permission) {170if (!(permission instanceof CryptoPermission)) {171return false;172}173174CryptoPermission cryptoPerm = (CryptoPermission)permission;175176PermissionCollection pc =177getPermissionCollection(cryptoPerm.getAlgorithm());178179if (pc != null) {180return pc.implies(cryptoPerm);181} else {182// none found183return false;184}185}186187/**188* Returns an enumeration of all the Permission objects in all the189* PermissionCollections in this CryptoPermissions object.190*191* @return an enumeration of all the Permissions.192*/193@Override194public Enumeration<Permission> elements() {195// go through each Permissions in the hash table196// and call their elements() function.197return new PermissionsEnumerator(perms.elements());198}199200/**201* Returns a CryptoPermissions object which202* represents the minimum of the specified203* CryptoPermissions object and this204* CryptoPermissions object.205*206* @param other the CryptoPermission207* object to compare with this object.208*/209CryptoPermissions getMinimum(CryptoPermissions other) {210if (other == null) {211return null;212}213214if (this.perms.containsKey(CryptoAllPermission.ALG_NAME)) {215return other;216}217218if (other.perms.containsKey(CryptoAllPermission.ALG_NAME)) {219return this;220}221222CryptoPermissions ret = new CryptoPermissions();223224225PermissionCollection thatWildcard =226other.perms.get(CryptoPermission.ALG_NAME_WILDCARD);227int maxKeySize = 0;228if (thatWildcard != null) {229maxKeySize = ((CryptoPermission)230thatWildcard.elements().nextElement()).getMaxKeySize();231}232// For each algorithm in this CryptoPermissions,233// find out if there is anything we should add into234// ret.235Enumeration<String> thisKeys = this.perms.keys();236while (thisKeys.hasMoreElements()) {237String alg = thisKeys.nextElement();238239PermissionCollection thisPc = this.perms.get(alg);240PermissionCollection thatPc = other.perms.get(alg);241242CryptoPermission[] partialResult;243244if (thatPc == null) {245if (thatWildcard == null) {246// The other CryptoPermissions247// doesn't allow this given248// algorithm at all. Just skip this249// algorithm.250continue;251}252partialResult = getMinimum(maxKeySize, thisPc);253} else {254partialResult = getMinimum(thisPc, thatPc);255}256257for (int i = 0; i < partialResult.length; i++) {258ret.add(partialResult[i]);259}260}261262PermissionCollection thisWildcard =263this.perms.get(CryptoPermission.ALG_NAME_WILDCARD);264265// If this CryptoPermissions doesn't266// have a wildcard, we are done.267if (thisWildcard == null) {268return ret;269}270271// Deal with the algorithms only appear272// in the other CryptoPermissions.273maxKeySize =274((CryptoPermission)275thisWildcard.elements().nextElement()).getMaxKeySize();276Enumeration<String> thatKeys = other.perms.keys();277while (thatKeys.hasMoreElements()) {278String alg = thatKeys.nextElement();279280if (this.perms.containsKey(alg)) {281continue;282}283284PermissionCollection thatPc = other.perms.get(alg);285286CryptoPermission[] partialResult;287288partialResult = getMinimum(maxKeySize, thatPc);289290for (int i = 0; i < partialResult.length; i++) {291ret.add(partialResult[i]);292}293}294return ret;295}296297/**298* Get the minimum of the two given PermissionCollection299* <code>thisPc</code> and <code>thatPc</code>.300*301* @param thisPc the first given PermissionColloection302* object.303*304* @param thatPc the second given PermissionCollection305* object.306*/307private CryptoPermission[] getMinimum(PermissionCollection thisPc,308PermissionCollection thatPc) {309Vector<CryptoPermission> permVector = new Vector<>(2);310311Enumeration<Permission> thisPcPermissions = thisPc.elements();312313// For each CryptoPermission in314// thisPc object, do the following:315// 1) if this CryptoPermission is implied316// by thatPc, this CryptoPermission317// should be returned, and we can318// move on to check the next319// CryptoPermission in thisPc.320// 2) otherwise, we should return321// all CryptoPermissions in thatPc322// which323// are implied by this CryptoPermission.324// Then we can move on to the325// next CryptoPermission in thisPc.326while (thisPcPermissions.hasMoreElements()) {327CryptoPermission thisCp =328(CryptoPermission)thisPcPermissions.nextElement();329330Enumeration<Permission> thatPcPermissions = thatPc.elements();331while (thatPcPermissions.hasMoreElements()) {332CryptoPermission thatCp =333(CryptoPermission)thatPcPermissions.nextElement();334335if (thatCp.implies(thisCp)) {336permVector.addElement(thisCp);337break;338}339if (thisCp.implies(thatCp)) {340permVector.addElement(thatCp);341}342}343}344345CryptoPermission[] ret = new CryptoPermission[permVector.size()];346permVector.copyInto(ret);347return ret;348}349350/**351* Returns all the CryptoPermission objects in the given352* PermissionCollection object353* whose maximum keysize no greater than <code>maxKeySize</code>.354* For all CryptoPermission objects with a maximum keysize greater355* than <code>maxKeySize</code>, this method constructs a356* corresponding CryptoPermission object whose maximum keysize is357* set to <code>maxKeySize</code>, and includes that in the result.358*359* @param maxKeySize the given maximum key size.360*361* @param pc the given PermissionCollection object.362*/363private CryptoPermission[] getMinimum(int maxKeySize,364PermissionCollection pc) {365Vector<CryptoPermission> permVector = new Vector<>(1);366367Enumeration<Permission> enum_ = pc.elements();368369while (enum_.hasMoreElements()) {370CryptoPermission cp =371(CryptoPermission)enum_.nextElement();372if (cp.getMaxKeySize() <= maxKeySize) {373permVector.addElement(cp);374} else {375if (cp.getCheckParam()) {376permVector.addElement(377new CryptoPermission(cp.getAlgorithm(),378maxKeySize,379cp.getAlgorithmParameterSpec(),380cp.getExemptionMechanism()));381} else {382permVector.addElement(383new CryptoPermission(cp.getAlgorithm(),384maxKeySize,385cp.getExemptionMechanism()));386}387}388}389390CryptoPermission[] ret = new CryptoPermission[permVector.size()];391permVector.copyInto(ret);392return ret;393}394395/**396* Returns the PermissionCollection for the397* specified algorithm. Returns null if there398* isn't such a PermissionCollection.399*400* @param alg the algorithm name.401*/402PermissionCollection getPermissionCollection(String alg) {403// If this CryptoPermissions includes CryptoAllPermission,404// we should return CryptoAllPermission.405PermissionCollection pc = perms.get(CryptoAllPermission.ALG_NAME);406if (pc == null) {407pc = perms.get(alg);408409// If there isn't a PermissionCollection for410// the given algorithm,we should return the411// PermissionCollection for the wildcard412// if there is one.413if (pc == null) {414pc = perms.get(CryptoPermission.ALG_NAME_WILDCARD);415}416}417return pc;418}419420/**421* Returns the PermissionCollection for the algorithm422* associated with the specified CryptoPermission423* object. Creates such a PermissionCollection424* if such a PermissionCollection does not425* exist yet.426*427* @param cryptoPerm the CryptoPermission object.428*/429private PermissionCollection getPermissionCollection(430CryptoPermission cryptoPerm) {431432String alg = cryptoPerm.getAlgorithm();433434PermissionCollection pc = perms.get(alg);435436if (pc == null) {437pc = cryptoPerm.newPermissionCollection();438}439return pc;440}441442@java.io.Serial443private void readObject(ObjectInputStream s)444throws IOException, ClassNotFoundException {445ObjectInputStream.GetField fields = s.readFields();446@SuppressWarnings("unchecked")447Hashtable<String,PermissionCollection> permTable =448(Hashtable<String,PermissionCollection>)449(fields.get("perms", null));450if (permTable != null) {451perms = new ConcurrentHashMap<>(permTable);452} else {453perms = new ConcurrentHashMap<>();454}455}456457@java.io.Serial458private void writeObject(ObjectOutputStream s) throws IOException {459Hashtable<String,PermissionCollection> permTable =460new Hashtable<>(perms);461ObjectOutputStream.PutField fields = s.putFields();462fields.put("perms", permTable);463s.writeFields();464}465}466467final class PermissionsEnumerator implements Enumeration<Permission> {468469// all the perms470private final Enumeration<PermissionCollection> perms;471// the current set472private Enumeration<Permission> permset;473474PermissionsEnumerator(Enumeration<PermissionCollection> e) {475perms = e;476permset = getNextEnumWithMore();477}478479@Override480public synchronized boolean hasMoreElements() {481// if we enter with permissionimpl null, we know482// there are no more left.483484if (permset == null) {485return false;486}487488// try to see if there are any left in the current one489490if (permset.hasMoreElements()) {491return true;492}493494// get the next one that has something in it...495permset = getNextEnumWithMore();496497// if it is null, we are done!498return (permset != null);499}500501@Override502public synchronized Permission nextElement() {503// hasMoreElements will update permset to the next permset504// with something in it...505506if (hasMoreElements()) {507return permset.nextElement();508} else {509throw new NoSuchElementException("PermissionsEnumerator");510}511}512513private Enumeration<Permission> getNextEnumWithMore() {514while (perms.hasMoreElements()) {515PermissionCollection pc = perms.nextElement();516Enumeration<Permission> next = pc.elements();517if (next.hasMoreElements()) {518return next;519}520}521return null;522}523}524525526