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

发布于 2024-08-08 23:17:29 字数 433 浏览 5 评论 0原文

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

jarsigner -verify -verbose -certs myApp.jar

但输出没有指定任何有关时间戳的信息。我这样问是因为即使我在 -tsa URL 路径中有拼写错误,jarsigner 也会成功。这是 GlobalSign TSA URL:http://timestamp.globalsign.com/scripts/timstamp.dll< /a> 并且它后面的服务器显然接受任何路径(即timestamp.globalsign.com/foobar),所以最后我不确定我的jar是否带有时间戳。

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

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.dll and 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

忘羡 2024-08-15 23:17:30

Java 的 keytool 可以确认签名的 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

...

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

$ 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

...
忱杏 2024-08-15 23:17:30

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

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

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

    ASN1Encodable dob = attribute.getAttrValues().getObjectAt(0);
    CMSSignedData signedData = new CMSSignedData(dob.toASN1Primitive().getEncoded());
放血 2024-08-15 23:17:29

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

您可以使用 jarsigner 实用程序确定签名的 JAR 是否已加时间戳,如下所示:

jarsigner -verify -verbose -certssigned.jar

其中 signed.jar 是您签名的 JAR 的名称。如果带有时间戳,输出将包含以下行,指示签名时间:

[条目于 2013 年 8 月 2 日下午 3:48 签署]

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

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

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

jarsigner -verify -verbose -certs signed.jar

where signed.jar is 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.

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

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

因此,我想出了以下代码,它将显示时间戳 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;
        }
    }
}

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.

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).

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

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;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文