当前位置: 首页 > 知识库问答 >
问题:

必须传递CMSSignedData对象中的哪些数据才能生成有效的时间戳?

徐英锐
2023-03-14

我有一个有效的PKCS7文件加载到CMSSignedData对象中。此PKCS7文件包括纯文本消息和有效的附加数字签名(全部在同一文件中)。

现在我想给这个文件打上时间戳。这是我正在使用的代码(来源):

 private static CMSSignedData addTimestamp(CMSSignedData signedData)
throws Exception {
        Collection ss = signedData.getSignerInfos().getSigners();
        SignerInformation si = (SignerInformation) ss.iterator().next();

        TimeStampToken tok = getTimeStampToken();

        ASN1InputStream asn1InputStream = new ASN1InputStream
(tok.getEncoded());
        DERObject tstDER = asn1InputStream.readObject();
        DERSet ds = new DERSet(tstDER);

        Attribute a = new Attribute(new
DERObjectIdentifier("1.2.840.113549.1.9.16.2.14"), ds);
        DEREncodableVector dv = new DEREncodableVector();
        dv.add(a);
        AttributeTable at = new AttributeTable(dv);
        si = SignerInformation.replaceUnsignedAttributes(si, at);
        ss.clear();
        ss.add(si);
        SignerInformationStore sis = new SignerInformationStore(ss);

        signedData = CMSSignedData.replaceSigners(signedData, sis);
        return signedData;
    }


 private static TimeStampToken getTimeStampToken() throws
Exception {
        Security.addProvider (new
org.bouncycastle.jce.provider.BouncyCastleProvider());

        PostMethod post = new PostMethod("http://My-TrustedTimeStampProvier.com");

// I'm omitting the part where I pass the user and password

        TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
        //request TSA to return certificate
        reqGen.setCertReq (true); // In my case this works

        //make a TSP request this is a dummy sha1 hash (20 zero bytes)
        TimeStampRequest request =
            reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));

        byte[] enc_req = request.getEncoded();
        ByteArrayInputStream bais = new ByteArrayInputStream(enc_req);

        post.setRequestBody(bais);
        post.setRequestContentLength (enc_req.length);
        post.setRequestHeader("Content-type","application/timestamp-query");

        HttpClient http_client = new HttpClient();
        http_client.executeMethod(post);
        InputStream in = post.getResponseBodyAsStream();

        //read TSP response
        TimeStampResponse resp = new TimeStampResponse (in);

        resp.validate(request);

        TimeStampToken  tsToken = resp.getTimeStampToken();       
        return tsToken;
    }  

我可以得到一个有效的时间戳,我可以把它放到我的CMSSignedData对象中,并把它保存到一个文件中,把signedData.getEncoded()中的字节写到硬盘上。但是当我用第三方软件验证我的新shinny时间戳文件时,该软件告诉我原始签名是正确的,但是时间戳与签名不一致。这个软件还可以显示原始的纯文本消息。

我认为问题出在这一行:

TimeStampRequest request =
    reqGen.generate(TSPAlgorithms.SHA1, new byte[20], BigInteger.valueOf(100));

我认为我必须传递一个摘要而不是一个虚拟字节数组,但是我不知道哪个摘要,或者什么是我必须时间戳的正确字节。我可以成功地从我的signedData中获取并验证一个Signerinfo对象。然后我尝试将reqGen.generate()函数中的字节传递给mySignerInformation.getSignature()。时间戳验证失败。然后我传递了mySignerInformation.getSignature()的Sha1摘要,但是我的时间戳验证再次失败。

RFC3161规范说:

2.4.1.请求格式

时间戳请求如下:

TimeStampReq ::= SEQUENCE { version INTEGER { v1(1) }, messageImprint MessageImprint, --a hash algorithm OID 和要处理的数据的哈希值

(...)

messageImprint字段应包含要加时间戳的数据的哈希。哈希表示为八位字节字符串。它的< br >长度必须与该算法的哈希值的长度相匹配< br >(例如,SHA-1为20字节,MD5为16字节)。

MessageImprint ::= SEQUENCE { hashAlgorithm AlgorithmIdentifier, hashedMessage Octet STRING }

但如果我想对CMSSignedData对象中的字节进行时间戳,它并没有告诉我在哪里或如何获取MessageImprint数据。

我是这方面的新手。

共有1个答案

颛孙智勇
2023-03-14

你是对的,问题是你给不正确的数据打了时间戳。其余的代码在我看来是正确的。

所以问题是您必须对签名的哈希进行时间戳。要从您的CMSSignedData中获取签名并对其进行哈希处理;您可以使用以下代码(假设您的PKCS7中只有一个签名者,并且您使用的是SHA1哈希算法):

CMSSignedData signedData = ...
// get the signers of your CMSSignedData signedData
Collection ss = signedData.getSignerInfos().getSigners();
SignerInformation si = (SignerInformation) ss.iterator().next();
// hash the signature
byte[] signDigest = MessageDigest
      .getInstance(TSPAlgorithms.SHA1, new BouncyCastleProvider())
      .digest(si.getSignature()); // since you're adding the bc provider with Security.addProvider you can use "BC" instead of passing the new BouncyCastleProvider() 
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
// generate the TSRequest
TimeStampRequest request =
            reqGen.generate(TSPAlgorithms.SHA1, signDigest, BigInteger.valueOf(100));
...

希望这有帮助,

 类似资料:
  • 本文向大家介绍Dubbo必须依赖的包有哪些?相关面试题,主要包含被问及Dubbo必须依赖的包有哪些?时的应答技巧和注意事项,需要的朋友参考一下 Dubbo 必须依赖 JDK,其他为可选。

  • 本文向大家介绍在两个iframe之间传递参数的方法有哪些?相关面试题,主要包含被问及在两个iframe之间传递参数的方法有哪些?时的应答技巧和注意事项,需要的朋友参考一下 通过postMessage与父级通过,父级传递消息 通过websocket通信 如果是同一个域名下 可用stroage,监听storageChange事件通信 通过web worker也可通信

  • 本文向大家介绍Node的全局对象有哪些?相关面试题,主要包含被问及Node的全局对象有哪些?时的应答技巧和注意事项,需要的朋友参考一下 setTimeout setInterval process console

  • 问题内容: 我有一个大数据框,然后尝试将其拆分。我用 但它返回一个错误 我该如何解决? 问题答案: IIUC您需要以下内容: 您需要将每个块附加到列表中,然后用于将它们全部串联起来,我也认为可能没有必要,但是我可能错了

  • React 的props传递是否只能传递对象,而不能传递数组? 我有如下的数组数据: 传递数据到: 我在组件内接受的时候,会变成对象: 所以,是否React 的props传递是否只能传递对象,而不能传递数组?如果想要传递数组应该怎么传递呢?对treeData 进一步封装是吗?

  • 问题内容: 伙计们,在上面的程序中,在执行过程中我发现了这些错误。怎么解决?我已经在文件夹位置下载了Jsoup.jar文件。我该怎么办? 问题答案: 当然是Jsoup的。 另请参阅Jsoup API文档。 也就是说,还有一个问题只有在运行时才会显现:您以ajava.lang.String而不是a的形式传递。AString将被视为纯HTML,而不是资源。也修复它: 更新:您只需要确保在编译时和运行时