2009-09-03 32 views
22

Sto cercando di firmare un jar utilizzando jarsigner, quindi di verificarlo utilizzando un'applicazione Java che non ha il jar firmato come parte del suo classpath (vale a dire solo utilizzando una posizione del file system di il vaso)Come verificare un jar firmato con jarsigner a livello di codice

Ora il mio problema è ottenere il file della firma dal barattolo, c'è un modo semplice per farlo?

Ho avuto un gioco con Inflater e Jar InputStreams senza fortuna.

O è qualcosa che può essere realizzato in un modo migliore?

Grazie

risposta

10

Il security Provider implementation guide delinea il processo di verifica JAR. Sebbene queste istruzioni siano rivolte a un fornitore di servizi di crittografia JCA per verificarsi, dovrebbero essere applicabili al tuo problema.

In particolare, controllare il metodo verify(X509Certificate targetCert) nel codice di esempio "MyJCE.java".

+1

Invece di suggerire il codice, avrebbero potuto pure fornito un metodo di verifyAllContent() ;-) – lapo

-2

È possibile utilizzare l'applicazione jarsigner per eseguire questa operazione. In ProcessBuilder (o Runtime.exec) è possibile eseguire il comando con questi argomenti

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

e se i contians uscita verificati poi viene firmato il vaso

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

ci sono cose più complicate si possono fare quando hai l'output del codice jarsigner.

+0

L'esempio è specifico per la piattaforma e in aggiunta lo strumento jarsigner di solito viene fornito solo con JDK. – Robert

+0

jarsigner non verificherà il certificato firmatario (quindi qualsiasi firma non attendibile farebbe), non controllerà i timestamp di fiducia (non può gestire firme valide dai firmatari i cui certificati sono scaduti) e il suo output è inutile ('verificato' viene restituito anche sugli errori , è possibile ottenere un po 'più di informazioni analizzando i messaggi di errore e di avviso, ma ciò non è ancora sufficiente per decidere se un certificato è valido). –

14

È possibile aprire semplicemente il JAR con java.util.jar.JarFile e comunicarlo per verificare il file JAR. Se il JAR è firmato, JarFile ha la possibilità di verificarlo (che è attivo per impostazione predefinita). Tuttavia, JarFile aprirà anche i JAR non firmati, quindi è necessario verificare anche se il file è stato firmato. È possibile farlo selezionando il manifest di JAR per gli attributi * -Digest: gli elementi con tale attributo attributo sono firmati.

Esempio:

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

L'apertura di un jar tramite JarFile (fileName) non verifica le classi nel JAR, consente solo la verifica dell'accesso. Pertanto per verificare tutte le voci di un Jar devi chiamare jar.getInputStream (..) per ogni voce: ciò innesca la verifica. – Robert

+0

vedere http://stackoverflow.com/a/5589898/3934807 per un codice che implementa il suggerimento di Robert – ingenue

2

È possibile utilizzare entry.getCodeSigners() per ottenere i firmatari per una particolare voce nel JAR.

Assicurarsi di aprire JarFile con verify = true e leggere completamente la voce JAR prima di chiamare entry.getCodeSigners().

Qualcosa di simile potrebbe essere utilizzato per verificare ogni voce che non è un file di firma:

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