2009-10-30 10 views
18

Después de un frasco se firma y se utilizó la opción -tsa, ¿cómo puedo validar que se incluye la marca de tiempo? Intenté:¿Cómo validar si un jar firmado contiene una marca de tiempo?

jarsigner -verify -verbose -certs myApp.jar 

Pero la salida no especifica nada sobre la marca de tiempo. Lo estoy preguntando porque incluso si tengo un error tipográfico en la ruta de la URL -tsa, el jarsigner tiene éxito. Esta es la URL GlobalSign TSA: http://timestamp.globalsign.com/scripts/timstamp.dll y el servidor detrás de él aparentemente acepta cualquier camino (es decir timestamp.globalsign.com/foobar.), Así que al final no estoy realmente seguro de que mi frasco es una marca de tiempo o no.

Respuesta

9

Acabo de pasar las últimas 2 horas buscando este problema y finalmente encontré una manera de identificar si un archivo jar realmente tiene información de sello de tiempo en el archivo Signature Block incluido. Pude ver el Certifcate GlobalSign en el editor hexadecimal del archivo /META-INF/FOO.DSA, pero no se encontró ninguna herramienta que se imprima la información que necesita.

puede cambiar el nombre del archivo FOO.DSA a foo.p7b para abrirlo en el CertMgr Windows, pero tampoco hay constancia de ninguna información de fecha y hora. Tampoco pude usar OpenSSL para verificar el archivo DSA (es el formato de archivo PKCS # 7).

Así me ocurrió con el siguiente código que mostrará la marca de tiempo SignerInfo y la fecha en que se creó la marca de tiempo. Espero que sea un buen comienzo para ti. Es necesario bcprov-jdk16-144.jar, bctsp-jdk16-144.jar y bcmail-jdk16-144.jar en la ruta de clase. Obtenerlos 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

Gracias, funciona. Necesita bcmail-jdk16-144.jar también para las cosas de CMS – user199092

+0

Muchas gracias por su esfuerzo y tiempo. – Edenshaw

+1

Lo tengo que trabajar también, pero tuve que cambiar 'endsWith ('. Dsa ')' para buscar rsa en su lugar. – JimN

15

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

Usted puede usar la utilidad jarsigner para determinar si un JAR firmado ha sido su fecha sea la siguiente manera:

jarsigner -verify -verbose -certs signed.jar

donde signed.jar es el nombre de tu JAR firmado Si se trata de sellos de tiempo, la salida se incluyen líneas de la siguiente indicando el momento en que se firmó:

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

si el frasco no está marcado con la fecha, la salida no incluirá esas líneas.

+1

¡Esa es en realidad la mejor respuesta! – thokuest

+0

Esto es un poco tarde para la fiesta, pero puede ser importante si los algos son importantes. Si necesita ver cómo fue sellado, necesitará un jdk8u111 o un jarsigner más nuevo.Luego, con -verify -verbose -certs, le mostrará al final: "Algoritmo de resumen Timestamp: SHA-1, algoritmo de firma Timestamp: SHA1withRSA, clave de 2048 bits". Entonces es importante si tiene que admitir instalaciones mixto de java7 donde la mezcla SHA-256 vs SHA256 causa un problema. –

5

Java de keytool puede confirmar si un JAR firmado es sellos de tiempo, y también puede mostrar el certificado de la 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 proporciona gran código (printDSAInfos). Me ayuda mucho en mi trabajo. Sin embargo, se requieren un par de cambios. La clase DEREncodable ahora se cambia a ASN1Encodable y el método getDERObject() se cambian a toASN1Primitive. Así que el código se ve así

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