8170157: Enable unlimited cryptographic policy by default in OracleJDK
authorwetmore
Mon, 05 Dec 2016 17:04:02 -0800
changeset 42365 5e640c2994d6
parent 42364 c5a725b3d358
child 42366 b1483ec50db1
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
jdk/make/gensrc/GensrcMisc.gmk
jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java
jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java.template
jdk/src/java.base/share/conf/security/java.security
jdk/src/java.base/share/conf/security/policy/README.txt
jdk/test/javax/crypto/CryptoPermissions/CryptoPolicyFallback.java
jdk/test/javax/crypto/CryptoPermissions/TestUnlimited.java
--- 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!");