src/share/classes/sun/security/tools/JarSigner.java

Print this page
rev 352 : 6948909: Jarsigner removes MANIFEST.MF info for badly packages jar's
Reviewed-by: mullan, xuelei

@@ -949,19 +949,26 @@
              *   generated one. (This may invalidate existing signatures!)
              */
             BASE64Encoder encoder = new JarBASE64Encoder();
             Vector<ZipEntry> mfFiles = new Vector<ZipEntry>();
 
+            boolean wasSigned = false;
+
             for (Enumeration<? extends ZipEntry> enum_=zipFile.entries();
                         enum_.hasMoreElements();) {
                 ZipEntry ze = enum_.nextElement();
 
                 if (ze.getName().startsWith(META_INF)) {
                     // Store META-INF files in vector, so they can be written
                     // out first
                     mfFiles.addElement(ze);
 
+                    if (SignatureFileVerifier.isBlockOrSF(
+                            ze.getName().toUpperCase(Locale.ENGLISH))) {
+                        wasSigned = true;
+                    }
+
                     if (signatureRelated(ze.getName())) {
                         // ignore signature-related and manifest files
                         continue;
                     }
                 }

@@ -985,10 +992,11 @@
 
             // Recalculate the manifest raw bytes if necessary
             if (mfModified) {
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
                 manifest.write(baos);
+                if (wasSigned) {
                 byte[] newBytes = baos.toByteArray();
                 if (mfRawBytes != null
                         && oldAttr.equals(manifest.getMainAttributes())) {
 
                     /*

@@ -1016,10 +1024,13 @@
                                 newBytes.length - newPos);
                         newBytes = lastBytes;
                     }
                 }
                 mfRawBytes = newBytes;
+                } else {
+                    mfRawBytes = baos.toByteArray();
+                }
             }
 
             // Write out the manifest
             if (mfModified) {
                 // manifest file has new length

@@ -1231,27 +1242,35 @@
         //     error(rb.getString("unable to sign jar: ")+ioe, ioe);
         // }
     }
 
     /**
-     * Find the position of an empty line inside bs
+     * Find the length of header inside bs. The header is a multiple (>=0)
+     * lines of attributes plus an empty line. The empty line is included
+     * in the header.
      */
     private int findHeaderEnd(byte[] bs) {
-        // An empty line can be at the beginning...
-        if (bs.length > 1 && bs[0] == '\r' && bs[1] == '\n') {
-            return 0;
-        }
-        // ... or after another line
-        for (int i=0; i<bs.length-3; i++) {
-            if (bs[i] == '\r' && bs[i+1] == '\n' &&
-                    bs[i+2] == '\r' && bs[i+3] == '\n') {
-               return i;
+        // Initial state true to deal with empty header
+        boolean newline = true;     // just met a newline
+        int len = bs.length;
+        for (int i=0; i<len; i++) {
+            switch (bs[i]) {
+                case '\r':
+                    if (i < len - 1 && bs[i+1] == '\n') i++;
+                    // fallthrough
+                case '\n':
+                    if (newline) return i+1;    //+1 to get length
+                    newline = true;
+                    break;
+                default:
+                    newline = false;
             }
         }
-        // If header end is not found, return 0,
-        // which means no behavior change.
-        return 0;
+        // If header end is not found, it means the MANIFEST.MF has only
+        // the main attributes section and it does not end with 2 newlines.
+        // Returns the whole length so that it can be completely replaced.
+        return len;
     }
 
     /**
      * signature-related files include:
      * . META-INF/MANIFEST.MF