1 package org.bouncycastle.cms;
2 
3 import org.bouncycastle.asn1.DEROctetString;
4 import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
5 import org.bouncycastle.asn1.cms.SignerIdentifier;
6 import org.bouncycastle.cert.X509CertificateHolder;
7 import org.bouncycastle.operator.ContentSigner;
8 import org.bouncycastle.operator.DigestCalculatorProvider;
9 import org.bouncycastle.operator.OperatorCreationException;
10 
11 /**
12  * Builder for SignerInfo generator objects.
13  */
14 public class SignerInfoGeneratorBuilder
15 {
16     private DigestCalculatorProvider digestProvider;
17     private boolean directSignature;
18     private CMSAttributeTableGenerator signedGen;
19     private CMSAttributeTableGenerator unsignedGen;
20     private CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder;
21 
22     /**
23      *  Base constructor.
24      *
25      * @param digestProvider  a provider of digest calculators for the algorithms required in the signature and attribute calculations.
26      */
SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider)27     public SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider)
28     {
29         this(digestProvider, new DefaultCMSSignatureEncryptionAlgorithmFinder());
30     }
31 
32         /**
33      *  Base constructor.
34      *
35      * @param digestProvider  a provider of digest calculators for the algorithms required in the signature and attribute calculations.
36      */
SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)37     public SignerInfoGeneratorBuilder(DigestCalculatorProvider digestProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)
38     {
39         this.digestProvider = digestProvider;
40         this.sigEncAlgFinder = sigEncAlgFinder;
41     }
42 
43     /**
44      * If the passed in flag is true, the signer signature will be based on the data, not
45      * a collection of signed attributes, and no signed attributes will be included.
46      *
47      * @return the builder object
48      */
setDirectSignature(boolean hasNoSignedAttributes)49     public SignerInfoGeneratorBuilder setDirectSignature(boolean hasNoSignedAttributes)
50     {
51         this.directSignature = hasNoSignedAttributes;
52 
53         return this;
54     }
55 
56     /**
57      *  Provide a custom signed attribute generator.
58      *
59      * @param signedGen a generator of signed attributes.
60      * @return the builder object
61      */
setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen)62     public SignerInfoGeneratorBuilder setSignedAttributeGenerator(CMSAttributeTableGenerator signedGen)
63     {
64         this.signedGen = signedGen;
65 
66         return this;
67     }
68 
69     /**
70      * Provide a generator of unsigned attributes.
71      *
72      * @param unsignedGen  a generator for signed attributes.
73      * @return the builder object
74      */
setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen)75     public SignerInfoGeneratorBuilder setUnsignedAttributeGenerator(CMSAttributeTableGenerator unsignedGen)
76     {
77         this.unsignedGen = unsignedGen;
78 
79         return this;
80     }
81 
82     /**
83      * Build a generator with the passed in certHolder issuer and serial number as the signerIdentifier.
84      *
85      * @param contentSigner  operator for generating the final signature in the SignerInfo with.
86      * @param certHolder  carrier for the X.509 certificate related to the contentSigner.
87      * @return  a SignerInfoGenerator
88      * @throws OperatorCreationException   if the generator cannot be built.
89      */
build(ContentSigner contentSigner, X509CertificateHolder certHolder)90     public SignerInfoGenerator build(ContentSigner contentSigner, X509CertificateHolder certHolder)
91         throws OperatorCreationException
92     {
93         SignerIdentifier sigId = new SignerIdentifier(new IssuerAndSerialNumber(certHolder.toASN1Structure()));
94 
95         SignerInfoGenerator sigInfoGen = createGenerator(contentSigner, sigId);
96 
97         sigInfoGen.setAssociatedCertificate(certHolder);
98 
99         return sigInfoGen;
100     }
101 
102     /**
103      * Build a generator with the passed in subjectKeyIdentifier as the signerIdentifier. If used  you should
104      * try to follow the calculation described in RFC 5280 section 4.2.1.2.
105      *
106      * @param contentSigner  operator for generating the final signature in the SignerInfo with.
107      * @param subjectKeyIdentifier    key identifier to identify the public key for verifying the signature.
108      * @return  a SignerInfoGenerator
109      * @throws OperatorCreationException if the generator cannot be built.
110      */
build(ContentSigner contentSigner, byte[] subjectKeyIdentifier)111     public SignerInfoGenerator build(ContentSigner contentSigner, byte[] subjectKeyIdentifier)
112         throws OperatorCreationException
113     {
114         SignerIdentifier sigId = new SignerIdentifier(new DEROctetString(subjectKeyIdentifier));
115 
116         return createGenerator(contentSigner, sigId);
117     }
118 
createGenerator(ContentSigner contentSigner, SignerIdentifier sigId)119     private SignerInfoGenerator createGenerator(ContentSigner contentSigner, SignerIdentifier sigId)
120         throws OperatorCreationException
121     {
122         if (directSignature)
123         {
124             return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder, true);
125         }
126 
127         if (signedGen != null || unsignedGen != null)
128         {
129             if (signedGen == null)
130             {
131                 signedGen = new DefaultSignedAttributeTableGenerator();
132             }
133 
134             return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder, signedGen, unsignedGen);
135         }
136 
137         return new SignerInfoGenerator(sigId, contentSigner, digestProvider, sigEncAlgFinder);
138     }
139 }
140