在工作中,我们使用了许多已签名的第三方库。其中一些不再维护,但我们仍然需要使用它们。由于最近的Java安全更新,需要更新这些jar中的清单文件以包含额外的安全属性。鉴于jar文件如何工作,我需要在每个jar上执行unpack-edit-repack过程。
这涉及解压缩jar,向清单添加额外属性,同时删除已存在的SHA1签名字符串,重新打包并使用我们自己的签名重新签名jar。这是我到目前为止打开jar包的代码:
public static void unpackJarFile(File srcJarFile) throws IOException{
File tmpJarFile = File.createTempFile("tempJar", ".tmp");
JarFile jarFile = new JarFile(srcJarFile);
JarOutputStream tempJarOutputStream = new JarOutputStream(new FileOutputStream(tmpJarFile));
//Copy original jar file to the temporary one.
Enumeration<JarEntry> jarEntries = jarFile.entries();
while(jarEntries.hasMoreElements()) {
JarEntry temp = jarEntries.nextElement();
//if file is manifest then unsign else carry on
JarEntry entry = isManifestFile(temp) ? unsignManifest(temp, jarFile) : temp;
// ingore files ending in .SF and .RSA
if (fileIsNotSignature(entry)){
InputStream entryInputStream = jarFile.getInputStream(entry);
tempJarOutputStream.putNextEntry(entry);
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = entryInputStream.read(buffer)) != -1) {
tempJarOutputStream.write(buffer, 0, bytesRead);
}
}
}
tempJarOutputStream.close();
jarFile.close();
srcJarFile.delete();
tmpJarFile.renameTo(srcJarFile);
}
private static JarEntry unsignManifest(JarEntry signed, JarFile jarFile) throws IOException {
//extract signed manifest contents into a temp text file
File tmpManifestFile = File.createTempFile("tempManifest", ".tmp");
tmpManifestFile.deleteOnExit();
Manifest manifest = jarFile.getManifest();
OutputStream fos = new FileOutputStream(tmpManifestFile);
//write out manifest contents to an actual file on disk for later editing
manifest.write(fos);
fos.close();
//read the physical file back in line by line so that SHA1 strings
//can be ignored when creating a new manifest file.
Path path = Paths.get(tmpManifestFile.getPath());
List<String> lines = Files.readAllLines(path, Charset.defaultCharset());
// some logic here. Something like
// for each line : lines
// if !line.contains("SHA1-Digest: SWDa1ic/T+le1N+UvrAYf89lY4E=")
// write it out to the new manifest file
// append extra security attributes
//convert new manifest file to new JarEntry unsigned
// return JarEntry
return unsigned;
}
鉴于Java的JarEntry和Manifest类的单向性,看起来我必须做所有繁重的工作。我可以把价值拿出去,但是我认为选择性地把它们放进去是很痛苦的。到目前为止,我可以解压并重新包装罐子。正如您在代码末尾所看到的那样,我无法弄清楚如何有选择地将内容放回清单文件并将其转换为JarEntry,以便unpackJarFile()方法认为新创建的清单文件来自原始jar
提前致谢。