8140353: Improve signature checking
authormullan
Tue, 04 Oct 2016 17:15:49 -0400
changeset 43206 4c18d1166944
parent 43205 df23cecb03ae
child 43207 569e0c1d851d
8140353: Improve signature checking Reviewed-by: xuelei, ahgross, mchung
jdk/src/java.base/share/classes/module-info.java
jdk/src/java.base/share/conf/security/java.security
jdk/src/java.base/share/lib/security/default.policy
jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java
jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Policy.java
--- a/jdk/src/java.base/share/classes/module-info.java	Tue Sep 27 16:35:28 2016 +0300
+++ b/jdk/src/java.base/share/classes/module-info.java	Tue Oct 04 17:15:49 2016 -0400
@@ -279,6 +279,7 @@
         java.security.jgss,
         java.security.sasl,
         java.smartcardio,
+        java.xml.crypto,
         jdk.crypto.ec,
         jdk.crypto.token,
         jdk.jartool,
--- a/jdk/src/java.base/share/conf/security/java.security	Tue Sep 27 16:35:28 2016 +0300
+++ b/jdk/src/java.base/share/conf/security/java.security	Tue Oct 04 17:15:49 2016 -0400
@@ -913,7 +913,7 @@
 #       Constraint {"," Constraint }
 #   Constraint:
 #       AlgConstraint | MaxTransformsConstraint | MaxReferencesConstraint |
-#       ReferenceUriSchemeConstraint | OtherConstraint
+#       ReferenceUriSchemeConstraint | KeySizeConstraint | OtherConstraint
 #   AlgConstraint
 #       "disallowAlg" Uri
 #   MaxTransformsConstraint:
@@ -922,12 +922,16 @@
 #       "maxReferences" Integer
 #   ReferenceUriSchemeConstraint:
 #       "disallowReferenceUriSchemes" String { String }
+#   KeySizeConstraint:
+#       "minKeySize" KeyAlg Integer
 #   OtherConstraint:
 #       "noDuplicateIds" | "noRetrievalMethodLoops"
 #
 # For AlgConstraint, Uri is the algorithm URI String that is not allowed.
 # See the XML Signature Recommendation for more information on algorithm
-# URI Identifiers. If the MaxTransformsConstraint or MaxReferencesConstraint is
+# URI Identifiers. For KeySizeConstraint, KeyAlg is the standard algorithm
+# name of the key type (ex: "RSA"). If the MaxTransformsConstraint,
+# MaxReferencesConstraint or KeySizeConstraint (for the same key type) is
 # specified more than once, only the last entry is enforced.
 #
 # Note: This property is currently used by the JDK Reference implementation. It
@@ -941,6 +945,8 @@
     maxTransforms 5,\
     maxReferences 30,\
     disallowReferenceUriSchemes file http https,\
+    minKeySize RSA 1024,\
+    minKeySize DSA 1024,\
     noDuplicateIds,\
     noRetrievalMethodLoops
 
