2009-09-03 129 views
22

我想使用jarsigner簽名jar,然後使用沒有簽名的jar作爲classpath的一部分的Java應用程序來驗證它(即只使用文件系統的位置罐子)如何驗證用jarsigner以編程方式簽名的jar

現在我的問題是從jar簽名文件,有沒有一種簡單的方法來做到這一點?

我已經與Inflater和Jar InputStreams一起玩,沒有運氣。

或者這是能夠以更好的方式完成的事情嗎?

由於

回答

10

security Provider implementation guide概述驗證JAR文件的過程。儘管這些說明適用於JCA加密服務提供商自行驗證,但它們應適用於您的問題。

具體而言,請查看示例代碼"MyJCE.java"中的verify(X509Certificate targetCert)方法。

+1

代替建議的代碼,他們可能以及提供一個verifyAllContent()方法;-) – lapo 2009-09-03 16:07:45

-2

您可以使用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代碼的輸出。

+0

示例是平臺特定的,另外jarsigner工具通常只附帶JDK。 – Robert 2010-12-06 10:12:56

+0

jarsigner不會驗證簽署者證書(因此任何不受信任的簽名會這樣做),它不會檢查受信任的時間戳(無法處理來自證書過期的簽署者的有效簽名),並且其輸出無用(即使出現錯誤也會返回「已驗證」 ,通過分析錯誤和警告消息可以獲得更多信息 - 但是仍然不足以確定證書是否有效)。 – 2012-06-14 06:30:22

14

您可以簡單地使用java.util.jar.JarFile打開JAR並告訴它來驗證JAR文件。如果JAR已簽名,那麼JarFile可以選擇驗證它(默認情況下它是打開的)。但是,JarFile也會高興地打開未簽名的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); 
+7

通過JarFile(fileName)打開jar不會驗證JAR中的類,它只啓用在訪問時發生的驗證。因此,要驗證Jar的所有條目,您必須調用jar.getInputStream(..)爲每個條目 - 這觸發驗證。 – Robert 2010-12-06 12:23:05

+0

請參閱http://stackoverflow.com/a/5589898/3934807瞭解實現Robert建議的某些代碼 – ingenue 2016-03-01 14:31:06

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