JDK-4263225 : JarInputStream doesn't work if the manifest isn't at the beginning of stream
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Won't Fix
  • OS: solaris_2.6
  • CPU: sparc
  • Submitted: 1999-08-17
  • Updated: 1999-09-03
  • Resolved: 1999-09-03
Description
The JDK jarsigner always puts the manifest at the beginning of a JAR file; but
the Netscape's signtool puts the manifest at the end of a JAR file.

The current JarInputStream implementation cannot verify a jar file signed
by Netscape' signtool since it doesn't even read the manifest in such a JAR
file.

JarFile can verify JAR files signed by Netscape's sihntool; but JarFile only
works with files, not other kind of inputstreams.

When you pass a JAR file signed by Netscape's signtool (e.g.,
/home/shliu/public_html/testJAR/getpropThawe.jar) to the
TestJarInputStream, you get exceptions; but the TestJarFile does get
the manifest from that JAR file.
 
=========================== TestJarInputStream.java ================
import java.util.jar.*;
import java.net.*;
import java.io.*;

public class TestJarInputStream {

    public static void main(String[] args) throws Exception {

        isJarSigned(new URL(args[0]));
        System.out.println("Okey:" + args[0]);
    }

    /*
     * Verify a jar file is signed by a signer with a certificate which can be 
     * traced back to a trusted CA.
     */
    private static void isJarSigned(URL jarURL)
        throws IOException
    {
        String jarURLString = jarURL.toString();

        URLConnection connection = jarURL.openConnection();
        JarInputStream jis = new JarInputStream(connection.getInputStream());

        Manifest man = jis.getManifest();
        if (man == null)
            throw new JarException(jarURL.toString() + " is not signed.");

    }    
}

============================= TestJarFile.java ===================
import java.util.jar.*;
import java.net.*;
import java.io.*;

public class TestJarFile {

    public static void main(String[] args) throws Exception {

        isJarSigned(args[0]);
        System.out.println("Okey:" + args[0]);
    }

    /*
     * Verify a jar file is signed by a signer with a certificate which can be 
     * traced back to a trusted CA.
     */
    private static void isJarSigned(String fName)
        throws IOException
    {
        JarFile jf = new JarFile(new File(fName));

        Manifest man = jf.getManifest();
        if (man == null)
            throw new JarException(fName + " is not signed.");

    }    
}




Comments
SUGGESTED FIX If the manifest isn't at the beginning of a JarInputStream, read the inputstream twice: 1) get the manifest; 2) read each entry and verify it against the manifest if necessary.
2004-06-11

EVALUATION JarInputStream is a sequential input stream which doesn't mean to provide random access to the input data. Requiring it to be able to find the manifest at the end of the stream is not reasonable. Secondly, the manifest file should always be the first entry in a particular jar file, in fact our jar tool enforces this restriction. Of course, we cannot prevent other vendors from manually putting the manifest at any other place in a jar, which is otherwise semantically equivalent. I think if we do want to support this random access functionality, we should do it somewhere else, either in the security checking code itself, or by using the ZipFile API with support of byte range transmission in http1.1 and adding more constructors to ZipFile class. ###@###.### 1999-08-23 For a remote URL source, JarURLConnection.getJarFile() can be used to get the locally cached jar file and random access is allowed. This code can be added to the security checking procedure and the location of the manifest will not matter any more. ###@###.### 1999-09-03
1999-09-03