0N/A/*
0N/A * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
809N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
809N/A *
809N/A * This code is free software; you can redistribute it and/or modify it
809N/A * under the terms of the GNU General Public License version 2 only, as
809N/A * published by the Free Software Foundation. Oracle designates this
809N/A * particular file as subject to the "Classpath" exception as provided
809N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
809N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
809N/A * 2 along with this work; if not, write to the Free Software Foundation,
809N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
809N/A *
809N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
809N/A * or visit www.oracle.com if you need additional information or have any
809N/A * questions.
809N/A */
0N/A
0N/Apackage javax.crypto;
809N/A
809N/Aimport java.util.*;
809N/Aimport java.util.jar.*;
809N/Aimport java.io.*;
809N/Aimport java.net.URL;
809N/Aimport java.security.*;
809N/A
809N/Aimport java.security.Provider.Service;
809N/A
809N/Aimport sun.security.jca.*;
809N/Aimport sun.security.jca.GetInstance.Instance;
809N/A
809N/A/**
0N/A * This class instantiates implementations of JCE engine classes from
809N/A * providers registered with the java.security.Security object.
0N/A *
809N/A * @author Jan Luehe
809N/A * @author Sharon Liu
809N/A * @since 1.4
809N/A */
809N/A
809N/Afinal class JceSecurity {
809N/A
809N/A static final SecureRandom RANDOM = new SecureRandom();
0N/A
809N/A // The defaultPolicy and exemptPolicy will be set up
0N/A // in the static initializer.
809N/A private static CryptoPermissions defaultPolicy = null;
809N/A private static CryptoPermissions exemptPolicy = null;
809N/A
809N/A // Map<Provider,?> of the providers we already have verified
809N/A // value == PROVIDER_VERIFIED is successfully verified
0N/A // value is failure cause Exception in error case
0N/A private final static Map verificationResults = new IdentityHashMap();
0N/A
5713N/A // Map<Provider,?> of the providers currently being verified
0N/A private final static Map verifyingProviders = new IdentityHashMap();
0N/A
809N/A // Set the default value. May be changed in the static initializer.
0N/A private static boolean isRestricted = true;
0N/A
0N/A /*
809N/A * Don't let anyone instantiate this.
809N/A */
809N/A private JceSecurity() {
809N/A }
809N/A
809N/A static {
809N/A try {
0N/A AccessController.doPrivileged(new PrivilegedExceptionAction() {
0N/A public Object run() throws Exception {
0N/A setupJurisdictionPolicies();
0N/A return null;
809N/A }
5713N/A });
809N/A
809N/A isRestricted = defaultPolicy.implies(
809N/A CryptoAllPermission.INSTANCE) ? false : true;
809N/A } catch (Exception e) {
809N/A SecurityException se =
809N/A new SecurityException(
809N/A "Can not initialize cryptographic mechanism");
0N/A se.initCause(e);
0N/A throw se;
0N/A }
0N/A }
0N/A
0N/A static Instance getInstance(String type, Class clazz, String algorithm,
0N/A String provider) throws NoSuchAlgorithmException,
0N/A NoSuchProviderException {
0N/A Service s = GetInstance.getService(type, algorithm, provider);
0N/A Exception ve = getVerificationResult(s.getProvider());
0N/A if (ve != null) {
0N/A String msg = "JCE cannot authenticate the provider " + provider;
0N/A throw (NoSuchProviderException)
0N/A new NoSuchProviderException(msg).initCause(ve);
0N/A }
0N/A return GetInstance.getInstance(s, clazz);
0N/A }
0N/A
0N/A static Instance getInstance(String type, Class clazz, String algorithm,
0N/A Provider provider) throws NoSuchAlgorithmException {
0N/A Service s = GetInstance.getService(type, algorithm, provider);
0N/A Exception ve = JceSecurity.getVerificationResult(provider);
0N/A if (ve != null) {
0N/A String msg = "JCE cannot authenticate the provider "
0N/A + provider.getName();
0N/A throw new SecurityException(msg, ve);
0N/A }
0N/A return GetInstance.getInstance(s, clazz);
0N/A }
0N/A
0N/A static Instance getInstance(String type, Class clazz, String algorithm)
0N/A throws NoSuchAlgorithmException {
0N/A List services = GetInstance.getServices(type, algorithm);
0N/A NoSuchAlgorithmException failure = null;
0N/A for (Iterator t = services.iterator(); t.hasNext(); ) {
0N/A Service s = (Service)t.next();
0N/A if (canUseProvider(s.getProvider()) == false) {
0N/A // allow only signed providers
0N/A continue;
0N/A }
809N/A try {
809N/A Instance instance = GetInstance.getInstance(s, clazz);
809N/A return instance;
809N/A } catch (NoSuchAlgorithmException e) {
809N/A failure = e;
809N/A }
0N/A }
0N/A throw new NoSuchAlgorithmException("Algorithm " + algorithm
809N/A + " not available", failure);
809N/A }
809N/A
809N/A /**
809N/A * Verify if the JAR at URL codeBase is a signed exempt application
0N/A * JAR file and returns the permissions bundled with the JAR.
0N/A *
0N/A * @throws Exception on error
809N/A */
809N/A static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {
809N/A JarVerifier jv = new JarVerifier(codeBase, true);
809N/A jv.verify();
809N/A return jv.getPermissions();
809N/A }
809N/A
809N/A /**
809N/A * Verify if the JAR at URL codeBase is a signed provider JAR file.
809N/A *
809N/A * @throws Exception on error
809N/A */
809N/A static void verifyProviderJar(URL codeBase) throws Exception {
809N/A // Verify the provider JAR file and all
0N/A // supporting JAR files if there are any.
0N/A JarVerifier jv = new JarVerifier(codeBase, false);
809N/A jv.verify();
809N/A }
809N/A
809N/A private final static Object PROVIDER_VERIFIED = Boolean.TRUE;
809N/A
0N/A /*
0N/A * Verify that the provider JAR files are signed properly, which
809N/A * means the signer's certificate can be traced back to a
809N/A * JCE trusted CA.
809N/A * Return null if ok, failure Exception if verification failed.
809N/A */
809N/A static synchronized Exception getVerificationResult(Provider p) {
809N/A Object o = verificationResults.get(p);
809N/A if (o == PROVIDER_VERIFIED) {
809N/A return null;
809N/A } else if (o != null) {
809N/A return (Exception)o;
809N/A }
809N/A if (verifyingProviders.get(p) != null) {
809N/A // this method is static synchronized, must be recursion
809N/A // return failure now but do not save the result
809N/A return new NoSuchProviderException("Recursion during verification");
809N/A }
809N/A try {
809N/A verifyingProviders.put(p, Boolean.FALSE);
809N/A URL providerURL = getCodeBase(p.getClass());
0N/A verifyProviderJar(providerURL);
809N/A // Verified ok, cache result
809N/A verificationResults.put(p, PROVIDER_VERIFIED);
809N/A return null;
809N/A } catch (Exception e) {
809N/A verificationResults.put(p, e);
0N/A return e;
809N/A } finally {
0N/A verifyingProviders.remove(p);
0N/A }
809N/A }
809N/A
809N/A // return whether this provider is properly signed and can be used by JCE
809N/A static boolean canUseProvider(Provider p) {
809N/A return getVerificationResult(p) == null;
809N/A }
0N/A
0N/A // dummy object to represent null
809N/A private static final URL NULL_URL;
809N/A
809N/A static {
809N/A try {
809N/A NULL_URL = new URL("http://null.sun.com/");
809N/A } catch (Exception e) {
809N/A throw new RuntimeException(e);
809N/A }
809N/A }
809N/A
809N/A // reference to a Map we use as a cache for codebases
809N/A private static final Map codeBaseCacheRef = new WeakHashMap();
809N/A
5713N/A /*
* Retuns the CodeBase for the given class.
*/
static URL getCodeBase(final Class clazz) {
URL url = (URL)codeBaseCacheRef.get(clazz);
if (url == null) {
url = (URL)AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
ProtectionDomain pd = clazz.getProtectionDomain();
if (pd != null) {
CodeSource cs = pd.getCodeSource();
if (cs != null) {
return cs.getLocation();
}
}
return NULL_URL;
}
});
codeBaseCacheRef.put(clazz, url);
}
return (url == NULL_URL) ? null : url;
}
private static void setupJurisdictionPolicies() throws Exception {
String javaHomeDir = System.getProperty("java.home");
String sep = File.separator;
String pathToPolicyJar = javaHomeDir + sep + "lib" + sep +
"security" + sep;
File exportJar = new File(pathToPolicyJar, "US_export_policy.jar");
File importJar = new File(pathToPolicyJar, "local_policy.jar");
URL jceCipherURL = ClassLoader.getSystemResource
("javax/crypto/Cipher.class");
if ((jceCipherURL == null) ||
!exportJar.exists() || !importJar.exists()) {
throw new SecurityException
("Cannot locate policy or framework files!");
}
// Read jurisdiction policies.
CryptoPermissions defaultExport = new CryptoPermissions();
CryptoPermissions exemptExport = new CryptoPermissions();
loadPolicies(exportJar, defaultExport, exemptExport);
CryptoPermissions defaultImport = new CryptoPermissions();
CryptoPermissions exemptImport = new CryptoPermissions();
loadPolicies(importJar, defaultImport, exemptImport);
// Merge the export and import policies for default applications.
if (defaultExport.isEmpty() || defaultImport.isEmpty()) {
throw new SecurityException("Missing mandatory jurisdiction " +
"policy files");
}
defaultPolicy = defaultExport.getMinimum(defaultImport);
// Merge the export and import policies for exempt applications.
if (exemptExport.isEmpty()) {
exemptPolicy = exemptImport.isEmpty() ? null : exemptImport;
} else {
exemptPolicy = exemptExport.getMinimum(exemptImport);
}
}
/**
* Load the policies from the specified file. Also checks that the
* policies are correctly signed.
*/
private static void loadPolicies(File jarPathName,
CryptoPermissions defaultPolicy,
CryptoPermissions exemptPolicy)
throws Exception {
JarFile jf = new JarFile(jarPathName);
Enumeration entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry je = (JarEntry)entries.nextElement();
InputStream is = null;
try {
if (je.getName().startsWith("default_")) {
is = jf.getInputStream(je);
defaultPolicy.load(is);
} else if (je.getName().startsWith("exempt_")) {
is = jf.getInputStream(je);
exemptPolicy.load(is);
} else {
continue;
}
} finally {
if (is != null) {
is.close();
}
}
// Enforce the signer restraint, i.e. signer of JCE framework
// jar should also be the signer of the two jurisdiction policy
// jar files.
JarVerifier.verifyPolicySigned(je.getCertificates());
}
// Close and nullify the JarFile reference to help GC.
jf.close();
jf = null;
}
static CryptoPermissions getDefaultPolicy() {
return defaultPolicy;
}
static CryptoPermissions getExemptPolicy() {
return exemptPolicy;
}
static boolean isRestricted() {
return isRestricted;
}
}