2009-09-03 4 views
22

Я хочу подписать банку с помощью jarsigner, а затем проверить ее с помощью приложения Java, которое не имеет подписанной банки как части ее пути к классам (то есть, просто используя расположение файловой системы банку)Как проверить банку, подписанную с программным обеспечением jarsigner

Теперь моя проблема заключается в получении файла подписи из банки, есть ли простой способ сделать это?

У меня была игра с Inflater и Jar InputStreams без везения.

Или это может быть сделано лучше?

Благодаря

ответ

10

security Provider implementation guide описывает процесс проверки JARs. Хотя эти инструкции предназначены для того, чтобы поставщик криптографических услуг JCA проверял себя, они должны быть применимы к вашей проблеме.

В частности, ознакомьтесь с методом verify(X509Certificate targetCert) в примере кода, "MyJCE.java".

+1

Вместо того, чтобы предложить код, они могли бы, а также предложен способ verifyAllContent() ;-) – lapo

-2

Вы можете использовать приложение jarsigner для этого. В ProcessBuilder (или Runtime.exec), вы можете запустить команду с этими аргументами

ProcessBulider pb = new ProcessBuilder("/usr/bin/jarsigner", "-verify", "-certs", f.getAbsolutePath()); 

и если выходные contians проверить то баночку подписанные

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 не будет проверять сертификат подписчика (так что любая ненадежная подпись будет делать), он не проверяет достоверные временные метки (не может обрабатывать действительные подписи у подписчиков, чьи сертификаты истекли), а его вывод бесполезен («проверено» возвращается даже при ошибках , немного больше информации может быть получено путем анализа ошибок и предупреждающих сообщений - но этого все еще недостаточно, чтобы решить, действительно ли сертификат). –

14

Вы можете просто открыть JAR с помощью java.util.jar.JarFile и сообщить ему, чтобы проверить файл 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

Открытие jar через JarFile (имя_файла) не проверяет классы в JAR, это только позволяет проверить, что происходит при доступе. Поэтому для проверки всех записей Jar вам нужно вызвать jar.getInputStream (..) для каждой записи - это вызывает проверку. – Robert

+0

см. Http://stackoverflow.com/a/5589898/3934807 для некоторого кода, который реализует предложение Роберта – ingenue

2

Вы можете использовать entry.getCodeSigners(), чтобы получить подписчик для конкретной записи в ЕАО.

Обязательно откройте JarFile с помощью verify = true и полностью прочитайте запись JAR перед вызовом entry.getCodeSigners().

Нечто подобное можно было бы использовать для проверки каждой записи, которая не является файлом подписи:

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