2009-09-03 40 views
22

jarsignerを使用してjarに署名し、署名付きjarがクラスパスの一部としてないJavaアプリケーションを使用して検証する必要があります。 jar)jarsignerでプログラムで署名されたjarを確認する方法

今、私の問題は、署名ファイルをjarファイルから取り出しています。これを行う簡単な方法はありますか?

私はInflaterとJar InputStreamを使って遊んでいませんでした。

これはもっと良い方法で達成できるものですか?

おかげ

答えて

10

security Provider implementation guideは、JARファイルを検証するプロセスの概要を説明します。これらの手順は、JCA暗号化サービスプロバイダが自身を検証するためのものですが、問題に適用できるはずです。

具体的には、"MyJCE.java"verify(X509Certificate targetCert)メソッドを確認してください。

+1

代わりのコードを示唆し、それらは同様にverifyAllContent()メソッド;-) – lapo

-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コードの出力があります。

+0

例設けられている可能性がプラットフォーム固有であり、さらにjarsignerツールには通常JDKしか付属していません。 – Robert

+0

jarsignerは信頼できるタイムスタンプをチェックせず(証明書が期限切れの署名者からの有効な署名を処理できない)、その出力は役に立たない(エラー時でも 'verified'が返される)エラーメッセージと警告メッセージを解析することでさらに多くの情報を得ることができますが、それでも証明書が有効かどうかを判断するには不十分です)。 –

14

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

JarFile(fileName)を使用してjarを開くと、JAR内のクラスが検証されず、アクセス時にのみ検証が有効になります。したがって、Jarのすべてのエントリを検証するには、jar.getInputStream()を呼び出す必要があります。)を入力すると、検証がトリガーされます。 – Robert

+0

Robertの提案を実装するコードについては、http://stackoverflow.com/a/5589898/3934807を参照してください。 – ingenue

2

あなたはJAR内の特定のエントリの署名者を取得するために)(entry.getCodeSignersを使用することができます。

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(); 
    } 
} 
関連する問題