2009-10-30 11 views
18

Dopo che un barattolo è stato firmato e l'opzione -tsa è stata utilizzata, come posso verificare che il timestamp sia stato incluso? Ho provato:Come convalidare se un jar firmato contiene un timestamp?

jarsigner -verify -verbose -certs myApp.jar 

Ma l'output non specifica nulla sulla data e ora. Sto chiedendo perché anche se ho un refuso nel percorso dell'URL -tsa, il jarsigner ha successo. Questo è l'URL TSA di GlobalSign: http://timestamp.globalsign.com/scripts/timstamp.dll e il server dietro ad esso accetta apparentemente qualsiasi percorso (ad esempio timestamp.globalsign.com/foobar), quindi alla fine non sono sicuro che il mio barattolo sia a tempo o meno.

risposta

9

Abbiamo appena trascorso le ultime 2 ore alla ricerca di questo problema e alla fine ho trovato un modo per identificare se un file jar ha effettivamente informazioni sul timestamp nel file Firma Block incluso. Ho potuto vedere il certificato GlobalSign nell'eseditor del file /META-INF/FOO.DSA, ma non ho trovato nessuno strumento che possa stampare le informazioni che ti servono.

È possibile rinominare il file FOO.DSA su foo.p7b per aprirlo in Windows CertMgr, ma non mostra alcuna informazione sul timestamp. Inoltre, non sono riuscito a utilizzare OpenSSL per verificare il file DSA (è il formato di file PKCS # 7).

Così ho trovato il seguente codice che mostrerà il Time Stamp SignerInfo e la data in cui è stato creato il Timestamp. Spero sia un buon inizio per te. È necessario bcprov-jdk16-144.jar, bctsp-jdk16-144.jar e bcmail-jdk16-144.jar nel classpath. Farli da Bouncycastle

package de.mhaller.bouncycastle; 

import java.io.FileInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.security.Security; 
import java.util.Collection; 
import java.util.jar.JarEntry; 
import java.util.jar.JarInputStream; 

import org.bouncycastle.asn1.DEREncodable; 
import org.bouncycastle.asn1.cms.Attribute; 
import org.bouncycastle.asn1.cms.AttributeTable; 
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; 
import org.bouncycastle.cms.CMSException; 
import org.bouncycastle.cms.CMSSignedData; 
import org.bouncycastle.cms.SignerId; 
import org.bouncycastle.cms.SignerInformation; 
import org.bouncycastle.cms.SignerInformationStore; 
import org.bouncycastle.jce.provider.BouncyCastleProvider; 
import org.bouncycastle.tsp.TSPException; 
import org.bouncycastle.tsp.TimeStampToken; 
import org.bouncycastle.tsp.TimeStampTokenInfo; 

public class VerifyTimestampSignature { 

    private static boolean found; 

    public static void main(String[] args) throws Exception { 
     if (args == null || args.length != 1) { 
      System.out.println("usage: java " + VerifyTimestampSignature.class.getName() 
        + " [jar-file|dsa-file]"); 
      return; 
     } 

     BouncyCastleProvider provider = new BouncyCastleProvider(); 
     Security.addProvider(provider); 

     String filename = args[0]; 

     if (filename.toLowerCase().endsWith(".dsa")) { 
      InputStream dsa = new FileInputStream(filename); 
      printDSAInfos(filename, dsa); 
      return; 
     } 

     if (filename.toLowerCase().endsWith(".jar")) { 
      InputStream jar = new FileInputStream(filename); 
      JarInputStream jarInputStream = new JarInputStream(jar); 
      JarEntry nextJarEntry; 
      do { 
       nextJarEntry = jarInputStream.getNextJarEntry(); 
       if (nextJarEntry == null) { 
        break; 
       } 
       if (nextJarEntry.getName().toLowerCase().endsWith(".dsa")) { 
        printDSAInfos(nextJarEntry.getName(), jarInputStream); 
       } 
      } while (nextJarEntry != null); 
     } 

     if (!found) { 
      System.out.println("No certificate with time stamp information found in " + filename); 
     } else { 
      System.out.println("Found at least one time stamp info"); 
      System.out.println("Note: But it was NOT verified for validity!"); 
     } 
    } 

    private static void printDSAInfos(String file, InputStream dsa) throws CMSException, 
      IOException, TSPException { 
     System.out.println("Retrieving time stamp token from: " + file); 
     CMSSignedData signature = new CMSSignedData(dsa); 
     SignerInformationStore store = signature.getSignerInfos(); 
     Collection<?> signers = store.getSigners(); 
     for (Object object : signers) { 
      SignerInformation signerInform = (SignerInformation) object; 
      AttributeTable attrs = signerInform.getUnsignedAttributes(); 
      if (attrs == null) { 
       System.err 
         .println("Signer Information does not contain any unsigned attributes. A signed jar file with Timestamp information should contain unsigned attributes."); 
       continue; 
      } 
      Attribute attribute = attrs.get(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken); 
      DEREncodable dob = attribute.getAttrValues().getObjectAt(0); 
      CMSSignedData signedData = new CMSSignedData(dob.getDERObject().getEncoded()); 
      TimeStampToken tst = new TimeStampToken(signedData); 

      SignerId signerId = tst.getSID(); 
      System.out.println("Signer: " + signerId.toString()); 

      TimeStampTokenInfo tstInfo = tst.getTimeStampInfo(); 
      System.out.println("Timestamp generated: " + tstInfo.getGenTime()); 
      found = true; 
     } 
    } 
} 
+0

Grazie, funziona. Ha bisogno anche di bcmail-jdk16-144.jar per le cose CMS – user199092

+0

Grazie mille per il tuo impegno e il tuo tempo. – Edenshaw

+1

Anche io ho funzionato, ma ho dovuto cambiare 'endsWith (". Dsa")' per controllare invece rsa. – JimN

15

Da https://blogs.oracle.com/mullan/entry/how_to_determine_if_a:

È possibile utilizzare l'utilità jarsigner per determinare se un JAR firmato è stato timestamped come segue:

jarsigner -verify -verbose -certs signed.jar

dove signed.jar è il nome del tuo JAR firmato. Se è timestamp, l'output includerà linee del seguente, che indica il tempo che è stato firmato:

[entry was signed on 8/2/13 3:48 PM]

se il vaso non è timestamped, l'uscita non includerà quelle linee.

+1

Questa è in realtà la migliore risposta! – thokuest

+0

Questo è un po 'in ritardo per la festa, ma può essere importante se la digest algos è importante. Se hai bisogno di vedere come è stato il timestamp, avrai bisogno di un jdk8u111 o di un nuovo jarsigner.Quindi, con -verify -verbose -certs, verrà visualizzato alla fine: "Algoritmo di acquisizione del timestamp: SHA-1, algoritmo di firma del timestamp: SHA1withRSA, chiave a 2048 bit". Quindi è importante se devi supportare installazioni miste di java7 in cui il mixup SHA-256 e SHA256 causa un problema. –

5

Java di keytool può confermare se un JAR firmato è timestamp, e possono anche visualizzare il certificato del TSA:

$ keytool -printcert -jarfile myApp.jar 

... 

Timestamp: 

Owner: CN=GeoTrust Timestamping Signer 1, O=GeoTrust Inc, C=US 
Issuer: CN=Thawte Timestamping CA, OU=Thawte Certification, O=Thawte, L=Durbanville, ST=Western Cape, C=ZA 
Serial number: 5e8d2daca44665546bb587978191a8bf 
Valid from: Wed Oct 31 00:00:00 GMT 2007 until: Mon Oct 30 23:59:59 GMT 2017 
Certificate fingerprints: 
    MD5: E5:30:07:8E:91:8D:A0:6C:18:6D:91:2A:B6:D2:3A:56 
    SHA1: 22:3C:DA:27:07:96:73:81:6B:60:8A:1B:8C:B0:AB:02:30:10:7F:CC 
    SHA256: D7:B8:44:BD:39:5A:17:36:02:39:51:C6:4D:6C:81:65:45:93:AD:29:1D:DC:E4:6C:8D:79:B6:65:DF:31:0C:F6 
    Signature algorithm name: SHA1withRSA 
    Version: 3 

... 
1

mhaller fornisce grande codice (printDSAInfos). Mi aiuta molto nel mio lavoro. Tuttavia sono necessarie un paio di modifiche. La classe DEREncodable viene ora modificata in ASN1Encodable e il metodo getDERObject() viene modificato inASN1Primitive. Quindi il codice assomiglia a questo

ASN1Encodable dob = attribute.getAttrValues().getObjectAt(0); 
    CMSSignedData signedData = new CMSSignedData(dob.toASN1Primitive().getEncoded());