jarsigner で署名された jar をプログラムで検証する方法
-
21-09-2019 - |
質問
jarsignerを使用してjarに署名し、クラスパスの一部として署名されたjarを持たないJavaアプリケーションを使用して検証したいと考えています(つまり、ファイルシステムのjarの場所を使用するだけです)
ここで私の問題は、jar から署名ファイルを取得することですが、これを行う簡単な方法はありますか?
Inflater と Jar InputStreams を試してみましたが、うまくいきませんでした。
それとも、これはもっと良い方法で実現できるのでしょうか?
ありがとう
解決
の セキュリティプロバイダー実装ガイド JAR を検証するプロセスの概要を説明します。これらの手順は、JCA 暗号化サービス プロバイダー自身を検証するためのものですが、問題にも適用できるはずです。
具体的には、 verify(X509Certificate targetCert)
サンプルコードのメソッドでは、 「MyJCE.java」.
他のヒント
あなたは、単に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);
あなたはJAR内の特定のエントリの署名者を取得するために)(entry.getCodeSignersを使用することができます。
)を検証=真で、完全にentry.getCodeSignersを(呼び出す前に、JARエントリを読み取るにするJarFileをオープンすることを確認します。
このような何かが署名ファイルではありません各エントリを確認するために使用することができます:
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();
}
}
これを行うには、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のコードの出力を持っているときに行うことができ、より複雑なものがあります。