如何以编程方式验证使用jarsigner签名的jar

时间:2009-09-03 15:32:54

标签: java code-signing signature jarsigner

我想使用jarsigner签署一个jar,然后使用一个Java应用程序验证它,该应用程序没有签名jar作为其类路径的一部分(即只使用jar的文件系统位置)

现在我的问题是从jar中获取签名文件,有一种简单的方法吗?

我玩过Inflater和Jar InputStreams没有运气。

或者这是可以更好地完成的事情吗?

由于

4 个答案:

答案 0 :(得分:15)

您只需使用java.util.jar.JarFile打开JAR并告诉它验证JAR文件。如果JAR已签名,则JarFile可以选择对其进行验证(默认情况下处于启用状态)。但是,JarFile也会愉快地打开未签名的JAR,因此您还必须检查文件是否已签名。您可以通过检查* -Digest属性的JAR清单来执行此操作:具有此类属性属性的元素已签名。

示例:

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);

答案 1 :(得分:14)

security Provider implementation guide概述了验证JAR的过程。虽然这些说明适用于JCA加密服务提供商进行自我验证,但它们应该适用于您的问题。

具体来说,请查看示例代码"MyJCE.java"中的verify(X509Certificate targetCert)方法。

答案 2 :(得分:2)

您可以使用entry.getCodeSigners()来获取JAR中特定条目的签名者。

确保使用verify = true打开JarFile并在调用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();
    }
 }

答案 3 :(得分:-2)

您可以使用jarsigner应用程序执行此操作。在processbuilder(或Runtime.exec)中,您可以使用这些参数运行命令

 ProcessBulider pb = new ProcessBuilder("/usr/bin/jarsigner", "-verify", "-certs", f.getAbsolutePath());

如果输出contians已验证,那么jar已签名

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代码时,你可以做更复杂的事情。