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