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