--- a/jdk/src/java.base/share/lib/security/default.policy	Tue Sep 27 16:35:28 2016 +0300
+++ b/jdk/src/java.base/share/lib/security/default.policy	Tue Oct 04 17:15:49 2016 -0400
@@ -81,6 +81,8 @@
 };
 
 grant codeBase "jrt:/java.xml.crypto" {
+    permission java.lang.RuntimePermission
+                   "accessClassInPackage.sun.security.util";
     permission java.util.PropertyPermission "*", "read";
     permission java.security.SecurityPermission "putProviderProperty.XMLDSig";
     permission java.security.SecurityPermission
--- a/jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java	Tue Sep 27 16:35:28 2016 +0300
+++ b/jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java	Tue Oct 04 17:15:49 2016 -0400
@@ -21,7 +21,7 @@
  * under the License.
  */
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * $Id: DOMSignatureMethod.java 1333415 2012-05-03 12:03:51Z coheigea $
@@ -41,6 +41,7 @@
 import com.sun.org.apache.xml.internal.security.algorithms.implementations.SignatureECDSA;
 import com.sun.org.apache.xml.internal.security.utils.JavaUtils;
 import org.jcp.xml.dsig.internal.SignerOutputStream;
+import sun.security.util.KeyUtil;
 
 /**
  * DOM-based abstract implementation of SignatureMethod.
@@ -207,6 +208,7 @@
         if (!(key instanceof PublicKey)) {
             throw new InvalidKeyException("key must be PublicKey");
         }
+        checkKeySize(context, key);
         if (signature == null) {
             Provider p = (Provider)context.getProperty(
                     "org.jcp.xml.dsig.internal.dom.SignatureProvider");
@@ -234,6 +236,37 @@
         return signature.verify(s);
     }
 
+    /**
+     * If secure validation mode is enabled, checks that the key size is
+     * restricted.
+     *
+     * @param context the context
+     * @param key the key to check
+     * @throws XMLSignatureException if the key size is restricted
+     */
+    private static void checkKeySize(XMLCryptoContext context, Key key)
+        throws XMLSignatureException {
+        if (Utils.secureValidation(context)) {
+            int size = KeyUtil.getKeySize(key);
+            if (size == -1) {
+                // key size cannot be determined, so we cannot check against
+                // restrictions. Note that a DSA key w/o params will be
+                // rejected later if the certificate chain is validated.
+                if (log.isLoggable(java.util.logging.Level.FINE)) {
+                    log.log(java.util.logging.Level.FINE, "Size for " +
+                            key.getAlgorithm() + " key cannot be determined");
+                }
+                return;
+            }
+            if (Policy.restrictKey(key.getAlgorithm(), size)) {
+                throw new XMLSignatureException(key.getAlgorithm() +
+                    " keys less than " +
+                    Policy.minKeySize(key.getAlgorithm()) + " bits are" +
+                    " forbidden when secure validation is enabled");
+            }
+        }
+    }
+
     byte[] sign(Key key, SignedInfo si, XMLSignContext context)
         throws InvalidKeyException, XMLSignatureException
     {
@@ -244,6 +277,7 @@
         if (!(key instanceof PrivateKey)) {
             throw new InvalidKeyException("key must be PrivateKey");
         }
+        checkKeySize(context, key);
         if (signature == null) {
             Provider p = (Provider)context.getProperty(
                     "org.jcp.xml.dsig.internal.dom.SignatureProvider");
--- a/jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Policy.java	Tue Sep 27 16:35:28 2016 +0300
+++ b/jdk/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Policy.java	Tue Oct 04 17:15:49 2016 -0400
@@ -31,8 +31,10 @@
 import java.security.PrivilegedAction;
 import java.security.Security;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -46,6 +48,7 @@
     private static int maxTrans = Integer.MAX_VALUE;
     private static int maxRefs = Integer.MAX_VALUE;
     private static Set<String> disallowedRefUriSchemes = new HashSet<>();
+    private static Map<String, Integer> minKeyMap = new HashMap<>();
     private static boolean noDuplicateIds = false;
     private static boolean noRMLoops = false;
 
@@ -101,6 +104,13 @@
                             scheme.toLowerCase(Locale.ROOT));
                     }
                     break;
+                case "minKeySize":
+                    if (tokens.length != 3) {
+                        error(entry);
+                    }
+                    minKeyMap.put(tokens[1],
+                                  Integer.parseUnsignedInt(tokens[2]));
+                    break;
                 case "noDuplicateIds":
                     if (tokens.length != 1) {
                         error(entry);
@@ -147,6 +157,10 @@
         return false;
     }
 
+    public static boolean restrictKey(String type, int size) {
+        return (size < minKeyMap.getOrDefault(type, 0));
+    }
+
     public static boolean restrictDuplicateIds() {
         return noDuplicateIds;
     }
@@ -171,6 +185,10 @@
         return Collections.<String>unmodifiableSet(disallowedRefUriSchemes);
     }
 
+    public static int minKeySize(String type) {
+        return minKeyMap.getOrDefault(type, 0);
+    }
+
     private static void error(String entry) {
         throw new IllegalArgumentException(
             "Invalid jdk.xml.dsig.secureValidationPolicy entry: " + entry);