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
This commit is contained in:
Bradford Wetmore 2016-12-05 17:04:02 -08:00
parent 615fbfe49c
commit fdb9c95f6b
6 changed files with 280 additions and 43 deletions
jdk
make/gensrc
src/java.base/share
classes/javax/crypto
conf/security
test/javax/crypto/CryptoPermissions

@ -108,3 +108,19 @@ ifeq ($(OPENJDK_TARGET_OS), solaris)
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)

@ -23,10 +23,33 @@
* 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.util.jar.*;
import java.io.*;
import java.net.URL;
import java.nio.file.*;
@ -36,6 +59,7 @@ 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
@ -47,6 +71,9 @@ import sun.security.jca.GetInstance.Instance;
*/
final class JceSecurity {
private static final Debug debug = Debug.getInstance("jca");
static final SecureRandom RANDOM = new SecureRandom();
@ -251,10 +278,27 @@ final class JceSecurity {
// 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 ((cryptoPolicyProperty == null) ||
(cpPath.getNameCount() != 1) ||
if ((cpPath.getNameCount() != 1) ||
(cpPath.compareTo(cpPath.getFileName()) != 0)) {
throw new SecurityException(
"Invalid policy directory name format: " +

@ -849,35 +849,35 @@ jdk.tls.legacyAlgorithms= \
# 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 @@ jdk.tls.legacyAlgorithms= \
# "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 @@ jdk.xml.dsig.secureValidationPolicy=\
#
# 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 @@ jdk.xml.dsig.secureValidationPolicy=\
#
# 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.
#

@ -10,11 +10,10 @@ The JCE architecture allows flexible cryptographic strength to be
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.

@ -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!");
}
}

@ -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 @@ public class TestUnlimited {
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();
}
System.out.println("Testing: " + args[0]);
Result expected = Result.UNKNOWN; // avoid NPE warnings
Result result;
if (args[0].equals("\"\"")) {
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");
}
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 @@ public class TestUnlimited {
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!");