1 /*
2 * Copyright (c) 1999, 2017, 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.net.*;
30 import java.util.*;
31 import java.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.ConcurrentMap;
33
34 /**
35 * The JCE security manager.
36 *
37 * <p>The JCE security manager is responsible for determining the maximum
38 * allowable cryptographic strength for a given applet/application, for a given
39 * algorithm, by consulting the configured jurisdiction policy files and
40 * the cryptographic permissions bundled with the applet/application.
41 *
42 * <p>Note that this security manager is never installed, only instantiated.
43 *
44 * @author Jan Luehe
45 *
46 * @since 1.4
47 */
48
49 final class JceSecurityManager extends SecurityManager {
50
51 private static final CryptoPermissions defaultPolicy;
52 private static final CryptoPermissions exemptPolicy;
53 private static final CryptoAllPermission allPerm;
54 private static final Vector<Class<?>> TrustedCallersCache =
55 new Vector<>(2);
56 private static final ConcurrentMap<URL,CryptoPermissions> exemptCache =
57 new ConcurrentHashMap<>();
58 private static final CryptoPermissions CACHE_NULL_MARK =
59 new CryptoPermissions();
60
61 // singleton instance
62 static final JceSecurityManager INSTANCE;
63
64 static {
65 defaultPolicy = JceSecurity.getDefaultPolicy();
66 exemptPolicy = JceSecurity.getExemptPolicy();
67 allPerm = CryptoAllPermission.INSTANCE;
68 INSTANCE = AccessController.doPrivileged(
69 new PrivilegedAction<>() {
70 public JceSecurityManager run() {
71 return new JceSecurityManager();
72 }
73 });
74 }
75
76 private JceSecurityManager() {
77 // empty
78 }
79
80 /**
81 * Returns the maximum allowable crypto strength for the given
82 * applet/application, for the given algorithm.
83 */
84 CryptoPermission getCryptoPermission(String alg) {
85 // Need to convert to uppercase since the crypto perm
86 // lookup is case sensitive.
87 alg = alg.toUpperCase(Locale.ENGLISH);
88
89 // If CryptoAllPermission is granted by default, we return that.
90 // Otherwise, this will be the permission we return if anything goes
91 // wrong.
92 CryptoPermission defaultPerm = getDefaultPermission(alg);
93 if (defaultPerm == CryptoAllPermission.INSTANCE) {
94 return defaultPerm;
95 }
96
97 // Determine the codebase of the caller of the JCE API.
98 // This is the codebase of the first class which is not in
99 // javax.crypto.* packages.
100 // NOTE: javax.crypto.* package maybe subject to package
101 // insertion, so need to check its classloader as well.
102 Class<?>[] context = getClassContext();
103 URL callerCodeBase = null;
104 int i;
105 for (i=0; i<context.length; i++) {
106 Class<?> cls = context[i];
107 callerCodeBase = JceSecurity.getCodeBase(cls);
108 if (callerCodeBase != null) {
109 break;
110 } else {
111 if (cls.getName().startsWith("javax.crypto.")) {
112 // skip jce classes since they aren't the callers
113 continue;
114 }
115 // use default permission when the caller is system classes
116 return defaultPerm;
117 }
118 }
119
120 if (i == context.length) {
121 return defaultPerm;
122 }
123
124 CryptoPermissions appPerms = exemptCache.get(callerCodeBase);
125 if (appPerms == null) {
126 // no match found in cache
127 synchronized (this.getClass()) {
128 appPerms = exemptCache.get(callerCodeBase);
129 if (appPerms == null) {
130 appPerms = getAppPermissions(callerCodeBase);
131 exemptCache.putIfAbsent(callerCodeBase,
132 (appPerms == null? CACHE_NULL_MARK:appPerms));
133 }
134 }
135 }
136 if (appPerms == null || appPerms == CACHE_NULL_MARK) {
137 return defaultPerm;
138 }
139
140 // If the app was granted the special CryptoAllPermission, return that.
141 if (appPerms.implies(allPerm)) {
142 return allPerm;
143 }
144
145 // Check if the crypto permissions granted to the app contain a
146 // crypto permission for the requested algorithm that does not require
147 // any exemption mechanism to be enforced.
148 // Return that permission, if present.
149 PermissionCollection appPc = appPerms.getPermissionCollection(alg);
150 if (appPc == null) {
151 return defaultPerm;
152 }
153 Enumeration<Permission> enum_ = appPc.elements();
154 while (enum_.hasMoreElements()) {
155 CryptoPermission cp = (CryptoPermission)enum_.nextElement();
156 if (cp.getExemptionMechanism() == null) {
157 return cp;
158 }
159 }
160
161 // Check if the jurisdiction file for exempt applications contains
162 // any entries for the requested algorithm.
163 // If not, return the default permission.
164 PermissionCollection exemptPc =
165 exemptPolicy.getPermissionCollection(alg);
166 if (exemptPc == null) {
167 return defaultPerm;
168 }
169
170 // In the jurisdiction file for exempt applications, go through the
171 // list of CryptoPermission entries for the requested algorithm, and
172 // stop at the first entry:
173 // - that is implied by the collection of crypto permissions granted
174 // to the app, and
175 // - whose exemption mechanism is available from one of the
176 // registered CSPs
177 enum_ = exemptPc.elements();
178 while (enum_.hasMoreElements()) {
179 CryptoPermission cp = (CryptoPermission)enum_.nextElement();
180 try {
181 ExemptionMechanism.getInstance(cp.getExemptionMechanism());
182 if (cp.getAlgorithm().equals(
183 CryptoPermission.ALG_NAME_WILDCARD)) {
184 CryptoPermission newCp;
185 if (cp.getCheckParam()) {
186 newCp = new CryptoPermission(
187 alg, cp.getMaxKeySize(),
188 cp.getAlgorithmParameterSpec(),
189 cp.getExemptionMechanism());
190 } else {
191 newCp = new CryptoPermission(
192 alg, cp.getMaxKeySize(),
193 cp.getExemptionMechanism());
194 }
195 if (appPerms.implies(newCp)) {
196 return newCp;
197 }
198 }
199
200 if (appPerms.implies(cp)) {
201 return cp;
202 }
203 } catch (Exception e) {
204 continue;
205 }
206 }
207 return defaultPerm;
208 }
209
210 private static CryptoPermissions getAppPermissions(URL callerCodeBase) {
211 // Check if app is exempt, and retrieve the permissions bundled with it
212 try {
213 return JceSecurity.verifyExemptJar(callerCodeBase);
214 } catch (Exception e) {
215 // Jar verification fails
216 return null;
217 }
218
219 }
220
221 /**
222 * Returns the default permission for the given algorithm.
223 */
224 private CryptoPermission getDefaultPermission(String alg) {
225 Enumeration<Permission> enum_ =
226 defaultPolicy.getPermissionCollection(alg).elements();
227 return (CryptoPermission)enum_.nextElement();
228 }
229
230 // Only used by javax.crypto.Cipher constructor to disallow Cipher
231 // objects being constructed by untrusted code (See bug 4341369 &
232 // 4334690 for more info).
233 boolean isCallerTrusted(Provider provider) {
234 // Get the caller and its codebase.
235 Class<?>[] context = getClassContext();
236 if (context.length >= 3) {
237 // context[0]: class javax.crypto.JceSecurityManager
238 // context[1]: class javax.crypto.Cipher (or other JCE API class)
239 // context[2]: this is what we are gonna check
240 Class<?> caller = context[2];
241 URL callerCodeBase = JceSecurity.getCodeBase(caller);
242 if (callerCodeBase == null) {
243 return true;
244 }
245 // The caller has been verified.
246 if (TrustedCallersCache.contains(caller)) {
247 return true;
248 }
249
250 // Check the association between caller and provider
251 Class<?> pCls = provider.getClass();
252 Module pMod = pCls.getModule();
253 // If they are in the same named module or share
254 // the same codebase, then they are associated
255 boolean sameOrigin = (pMod.isNamed()?
256 caller.getModule().equals(pMod) :
257 callerCodeBase.equals(JceSecurity.getCodeBase(pCls)));
258 if (sameOrigin) {
259 // The caller is from trusted provider
260 if (ProviderVerifier.isTrustedCryptoProvider(provider)) {
261 TrustedCallersCache.addElement(caller);
262 return true;
263 }
264 } else {
265 // Don't include the provider in the subsequent
266 // JceSecurity.verifyProvider(...) call
267 provider = null;
268 }
269
270 // Check whether the caller is a trusted provider.
271 try {
272 JceSecurity.verifyProvider(callerCodeBase, provider);
273 } catch (Exception e2) {
274 return false;
275 }
276 TrustedCallersCache.addElement(caller);
277 return true;
278 }
279 return false;
280 }
281 }
282