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