blob: b0ae07ed109ed2721a311a2c0d9d635e913e46b2 [file] [log] [blame]
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +00001/*
Adam Vartanian6582f182017-05-24 16:15:08 +01002 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +00003 * 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
Sergio Giro17982542016-08-03 19:21:52 +010060 private final static Map<Provider, Object> verificationResults =
61 new IdentityHashMap<>();
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000062
63 // Map<Provider,?> of the providers currently being verified
Sergio Giro17982542016-08-03 19:21:52 +010064 private final static Map<Provider, Object> verifyingProviders =
65 new IdentityHashMap<>();
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000066
Adam Vartanian6582f182017-05-24 16:15:08 +010067 // 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 */
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000075
76 /*
77 * Don't let anyone instantiate this.
78 */
79 private JceSecurity() {
80 }
81
Adam Vartanian6582f182017-05-24 16:15:08 +010082 // BEGIN Android-removed: JCE crypto strength restrictions are never in place on Android.
Tobias Thierer40870112017-03-15 17:54:09 +110083 /*
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000084 static {
85 try {
Sergio Giro17982542016-08-03 19:21:52 +010086 AccessController.doPrivileged(
87 new PrivilegedExceptionAction<Object>() {
88 public Object run() throws Exception {
89 setupJurisdictionPolicies();
90 return null;
91 }
92 });
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000093
94 isRestricted = defaultPolicy.implies(
95 CryptoAllPermission.INSTANCE) ? false : true;
96 } catch (Exception e) {
Sergio Giro17982542016-08-03 19:21:52 +010097 throw new SecurityException(
98 "Can not initialize cryptographic mechanism", e);
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +000099 }
100 }
Tobias Thierer40870112017-03-15 17:54:09 +1100101 */
Adam Vartanian6582f182017-05-24 16:15:08 +0100102 // END Android-removed: JCE crypto strength restrictions are never in place on Android.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000103
Sergio Giro17982542016-08-03 19:21:52 +0100104 static Instance getInstance(String type, Class<?> clazz, String algorithm,
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000105 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
Sergio Giro17982542016-08-03 19:21:52 +0100117 static Instance getInstance(String type, Class<?> clazz, String algorithm,
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000118 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
Sergio Giro17982542016-08-03 19:21:52 +0100129 static Instance getInstance(String type, Class<?> clazz, String algorithm)
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000130 throws NoSuchAlgorithmException {
Sergio Giro17982542016-08-03 19:21:52 +0100131 List<Service> services = GetInstance.getServices(type, algorithm);
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000132 NoSuchAlgorithmException failure = null;
Sergio Giro17982542016-08-03 19:21:52 +0100133 for (Service s : services) {
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000134 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) {
Adam Vartanian6582f182017-05-24 16:15:08 +0100210 // BEGIN Android-changed: All providers are available.
Tobias Thierer40870112017-03-15 17:54:09 +1100211 // return getVerificationResult(p) == null;
Piotr Jastrzebski9af80462015-02-24 15:48:00 +0000212 return true;
Adam Vartanian6582f182017-05-24 16:15:08 +0100213 // END Android-changed: All providers are available.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000214 }
215
216 // dummy object to represent null
217 private static final URL NULL_URL;
218
219 static {
220 try {
Tobias Thierer51fcdbc2018-05-03 22:29:51 +0100221 NULL_URL = new URL("http://null.sun.com/");
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000222 } catch (Exception e) {
223 throw new RuntimeException(e);
224 }
225 }
226
227 // reference to a Map we use as a cache for codebases
Sergio Giro17982542016-08-03 19:21:52 +0100228 private static final Map<Class<?>, URL> codeBaseCacheRef =
229 new WeakHashMap<>();
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000230
231 /*
Sergio Giro17982542016-08-03 19:21:52 +0100232 * Returns the CodeBase for the given class.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000233 */
Sergio Giro17982542016-08-03 19:21:52 +0100234 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 }
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000246 }
Sergio Giro17982542016-08-03 19:21:52 +0100247 return NULL_URL;
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000248 }
Sergio Giro17982542016-08-03 19:21:52 +0100249 });
250 codeBaseCacheRef.put(clazz, url);
251 }
252 return (url == NULL_URL) ? null : url;
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000253 }
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000254 }
255
Adam Vartanian6582f182017-05-24 16:15:08 +0100256 // BEGIN Android-removed: JCE crypto strength restrictions are never in place on Android.
257 /*
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000258 private static void setupJurisdictionPolicies() throws Exception {
Tobias Thierer51fcdbc2018-05-03 22:29:51 +0100259 String javaHomeDir = System.getProperty("java.home");
260 String sep = File.separator;
261 String pathToPolicyJar = javaHomeDir + sep + "lib" + sep +
262 "security" + sep;
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000263
Tobias Thierer51fcdbc2018-05-03 22:29:51 +0100264 File exportJar = new File(pathToPolicyJar, "US_export_policy.jar");
265 File importJar = new File(pathToPolicyJar, "local_policy.jar");
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000266 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 }
Adam Vartanian6582f182017-05-24 16:15:08 +0100298 */
299 // END Android-removed: JCE crypto strength restrictions are never in place on Android.
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000300
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
Sergio Giro17982542016-08-03 19:21:52 +0100312 Enumeration<JarEntry> entries = jf.entries();
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000313 while (entries.hasMoreElements()) {
Sergio Giro17982542016-08-03 19:21:52 +0100314 JarEntry je = entries.nextElement();
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000315 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
Adam Vartanian6582f182017-05-24 16:15:08 +0100350 // Android-removed: JCE crypto strength restrictions are never in place on Android.
351 // static boolean isRestricted() {
352 // return isRestricted;
353 // }
Piotr Jastrzebski51b1b692015-02-16 15:01:09 +0000354}