java 如何验证签名的 jar 是否包含时间戳?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1647759/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 17:25:24  来源:igfitidea点击:

How to validate if a signed jar contains a timestamp?

javajardigital-signaturecode-signingtrusted-timestamp

提问by user199092

After a jar is signed and the -tsa option was used, how can I validate that the time stamp was included? I tried:

在 jar 签名并使用 -tsa 选项后,如何验证是否包含时间戳?我试过:

jarsigner -verify -verbose -certs myApp.jar

But the output does not specify anything about the time stamp. I'm asking because even if I have a typo in the -tsa URL path, the jarsigner succeeds. This is the GlobalSign TSA URL: http://timestamp.globalsign.com/scripts/timstamp.dlland the server behind it apparently accepts any path (ie. timestamp.globalsign.com/foobar), so in the end I'm not really sure my jar is time stamped or not.

但是输出没有指定任何关于时间戳的信息。我问是因为即使我在 -tsa URL 路径中有错字,jarsigner 也会成功。这是 GlobalSign TSA URL:http: //timestamp.globalsign.com/scripts/timstamp.dll和它背后的服务器显然接受任何路径(即 timestamp.globalsign.com/foobar),所以最后我不确定我的罐子是否有时间戳。

采纳答案by mhaller

Just spent the last 2 hours looking for this issue and finally found a way to identify whether a jar file actually has time stamp information in the Signature Block file included. I could see the GlobalSign certifcate in the hexeditor of the /META-INF/FOO.DSA file, but I did not find any tool which would print out the information you need.

刚刚花了最后2个小时寻找这个问题,终于找到了一种方法来识别jar文件中是否包含签名块文件中的时间戳信息。我可以在 /META-INF/FOO.DSA 文件的十六进制编辑器中看到 GlobalSign 证书,但我没有找到任何可以打印出您需要的信息的工具。

You can rename the FOO.DSA file to foo.p7b to open it in the Windows CertMgr, but it does also not show any time stamp information. I also did not manage to use OpenSSL to verify the DSA file (It's PKCS#7 file format).

您可以将 FOO.DSA 文件重命名为 foo.p7b 以在 Windows CertMgr 中打开它,但它也不显示任何时间戳信息。我也没有设法使用 OpenSSL 来验证 DSA 文件(它是 PKCS#7 文件格式)。

So I came up with the following code which will show the Time Stamp SignerInfo and the date when the Timestamp was created. I hope it is a good start for you. You need bcprov-jdk16-144.jar, bctsp-jdk16-144.jar and bcmail-jdk16-144.jar in the classpath. Get them from Bouncycastle

所以我想出了以下代码,它将显示时间戳 SignerInfo 和创建时间戳的日期。我希望这对你来说是一个好的开始。在类路径中需要 bcprov-jdk16-144.jar、bctsp-jdk16-144.jar 和 bcmail-jdk16-144.jar。从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;
        }
    }
}

回答by Andrei T

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

来自https://blogs.oracle.com/mullan/entry/how_to_determine_if_a

You can use the jarsignerutility to determine if a signed JAR has been timestamped as follows:

jarsigner -verify -verbose -certs signed.jar

where signed.jaris the name of your signed JAR. If it is timestamped, the output will include lines of the following indicating the time it was signed:

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

If the JAR is not timestamped, the output will not include those lines.

您可以使用jarsigner实用程序来确定已签名的 JAR 是否已按如下方式添加时间戳:

jarsigner -verify -verbose -certs signed.jar

signed.jar您签名的 JAR 的名称在哪里。如果它带有时间戳,则输出将包含以下几行,指示它的签名时间:

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

如果 JAR 没有时间戳,则输出将不包括这些行。

回答by TachyonVortex

Java's keytoolcan confirm whether a signed JAR is timestamped, and can also display the TSA's certificate:

Javakeytool可以确认签名的 JAR 是否带有时间戳,还可以显示 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

...

回答by Pandir

mhaller provides great code (printDSAInfos). Helps me greatly in my work. However a couple of changes required. DEREncodable class is now changed to ASN1Encodable and getDERObject() method are changed to toASN1Primitive. So the code look like this

mhaller 提供了很棒的代码(printDSAInfos)。对我的工作有很大帮助。但是需要进行一些更改。DEREncodable 类现在更改为 ASN1Encodable,getDERObject() 方法更改为 toASN1Primitive。所以代码看起来像这样

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