package org.bouncycastle.cms;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.BEROctetString;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.SignedData;
import org.bouncycastle.asn1.cms.SignerInfo;

general class for generating a pkcs7-signature message.

A simple example of usage, generating a detached signature.

     List             certList = new ArrayList();
     CMSTypedData     msg = new CMSProcessableByteArray("Hello world!".getBytes());
     certList.add(signCert);
     Store           certs = new JcaCertStore(certList);
     CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
     ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(signKP.getPrivate());
     gen.addSignerInfoGenerator(
               new JcaSignerInfoGeneratorBuilder(
                    new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
                    .build(sha1Signer, signCert));
     gen.addCertificates(certs);
     CMSSignedData sigData = gen.generate(msg, false);
/** * general class for generating a pkcs7-signature message. * <p> * A simple example of usage, generating a detached signature. * * <pre> * List certList = new ArrayList(); * CMSTypedData msg = new CMSProcessableByteArray("Hello world!".getBytes()); * * certList.add(signCert); * * Store certs = new JcaCertStore(certList); * * CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); * ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(signKP.getPrivate()); * * gen.addSignerInfoGenerator( * new JcaSignerInfoGeneratorBuilder( * new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()) * .build(sha1Signer, signCert)); * * gen.addCertificates(certs); * * CMSSignedData sigData = gen.generate(msg, false); * </pre> */
public class CMSSignedDataGenerator extends CMSSignedGenerator { private List signerInfs = new ArrayList();
base constructor
/** * base constructor */
public CMSSignedDataGenerator() { }
Generate a CMS Signed Data object carrying a detached CMS signature.
Params:
  • content – the content to be signed.
/** * Generate a CMS Signed Data object carrying a detached CMS signature. * * @param content the content to be signed. */
public CMSSignedData generate( CMSTypedData content) throws CMSException { return generate(content, false); }
Generate a CMS Signed Data object which can be carrying a detached CMS signature, or have encapsulated data, depending on the value of the encapsulated parameter.
Params:
  • content – the content to be signed.
  • encapsulate – true if the content should be encapsulated in the signature, false otherwise.
/** * Generate a CMS Signed Data object which can be carrying a detached CMS signature, or have encapsulated data, depending on the value * of the encapsulated parameter. * * @param content the content to be signed. * @param encapsulate true if the content should be encapsulated in the signature, false otherwise. */
public CMSSignedData generate( // FIXME Avoid accessing more than once to support CMSProcessableInputStream CMSTypedData content, boolean encapsulate) throws CMSException { if (!signerInfs.isEmpty()) { throw new IllegalStateException("this method can only be used with SignerInfoGenerator"); } // TODO // if (signerInfs.isEmpty()) // { // /* RFC 3852 5.2 // * "In the degenerate case where there are no signers, the // * EncapsulatedContentInfo value being "signed" is irrelevant. In this // * case, the content type within the EncapsulatedContentInfo value being // * "signed" MUST be id-data (as defined in section 4), and the content // * field of the EncapsulatedContentInfo value MUST be omitted." // */ // if (encapsulate) // { // throw new IllegalArgumentException("no signers, encapsulate must be false"); // } // if (!DATA.equals(eContentType)) // { // throw new IllegalArgumentException("no signers, eContentType must be id-data"); // } // } // // if (!DATA.equals(eContentType)) // { // /* RFC 3852 5.3 // * [The 'signedAttrs']... // * field is optional, but it MUST be present if the content type of // * the EncapsulatedContentInfo value being signed is not id-data. // */ // // TODO signedAttrs must be present for all signers // } ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); ASN1EncodableVector signerInfos = new ASN1EncodableVector(); digests.clear(); // clear the current preserved digest state // // add the precalculated SignerInfo objects. // for (Iterator it = _signers.iterator(); it.hasNext();) { SignerInformation signer = (SignerInformation)it.next(); digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID())); // TODO Verify the content type and calculated digest match the precalculated SignerInfo signerInfos.add(signer.toASN1Structure()); } // // add the SignerInfo objects // ASN1ObjectIdentifier contentTypeOID = content.getContentType(); ASN1OctetString octs = null; if (content.getContent() != null) { ByteArrayOutputStream bOut = null; if (encapsulate) { bOut = new ByteArrayOutputStream(); } OutputStream cOut = CMSUtils.attachSignersToOutputStream(signerGens, bOut); // Just in case it's unencapsulated and there are no signers! cOut = CMSUtils.getSafeOutputStream(cOut); try { content.write(cOut); cOut.close(); } catch (IOException e) { throw new CMSException("data processing exception: " + e.getMessage(), e); } if (encapsulate) { octs = new BEROctetString(bOut.toByteArray()); } } for (Iterator it = signerGens.iterator(); it.hasNext();) { SignerInfoGenerator sGen = (SignerInfoGenerator)it.next(); SignerInfo inf = sGen.generate(contentTypeOID); digestAlgs.add(inf.getDigestAlgorithm()); signerInfos.add(inf); byte[] calcDigest = sGen.getCalculatedDigest(); if (calcDigest != null) { digests.put(inf.getDigestAlgorithm().getAlgorithm().getId(), calcDigest); } } ASN1Set certificates = null; if (certs.size() != 0) { certificates = CMSUtils.createBerSetFromList(certs); } ASN1Set certrevlist = null; if (crls.size() != 0) { certrevlist = CMSUtils.createBerSetFromList(crls); } ContentInfo encInfo = new ContentInfo(contentTypeOID, octs); SignedData sd = new SignedData( new DERSet(digestAlgs), encInfo, certificates, certrevlist, new DERSet(signerInfos)); ContentInfo contentInfo = new ContentInfo( CMSObjectIdentifiers.signedData, sd); return new CMSSignedData(content, contentInfo); }
generate a set of one or more SignerInformation objects representing counter signatures on the passed in SignerInformation object.
Params:
  • signer – the signer to be countersigned
Returns:a store containing the signers.
/** * generate a set of one or more SignerInformation objects representing counter signatures on * the passed in SignerInformation object. * * @param signer the signer to be countersigned * @return a store containing the signers. */
public SignerInformationStore generateCounterSigners(SignerInformation signer) throws CMSException { return this.generate(new CMSProcessableByteArray(null, signer.getSignature()), false).getSignerInfos(); } }