【问题标题】:Bouncycastle and S/MIME signing-time attributeBouncycastle 和 S/MIME 签名时间属性
【发布时间】:2013-08-08 04:26:23
【问题描述】:

我对签名/证书有点陌生,但是在检查了 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 签名时间属性的整体方式...

欢迎对我遗漏的内容提供任何提示或总体解释。

【问题讨论】:

    标签: java certificate bouncycastle signing


    【解决方案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),那基本上会撤销之前完成的所有工作。根据文档:

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

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

    我与我的新客户进行了验证,我之前收到的错误/日志已经消失了

    【讨论】:

    • 你好 Yoda,我猜你设法使用 PKCS#7(只有公钥)来签署/加密发送给拥有私钥的人的 SMIME 消息。我被这个问题困住了,也许你可以把你的代码摘录发给我吗?感谢您的帮助!
    猜你喜欢
    • 2012-07-16
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 2011-04-25
    • 2016-12-01
    • 2018-07-10
    • 2015-05-29
    • 2014-05-04
    相关资源
    最近更新 更多