Java 如何以编程方式验证使用 jarsigner 签名的 jar
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1374170/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to verify a jar signed with jarsigner programmatically
提问by James Carr
I'm wanting to sign a jar using jarsigner, then verify it using a Java application which does not have the signed jar as part of it's classpath (i.e. just using a filesystem location of the jar)
我想使用 jarsigner 对 jar 进行签名,然后使用 Java 应用程序对其进行验证,该应用程序没有将已签名的 jar 作为类路径的一部分(即仅使用 jar 的文件系统位置)
Now my problem is getting the signature file out of the jar, is there a simple way to do this?
现在我的问题是从 jar 中取出签名文件,有没有一种简单的方法可以做到这一点?
I've had a play with the Inflater and Jar InputStreams with no luck.
我玩过 Inflater 和 Jar InputStreams,但运气不佳。
Or is this something that can be accomplished in a better way?
或者这是可以以更好的方式完成的事情?
Thanks
谢谢
采纳答案by erickson
The security Provider implementation guideoutlines the process of verifying JARs. Although these instructions are for a JCA cryptographic service provider to verify itself, they should be applicable to your problem.
在安全提供者实施指南列出了验证JAR文件的过程。尽管这些说明是供 JCA 加密服务提供商进行自我验证的,但它们应该适用于您的问题。
Specifically, check out the verify(X509Certificate targetCert)
method in the sample code, "MyJCE.java".
具体来说,请查看verify(X509Certificate targetCert)
示例代码“MyJCE.java”中的方法。
回答by Milhous
You can use the jarsigner application to do this. In processbuilder (or Runtime.exec) you can run the command with these arguments
您可以使用 jarsigner 应用程序来执行此操作。在 processbuilder(或 Runtime.exec)中,您可以使用这些参数运行命令
ProcessBulider pb = new ProcessBuilder("/usr/bin/jarsigner", "-verify", "-certs", f.getAbsolutePath());
and if the output contians verified then the jar is signed
如果输出 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");
...
THere are more complicated things you can do when you have the output of the jarsigner code.
当您拥有 jarsigner 代码的输出时,您可以做更复杂的事情。
回答by nd.
You can simply open the JAR with java.util.jar.JarFile and tell it to verify the JAR file. If the JAR is signed, then JarFile has the option to verify it (which is on by default). However, JarFile will also open unsigned JARs happily, therefore you must also check, whether or not the file is signed. You can do so by checking the JAR's manifest for *-Digest attributes: Elements with such an attribute attribute are signed.
您可以简单地使用 java.util.jar.JarFile 打开 JAR 并告诉它验证 JAR 文件。如果 JAR 已签名,则 JarFile 可以选择对其进行验证(默认情况下处于启用状态)。但是,JarFile 也会愉快地打开未签名的 JAR,因此您还必须检查文件是否已签名。您可以通过检查 JAR 的清单来获取 *-Digest 属性:具有此类属性的元素已签名。
Example:
例子:
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);
回答by Markus
You can use entry.getCodeSigners() to get the signers for a particular entry in the JAR.
您可以使用 entry.getCodeSigners() 来获取 JAR 中特定条目的签名者。
Make sure to open the JarFile with verify=true and to fully read the JAR entry before calling entry.getCodeSigners().
确保在调用 entry.getCodeSigners() 之前使用 verify=true 打开 JarFile 并完全读取 JAR 条目。
Something like this could be used to verify each entry that is not a signature file:
像这样的东西可以用来验证每个不是签名文件的条目:
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();
}
}