| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package javax.crypto;  | 
 | 
 | 
 | 
import java.util.*;  | 
 | 
import java.util.jar.*;  | 
 | 
import java.io.*;  | 
 | 
import java.net.URL;  | 
 | 
import java.nio.file.*;  | 
 | 
import java.security.*;  | 
 | 
 | 
 | 
import java.security.Provider.Service;  | 
 | 
 | 
 | 
import sun.security.jca.*;  | 
 | 
import sun.security.jca.GetInstance.Instance;  | 
 | 
import sun.security.util.Debug;  | 
 | 
 | 
 | 
/**  | 
 | 
 * This class instantiates implementations of JCE engine classes from  | 
 | 
 * providers registered with the java.security.Security object.  | 
 | 
 *  | 
 | 
 * @author Jan Luehe  | 
 | 
 * @author Sharon Liu  | 
 | 
 * @since 1.4  | 
 | 
 */  | 
 | 
 | 
 | 
final class JceSecurity { | 
 | 
 | 
 | 
    static final SecureRandom RANDOM = new SecureRandom();  | 
 | 
 | 
 | 
    // The defaultPolicy and exemptPolicy will be set up  | 
 | 
      | 
 | 
    private static CryptoPermissions defaultPolicy = null;  | 
 | 
    private static CryptoPermissions exemptPolicy = null;  | 
 | 
 | 
 | 
    // Map<Provider,?> of the providers we already have verified  | 
 | 
    // value == PROVIDER_VERIFIED is successfully verified  | 
 | 
      | 
 | 
    private final static Map<Provider, Object> verificationResults =  | 
 | 
            new IdentityHashMap<>();  | 
 | 
 | 
 | 
      | 
 | 
    private final static Map<Provider, Object> verifyingProviders =  | 
 | 
            new IdentityHashMap<>();  | 
 | 
 | 
 | 
    private static final boolean isRestricted;  | 
 | 
 | 
 | 
    private static final Debug debug =  | 
 | 
                        Debug.getInstance("jca", "Cipher"); | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private JceSecurity() { | 
 | 
    }  | 
 | 
 | 
 | 
    static { | 
 | 
        try { | 
 | 
            AccessController.doPrivileged(  | 
 | 
                new PrivilegedExceptionAction<Object>() { | 
 | 
                    public Object run() throws Exception { | 
 | 
                        setupJurisdictionPolicies();  | 
 | 
                        return null;  | 
 | 
                    }  | 
 | 
                });  | 
 | 
 | 
 | 
            isRestricted = defaultPolicy.implies(  | 
 | 
                CryptoAllPermission.INSTANCE) ? false : true;  | 
 | 
        } catch (Exception e) { | 
 | 
            throw new SecurityException(  | 
 | 
                    "Can not initialize cryptographic mechanism", e);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    static Instance getInstance(String type, Class<?> clazz, String algorithm,  | 
 | 
            String provider) throws NoSuchAlgorithmException,  | 
 | 
            NoSuchProviderException { | 
 | 
        Service s = GetInstance.getService(type, algorithm, provider);  | 
 | 
        Exception ve = getVerificationResult(s.getProvider());  | 
 | 
        if (ve != null) { | 
 | 
            String msg = "JCE cannot authenticate the provider " + provider;  | 
 | 
            throw (NoSuchProviderException)  | 
 | 
                                new NoSuchProviderException(msg).initCause(ve);  | 
 | 
        }  | 
 | 
        return GetInstance.getInstance(s, clazz);  | 
 | 
    }  | 
 | 
 | 
 | 
    static Instance getInstance(String type, Class<?> clazz, String algorithm,  | 
 | 
            Provider provider) throws NoSuchAlgorithmException { | 
 | 
        Service s = GetInstance.getService(type, algorithm, provider);  | 
 | 
        Exception ve = JceSecurity.getVerificationResult(provider);  | 
 | 
        if (ve != null) { | 
 | 
            String msg = "JCE cannot authenticate the provider "  | 
 | 
                + provider.getName();  | 
 | 
            throw new SecurityException(msg, ve);  | 
 | 
        }  | 
 | 
        return GetInstance.getInstance(s, clazz);  | 
 | 
    }  | 
 | 
 | 
 | 
    static Instance getInstance(String type, Class<?> clazz, String algorithm)  | 
 | 
            throws NoSuchAlgorithmException { | 
 | 
        List<Service> services = GetInstance.getServices(type, algorithm);  | 
 | 
        NoSuchAlgorithmException failure = null;  | 
 | 
        for (Service s : services) { | 
 | 
            if (canUseProvider(s.getProvider()) == false) { | 
 | 
                  | 
 | 
                continue;  | 
 | 
            }  | 
 | 
            try { | 
 | 
                Instance instance = GetInstance.getInstance(s, clazz);  | 
 | 
                return instance;  | 
 | 
            } catch (NoSuchAlgorithmException e) { | 
 | 
                failure = e;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        throw new NoSuchAlgorithmException("Algorithm " + algorithm | 
 | 
                + " not available", failure);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception { | 
 | 
        JarVerifier jv = new JarVerifier(codeBase, true);  | 
 | 
        jv.verify();  | 
 | 
        return jv.getPermissions();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static void verifyProviderJar(URL codeBase) throws Exception { | 
 | 
        // Verify the provider JAR file and all  | 
 | 
          | 
 | 
        JarVerifier jv = new JarVerifier(codeBase, false);  | 
 | 
        jv.verify();  | 
 | 
    }  | 
 | 
 | 
 | 
    private final static Object PROVIDER_VERIFIED = Boolean.TRUE;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static synchronized Exception getVerificationResult(Provider p) { | 
 | 
        Object o = verificationResults.get(p);  | 
 | 
        if (o == PROVIDER_VERIFIED) { | 
 | 
            return null;  | 
 | 
        } else if (o != null) { | 
 | 
            return (Exception)o;  | 
 | 
        }  | 
 | 
        if (verifyingProviders.get(p) != null) { | 
 | 
            // this method is static synchronized, must be recursion  | 
 | 
              | 
 | 
            return new NoSuchProviderException("Recursion during verification"); | 
 | 
        }  | 
 | 
        try { | 
 | 
            verifyingProviders.put(p, Boolean.FALSE);  | 
 | 
            URL providerURL = getCodeBase(p.getClass());  | 
 | 
            verifyProviderJar(providerURL);  | 
 | 
              | 
 | 
            verificationResults.put(p, PROVIDER_VERIFIED);  | 
 | 
            return null;  | 
 | 
        } catch (Exception e) { | 
 | 
            verificationResults.put(p, e);  | 
 | 
            return e;  | 
 | 
        } finally { | 
 | 
            verifyingProviders.remove(p);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    static boolean canUseProvider(Provider p) { | 
 | 
        return getVerificationResult(p) == null;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private static final URL NULL_URL;  | 
 | 
 | 
 | 
    static { | 
 | 
        try { | 
 | 
            NULL_URL = new URL("http://null.oracle.com/"); | 
 | 
        } catch (Exception e) { | 
 | 
            throw new RuntimeException(e);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private static final Map<Class<?>, URL> codeBaseCacheRef =  | 
 | 
            new WeakHashMap<>();  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static URL getCodeBase(final Class<?> clazz) { | 
 | 
        synchronized (codeBaseCacheRef) { | 
 | 
            URL url = codeBaseCacheRef.get(clazz);  | 
 | 
            if (url == null) { | 
 | 
                url = AccessController.doPrivileged(new PrivilegedAction<URL>() { | 
 | 
                    public URL 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 { | 
 | 
        // Sanity check the crypto.policy Security property.  Single  | 
 | 
        // directory entry, no pseudo-directories (".", "..", leading/trailing | 
 | 
          | 
 | 
        String javaHomeProperty = System.getProperty("java.home"); | 
 | 
        String cryptoPolicyProperty = Security.getProperty("crypto.policy"); | 
 | 
        Path cpPath = (cryptoPolicyProperty == null) ? null :  | 
 | 
                Paths.get(cryptoPolicyProperty);  | 
 | 
 | 
 | 
        if ((cpPath != null) && ((cpPath.getNameCount() != 1) ||  | 
 | 
                (cpPath.compareTo(cpPath.getFileName())) != 0)) { | 
 | 
            throw new SecurityException(  | 
 | 
                    "Invalid policy directory name format: " +  | 
 | 
                            cryptoPolicyProperty);  | 
 | 
        }  | 
 | 
 | 
 | 
        if (cpPath == null) { | 
 | 
              | 
 | 
            cpPath = Paths.get(javaHomeProperty, "lib", "security");  | 
 | 
        } else { | 
 | 
              | 
 | 
            cpPath = Paths.get(javaHomeProperty, "lib", "security",  | 
 | 
                    "policy", cryptoPolicyProperty);  | 
 | 
        }  | 
 | 
 | 
 | 
        if (debug != null) { | 
 | 
            debug.println("crypto policy directory: " + cpPath); | 
 | 
        }  | 
 | 
 | 
 | 
        File exportJar = new File(cpPath.toFile(),"US_export_policy.jar");  | 
 | 
        File importJar = new File(cpPath.toFile(),"local_policy.jar");  | 
 | 
 | 
 | 
        if (cryptoPolicyProperty == null && (!exportJar.exists() ||  | 
 | 
                !importJar.exists())) { | 
 | 
            // Compatibility set up. If crypto.policy is not defined.  | 
 | 
            // check to see if legacy jars exist in lib directory. If  | 
 | 
              | 
 | 
            cpPath = Paths.get(  | 
 | 
                    javaHomeProperty, "lib", "security", "policy", "unlimited");  | 
 | 
              | 
 | 
            exportJar = new File(cpPath.toFile(),"US_export_policy.jar");  | 
 | 
            importJar = new File(cpPath.toFile(),"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!"); | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        CryptoPermissions defaultExport = new CryptoPermissions();  | 
 | 
        CryptoPermissions exemptExport = new CryptoPermissions();  | 
 | 
        loadPolicies(exportJar, defaultExport, exemptExport);  | 
 | 
 | 
 | 
        CryptoPermissions defaultImport = new CryptoPermissions();  | 
 | 
        CryptoPermissions exemptImport = new CryptoPermissions();  | 
 | 
        loadPolicies(importJar, defaultImport, exemptImport);  | 
 | 
 | 
 | 
          | 
 | 
        if (defaultExport.isEmpty() || defaultImport.isEmpty()) { | 
 | 
            throw new SecurityException("Missing mandatory jurisdiction " + | 
 | 
                                        "policy files");  | 
 | 
        }  | 
 | 
        defaultPolicy = defaultExport.getMinimum(defaultImport);  | 
 | 
 | 
 | 
          | 
 | 
        if (exemptExport.isEmpty())  { | 
 | 
            exemptPolicy = exemptImport.isEmpty() ? null : exemptImport;  | 
 | 
        } else { | 
 | 
            exemptPolicy = exemptExport.getMinimum(exemptImport);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static void loadPolicies(File jarPathName,  | 
 | 
                                     CryptoPermissions defaultPolicy,  | 
 | 
                                     CryptoPermissions exemptPolicy)  | 
 | 
        throws Exception { | 
 | 
 | 
 | 
        JarFile jf = new JarFile(jarPathName);  | 
 | 
 | 
 | 
        Enumeration<JarEntry> entries = jf.entries();  | 
 | 
        while (entries.hasMoreElements()) { | 
 | 
            JarEntry je = 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  | 
 | 
              | 
 | 
            JarVerifier.verifyPolicySigned(je.getCertificates());  | 
 | 
        }  | 
 | 
          | 
 | 
        jf.close();  | 
 | 
        jf = null;  | 
 | 
    }  | 
 | 
 | 
 | 
    static CryptoPermissions getDefaultPolicy() { | 
 | 
        return defaultPolicy;  | 
 | 
    }  | 
 | 
 | 
 | 
    static CryptoPermissions getExemptPolicy() { | 
 | 
        return exemptPolicy;  | 
 | 
    }  | 
 | 
 | 
 | 
    static boolean isRestricted() { | 
 | 
        return isRestricted;  | 
 | 
    }  | 
 | 
}  |