Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/crypto/JceSecurity.java
38829 views
/*1* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.crypto;2627import java.util.*;28import java.util.jar.*;29import java.io.*;30import java.net.URL;31import java.nio.file.*;32import java.security.*;3334import java.security.Provider.Service;3536import sun.security.jca.*;37import sun.security.jca.GetInstance.Instance;38import sun.security.util.Debug;3940/**41* This class instantiates implementations of JCE engine classes from42* providers registered with the java.security.Security object.43*44* @author Jan Luehe45* @author Sharon Liu46* @since 1.447*/4849final class JceSecurity {5051static final SecureRandom RANDOM = new SecureRandom();5253// The defaultPolicy and exemptPolicy will be set up54// in the static initializer.55private static CryptoPermissions defaultPolicy = null;56private static CryptoPermissions exemptPolicy = null;5758// Map<Provider,?> of the providers we already have verified59// value == PROVIDER_VERIFIED is successfully verified60// value is failure cause Exception in error case61private final static Map<Provider, Object> verificationResults =62new IdentityHashMap<>();6364// Map<Provider,?> of the providers currently being verified65private final static Map<Provider, Object> verifyingProviders =66new IdentityHashMap<>();6768private static final boolean isRestricted;6970private static final Debug debug =71Debug.getInstance("jca", "Cipher");7273/*74* Don't let anyone instantiate this.75*/76private JceSecurity() {77}7879static {80try {81AccessController.doPrivileged(82new PrivilegedExceptionAction<Object>() {83public Object run() throws Exception {84setupJurisdictionPolicies();85return null;86}87});8889isRestricted = defaultPolicy.implies(90CryptoAllPermission.INSTANCE) ? false : true;91} catch (Exception e) {92throw new SecurityException(93"Can not initialize cryptographic mechanism", e);94}95}9697static Instance getInstance(String type, Class<?> clazz, String algorithm,98String provider) throws NoSuchAlgorithmException,99NoSuchProviderException {100Service s = GetInstance.getService(type, algorithm, provider);101Exception ve = getVerificationResult(s.getProvider());102if (ve != null) {103String msg = "JCE cannot authenticate the provider " + provider;104throw (NoSuchProviderException)105new NoSuchProviderException(msg).initCause(ve);106}107return GetInstance.getInstance(s, clazz);108}109110static Instance getInstance(String type, Class<?> clazz, String algorithm,111Provider provider) throws NoSuchAlgorithmException {112Service s = GetInstance.getService(type, algorithm, provider);113Exception ve = JceSecurity.getVerificationResult(provider);114if (ve != null) {115String msg = "JCE cannot authenticate the provider "116+ provider.getName();117throw new SecurityException(msg, ve);118}119return GetInstance.getInstance(s, clazz);120}121122static Instance getInstance(String type, Class<?> clazz, String algorithm)123throws NoSuchAlgorithmException {124List<Service> services = GetInstance.getServices(type, algorithm);125NoSuchAlgorithmException failure = null;126for (Service s : services) {127if (canUseProvider(s.getProvider()) == false) {128// allow only signed providers129continue;130}131try {132Instance instance = GetInstance.getInstance(s, clazz);133return instance;134} catch (NoSuchAlgorithmException e) {135failure = e;136}137}138throw new NoSuchAlgorithmException("Algorithm " + algorithm139+ " not available", failure);140}141142/**143* Verify if the JAR at URL codeBase is a signed exempt application144* JAR file and returns the permissions bundled with the JAR.145*146* @throws Exception on error147*/148static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {149JarVerifier jv = new JarVerifier(codeBase, true);150jv.verify();151return jv.getPermissions();152}153154/**155* Verify if the JAR at URL codeBase is a signed provider JAR file.156*157* @throws Exception on error158*/159static void verifyProviderJar(URL codeBase) throws Exception {160// Verify the provider JAR file and all161// supporting JAR files if there are any.162JarVerifier jv = new JarVerifier(codeBase, false);163jv.verify();164}165166private final static Object PROVIDER_VERIFIED = Boolean.TRUE;167168/*169* Verify that the provider JAR files are signed properly, which170* means the signer's certificate can be traced back to a171* JCE trusted CA.172* Return null if ok, failure Exception if verification failed.173*/174static synchronized Exception getVerificationResult(Provider p) {175Object o = verificationResults.get(p);176if (o == PROVIDER_VERIFIED) {177return null;178} else if (o != null) {179return (Exception)o;180}181if (verifyingProviders.get(p) != null) {182// this method is static synchronized, must be recursion183// return failure now but do not save the result184return new NoSuchProviderException("Recursion during verification");185}186try {187verifyingProviders.put(p, Boolean.FALSE);188URL providerURL = getCodeBase(p.getClass());189verifyProviderJar(providerURL);190// Verified ok, cache result191verificationResults.put(p, PROVIDER_VERIFIED);192return null;193} catch (Exception e) {194verificationResults.put(p, e);195return e;196} finally {197verifyingProviders.remove(p);198}199}200201// return whether this provider is properly signed and can be used by JCE202static boolean canUseProvider(Provider p) {203return getVerificationResult(p) == null;204}205206// dummy object to represent null207private static final URL NULL_URL;208209static {210try {211NULL_URL = new URL("http://null.oracle.com/");212} catch (Exception e) {213throw new RuntimeException(e);214}215}216217// reference to a Map we use as a cache for codebases218private static final Map<Class<?>, URL> codeBaseCacheRef =219new WeakHashMap<>();220221/*222* Returns the CodeBase for the given class.223*/224static URL getCodeBase(final Class<?> clazz) {225synchronized (codeBaseCacheRef) {226URL url = codeBaseCacheRef.get(clazz);227if (url == null) {228url = AccessController.doPrivileged(new PrivilegedAction<URL>() {229public URL run() {230ProtectionDomain pd = clazz.getProtectionDomain();231if (pd != null) {232CodeSource cs = pd.getCodeSource();233if (cs != null) {234return cs.getLocation();235}236}237return NULL_URL;238}239});240codeBaseCacheRef.put(clazz, url);241}242return (url == NULL_URL) ? null : url;243}244}245246/*247* This is called from within an doPrivileged block.248*249* Following logic is used to decide what policy files are selected.250*251* If the new Security property (crypto.policy) is set in the252* java.security file, or has been set dynamically using the253* Security.setProperty() call before the JCE framework has254* been initialized, that setting will be used.255* Remember - this property is not defined by default. A conscious256* user edit or an application call is required.257*258* Otherwise, if user has policy jar files installed in the legacy259* <java-home>/lib/security/ directory, the JDK will honor whatever260* setting is set by those policy files. (legacy/current behavior)261*262* If none of the above 2 conditions are met, the JDK will default263* to using the unlimited crypto policy files found in the264* <java-home>/lib/security/policy/unlimited/ directory265*/266private static void setupJurisdictionPolicies() throws Exception {267// Sanity check the crypto.policy Security property. Single268// directory entry, no pseudo-directories (".", "..", leading/trailing269// path separators). normalize()/getParent() will help later.270String javaHomeProperty = System.getProperty("java.home");271String cryptoPolicyProperty = Security.getProperty("crypto.policy");272Path cpPath = (cryptoPolicyProperty == null) ? null :273Paths.get(cryptoPolicyProperty);274275if ((cpPath != null) && ((cpPath.getNameCount() != 1) ||276(cpPath.compareTo(cpPath.getFileName())) != 0)) {277throw new SecurityException(278"Invalid policy directory name format: " +279cryptoPolicyProperty);280}281282if (cpPath == null) {283// Security property is not set, use default path284cpPath = Paths.get(javaHomeProperty, "lib", "security");285} else {286// populate with java.home287cpPath = Paths.get(javaHomeProperty, "lib", "security",288"policy", cryptoPolicyProperty);289}290291if (debug != null) {292debug.println("crypto policy directory: " + cpPath);293}294295File exportJar = new File(cpPath.toFile(),"US_export_policy.jar");296File importJar = new File(cpPath.toFile(),"local_policy.jar");297298if (cryptoPolicyProperty == null && (!exportJar.exists() ||299!importJar.exists())) {300// Compatibility set up. If crypto.policy is not defined.301// check to see if legacy jars exist in lib directory. If302// they don't exist, we default to unlimited policy mode.303cpPath = Paths.get(304javaHomeProperty, "lib", "security", "policy", "unlimited");305// point to the new jar files in limited directory306exportJar = new File(cpPath.toFile(),"US_export_policy.jar");307importJar = new File(cpPath.toFile(),"local_policy.jar");308}309310URL jceCipherURL = ClassLoader.getSystemResource311("javax/crypto/Cipher.class");312313if ((jceCipherURL == null) ||314!exportJar.exists() || !importJar.exists()) {315throw new SecurityException316("Cannot locate policy or framework files!");317}318319// Read jurisdiction policies.320CryptoPermissions defaultExport = new CryptoPermissions();321CryptoPermissions exemptExport = new CryptoPermissions();322loadPolicies(exportJar, defaultExport, exemptExport);323324CryptoPermissions defaultImport = new CryptoPermissions();325CryptoPermissions exemptImport = new CryptoPermissions();326loadPolicies(importJar, defaultImport, exemptImport);327328// Merge the export and import policies for default applications.329if (defaultExport.isEmpty() || defaultImport.isEmpty()) {330throw new SecurityException("Missing mandatory jurisdiction " +331"policy files");332}333defaultPolicy = defaultExport.getMinimum(defaultImport);334335// Merge the export and import policies for exempt applications.336if (exemptExport.isEmpty()) {337exemptPolicy = exemptImport.isEmpty() ? null : exemptImport;338} else {339exemptPolicy = exemptExport.getMinimum(exemptImport);340}341}342343/**344* Load the policies from the specified file. Also checks that the345* policies are correctly signed.346*/347private static void loadPolicies(File jarPathName,348CryptoPermissions defaultPolicy,349CryptoPermissions exemptPolicy)350throws Exception {351352JarFile jf = new JarFile(jarPathName);353354Enumeration<JarEntry> entries = jf.entries();355while (entries.hasMoreElements()) {356JarEntry je = entries.nextElement();357InputStream is = null;358try {359if (je.getName().startsWith("default_")) {360is = jf.getInputStream(je);361defaultPolicy.load(is);362} else if (je.getName().startsWith("exempt_")) {363is = jf.getInputStream(je);364exemptPolicy.load(is);365} else {366continue;367}368} finally {369if (is != null) {370is.close();371}372}373374// Enforce the signer restraint, i.e. signer of JCE framework375// jar should also be the signer of the two jurisdiction policy376// jar files.377JarVerifier.verifyPolicySigned(je.getCertificates());378}379// Close and nullify the JarFile reference to help GC.380jf.close();381jf = null;382}383384static CryptoPermissions getDefaultPolicy() {385return defaultPolicy;386}387388static CryptoPermissions getExemptPolicy() {389return exemptPolicy;390}391392static boolean isRestricted() {393return isRestricted;394}395}396397398