8155847: SHA groups needed for jdk.security.provider.preferred
authorascarpino
Thu, 19 May 2016 16:05:33 -0700
changeset 38435 292ad46c1bf1
parent 38434 a38df2210d1f
child 38436 4676f6c9ebee
8155847: SHA groups needed for jdk.security.provider.preferred Reviewed-by: valeriep, mullan
jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java
jdk/src/java.base/share/conf/security/java.security
jdk/test/sun/security/jca/PreferredProviderTest.java
--- a/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java	Thu May 19 20:14:17 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java	Thu May 19 16:05:33 2016 -0700
@@ -650,12 +650,29 @@
         }
     }
 
+    /* Defined Groups for jdk.security.provider.preferred */
+    private static final String SHA2Group[] = { "SHA-224", "SHA-256",
+            "SHA-384", "SHA-512", "SHA-512/224", "SHA-512/256" };
+    private static final String HmacSHA2Group[] = { "HmacSHA224",
+            "HmacSHA256", "HmacSHA384", "HmacSHA512"};
+    private static final String SHA2RSAGroup[] = { "SHA224withRSA",
+            "SHA256withRSA", "SHA384withRSA", "SHA512withRSA"};
+    private static final String SHA2DSAGroup[] = { "SHA224withDSA",
+            "SHA256withDSA", "SHA384withDSA", "SHA512withDSA"};
+    private static final String SHA2ECDSAGroup[] = { "SHA224withECDSA",
+            "SHA256withECDSA", "SHA384withECDSA", "SHA512withECDSA"};
+    private static final String SHA3Group[] = { "SHA3-224", "SHA3-256",
+            "SHA3-384", "SHA3-512" };
+    private static final String HmacSHA3Group[] = { "HmacSHA3-224",
+            "HmacSHA3-256", "HmacSHA3-384", "HmacSHA3-512"};
+
     // Individual preferred property entry from jdk.security.provider.preferred
