1 /* 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 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<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 */ JceSecurity()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 getInstance(String type, Class<?> clazz, String algorithm, String provider)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 getInstance(String type, Class<?> clazz, String algorithm, Provider provider)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 getInstance(String type, Class<?> clazz, String algorithm)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 */ verifyExemptJar(URL codeBase)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 */ verifyProviderJar(URL codeBase)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 */ getVerificationResult(Provider p)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 canUseProvider(Provider p)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.oracle.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 */ getCodeBase(final Class<?> clazz)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 * This is called from within an doPrivileged block. 259 * 260 * Following logic is used to decide what policy files are selected. 261 * 262 * If the new Security property (crypto.policy) is set in the 263 * java.security file, or has been set dynamically using the 264 * Security.setProperty() call before the JCE framework has 265 * been initialized, that setting will be used. 266 * Remember - this property is not defined by default. A conscious 267 * user edit or an application call is required. 268 * 269 * Otherwise, if user has policy jar files installed in the legacy 270 * jre/lib/security/ directory, the JDK will honor whatever 271 * setting is set by those policy files. (legacy/current behavior) 272 * 273 * If none of the above 2 conditions are met, the JDK will default 274 * to using the limited crypto policy files found in the 275 * jre/lib/security/policy/limited/ directory 276 * 277 private static void setupJurisdictionPolicies() throws Exception { 278 // Sanity check the crypto.policy Security property. Single 279 // directory entry, no pseudo-directories (".", "..", leading/trailing 280 // path separators). normalize()/getParent() will help later. 281 String javaHomeProperty = System.getProperty("java.home"); 282 String cryptoPolicyProperty = Security.getProperty("crypto.policy"); 283 Path cpPath = (cryptoPolicyProperty == null) ? null : 284 Paths.get(cryptoPolicyProperty); 285 286 if ((cpPath != null) && ((cpPath.getNameCount() != 1) || 287 (cpPath.compareTo(cpPath.getFileName())) != 0)) { 288 throw new SecurityException( 289 "Invalid policy directory name format: " + 290 cryptoPolicyProperty); 291 } 292 293 if (cpPath == null) { 294 // Security property is not set, use default path 295 cpPath = Paths.get(javaHomeProperty, "lib", "security"); 296 } else { 297 // populate with java.home 298 cpPath = Paths.get(javaHomeProperty, "lib", "security", 299 "policy", cryptoPolicyProperty); 300 } 301 302 if (debug != null) { 303 debug.println("crypto policy directory: " + cpPath); 304 } 305 306 File exportJar = new File(cpPath.toFile(),"US_export_policy.jar"); 307 File importJar = new File(cpPath.toFile(),"local_policy.jar"); 308 309 if (cryptoPolicyProperty == null && (!exportJar.exists() || 310 !importJar.exists())) { 311 // Compatibility set up. If crypto.policy is not defined. 312 // check to see if legacy jars exist in lib directory. If 313 // they don't exist, we default to limited policy mode. 314 cpPath = Paths.get( 315 javaHomeProperty, "lib", "security", "policy", "limited"); 316 // point to the new jar files in limited directory 317 exportJar = new File(cpPath.toFile(),"US_export_policy.jar"); 318 importJar = new File(cpPath.toFile(),"local_policy.jar"); 319 } 320 321 URL jceCipherURL = ClassLoader.getSystemResource 322 ("javax/crypto/Cipher.class"); 323 324 if ((jceCipherURL == null) || 325 !exportJar.exists() || !importJar.exists()) { 326 throw new SecurityException 327 ("Cannot locate policy or framework files!"); 328 } 329 330 // Read jurisdiction policies. 331 CryptoPermissions defaultExport = new CryptoPermissions(); 332 CryptoPermissions exemptExport = new CryptoPermissions(); 333 loadPolicies(exportJar, defaultExport, exemptExport); 334 335 CryptoPermissions defaultImport = new CryptoPermissions(); 336 CryptoPermissions exemptImport = new CryptoPermissions(); 337 loadPolicies(importJar, defaultImport, exemptImport); 338 339 // Merge the export and import policies for default applications. 340 if (defaultExport.isEmpty() || defaultImport.isEmpty()) { 341 throw new SecurityException("Missing mandatory jurisdiction " + 342 "policy files"); 343 } 344 defaultPolicy = defaultExport.getMinimum(defaultImport); 345 346 // Merge the export and import policies for exempt applications. 347 if (exemptExport.isEmpty()) { 348 exemptPolicy = exemptImport.isEmpty() ? null : exemptImport; 349 } else { 350 exemptPolicy = exemptExport.getMinimum(exemptImport); 351 } 352 } 353 */ 354 // END Android-removed: JCE crypto strength restrictions are never in place on Android. 355 356 /** 357 * Load the policies from the specified file. Also checks that the 358 * policies are correctly signed. 359 */ loadPolicies(File jarPathName, CryptoPermissions defaultPolicy, CryptoPermissions exemptPolicy)360 private static void loadPolicies(File jarPathName, 361 CryptoPermissions defaultPolicy, 362 CryptoPermissions exemptPolicy) 363 throws Exception { 364 365 JarFile jf = new JarFile(jarPathName); 366 367 Enumeration<JarEntry> entries = jf.entries(); 368 while (entries.hasMoreElements()) { 369 JarEntry je = entries.nextElement(); 370 InputStream is = null; 371 try { 372 if (je.getName().startsWith("default_")) { 373 is = jf.getInputStream(je); 374 defaultPolicy.load(is); 375 } else if (je.getName().startsWith("exempt_")) { 376 is = jf.getInputStream(je); 377 exemptPolicy.load(is); 378 } else { 379 continue; 380 } 381 } finally { 382 if (is != null) { 383 is.close(); 384 } 385 } 386 387 // Enforce the signer restraint, i.e. signer of JCE framework 388 // jar should also be the signer of the two jurisdiction policy 389 // jar files. 390 JarVerifier.verifyPolicySigned(je.getCertificates()); 391 } 392 // Close and nullify the JarFile reference to help GC. 393 jf.close(); 394 jf = null; 395 } 396 getDefaultPolicy()397 static CryptoPermissions getDefaultPolicy() { 398 return defaultPolicy; 399 } 400 getExemptPolicy()401 static CryptoPermissions getExemptPolicy() { 402 return exemptPolicy; 403 } 404 405 // Android-removed: JCE crypto strength restrictions are never in place on Android. 406 // static boolean isRestricted() { 407 // return isRestricted; 408 // } 409 } 410