• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1997, 2009, 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.util.*;
29 import java.util.jar.*;
30 import java.io.*;
31 import java.net.URL;
32 import java.security.*;
33 
34 import java.security.Provider.Service;
35 
36 import sun.security.jca.*;
37 import sun.security.jca.GetInstance.Instance;
38 
39 /**
40  * This class instantiates implementations of JCE engine classes from
41  * providers registered with the java.security.Security object.
42  *
43  * @author Jan Luehe
44  * @author Sharon Liu
45  * @since 1.4
46  */
47 
48 final class JceSecurity {
49 
50     static final SecureRandom RANDOM = new SecureRandom();
51 
52     // The defaultPolicy and exemptPolicy will be set up
53     // in the static initializer.
54     private static CryptoPermissions defaultPolicy = null;
55     private static CryptoPermissions exemptPolicy = null;
56 
57     // Map<Provider,?> of the providers we already have verified
58     // value == PROVIDER_VERIFIED is successfully verified
59     // value is failure cause Exception in error case
60     private final static Map verificationResults = new IdentityHashMap();
61 
62     // Map<Provider,?> of the providers currently being verified
63     private final static Map verifyingProviders = new IdentityHashMap();
64 
65     // Set the default value. May be changed in the static initializer.
66     private static boolean isRestricted = true;
67 
68     /*
69      * Don't let anyone instantiate this.
70      */
JceSecurity()71     private JceSecurity() {
72     }
73 
74     /* ----- BEGIN android -----
75     static {
76         try {
77             AccessController.doPrivileged(new PrivilegedExceptionAction() {
78                 public Object run() throws Exception {
79                     setupJurisdictionPolicies();
80                     return null;
81                 }
82             });
83 
84             isRestricted = defaultPolicy.implies(
85                 CryptoAllPermission.INSTANCE) ? false : true;
86         } catch (Exception e) {
87             SecurityException se =
88                 new SecurityException(
89                     "Can not initialize cryptographic mechanism");
90             se.initCause(e);
91             throw se;
92         }
93     }
94     ----- END android ----- */
95 
getInstance(String type, Class clazz, String algorithm, String provider)96     static Instance getInstance(String type, Class clazz, String algorithm,
97             String provider) throws NoSuchAlgorithmException,
98             NoSuchProviderException {
99         Service s = GetInstance.getService(type, algorithm, provider);
100         Exception ve = getVerificationResult(s.getProvider());
101         if (ve != null) {
102             String msg = "JCE cannot authenticate the provider " + provider;
103             throw (NoSuchProviderException)
104                                 new NoSuchProviderException(msg).initCause(ve);
105         }
106         return GetInstance.getInstance(s, clazz);
107     }
108 
getInstance(String type, Class clazz, String algorithm, Provider provider)109     static Instance getInstance(String type, Class clazz, String algorithm,
110             Provider provider) throws NoSuchAlgorithmException {
111         Service s = GetInstance.getService(type, algorithm, provider);
112         Exception ve = JceSecurity.getVerificationResult(provider);
113         if (ve != null) {
114             String msg = "JCE cannot authenticate the provider "
115                 + provider.getName();
116             throw new SecurityException(msg, ve);
117         }
118         return GetInstance.getInstance(s, clazz);
119     }
120 
getInstance(String type, Class clazz, String algorithm)121     static Instance getInstance(String type, Class clazz, String algorithm)
122             throws NoSuchAlgorithmException {
123         List services = GetInstance.getServices(type, algorithm);
124         NoSuchAlgorithmException failure = null;
125         for (Iterator t = services.iterator(); t.hasNext(); ) {
126             Service s = (Service)t.next();
127             if (canUseProvider(s.getProvider()) == false) {
128                 // allow only signed providers
129                 continue;
130             }
131             try {
132                 Instance instance = GetInstance.getInstance(s, clazz);
133                 return instance;
134             } catch (NoSuchAlgorithmException e) {
135                 failure = e;
136             }
137         }
138         throw new NoSuchAlgorithmException("Algorithm " + algorithm
139                 + " not available", failure);
140     }
141 
142     /**
143      * Verify if the JAR at URL codeBase is a signed exempt application
144      * JAR file and returns the permissions bundled with the JAR.
145      *
146      * @throws Exception on error
147      */
verifyExemptJar(URL codeBase)148     static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {
149         JarVerifier jv = new JarVerifier(codeBase, true);
150         jv.verify();
151         return jv.getPermissions();
152     }
153 
154     /**
155      * Verify if the JAR at URL codeBase is a signed provider JAR file.
156      *
157      * @throws Exception on error
158      */
verifyProviderJar(URL codeBase)159     static void verifyProviderJar(URL codeBase) throws Exception {
160         // Verify the provider JAR file and all
161         // supporting JAR files if there are any.
162         JarVerifier jv = new JarVerifier(codeBase, false);
163         jv.verify();
164     }
165 
166     private final static Object PROVIDER_VERIFIED = Boolean.TRUE;
167 
168     /*
169      * Verify that the provider JAR files are signed properly, which
170      * means the signer's certificate can be traced back to a
171      * JCE trusted CA.
172      * Return null if ok, failure Exception if verification failed.
173      */
getVerificationResult(Provider p)174     static synchronized Exception getVerificationResult(Provider p) {
175         Object o = verificationResults.get(p);
176         if (o == PROVIDER_VERIFIED) {
177             return null;
178         } else if (o != null) {
179             return (Exception)o;
180         }
181         if (verifyingProviders.get(p) != null) {
182             // this method is static synchronized, must be recursion
183             // return failure now but do not save the result
184             return new NoSuchProviderException("Recursion during verification");
185         }
186         try {
187             verifyingProviders.put(p, Boolean.FALSE);
188             URL providerURL = getCodeBase(p.getClass());
189             verifyProviderJar(providerURL);
190             // Verified ok, cache result
191             verificationResults.put(p, PROVIDER_VERIFIED);
192             return null;
193         } catch (Exception e) {
194             verificationResults.put(p, e);
195             return e;
196         } finally {
197             verifyingProviders.remove(p);
198         }
199     }
200 
201     // return whether this provider is properly signed and can be used by JCE
canUseProvider(Provider p)202     static boolean canUseProvider(Provider p) {
203         /* ----- BEGIN android
204         return getVerificationResult(p) == null;
205         */
206         return true;
207         // ----- END android -----
208     }
209 
210     // dummy object to represent null
211     private static final URL NULL_URL;
212 
213     static {
214         try {
215             NULL_URL = new URL("http://null.sun.com/");
216         } catch (Exception e) {
217             throw new RuntimeException(e);
218         }
219     }
220 
221     // reference to a Map we use as a cache for codebases
222     private static final Map codeBaseCacheRef = new WeakHashMap();
223 
224     /*
225      * Retuns the CodeBase for the given class.
226      */
getCodeBase(final Class clazz)227     static URL getCodeBase(final Class clazz) {
228         URL url = (URL)codeBaseCacheRef.get(clazz);
229         if (url == null) {
230             url = (URL)AccessController.doPrivileged(new PrivilegedAction() {
231                 public Object run() {
232                     ProtectionDomain pd = clazz.getProtectionDomain();
233                     if (pd != null) {
234                         CodeSource cs = pd.getCodeSource();
235                         if (cs != null) {
236                             return cs.getLocation();
237                         }
238                     }
239                     return NULL_URL;
240                 }
241             });
242             codeBaseCacheRef.put(clazz, url);
243         }
244         return (url == NULL_URL) ? null : url;
245     }
246 
setupJurisdictionPolicies()247     private static void setupJurisdictionPolicies() throws Exception {
248         String javaHomeDir = System.getProperty("java.home");
249         String sep = File.separator;
250         String pathToPolicyJar = javaHomeDir + sep + "lib" + sep +
251             "security" + sep;
252 
253         File exportJar = new File(pathToPolicyJar, "US_export_policy.jar");
254         File importJar = new File(pathToPolicyJar, "local_policy.jar");
255         URL jceCipherURL = ClassLoader.getSystemResource
256                 ("javax/crypto/Cipher.class");
257 
258         if ((jceCipherURL == null) ||
259                 !exportJar.exists() || !importJar.exists()) {
260             throw new SecurityException
261                                 ("Cannot locate policy or framework files!");
262         }
263 
264         // Read jurisdiction policies.
265         CryptoPermissions defaultExport = new CryptoPermissions();
266         CryptoPermissions exemptExport = new CryptoPermissions();
267         loadPolicies(exportJar, defaultExport, exemptExport);
268 
269         CryptoPermissions defaultImport = new CryptoPermissions();
270         CryptoPermissions exemptImport = new CryptoPermissions();
271         loadPolicies(importJar, defaultImport, exemptImport);
272 
273         // Merge the export and import policies for default applications.
274         if (defaultExport.isEmpty() || defaultImport.isEmpty()) {
275             throw new SecurityException("Missing mandatory jurisdiction " +
276                                         "policy files");
277         }
278         defaultPolicy = defaultExport.getMinimum(defaultImport);
279 
280         // Merge the export and import policies for exempt applications.
281         if (exemptExport.isEmpty())  {
282             exemptPolicy = exemptImport.isEmpty() ? null : exemptImport;
283         } else {
284             exemptPolicy = exemptExport.getMinimum(exemptImport);
285         }
286     }
287 
288     /**
289      * Load the policies from the specified file. Also checks that the
290      * policies are correctly signed.
291      */
loadPolicies(File jarPathName, CryptoPermissions defaultPolicy, CryptoPermissions exemptPolicy)292     private static void loadPolicies(File jarPathName,
293                                      CryptoPermissions defaultPolicy,
294                                      CryptoPermissions exemptPolicy)
295         throws Exception {
296 
297         JarFile jf = new JarFile(jarPathName);
298 
299         Enumeration entries = jf.entries();
300         while (entries.hasMoreElements()) {
301             JarEntry je = (JarEntry)entries.nextElement();
302             InputStream is = null;
303             try {
304                 if (je.getName().startsWith("default_")) {
305                     is = jf.getInputStream(je);
306                     defaultPolicy.load(is);
307                 } else if (je.getName().startsWith("exempt_")) {
308                     is = jf.getInputStream(je);
309                     exemptPolicy.load(is);
310                 } else {
311                     continue;
312                 }
313             } finally {
314                 if (is != null) {
315                     is.close();
316                 }
317             }
318 
319             // Enforce the signer restraint, i.e. signer of JCE framework
320             // jar should also be the signer of the two jurisdiction policy
321             // jar files.
322             JarVerifier.verifyPolicySigned(je.getCertificates());
323         }
324         // Close and nullify the JarFile reference to help GC.
325         jf.close();
326         jf = null;
327     }
328 
getDefaultPolicy()329     static CryptoPermissions getDefaultPolicy() {
330         return defaultPolicy;
331     }
332 
getExemptPolicy()333     static CryptoPermissions getExemptPolicy() {
334         return exemptPolicy;
335     }
336 
isRestricted()337     static boolean isRestricted() {
338         return isRestricted;
339     }
340 }
341