2009-10-30 23 views
18

Après la signature d'un pot et l'utilisation de l'option -tsa, comment puis-je valider que l'horodatage a été inclus? J'ai essayé:Comment valider si un jar signé contient un horodatage?

jarsigner -verify -verbose -certs myApp.jar 

Mais la sortie ne spécifie rien sur l'horodatage. Je demande parce que même si j'ai une faute de frappe dans le chemin de l'URL -tsa, le jarsigner réussit. Il s'agit de l'URL GlobalSign TSA: http://timestamp.globalsign.com/scripts/timstamp.dll et le serveur derrière elle semble accepter n'importe quel chemin (par exemple timestamp.globalsign.com/foobar), donc à la fin, je ne suis pas vraiment sûr que mon pot est horodaté ou non.

Répondre

9

J'ai passé les deux dernières heures à chercher ce problème et j'ai finalement trouvé un moyen d'identifier si un fichier jar contient réellement des informations d'horodatage dans le fichier Signature Block inclus. J'ai pu voir le certificat de GlobalSign dans l'hexeditor du fichier /META-INF/FOO.DSA, mais je n'ai trouvé aucun outil pour imprimer les informations dont vous aviez besoin.

Vous pouvez renommer le fichier FOO.DSA en foo.p7b pour l'ouvrir dans Windows CertMgr, mais il n'affiche aucune information d'horodatage. Je n'ai pas non plus réussi à utiliser OpenSSL pour vérifier le fichier DSA (format de fichier PKCS # 7).

Donc je suis venu avec le code suivant qui montrera l'horodateur SignerInfo et la date à laquelle l'horodatage a été créé. J'espère que c'est un bon début pour toi. Vous avez besoin de bcprov-jdk16-144.jar, de bctsp-jdk16-144.jar et de bcmail-jdk16-144.jar dans le classpath. Faites-leur de 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

Merci, fonctionne. Besoins bcmail-jdk16-144.jar aussi pour les choses CMS – user199092

+0

Merci beaucoup pour vos efforts et votre temps. – Edenshaw

+1

Je l'ai eu à travailler aussi, mais a dû changer 'endsWith (". Dsa")' pour vérifier plutôt rsa. – JimN

15

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

Vous pouvez utiliser l'utilitaire jarsigner pour déterminer si un JAR signé a été horodaté comme suit:

jarsigner -verify -verbose -certs signed.jar

signed.jar est le nom de votre JAR signé. Si elle est horodatée, la sortie comprendra des lignes du suivant indiquant le temps qu'il a été signé:

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

Si le JAR n'est pas horodatées, la sortie ne comprend pas ces lignes.

+1

C'est en fait la meilleure réponse! – thokuest

+0

Ceci est un peu en retard à la fête, mais peut être important si la digestion algos importe. Si vous avez besoin de voir à quel point il a été horodaté, vous aurez besoin d'un jarson jdk8u111 ou plus récent.Ensuite, avec le -verify -verbose -certs, il vous montrera à la fin: "algorithme de digest horodatage: SHA-1, algorithme de signature d'horodatage: SHA1withRSA, clé de 2048 bits". Ensuite, il est important de prendre en charge les installations java7 mixtes où le mélange SHA-256 vs SHA256 cause un problème. –

5

Java de keytool peut confirmer si un JAR signé est horodatée, et peut également afficher le certificat de 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 offre un grand code (printDSAInfos). Ça m'aide beaucoup dans mon travail. Cependant un couple de changements requis. La classe DEREncodable est maintenant remplacée par ASN1Encodable et la méthode getDERbout() est remplacée par ASN1Primitive. Donc, le code ressemble à ceci

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