8170157: Enable unlimited cryptographic policy by default in OracleJDK
8169335: Add a crypto policy fallback in case Security Property 'crypto.policy' does not exist
Reviewed-by: erikj, ihse, weijun, xuelei, coffeys
--- a/jdk/make/gensrc/GensrcMisc.gmk Mon Dec 05 16:27:50 2016 -0800
+++ b/jdk/make/gensrc/GensrcMisc.gmk Mon Dec 05 17:04:02 2016 -0800
@@ -108,3 +108,19 @@
endif
################################################################################
+# Create the javax/crypto/JceSecurity.class, using the build default.
+#
+ifeq ($(UNLIMITED_CRYPTO), true)
+ JCE_DEFAULT_POLICY = unlimited
+else
+ JCE_DEFAULT_POLICY = limited
+endif
+
+$(eval $(call SetupTextFileProcessing, BUILD_JCESECURITY_JAVA, \
+ SOURCE_FILES := $(JDK_TOPDIR)/src/java.base/share/classes/javax/crypto/JceSecurity.java.template, \
+ OUTPUT_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/javax/crypto/JceSecurity.java, \
+ REPLACEMENTS := \
+ @@JCE_DEFAULT_POLICY@@ => $(JCE_DEFAULT_POLICY), \
+))
+
+GENSRC_JAVA_BASE += $(BUILD_JCESECURITY_JAVA)
--- a/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java Mon Dec 05 16:27:50 2016 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,348 +0,0 @@
-/*
- * 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.
- */
-
-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;
-
-/**
- * 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
- // 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
- */
- 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
- */
- 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");
- Path cpPath = Paths.get(cryptoPolicyProperty);
-
- if ((cryptoPolicyProperty == null) ||
- (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 = System.getProperty("java.home");
- 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;
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java.template Mon Dec 05 17:04:02 2016 -0800
@@ -0,0 +1,392 @@
+/*
+ * 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 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 {
+
+
+ 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
+ */
+ 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
+ */
+ 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 = "@@JCE_DEFAULT_POLICY@@";
+ 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 = System.getProperty("java.home");
+ 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;
+ }
+}
--- a/jdk/src/java.base/share/conf/security/java.security Mon Dec 05 16:27:50 2016 -0800
+++ b/jdk/src/java.base/share/conf/security/java.security Mon Dec 05 17:04:02 2016 -0800
@@ -849,35 +849,35 @@
# FFFFFFFF FFFFFFFF, 2}
# Cryptographic Jurisdiction Policy defaults
-#
+#
# Due to the import control restrictions of some countries, the default
# JCE policy files allow for strong but "limited" cryptographic key
# lengths to be used. If your country's cryptographic regulations allow,
# the "unlimited" strength policy files can be used instead, which contain
# no restrictions on cryptographic strengths.
-#
+#
# If your country has restrictions that don't fit either "limited" or
# "unlimited", an appropriate set of policy files should be created and
# configured before using this distribution. The jurisdiction policy file
# configuration must reflect the cryptographic restrictions appropriate
# for your country.
-#
+#
# YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY
# TO DETERMINE THE EXACT REQUIREMENTS.
-#
+#
# The policy files are flat text files organized into subdirectories of
# <java-home>/conf/security/policy. Each directory contains a complete
# set of policy files.
#
# The "crypto.policy" Security property controls the directory selection,
# and thus the effective cryptographic policy.
-#
-# The default set of directories is:
-#
-# limited | unlimited
-#
+#
+# The default set of directories is:
+#
+# limited | unlimited
+#
# however other directories can be created and configured.
-#
+#
# Within a directory, the effective policy is the combined minimum
# permissions of the grant statements in the file(s) with the filename
# pattern "default_*.policy". At least one grant is required. For
@@ -891,11 +891,15 @@
# "exempt_*.policy". Exemption grants are optional.
#
# limited = grants exemption permissions, by which the
-# effective policy can be circumvented.
+# effective policy can be circumvented.
# e.g. KeyRecovery/Escrow/Weakening.
-#
+#
# Please see the JCA documentation for additional information on these
# files and formats.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
crypto.policy=crypto.policydir-tbd
#
@@ -951,7 +955,8 @@
#
# If a pattern includes a "=", it sets a limit.
# If a limit appears more than once the last value is used.
-# Limits are checked before classes regardless of the order in the sequence of patterns.
+# Limits are checked before classes regardless of the order in the
+# sequence of patterns.
# If any of the limits are exceeded, the filter status is REJECTED.
#
# maxdepth=value - the maximum depth of a graph
@@ -961,20 +966,24 @@
#
# Other patterns, from left to right, match the class or package name as
# returned from Class.getName.
-# If the class is an array type, the class or package to be matched is the element type.
+# If the class is an array type, the class or package to be matched is the
+# element type.
# Arrays of any number of dimensions are treated the same as the element type.
# For example, a pattern of "!example.Foo", rejects creation of any instance or
# array of example.Foo.
#
-# If the pattern starts with "!", the status is REJECTED if the remaining pattern
-# is matched; otherwise the status is ALLOWED if the pattern matches.
-# If the pattern contains "/", the non-empty prefix up to the "/" is the module name;
+# If the pattern starts with "!", the status is REJECTED if the remaining
+# pattern is matched; otherwise the status is ALLOWED if the pattern matches.
+# If the pattern contains "/", the non-empty prefix up to the "/" is the
+# module name;
# if the module name matches the module name of the class then
# the remaining pattern is matched with the class name.
# If there is no "/", the module name is not compared.
-# If the pattern ends with ".**" it matches any class in the package and all subpackages.
+# If the pattern ends with ".**" it matches any class in the package and all
+# subpackages.
# If the pattern ends with ".*" it matches any class in the package.
-# If the pattern ends with "*", it matches any class with the pattern as a prefix.
+# If the pattern ends with "*", it matches any class with the pattern as a
+# prefix.
# If the pattern is equal to the class name, it matches.
# Otherwise, the status is UNDECIDED.
#
--- a/jdk/src/java.base/share/conf/security/policy/README.txt Mon Dec 05 16:27:50 2016 -0800
+++ b/jdk/src/java.base/share/conf/security/policy/README.txt Mon Dec 05 17:04:02 2016 -0800
@@ -10,11 +10,10 @@
configured via the jurisdiction policy files contained within these
directories.
-Due to import control restrictions of some countries, the default
-JCE policy files bundled in this Java Runtime Environment allow
-for strong but "limited" cryptographic strengths. For convenience,
-this build also contains the "unlimited strength" policy files which
-contain no restrictions on cryptographic strengths, but they must be
+The default JCE policy files bundled in this Java Runtime Environment
+allow for "unlimited" cryptographic strengths. For convenience,
+this build also contains the historic "limited" strength policy files
+which contain restrictions on cryptographic strengths, but they must be
specifically activated by updating the "crypto.policy" Security property
(e.g. <java-home>/conf/security/java.security) to point to the appropriate
directory.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/crypto/CryptoPermissions/CryptoPolicyFallback.java Mon Dec 05 17:04:02 2016 -0800
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 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.
+ */
+
+/**
+ * @test
+ * @bug 8169335
+ * @summary Add a crypto policy fallback in case Security Property
+ * 'crypto.policy' does not exist.
+ * @run main/othervm CryptoPolicyFallback
+ */
+import java.io.*;
+import java.nio.file.*;
+import java.util.stream.*;
+import javax.crypto.*;
+
+/*
+ * Take the current java.security file, strip out the 'crypto.policy' entry,
+ * write to a new file in the current directory, then use that file as the
+ * replacement java.security file. This test will fail if the crypto.policy
+ * entry doesn't match the compiled in value.
+ */
+public class CryptoPolicyFallback {
+
+ private static final String FILENAME = "java.security";
+
+ public static void main(String[] args) throws Exception {
+
+ String javaHome = System.getProperty("java.home");
+
+ Path path = Paths.get(javaHome, "conf", "security", FILENAME);
+
+ /*
+ * Get the default value.
+ */
+ String defaultPolicy;
+ try (Stream<String> lines = Files.lines(path)) {
+ /*
+ * If the input java.security file is malformed
+ * (missing crypto.policy, attribute/no value, etc), throw
+ * exception. split() might throw AIOOB which
+ * is ok behavior.
+ */
+ defaultPolicy = lines.filter(x -> x.startsWith("crypto.policy="))
+ .findFirst().orElseThrow(
+ () -> new Exception("Missing crypto.policy"))
+ .split("=")[1].trim();
+ }
+
+ /*
+ * We know there is at least one crypto.policy entry, strip
+ * all of them out of the java.security file.
+ */
+ try (PrintWriter out = new PrintWriter(FILENAME);
+ Stream<String> lines = Files.lines(path)) {
+ lines.filter(x -> !x.trim().startsWith("crypto.policy="))
+ .forEach(out::println);
+ }
+
+ /*
+ * "-Djava.security.properties==file" does a complete replacement
+ * of the system java.security file. i.e. value must be "=file"
+ */
+ System.setProperty("java.security.properties", "=" + FILENAME);
+
+ /*
+ * Find out expected value.
+ */
+ int expected;
+ switch (defaultPolicy) {
+ case "limited":
+ expected = 128;
+ break;
+ case "unlimited":
+ expected = Integer.MAX_VALUE;
+ break;
+ default:
+ throw new Exception(
+ "Unexpected Default Policy Value: " + defaultPolicy);
+ }
+
+ /*
+ * Do the actual check. If the JCE Framework can't initialize
+ * an Exception is normally thrown here.
+ */
+ int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
+
+ System.out.println("Default Policy: " + defaultPolicy
+ + "\nExpected max AES key length: " + expected
+ + ", received : " + maxKeyLen);
+
+ if (expected != maxKeyLen) {
+ throw new Exception("Wrong Key Length size!");
+ }
+
+ System.out.println("PASSED!");
+ }
+}
--- a/jdk/test/javax/crypto/CryptoPermissions/TestUnlimited.java Mon Dec 05 16:27:50 2016 -0800
+++ b/jdk/test/javax/crypto/CryptoPermissions/TestUnlimited.java Mon Dec 05 17:04:02 2016 -0800
@@ -27,10 +27,11 @@
* @test
* @bug 8061842
* @summary Package jurisdiction policy files as something other than JAR
+ * @run main/othervm TestUnlimited use_default default
* @run main/othervm TestUnlimited "" exception
- * @run main/othervm TestUnlimited limited fail
- * @run main/othervm TestUnlimited unlimited pass
- * @run main/othervm TestUnlimited unlimited/ pass
+ * @run main/othervm TestUnlimited limited limited
+ * @run main/othervm TestUnlimited unlimited unlimited
+ * @run main/othervm TestUnlimited unlimited/ unlimited
* @run main/othervm TestUnlimited NosuchDir exception
* @run main/othervm TestUnlimited . exception
* @run main/othervm TestUnlimited /tmp/unlimited exception
@@ -40,9 +41,38 @@
*/
import javax.crypto.*;
import java.security.Security;
+import java.nio.file.*;
+import java.util.stream.*;
public class TestUnlimited {
+ private enum Result {
+ UNLIMITED,
+ LIMITED,
+ EXCEPTION,
+ UNKNOWN
+ };
+
+ /*
+ * Grab the default policy entry from java.security.
+ *
+ * If the input java.security file is malformed
+ * (missing crypto.policy, attribute/no value, etc), throw
+ * exception. split() might throw AIOOB which
+ * is ok behavior.
+ */
+ private static String getDefaultPolicy() throws Exception {
+ String javaHome = System.getProperty("java.home");
+ Path path = Paths.get(javaHome, "conf", "security", "java.security");
+
+ try (Stream<String> lines = Files.lines(path)) {
+ return lines.filter(x -> x.startsWith("crypto.policy="))
+ .findFirst().orElseThrow(
+ () -> new Exception("Missing crypto.policy"))
+ .split("=")[1].trim();
+ }
+ }
+
public static void main(String[] args) throws Exception {
/*
* Override the Security property to allow for unlimited policy.
@@ -53,16 +83,37 @@
throw new Exception("Two args required");
}
- boolean expected = args[1].equals("pass");
- boolean exception = args[1].equals("exception");
- boolean result = false;
+ String testStr = args[0];
+ String expectedStr = args[1];
+ if (testStr.equals("use_default")) {
+ expectedStr = getDefaultPolicy();
+ }
+
+ Result expected = Result.UNKNOWN; // avoid NPE warnings
+ Result result;
- System.out.println("Testing: " + args[0]);
+ switch (expectedStr) {
+ case "unlimited":
+ expected = Result.UNLIMITED;
+ break;
+ case "limited":
+ expected = Result.LIMITED;
+ break;
+ case "exception":
+ expected = Result.EXCEPTION;
+ break;
+ default:
+ throw new Exception("Unexpected argument");
+ }
- if (args[0].equals("\"\"")) {
+ System.out.println("Testing: " + testStr);
+ if (testStr.equals("\"\"")) {
Security.setProperty("crypto.policy", "");
} else {
- Security.setProperty("crypto.policy", args[0]);
+ // skip default case.
+ if (!testStr.equals("use_default")) {
+ Security.setProperty("crypto.policy", testStr);
+ }
}
/*
@@ -74,21 +125,20 @@
System.out.println("max AES key len:" + maxKeyLen);
if (maxKeyLen > 128) {
System.out.println("Unlimited policy is active");
- result = true;
+ result = Result.UNLIMITED;
} else {
System.out.println("Unlimited policy is NOT active");
- result = false;
+ result = Result.LIMITED;
}
} catch (Throwable e) {
- if (!exception) {
- throw new Exception();
- }
+ //ExceptionInInitializerError's
+ result = Result.EXCEPTION;
}
System.out.println(
"Expected:\t" + expected + "\nResult:\t\t" + result);
- if (expected != result) {
- throw new Exception();
+ if (!expected.equals(result)) {
+ throw new Exception("Didn't match");
}
System.out.println("DONE!");