问题描述
我想使用 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 签名添加签名/认证属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!