Pregunta

Después de firmar un jar y usar la opción -tsa, ¿cómo puedo validar que se incluye la marca de tiempo? Intenté:

jarsigner -verify -verbose -certs myApp.jar

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

¿Fue útil?

Solución

Pasé 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 de Bloque de firma incluido. Pude ver el certificado de GlobalSign en el editor hexadecimal del archivo /META-INF/FOO.DSA, pero no encontré ninguna herramienta que imprimiera la información que necesita.

Puede cambiar el nombre del archivo FOO.DSA a foo.p7b para abrirlo en Windows CertMgr, pero tampoco muestra ninguna información de marca de tiempo. Tampoco logré usar OpenSSL para verificar el archivo DSA (es el formato de archivo PKCS # 7).

Así que se me ocurrió el siguiente código que mostrará la información de firma de sello de tiempo y la fecha en que se creó la marca de tiempo. Espero que sea un buen comienzo para ti. Necesita bcprov-jdk16-144.jar, bctsp-jdk16-144.jar y bcmail-jdk16-144.jar en el classpath. Consíguelos en 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;
        }
    }
}

Otros consejos

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

  

Puede usar la utilidad jarsigner para determinar si un JAR firmado se ha sellado de la siguiente manera:

     

jarsigner -verify -verbose -certsigned.jar

     

donde igned.jar es el nombre de su JAR firmado. Si tiene una marca de tiempo, la salida incluirá líneas de lo siguiente que indica la hora en que se firmó:

     

[la entrada se firmó el 8/2/13 3:48 PM]

     

Si el JAR no tiene marca de tiempo, la salida no incluirá esas líneas.

Java keytool puede confirmar si un JAR firmado tiene una marca 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

...

mhaller proporciona un 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 cambia a ASN1Primitive. Entonces el código se ve así

    ASN1Encodable dob = attribute.getAttrValues().getObjectAt(0);
    CMSSignedData signedData = new CMSSignedData(dob.toASN1Primitive().getEncoded());
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top