使用 BouncyCastle 向 CMS 签名添加签名/认证属性

Add signed/authenticated attributes to CMS signature using BouncyCastle (使用 BouncyCastle 向 CMS 签名添加签名/认证属性)
本文介绍了使用 BouncyCastle 向 CMS 签名添加签名/认证属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我想使用 bouncycastle 生成一个简单的 CMS 签名.此代码有效!

I want to generate a simple CMS signature using bouncycastle. This code works!

  Security.addProvider(new BouncyCastleProvider());
  String password = "123456";
  KeyStore ks = KeyStore.getInstance("PKCS12");
  ks.load(new FileInputStream("c:/cert_123456.p12"), password.toCharArray());
  String alias = (String)ks.aliases().nextElement();
  PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray());
  Certificate[] chain = ks.getCertificateChain(alias);

  CMSSignedDataGenerator generator = new CMSSignedDataGenerator();

  generator.addSigner(key, (X509Certificate)chain[0], CMSSignedDataGenerator.DIGEST_SHA1);
  ArrayList list = new ArrayList();
  for (int i = 0; i < chain.length; i++) {
       list.add(chain[i]);
  }
  CertStore chainStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(list), "BC");
  generator.addCertificatesAndCRLs(chainStore);
  CMSProcessable content = new CMSProcessableByteArray("test".getBytes());
  CMSSignedData signedData = generator.generate(content, false, "BC");

  byte[] pk = signedData.getEncoded();

但是,如何添加签名属性?
我想删除默认签名属性并添加签名策略标识符.

But, how to add signed attributes?
I want to remove default signed attributes and add signature-policy-identifier.

文章非常受欢迎.

推荐答案

首先,您似乎在使用在最新版本的 Bouncy Castle 中已弃用的构造.要添加经过身份验证/签名的 属性,您必须将它们打包到 AttributeTable 签名属性被添加到签名者中所以:

First of all you appear to be using constructs that are deprecated in the latest versions of Bouncy Castle. To add authenticated/signed attributes you have to package them into an AttributeTable Signed attributes are added to the signer like so:

ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
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(digestBytes))));
signedAttributes.add(new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(signingDate))));

AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);

然后在 addSigner 方法之一中使用它.正如我在开始时已经提到的,这种方法已被弃用,我们鼓励您使用生成器和生成器生成器.这是一个简短的例子:

Then use it in one of the addSigner methods. As I already mentioned in the beginning this method is deprecated and you are encouraged to use Generators and Generator Builders. Here's a short example:

    /* Construct signed attributes */
    ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
    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(digestBytes))));
    signedAttributes.add(new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(signingDate))));

    AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
    signedAttributesTable.toASN1EncodableVector();
    DefaultSignedAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator(signedAttributesTable);

    /* Build the SignerInfo generator builder, that will build the generator... that will generate the SignerInformation... */
    SignerInfoGeneratorBuilder signerInfoBuilder = new SignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());
    signerInfoBuilder.setSignedAttributeGenerator(signedAttributeGenerator);
    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    JcaContentSignerBuilder contentSigner = new JcaContentSignerBuilder("SHA1withRSA");
    contentSigner.setProvider("BC");

    generator.addSignerInfoGenerator(signerInfoBuilder.build(contentSigner.build(this.signingKey), new X509CertificateHolder(this.signingCert.getEncoded())));

    ArrayList<X509CertificateHolder> signingChainHolder = new ArrayList<X509CertificateHolder>();
    Iterator i = this.signingChain.iterator();
    while (i.hasNext()) {
        X509CertificateObject cert = (X509CertificateObject)i.next();
        signingChainHolder.add(new X509CertificateHolder(cert.getEncoded()));
    }

    generator.addCertificates(new JcaCertStore(signingChainHolder));
    generator.generate(new CMSAbsentContent(), "BC").getEncoded();

它相当笨重,可能还不能工作(我正在编写它,并在研究一些东西时偶然发现了你的问题),尤其是签名日期部分,它可能必须是 new DERSet(新时间(新日期))(更新:它适用于DERUTCTime).

It's quite bulky and probably doesn't work yet (I'm in the process of writing it and stumbled upon your question while researching some stuff), especially the signingDate part, it probably has to be new DERSet(new Time(new Date)) (update: it works with DERUTCTime).

有点离题:我仍然无法理解 Signed 和 Authenticated 属性之间的区别,Bouncy Castle 拥有 DefaultAuthenticatedAttributeTableGenerator、DefaultSignedAttributeTableGenerator 类,它们与 Signers 完美配合.两者在签名时间方面似乎存在一些细微差别,如果不存在,SignedAttributes 默认会添加签名时间.RFC 提到了这两种属性类型,但我找不到任何确定的内容.

A bit of offtopic: I still can't get my head around the difference between Signed and Authenticated attributes, Bouncy Castle has got both DefaultAuthenticatedAttributeTableGenerator, DefaultSignedAttributeTableGenerator classes which work perfectly well with Signers. There seem to be some minor differences between the two in regards to signingTime, SignedAttributes adds the signingTime by default if not present. The RFCs mention both attribute types, but I couldn't find anything definite.

这篇关于使用 BouncyCastle 向 CMS 签名添加签名/认证属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Reliable implementation of PBKDF2-HMAC-SHA256 for JAVA(PBKDF2-HMAC-SHA256 for JAVA 的可靠实现)
Correct way to sign and verify signature using bouncycastle(使用 bouncycastle 签名和验证签名的正确方法)
Creating RSA Public Key From String(从字符串创建 RSA 公钥)
Why java.security.NoSuchProviderException No such provider: BC?(为什么 java.security.NoSuchProviderException 没有这样的提供者:BC?)
Generating X509 Certificate using Bouncy Castle Java(使用 Bouncy Castle Java 生成 X509 证书)
How can I get a PublicKey object from EC public key bytes?(如何从 EC 公钥字节中获取 PublicKey 对象?)