Path: blob/master/src/java.base/share/classes/javax/crypto/JceSecurityManager.java
41152 views
/*1* Copyright (c) 1999, 2021, 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.net.*;29import java.util.*;30import java.util.concurrent.ConcurrentHashMap;31import java.util.concurrent.ConcurrentMap;3233/**34* The JCE security manager.35*36* <p>The JCE security manager is responsible for determining the maximum37* allowable cryptographic strength for a given applet/application, for a given38* algorithm, by consulting the configured jurisdiction policy files and39* the cryptographic permissions bundled with the applet/application.40*41* <p>Note that this security manager is never installed, only instantiated.42*43* @author Jan Luehe44*45* @since 1.446*/4748@SuppressWarnings("removal")49final class JceSecurityManager extends SecurityManager {5051private static final CryptoPermissions defaultPolicy;52private static final CryptoPermissions exemptPolicy;53private static final CryptoAllPermission allPerm;54private static final Vector<Class<?>> TrustedCallersCache =55new Vector<>(2);56private static final ConcurrentMap<URL,CryptoPermissions> exemptCache =57new ConcurrentHashMap<>();58private static final CryptoPermissions CACHE_NULL_MARK =59new CryptoPermissions();6061// singleton instance62static final JceSecurityManager INSTANCE;6364static {65defaultPolicy = JceSecurity.getDefaultPolicy();66exemptPolicy = JceSecurity.getExemptPolicy();67allPerm = CryptoAllPermission.INSTANCE;68INSTANCE = AccessController.doPrivileged(69new PrivilegedAction<>() {70public JceSecurityManager run() {71return new JceSecurityManager();72}73});74}7576private JceSecurityManager() {77// empty78}7980/**81* Returns the maximum allowable crypto strength for the given82* applet/application, for the given algorithm.83*/84CryptoPermission getCryptoPermission(String alg) {85// Need to convert to uppercase since the crypto perm86// lookup is case sensitive.87alg = alg.toUpperCase(Locale.ENGLISH);8889// If CryptoAllPermission is granted by default, we return that.90// Otherwise, this will be the permission we return if anything goes91// wrong.92CryptoPermission defaultPerm = getDefaultPermission(alg);93if (defaultPerm == CryptoAllPermission.INSTANCE) {94return defaultPerm;95}9697// Determine the codebase of the caller of the JCE API.98// This is the codebase of the first class which is not in99// javax.crypto.* packages.100// NOTE: javax.crypto.* package maybe subject to package101// insertion, so need to check its classloader as well.102Class<?>[] context = getClassContext();103URL callerCodeBase = null;104int i;105for (i=0; i<context.length; i++) {106Class<?> cls = context[i];107callerCodeBase = JceSecurity.getCodeBase(cls);108if (callerCodeBase != null) {109break;110} else {111if (cls.getName().startsWith("javax.crypto.")) {112// skip jce classes since they aren't the callers113continue;114}115// use default permission when the caller is system classes116return defaultPerm;117}118}119120if (i == context.length) {121return defaultPerm;122}123124CryptoPermissions appPerms = exemptCache.get(callerCodeBase);125if (appPerms == null) {126// no match found in cache127synchronized (this.getClass()) {128appPerms = exemptCache.get(callerCodeBase);129if (appPerms == null) {130appPerms = getAppPermissions(callerCodeBase);131exemptCache.putIfAbsent(callerCodeBase,132(appPerms == null? CACHE_NULL_MARK:appPerms));133}134}135}136if (appPerms == null || appPerms == CACHE_NULL_MARK) {137return defaultPerm;138}139140// If the app was granted the special CryptoAllPermission, return that.141if (appPerms.implies(allPerm)) {142return allPerm;143}144145// Check if the crypto permissions granted to the app contain a146// crypto permission for the requested algorithm that does not require147// any exemption mechanism to be enforced.148// Return that permission, if present.149PermissionCollection appPc = appPerms.getPermissionCollection(alg);150if (appPc == null) {151return defaultPerm;152}153Enumeration<Permission> enum_ = appPc.elements();154while (enum_.hasMoreElements()) {155CryptoPermission cp = (CryptoPermission)enum_.nextElement();156if (cp.getExemptionMechanism() == null) {157return cp;158}159}160161// Check if the jurisdiction file for exempt applications contains162// any entries for the requested algorithm.163// If not, return the default permission.164PermissionCollection exemptPc =165exemptPolicy.getPermissionCollection(alg);166if (exemptPc == null) {167return defaultPerm;168}169170// In the jurisdiction file for exempt applications, go through the171// list of CryptoPermission entries for the requested algorithm, and172// stop at the first entry:173// - that is implied by the collection of crypto permissions granted174// to the app, and175// - whose exemption mechanism is available from one of the176// registered CSPs177enum_ = exemptPc.elements();178while (enum_.hasMoreElements()) {179CryptoPermission cp = (CryptoPermission)enum_.nextElement();180try {181ExemptionMechanism.getInstance(cp.getExemptionMechanism());182if (cp.getAlgorithm().equals(183CryptoPermission.ALG_NAME_WILDCARD)) {184CryptoPermission newCp;185if (cp.getCheckParam()) {186newCp = new CryptoPermission(187alg, cp.getMaxKeySize(),188cp.getAlgorithmParameterSpec(),189cp.getExemptionMechanism());190} else {191newCp = new CryptoPermission(192alg, cp.getMaxKeySize(),193cp.getExemptionMechanism());194}195if (appPerms.implies(newCp)) {196return newCp;197}198}199200if (appPerms.implies(cp)) {201return cp;202}203} catch (Exception e) {204continue;205}206}207return defaultPerm;208}209210private static CryptoPermissions getAppPermissions(URL callerCodeBase) {211// Check if app is exempt, and retrieve the permissions bundled with it212try {213return JceSecurity.verifyExemptJar(callerCodeBase);214} catch (Exception e) {215// Jar verification fails216return null;217}218219}220221/**222* Returns the default permission for the given algorithm.223*/224private CryptoPermission getDefaultPermission(String alg) {225Enumeration<Permission> enum_ =226defaultPolicy.getPermissionCollection(alg).elements();227return (CryptoPermission)enum_.nextElement();228}229230// Only used by javax.crypto.Cipher constructor to disallow Cipher231// objects being constructed by untrusted code (See bug 4341369 &232// 4334690 for more info).233boolean isCallerTrusted(Provider provider) {234// Get the caller and its codebase.235Class<?>[] context = getClassContext();236if (context.length >= 3) {237// context[0]: class javax.crypto.JceSecurityManager238// context[1]: class javax.crypto.Cipher (or other JCE API class)239// context[2]: this is what we are gonna check240Class<?> caller = context[2];241URL callerCodeBase = JceSecurity.getCodeBase(caller);242if (callerCodeBase == null) {243return true;244}245// The caller has been verified.246if (TrustedCallersCache.contains(caller)) {247return true;248}249250// Check the association between caller and provider251Class<?> pCls = provider.getClass();252Module pMod = pCls.getModule();253// If they are in the same named module or share254// the same codebase, then they are associated255boolean sameOrigin = (pMod.isNamed()?256caller.getModule().equals(pMod) :257callerCodeBase.equals(JceSecurity.getCodeBase(pCls)));258if (sameOrigin) {259// The caller is from trusted provider260if (ProviderVerifier.isTrustedCryptoProvider(provider)) {261TrustedCallersCache.addElement(caller);262return true;263}264} else {265// Don't include the provider in the subsequent266// JceSecurity.verifyProvider(...) call267provider = null;268}269270// Check whether the caller is a trusted provider.271try {272JceSecurity.verifyProvider(callerCodeBase, provider);273} catch (Exception e2) {274return false;275}276TrustedCallersCache.addElement(caller);277return true;278}279return false;280}281}282283284