-    private class PreferredEntry {
-        String type = null;
-        String algorithm;
-        String provider;
-        String alternateName = null;
+    private static class PreferredEntry {
+        private String type = null;
+        private String algorithm;
+        private String provider;
+        private String alternateNames[] = null;
+        private boolean group = false;
 
         PreferredEntry(String t, String p) {
             int i = t.indexOf('.');
@@ -667,47 +684,83 @@
             }
 
             provider = p;
-            if (algorithm.compareToIgnoreCase("SHA1") == 0) {
-                alternateName = "SHA-1";
+            // Group definitions
+            if (type != null && type.compareToIgnoreCase("Group") == 0) {
+                // Currently intrinsic algorithm groups
+                if (algorithm.compareToIgnoreCase("SHA2") == 0) {
+                    alternateNames = SHA2Group;
+                } else if (algorithm.compareToIgnoreCase("HmacSHA2") == 0) {
+                    alternateNames = HmacSHA2Group;
+                } else if (algorithm.compareToIgnoreCase("SHA2RSA") == 0) {
+                    alternateNames = SHA2RSAGroup;
+                } else if (algorithm.compareToIgnoreCase("SHA2DSA") == 0) {
+                    alternateNames = SHA2DSAGroup;
+                } else if (algorithm.compareToIgnoreCase("SHA2ECDSA") == 0) {
+                    alternateNames = SHA2ECDSAGroup;
+                } else if (algorithm.compareToIgnoreCase("SHA3") == 0) {
+                    alternateNames = SHA3Group;
+                } else if (algorithm.compareToIgnoreCase("HmacSHA3") == 0) {
+                    alternateNames = HmacSHA3Group;
+                }
+                if (alternateNames != null) {
+                    group = true;
+                }
+
+            // If the algorithm name given is SHA1
+            } else if (algorithm.compareToIgnoreCase("SHA1") == 0) {
+                alternateNames = new String[] { "SHA-1" };
             } else if (algorithm.compareToIgnoreCase("SHA-1") == 0) {
-                alternateName = "SHA1";
+                alternateNames = new String[] { "SHA1" };
             }
         }
 
         boolean match(String t, String a) {
             if (debug != null) {
-                debug.println("Config match:  " + toString() + " == [" + t +
-                        ", " + a + "]");
+                debug.println("Config check:  " + toString() + " == " +
+                        print(t, a, null));
             }
 
             // Compare service type if configured
-            if (type != null && type.compareToIgnoreCase(t) != 0) {
+            if (type != null && !group && type.compareToIgnoreCase(t) != 0) {
                 return false;
             }
 
             // Compare the algorithm string.
-            if (a.compareToIgnoreCase(algorithm) == 0) {
+            if (!group && a.compareToIgnoreCase(algorithm) == 0) {
                 if (debug != null) {
-                    debug.println("Config entry found:  " + toString());
+                    debug.println("Config entry matched:  " + toString());
                 }
                 return true;
             }
 
-            if (alternateName != null &&
-                    a.compareToIgnoreCase(alternateName) == 0) {
-                if (debug != null) {
-                    debug.println("Config entry found (alternateName):  " +
-                            toString());
+            if (alternateNames != null) {
+                for (String alt : alternateNames) {
+                    if (debug != null) {
+                        debug.println("AltName check:  " + print(type, alt,
+                                provider));
+                    }
+                    if (a.compareToIgnoreCase(alt) == 0) {
+                        if (debug != null) {
+                            debug.println("AltName entry matched:  " +
+                                    provider);
+                        }
+                        return true;
+                    }
                 }
-                return true;
             }
 
             // No match
             return false;
         }
 
+        // Print debugging output of PreferredEntry
+        private String print(String t, String a, String p) {
+            return "[" + ((t != null) ? t : "" ) + ", " + a +
+                    ((p != null) ? " : " + p : "" ) + "] ";
+        }
+
         public String toString() {
-            return "[" + type + ", " + algorithm + " : " + provider + "] ";
+            return print(type, algorithm, provider);
         }
     }
 
--- a/jdk/src/java.base/share/conf/security/java.security	Thu May 19 20:14:17 2016 +0000
+++ b/jdk/src/java.base/share/conf/security/java.security	Thu May 19 16:05:33 2016 -0700
@@ -105,15 +105,30 @@
 # The provider is the name of the provider. Any provider that does not
 # also appear in the registered list will be ignored.
 #
+# There is a special serviceType for this property only to group a set of
+# algorithms together. The type is "Group" and is followed by an algorithm
+# keyword. Groups are to simplify and lessen the entries on the property
+# line. Current groups are:
+#   Group.SHA2 = SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256
+#   Group.HmacSHA2 = HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512
+#   Group.SHA2RSA = SHA224withRSA, SHA256withRSA, SHA384withRSA, SHA512withRSA
+#   Group.SHA2DSA = SHA224withDSA, SHA256withDSA, SHA384withDSA, SHA512withDSA
+#   Group.SHA2ECDSA = SHA224withECDSA, SHA256withECDSA, SHA384withECDSA, \
+#                     SHA512withECDSA
+#   Group.SHA3 = SHA3-224, SHA3-256, SHA3-384, SHA3-512
+#   Group.HmacSHA3 = HmacSHA3-224, HmacSHA3-256, HmacSHA3-384, HmacSHA3-512
+#
 # Example:
 #   jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, \
-#         MessageDigest.SHA-256:SUN
+#         MessageDigest.SHA-256:SUN, Group.HmacSHA2:SunJCE
 #ifdef solaris-sparc
-jdk.security.provider.preferred=AES:SunJCE, SHA1:SUN, SHA-224:SUN, \
-      SHA-256:SUN, SHA-384:SUN, SHA-512:SUN
+jdk.security.provider.preferred=AES:SunJCE, SHA1:SUN, Group.SHA2:SUN, \
+      HmacSHA1:SunJCE, Group.HmacSHA2:SunJCE
 #endif
 #ifdef solaris-x86
-jdk.security.provider.preferred=AES:SunJCE, RSA:SunRsaSign
+jdk.security.provider.preferred=AES:SunJCE, SHA1:SUN, Group.SHA2:SUN, \
+      HmacSHA1:SunJCE, Group.HmacSHA2:SunJCE, RSA:SunRsaSign, \
+      SHA1withRSA:SunRsaSign, Group.SHA2RSA:SunRsaSign
 #endif
 
 
@@ -613,14 +628,14 @@
 # "CertConstraint" specifies additional constraints for
 # certificates that contain algorithms that are restricted:
 #
-#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
-#     in a certificate chain that terminates at a marked trust anchor in the
-#     lib/security/cacerts keystore.  All other chains are not affected.
-#     If the jdkCA constraint is not set, then all chains using the
-#     specified algorithm are restricted.  jdkCA may only be used once in
+#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
+#     in a certificate chain that terminates at a marked trust anchor in the
+#     lib/security/cacerts keystore.  All other chains are not affected.
+#     If the jdkCA constraint is not set, then all chains using the
+#     specified algorithm are restricted.  jdkCA may only be used once in
 #     a DisabledAlgorithm expression.
-#     Example:  To apply this constraint to SHA-1 certificates, include
-#     the following:  "SHA1 jdkCA"
+#     Example:  To apply this constraint to SHA-1 certificates, include
+#     the following:  "SHA1 jdkCA"
 #
 # When an algorithm must satisfy more than one constraint, it must be
 # delimited by an ampersand '&'.  For example, to restrict certificates in a
--- a/jdk/test/sun/security/jca/PreferredProviderTest.java	Thu May 19 20:14:17 2016 +0000
+++ b/jdk/test/sun/security/jca/PreferredProviderTest.java	Thu May 19 16:05:33 2016 -0700
@@ -25,15 +25,17 @@
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.Security;
+import java.security.Signature;
 import java.security.Provider;
 import java.util.Arrays;
 import java.util.List;
 import javax.crypto.Cipher;
+import javax.crypto.Mac;
 import javax.crypto.NoSuchPaddingException;
 
 /**
  * @test
- * @bug 8076359 8133151 8145344 8150512
+ * @bug 8076359 8133151 8145344 8150512 8155847
  * @summary Test the value for new jdk.security.provider.preferred
  *          security property
  */
@@ -61,8 +63,8 @@
             //java.security file which will be verified.
             switch (type) {
                 case "sparcv9":
-                    preferredProp = "AES:SunJCE, SHA1:SUN, SHA-224:SUN,"
-                            + " SHA-256:SUN, SHA-384:SUN, SHA-512:SUN";
+                    preferredProp = "AES:SunJCE, SHA1:SUN, Group.SHA2:SUN, " +
+                            "HmacSHA1:SunJCE, Group.HmacSHA2:SunJCE";
                     verifyPreferredProviderProperty(os, type, preferredProp);
 
                     verifyDigestProvider(os, type, Arrays.asList(
@@ -71,14 +73,51 @@
                             new DataTuple("SHA-224", "SUN"),
                             new DataTuple("SHA-256", "SUN"),
                             new DataTuple("SHA-384", "SUN"),
-                            new DataTuple("SHA-512", "SUN")));
+                            new DataTuple("SHA-512", "SUN"),
+                            new DataTuple("SHA-512/224", "SUN"),
+                            new DataTuple("SHA-512/256", "SUN")));
+
+                    verifyMacProvider(os, type, Arrays.asList(
+                            new DataTuple("HmacSHA1", "SunJCE"),
+                            new DataTuple("HmacSHA224", "SunJCE"),
+                            new DataTuple("HmacSHA256", "SunJCE"),
+                            new DataTuple("HmacSHA384", "SunJCE"),
+                            new DataTuple("HmacSHA512", "SunJCE")));
                     break;
                 case "amd64":
-                    preferredProp = "AES:SunJCE, RSA:SunRsaSign";
+                    preferredProp = "AES:SunJCE, SHA1:SUN, Group.SHA2:SUN, " +
+                            "HmacSHA1:SunJCE, Group.HmacSHA2:SunJCE, " +
+                            "RSA:SunRsaSign, SHA1withRSA:SunRsaSign, " +
+                            "Group.SHA2RSA:SunRsaSign";
+
                     verifyPreferredProviderProperty(os, type, preferredProp);
 
                     verifyKeyFactoryProvider(os, type, Arrays.asList(
                             new DataTuple("RSA", "SunRsaSign")));
+
+                    verifyDigestProvider(os, type, Arrays.asList(
+                            new DataTuple("SHA1", "SUN"),
+                            new DataTuple("SHA-1", "SUN"),
+                            new DataTuple("SHA-224", "SUN"),
+                            new DataTuple("SHA-256", "SUN"),
+                            new DataTuple("SHA-384", "SUN"),
+                            new DataTuple("SHA-512", "SUN"),
+                            new DataTuple("SHA-512/224", "SUN"),
+                            new DataTuple("SHA-512/256", "SUN")));
+
+                    verifyMacProvider(os, type, Arrays.asList(
+                            new DataTuple("HmacSHA1", "SunJCE"),
+                            new DataTuple("HmacSHA224", "SunJCE"),
+                            new DataTuple("HmacSHA256", "SunJCE"),
+                            new DataTuple("HmacSHA384", "SunJCE"),
+                            new DataTuple("HmacSHA512", "SunJCE")));
+
+                    verifySignatureProvider(os, type, Arrays.asList(
+                            new DataTuple("SHA1withRSA", "SunRsaSign"),
+                            new DataTuple("SHA224withRSA", "SunRsaSign"),
+                            new DataTuple("SHA256withRSA", "SunRsaSign"),
+                            new DataTuple("SHA384withRSA", "SunRsaSign"),
+                            new DataTuple("SHA512withRSA", "SunRsaSign")));
                     break;
             }
             verifyDigestProvider(os, type, Arrays.asList(
@@ -99,6 +138,8 @@
         String preferredProvider
                 = Security.getProperty("jdk.security.provider.preferred");
         if (!preferredProvider.equals(preferred)) {
+            System.out.println("Expected: " + preferred + "\nResult: " +
+                    preferredProvider);
             throw new RuntimeException(String.format(
                     "Test Failed: wrong jdk.security.provider.preferred value "
                     + "on %s-%s", os, arch));
@@ -120,6 +161,19 @@
                 "Preferred MessageDigest algorithm verification successful.");
     }
 
+    private static void verifyMacProvider(String os, String arch,
+            List<DataTuple> algoProviders) throws NoSuchAlgorithmException {
+        for (DataTuple dataTuple : algoProviders) {
+            System.out.printf(
+                    "Verifying Mac for '%s'%n", dataTuple.algorithm);
+            Mac mac = Mac.getInstance(dataTuple.algorithm);
+            matchProvider(mac.getProvider(), dataTuple.provider,
+                    dataTuple.algorithm, os, arch);
+        }
+        System.out.println(
+                "Preferred Mac algorithm verification successful.");
+    }
+
     private static void verifyKeyFactoryProvider(String os, String arch,
             List<DataTuple> algoProviders) throws NoSuchAlgorithmException {
         for (DataTuple dataTuple : algoProviders) {
@@ -133,6 +187,19 @@
                 "Preferred KeyFactory algorithm verification successful.");
     }
 
+    private static void verifySignatureProvider(String os, String arch,
+            List<DataTuple> algoProviders) throws NoSuchAlgorithmException {
+        for (DataTuple dataTuple : algoProviders) {
+            System.out.printf(
+                    "Verifying Signature for '%s'%n", dataTuple.algorithm);
+            Signature si = Signature.getInstance(dataTuple.algorithm);
+            matchProvider(si.getProvider(), dataTuple.provider,
+                    dataTuple.algorithm, os, arch);
+        }
+        System.out.println(
+                "Preferred Signature algorithm verification successful.");
+    }
+
     private static void matchProvider(Provider provider, String expected,
             String algo, String os, String arch) {
         if (!provider.getName().equals(expected)) {