1

我对签名/证书有点陌生,但是在检查了 Google + SO 之后,我找不到答案。我有为 PKCS #7 分离签名的文件生成签名的基本代码,到目前为止一切都很好......验证签名的客户端对生成的签名感到满意。我现在有一个新要求,包括使用 S/MIME 签名时间属性对原始文件进行签名的日期/时间。

到目前为止,我处理它的代码是:

    final Attribute signingAttribute = new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(new Date()))); 
    signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(new ASN1ObjectIdentifier("1.2.840.113549.1.7.1"))));
    signedAttributes.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(hash))));
    signedAttributes.add(signingAttribute);
    final AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
    final DefaultSignedAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator(signedAttributesTable);
    // now proceed for the signing process with BouncyCastle
    final JcaSimpleSignerInfoGeneratorBuilder builder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").setDirectSignature(true);
    builder.setSignedAttributeGenerator(signedAttributeGenerator);
    final SignerInfoGenerator signerGenerator = builder.build("SHA1withRSA", key, cert);

    final CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
    ...

然后之后的代码与我用来生成签名的代码相同......但不起作用。

我不是真的一件事是messageDigest的哈希:

    signedAttributes.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(hash))));

我得到的哈希生成为:

    MessageDigest md = MessageDigest.getInstance("SHA1", "BC");
    md.update(fileToSign.getBytes("UTF-8"));
    hash = md.digest();        

但我绝对不确定这是获取哈希的正确方法吗?以及生成 S/MIME 签名时间属性的整体方式......

欢迎任何关于我错过的提示或总体解释。

4

1 回答 1

1

好的,在深入研究代码之后,解决方案很简单......首先代码可以简化,问题与哈希完全无关。

为了获取签名时间,我们只能有一个属性:

final ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
final Attribute signingAttribute = new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(new Date()))); 
signedAttributes.add(signingAttribute);
// Create the signing table
final AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
// Create the table table generator that will added to the Signer builder
final DefaultSignedAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator(signedAttributesTable);


final JcaSimpleSignerInfoGeneratorBuilder builder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME);
builder.setSignedAttributeGenerator(signedAttributeGenerator); 
// ****** DO NOT call: setDirectSignature(true); *****
final SignerInfoGenerator signerGenerator = builder.build("SHA1withRSA", key, cert);

这里的关键部分在评论部分:

// ****** DO NOT call: setDirectSignature(true); *****

如果调用 setDirectSignature(true),则基本上撤消了之前完成的所有工作。根据文档:

如果传入的标志为真,则签名者签名将基于数据,而不是签名属性的集合,并且不会包含签名属性。

就是这样...从那时起生成的签名将具有签名时间...

我用我的新客户进行了验证,我得到的以前的错误/日志已经消失了

于 2013-08-08T19:18:55.283 回答