/*
 * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * README README README README README README README README README
 *
 * This file is the template for generating the JceSecurity.java source
 * file.
 *
 * In the current jdk builds, this file is first preprocessed to replace
 * @@JCE_DEFAULT_POLICY@ [sic] with "limited" or "unlimited" which is
 * determined by the $(UNLIMTED_CRYPTO) make variable.  This variable is
 * set by top-level configure script, using either
 * --disable-unlimited-crypto or --enable-unlimited-crypto [default].
 *
 * Since this file is a generated source, incremental changes to
 * this file require regenerating the source.  Compilation options:
 *
 *     (fewer dependencies/"faster" ones first)
 *
 * 1.  make JDK_FILTER=javax/crypto java.base-gensrc-only java.base-java-only
 * 2.  make java.base-gensrc-only java.base-java-only
 * 3.  make java.base-gensrc-only java.base-only
 * 4.  make java.base-only
 * 5.  make
 */

package javax.crypto;

import java.util.*;
import java.io.*;
import java.net.URL;
import java.nio.file.*;
import java.security.*;

import java.security.Provider.Service;

import jdk.internal.util.StaticProperty;

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, Sharon Liu
Since:1.4
/** * 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 { private static final Debug debug = Debug.getInstance("jca"); static final SecureRandom RANDOM = new SecureRandom(); // The defaultPolicy and exemptPolicy will be set up // in the static initializer. 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 // value is failure cause Exception in error case private static final Map<Provider, Object> verificationResults = new IdentityHashMap<>(); // Map<Provider,?> of the providers currently being verified private static final Map<Provider, Object> verifyingProviders = new IdentityHashMap<>(); private static final boolean isRestricted; /* * Don't let anyone instantiate this. */ private JceSecurity() { } static { try { AccessController.doPrivileged( new PrivilegedExceptionAction<> () { @Override public Void 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) { // allow only signed providers continue; } try { Instance instance = GetInstance.getInstance(s, clazz); return instance; } catch (NoSuchAlgorithmException e) { failure = e; } } throw new NoSuchAlgorithmException("Algorithm " + algorithm + " not available", failure); }
Verify if the JAR at URL codeBase is a signed exempt application JAR file and returns the permissions bundled with the JAR.
Throws:
  • Exception – on error
/** * Verify if the JAR at URL codeBase is a signed exempt application * JAR file and returns the permissions bundled with the JAR. * * @throws Exception on error */
static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception { ProviderVerifier pv = new ProviderVerifier(codeBase, true); pv.verify(); return pv.getPermissions(); }
Verify if the JAR at URL codeBase is a signed provider JAR file.
Throws:
  • Exception – on error
/** * Verify if the JAR at URL codeBase is a signed provider JAR file. * * @throws Exception on error */
static void verifyProvider(URL codeBase, Provider p) throws Exception { // Verify the provider JAR file and all // supporting JAR files if there are any. ProviderVerifier pv = new ProviderVerifier(codeBase, p, false); pv.verify(); } private static final Object PROVIDER_VERIFIED = Boolean.TRUE; /* * Verify that the provider JAR files are signed properly, which * means the signer's certificate can be traced back to a * JCE trusted CA. * Return null if ok, failure Exception if verification failed. */ 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 failure now but do not save the result return new NoSuchProviderException("Recursion during verification"); } try { verifyingProviders.put(p, Boolean.FALSE); URL providerURL = getCodeBase(p.getClass()); verifyProvider(providerURL, p); // Verified ok, cache result verificationResults.put(p, PROVIDER_VERIFIED); return null; } catch (Exception e) { verificationResults.put(p, e); return e; } finally { verifyingProviders.remove(p); } } // return whether this provider is properly signed and can be used by JCE static boolean canUseProvider(Provider p) { return getVerificationResult(p) == null; } // dummy object to represent null private static final URL NULL_URL; static { try { NULL_URL = new URL("http://null.oracle.com/"); } catch (Exception e) { throw new RuntimeException(e); } } // reference to a Map we use as a cache for codebases private static final Map<Class<?>, URL> codeBaseCacheRef = new WeakHashMap<>(); /* * Returns the CodeBase for the given class. */ static URL getCodeBase(final Class<?> clazz) { synchronized (codeBaseCacheRef) { URL url = codeBaseCacheRef.get(clazz); if (url == null) { url = AccessController.doPrivileged( new PrivilegedAction<>() { @Override 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; } } // This is called from within an doPrivileged block. private static void setupJurisdictionPolicies() throws Exception { // Sanity check the crypto.policy Security property. Single // directory entry, no pseudo-directories (".", "..", leading/trailing // path separators). normalize()/getParent() will help later. String cryptoPolicyProperty = Security.getProperty("crypto.policy"); /* * In case no property is present, rather than fail catastrophically, * we at least try for a "sane" value, which is what we were * built with. We first preprocess this file to plug in that * value, then compile the result gensrc. * * Log the warning first. */ if (cryptoPolicyProperty == null) { cryptoPolicyProperty = "unlimited"; if (debug != null) { debug.println( "Security Property 'crypto.policy' not found: " + "using '" + cryptoPolicyProperty + "' as fallback"); } } Path cpPath = Paths.get(cryptoPolicyProperty); if ((cpPath.getNameCount() != 1) || (cpPath.compareTo(cpPath.getFileName()) != 0)) { throw new SecurityException( "Invalid policy directory name format: " + cryptoPolicyProperty); } // Prepend java.home to get the full path. normalize() in // case an extra "." or ".." snuck in somehow. String javaHomeProperty = StaticProperty.javaHome(); Path javaHomePolicyPath = Paths.get(javaHomeProperty, "conf", "security", "policy").normalize(); Path cryptoPolicyPath = Paths.get(javaHomeProperty, "conf", "security", "policy", cryptoPolicyProperty).normalize(); if (cryptoPolicyPath.getParent().compareTo(javaHomePolicyPath) != 0) { throw new SecurityException( "Invalid cryptographic jurisdiction policy directory path: " + cryptoPolicyProperty); } if (!Files.isDirectory(cryptoPolicyPath) || !Files.isReadable(cryptoPolicyPath)) { throw new SecurityException( "Can't read cryptographic policy directory: " + cryptoPolicyProperty); } try (DirectoryStream<Path> stream = Files.newDirectoryStream( cryptoPolicyPath, "{default,exempt}_*.policy")) { for (Path entry : stream) { try (InputStream is = new BufferedInputStream( Files.newInputStream(entry))) { String filename = entry.getFileName().toString(); CryptoPermissions tmpPerms = new CryptoPermissions(); tmpPerms.load(is); if (filename.startsWith("default_")) { // Did we find a default perms? defaultPolicy = ((defaultPolicy == null) ? tmpPerms : defaultPolicy.getMinimum(tmpPerms)); } else if (filename.startsWith("exempt_")) { // Did we find a exempt perms? exemptPolicy = ((exemptPolicy == null) ? tmpPerms : exemptPolicy.getMinimum(tmpPerms)); } else { // This should never happen. newDirectoryStream // should only throw return "{default,exempt}_*.policy" throw new SecurityException( "Unexpected jurisdiction policy files in : " + cryptoPolicyProperty); } } catch (Exception e) { throw new SecurityException( "Couldn't parse jurisdiction policy files in: " + cryptoPolicyProperty); } } } catch (DirectoryIteratorException ex) { // I/O error encountered during the iteration, // the cause is an IOException throw new SecurityException( "Couldn't iterate through the jurisdiction policy files: " + cryptoPolicyProperty); } // Must have a default policy if ((defaultPolicy == null) || defaultPolicy.isEmpty()) { throw new SecurityException( "Missing mandatory jurisdiction policy files: " + cryptoPolicyProperty); } // If there was an empty exempt policy file, ignore it. if ((exemptPolicy != null) && exemptPolicy.isEmpty()) { exemptPolicy = null; } } static CryptoPermissions getDefaultPolicy() { return defaultPolicy; } static CryptoPermissions getExemptPolicy() { return exemptPolicy; } static boolean isRestricted() { return isRestricted; } }