Comment vérifier un bocal signé avec jarsigner par programmation

je veux signer un jar en utilisant jarsigner, puis le vérifier en utilisant une application Java qui n'a pas le jar signé dans le cadre de son classpath (i.e. en utilisant simplement un emplacement du système de fichiers du jar)

Maintenant, mon problème est d'obtenir le fichier de signature du pot, est-il une façon simple de le faire?

j'ai eu un jeu avec le gonfleur et Jar InputStreams avec pas de chance.

Ou est-ce quelque chose qui peut être accompli en mieux façon?

Merci

22
demandé sur James Carr 2009-09-03 19:32:54

4 réponses

guide de mise en oeuvre pour les fournisseurs de services de sécurité décrit le processus de vérification des bocaux. Bien que ces instructions soient pour un fournisseur de services cryptographiques JCA de vérifier lui-même, elles devraient être applicables à votre problème.

en particulier, regardez le verify(X509Certificate targetCert) méthode dans l'exemple de code, "MyJCE.java".

11
répondu erickson 2009-09-03 16:11:00

Vous pouvez simplement ouvrir le bocal avec java.util.pot.JarFile et dites-lui de vérifier le fichier JAR. Si le JAR est signé, alors JarFile a l'option de le vérifier (qui est activée par défaut). Cependant, JarFile ouvrira également JARs non signé heureux, donc vous devez également vérifier, si oui ou non le fichier est signé. Vous pouvez le faire en vérifiant le Manifeste du bocal pour les attributs * - Digest: les éléments avec un tel attribut sont signés.

Exemple:

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);
14
répondu nd. 2009-11-25 13:02:09

Vous pouvez utiliser l'entrée.getCodeSigners() pour obtenir les signataires d'une entrée particulière dans le POT.

assurez-vous d'ouvrir le fichier JarFile avec verify=true et de bien lire l'entrée JAR avant d'appeler l'entrée.getCodeSigners ().

quelque Chose comme cela pourrait être utilisé pour vérifier chaque entrée qui n'est pas un fichier de signature:

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();
    }
 }
2
répondu Markus 2016-06-05 10:54:15

vous pouvez utiliser l'application jarsigner pour ce faire. Dans processbuilder (ou Runtime.exec) vous pouvez lancer la commande avec ces arguments

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

et si la sortie contient vérifié alors le pot est signé

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");
...

il y a des choses plus compliquées que vous pouvez faire quand vous avez la sortie du code jarsigner.

-2
répondu Milhous 2009-09-03 16:13:43