I need to verify a signed jar from my application. I found I can do it by reading all contents, like this:
public boolean verifyJar(String filePath) {
try {
JarFile jar = new JarFile(filePath, true);
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
InputStream is = jar.getInputStream(entry);
byte[] buffer = new byte[10000];
while (is.read(buffer, 0, buffer.length) != -1) {
// we just read. this will throw a SecurityException
// if a signature/digest check fails.
}
is.close();
}
return true;
} catch (Exception e) {
return false;
}
}
If I execute the checker with a valid jar, it passes. If I corrupt the jar by cutting it in half, it fails. But if I do both in one process, the second check passes (as if it read the previous version of the file)!
public static void main(String[] args) throws Exception {
String path = "src/test/resources/temp/lib.jar";
// Passes - that's good
System.out.println(new Validator().verifyJar(path));
byte[] content = FileUtil.readFile(path);
FileUtil.save(path, Arrays.copyOf(content, content.length / 2));
// Passes - but it shouldn't.
// Fails if the first check is commented out though.
System.out.println(new Validator().verifyJar(path));
}
So it looks like ZipFile or JarFile is cached somehow. How do I suppress this behavior?
ZipFile has to be closed in order native code not to cache. Iirc ZipFile wraps the same handle (jzfile) if the path and File.lastModified are the same.
Alternatively touching File.lastModified may do the trick too but closing anything open manually (incl. ZipFile) is necessary to prevent resource leaks.