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