如何以编程方式验证使用 jarsigner 签名的 jar
-
21-09-2019 - |
题
我想使用 jarsigner 对 jar 进行签名,然后使用 Java 应用程序验证它,该应用程序没有将签名的 jar 作为其类路径的一部分(即仅使用 jar 的文件系统位置)
现在我的问题是从 jar 中获取签名文件,有没有一种简单的方法可以做到这一点?
我尝试过 Inflater 和 Jar InputStreams,但没有成功。
或者这是否可以通过更好的方式来完成?
谢谢
解决方案
这 安全提供商实施指南 概述了验证 JAR 的过程。尽管这些说明是供 JCA 加密服务提供商验证自身的,但它们应该适用于您的问题。
具体来说,请查看 verify(X509Certificate targetCert)
示例代码中的方法, “MyJCE.java”.
其他提示
您可以简单地打开与java.util.jar.JarFile中的JAR,并告诉它来验证JAR文件。如果JAR进行签名,然后jar文件必须验证它(这是在默认情况下)的选项。然而,jar文件也将愉快地打开未签名的JAR文件,因此,你还必须检查,该文件是否被签名。您可以通过检查JAR对* -Digest清单这么做属性:具有这样的属性属性的元素签署
示例:
JarFile jar = new JarFile(new File("path/to/your/jar-file"));
// This call will throw a java.lang.SecurityException if someone has tampered
// with the signature of _any_ element of the JAR file.
// Alas, it will proceed without a problem if the JAR file is not signed at all
InputStream is = jar.getInputStream(jar.getEntry("META-INF/MANIFEST.MF"));
Manifest man = new Manifest(is);
is.close();
Set<String> signed = new HashSet();
for(Map.Entry<String, Attributes> entry: man.getEntries().entrySet()) {
for(Object attrkey: entry.getValue().keySet()) {
if (attrkey instanceof Attributes.Name &&
((Attributes.Name)attrkey).toString().indexOf("-Digest") != -1)
signed.add(entry.getKey());
}
}
Set<String> entries = new HashSet<String>();
for(Enumeration<JarEntry> entry = jar.entries(); entry.hasMoreElements(); ) {
JarEntry je = entry.nextElement();
if (!je.isDirectory())
entries.add(je.getName());
}
// contains all entries in the Manifest that are not signed.
// Ususally, this contains:
// * MANIFEST.MF itself
// * *.SF files containing the signature of MANIFEST.MF
// * *.DSA files containing public keys of the signer
Set<String> unsigned = new HashSet<String>(entries);
unsigned.removeAll(signed);
// contains all the entries with a signature that are not present in the JAR
Set<String> missing = new HashSet<String>(signed);
missing.removeAll(entries);
您可以使用entry.getCodeSigners()来获得签名者在JAR中的特定条目。
请一定要打开jar文件以验证= TRUE,并调用entry.getCodeSigners()之前完全阅读JAR条目。
像这样可用于验证不是签名文件中的每个条目:
boolean verify = true;
JarFile jar = new JarFile(signedFile, verify);
// Need each entry so that future calls to entry.getCodeSigners will return anything
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
IOUtils.copy(jar.getInputStream(entry), new NullOutputStream());
}
// Now check each entry that is not a signature file
entries = jar.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
String fileName = entry.getName().toUpperCase(Locale.ENGLISH);
if (!fileName.endsWith(".SF")
&& !fileName.endsWith(".DSA")
&& !fileName.endsWith(".EC")
&& !fileName.endsWith(".RSA")) {
// Now get code signers, inspect certificates etc here...
// entry.getCodeSigners();
}
}
您可以使用的jarsigner应用程序来做到这一点。在的ProcessBuilder(或的Runtime.exec)可以运行与这些参数的命令
ProcessBulider pb = new ProcessBuilder("/usr/bin/jarsigner", "-verify", "-certs", f.getAbsolutePath());
和如果证实输出,则为那么罐子签署
Process p = pb.start();
p.waitFor();
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null)
{
if(line.contains("verified");
...
有更复杂的东西时,你有的jarsigner代码的输出可以做。