web-dev-qa-db-ja.com

プログラムでjarsignerで署名されたjarを検証する方法

Jarsignerを使用してjarに署名したいので、クラスパスの一部として署名されたjarを持たないJavaアプリケーションを使用して(つまり、jarのファイルシステムの場所を使用して)確認します)

今私の問題はjarから署名ファイルを取得することです、これを行う簡単な方法はありますか?

InflaterとJarInputStreamsを試してみましたが運がありませんでした。

それとも、これはより良い方法で達成できるものですか?

ありがとう

24
James Carr

セキュリティプロバイダー実装ガイド は、JARを検証するプロセスの概要を示しています。これらの手順は、JCA暗号化サービスプロバイダーがそれ自体を検証するためのものですが、問題に適用できるはずです。

具体的には、サンプルコードのverify(X509Certificate targetCert)メソッド "MyJCE.Java" を確認してください。

14
erickson

Java.util.jar.JarFileを使用してJARを開き、JARファイルを検証するように指示するだけです。 JARが署名されている場合、JarFileにはそれを検証するオプションがあります(デフォルトでオンになっています)。ただし、JarFileは署名されていないJARも問題なく開くため、ファイルが署名されているかどうかも確認する必要があります。これを行うには、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);
16
nd.

Entry.getCodeSigners()を使用して、JAR内の特定のエントリの署名者を取得できます。

Entry.getCodeSigners()を呼び出す前に、必ずverify = trueでJarFileを開き、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
Markus