使用BouncyCastle将签名/身份validation的属性添加到CMS签名

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

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(); 

但是,如何添加签名属性?
我想删除默认的签名属性并添加signature-policy-identifier。

文章非常受欢迎。

首先,您似乎使用了最新版本的Bouncy Castle中不推荐使用的构造。 要添加经过身份validation/签名的属性 ,必须将它们打包到一个AttributeTable中。签名属性会添加到签名者中,如下所示:

 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方法中使用它。 正如我在开始时提到的,这种方法已被弃用,我们鼓励您使用Generators和Generator Builders。 这是一个简短的例子:

  /* 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 signingChainHolder = new ArrayList(); 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(new Time(new Date)) (更新:它适用于DERUTCTime )。

一点offtopic:我仍然无法理解Signed和Authenticated属性之间的区别,Bouncy Castle已经获得了DefaultAuthenticatedAttributeTableGenerator,DefaultSignedAttributeTableGenerator类,它们与Signer完美配合。 在签名时,两者之间似乎存在一些细微差别,如果不存在,SignedAttributes会默认添加signedTime。 RFC提到了两种属性类型,但我找不到任何确定的东西。