8026067: Enhance signed jar verification
authorweijun
Mon, 25 Nov 2013 15:00:36 +0800
changeset 23912 9eab25093a89
parent 23911 f93d74f7d6fe
child 23913 049a0df69b88
8026067: Enhance signed jar verification Reviewed-by: ddehaven, ahgross, mullan
jdk/src/share/classes/java/util/jar/JarVerifier.java
jdk/src/share/classes/sun/security/tools/jarsigner/Main.java
jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java
--- a/jdk/src/share/classes/java/util/jar/JarVerifier.java	Wed Jan 22 14:59:33 2014 -0800
+++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java	Mon Nov 25 15:00:36 2013 +0800
@@ -676,6 +676,8 @@
                 } else {
                     matchUnsigned = true;
                 }
+            } else {
+                matchUnsigned = true;
             }
         }
 
@@ -778,23 +780,7 @@
 
     // true if file is part of the signature mechanism itself
     static boolean isSigningRelated(String name) {
-        name = name.toUpperCase(Locale.ENGLISH);
-        if (!name.startsWith("META-INF/")) {
-            return false;
-        }
-        name = name.substring(9);
-        if (name.indexOf('/') != -1) {
-            return false;
-        }
-        if (name.endsWith(".DSA")
-                || name.endsWith(".RSA")
-                || name.endsWith(".SF")
-                || name.endsWith(".EC")
-                || name.startsWith("SIG-")
-                || name.equals("MANIFEST.MF")) {
-            return true;
-        }
-        return false;
+        return SignatureFileVerifier.isSigningRelated(name);
     }
 
     private Enumeration<String> unsignedEntryNames(JarFile jar) {
--- a/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java	Wed Jan 22 14:59:33 2014 -0800
+++ b/jdk/src/share/classes/sun/security/tools/jarsigner/Main.java	Mon Nov 25 15:00:36 2013 +0800
@@ -90,9 +90,6 @@
 
     private static final String META_INF = "META-INF/";
 
-    // prefix for new signature-related files in META-INF directory
-    private static final String SIG_PREFIX = META_INF + "SIG-";
-
     private static final Class<?>[] PARAM_STRING = { String.class };
 
     private static final String NONE = "NONE";
@@ -1522,22 +1519,7 @@
      * . META-INF/*.EC
      */
     private boolean signatureRelated(String name) {
-        String ucName = name.toUpperCase(Locale.ENGLISH);
-        if (ucName.equals(JarFile.MANIFEST_NAME) ||
-            ucName.equals(META_INF) ||
-            (ucName.startsWith(SIG_PREFIX) &&
-                ucName.indexOf("/") == ucName.lastIndexOf("/"))) {
-            return true;
-        }
-
-        if (ucName.startsWith(META_INF) &&
-            SignatureFileVerifier.isBlockOrSF(ucName)) {
-            // .SF/.DSA/.RSA/.EC files in META-INF subdirs
-            // are not considered signature-related
-            return (ucName.indexOf("/") == ucName.lastIndexOf("/"));
-        }
-
-        return false;
+        return SignatureFileVerifier.isSigningRelated(name);
     }
 
     Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<>();
--- a/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java	Wed Jan 22 14:59:33 2014 -0800
+++ b/jdk/src/share/classes/sun/security/util/SignatureFileVerifier.java	Mon Nov 25 15:00:36 2013 +0800
@@ -152,6 +152,52 @@
         return false;
     }
 
+    /**
+     * Yet another utility method used by JarVerifier and JarSigner
+     * to determine what files are signature related, which includes
+     * the MANIFEST, SF files, known signature block files, and other
+     * unknown signature related files (those starting with SIG- with
+     * an optional [A-Z0-9]{1,3} extension right inside META-INF).
+     *
+     * @param s file name
+     * @return true if the input file name is signature related
+     */
+    public static boolean isSigningRelated(String name) {
+        name = name.toUpperCase(Locale.ENGLISH);
+        if (!name.startsWith("META-INF/")) {
+            return false;
+        }
+        name = name.substring(9);
+        if (name.indexOf('/') != -1) {
+            return false;
+        }
+        if (isBlockOrSF(name) || name.equals("MANIFEST.MF")) {
+            return true;
+        } else if (name.startsWith("SIG-")) {
+            // check filename extension
+            // see http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Digital_Signatures
+            // for what filename extensions are legal
+            int extIndex = name.lastIndexOf('.');
+            if (extIndex != -1) {
+                String ext = name.substring(extIndex + 1);
+                // validate length first
+                if (ext.length() > 3 || ext.length() < 1) {
+                    return false;
+                }
+                // then check chars, must be in [a-zA-Z0-9] per the jar spec
+                for (int index = 0; index < ext.length(); index++) {
+                    char cc = ext.charAt(index);
+                    // chars are promoted to uppercase so skip lowercase checks
+                    if ((cc < 'A' || cc > 'Z') && (cc < '0' || cc > '9')) {
+                        return false;
+                    }
+                }
+            }
+            return true; // no extension is OK
+        }
+        return false;
+    }
+
     /** get digest from cache */
 
     private MessageDigest getDigest(String algorithm)