• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.cms;
2 
3 import java.io.IOException;
4 import java.io.OutputStream;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.Map;
8 
9 import org.bouncycastle.asn1.ASN1Encoding;
10 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
11 import org.bouncycastle.asn1.ASN1Set;
12 import org.bouncycastle.asn1.DEROctetString;
13 import org.bouncycastle.asn1.DERSet;
14 import org.bouncycastle.asn1.cms.AttributeTable;
15 import org.bouncycastle.asn1.cms.SignerIdentifier;
16 import org.bouncycastle.asn1.cms.SignerInfo;
17 // import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
18 // import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
19 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
20 import org.bouncycastle.cert.X509CertificateHolder;
21 import org.bouncycastle.operator.ContentSigner;
22 import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
23 import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder;
24 import org.bouncycastle.operator.DigestCalculator;
25 import org.bouncycastle.operator.DigestCalculatorProvider;
26 import org.bouncycastle.operator.OperatorCreationException;
27 import org.bouncycastle.util.Arrays;
28 import org.bouncycastle.util.io.TeeOutputStream;
29 
30 public class SignerInfoGenerator
31 {
32     private final SignerIdentifier signerIdentifier;
33     private final CMSAttributeTableGenerator sAttrGen;
34     private final CMSAttributeTableGenerator unsAttrGen;
35     private final ContentSigner signer;
36     private final DigestCalculator digester;
37     private final DigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
38     private final CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder;
39 
40     private byte[] calculatedDigest = null;
41     private X509CertificateHolder certHolder;
42 
SignerInfoGenerator( SignerIdentifier signerIdentifier, ContentSigner signer, DigestCalculatorProvider digesterProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)43     SignerInfoGenerator(
44         SignerIdentifier signerIdentifier,
45         ContentSigner signer,
46         DigestCalculatorProvider digesterProvider,
47         CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder)
48         throws OperatorCreationException
49     {
50         this(signerIdentifier, signer, digesterProvider, sigEncAlgFinder, false);
51     }
52 
SignerInfoGenerator( SignerIdentifier signerIdentifier, ContentSigner signer, DigestCalculatorProvider digesterProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder, boolean isDirectSignature)53     SignerInfoGenerator(
54         SignerIdentifier signerIdentifier,
55         ContentSigner signer,
56         DigestCalculatorProvider digesterProvider,
57         CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder,
58         boolean isDirectSignature)
59         throws OperatorCreationException
60     {
61         this.signerIdentifier = signerIdentifier;
62         this.signer = signer;
63 
64         if (digesterProvider != null)
65         {
66             this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier()));
67         }
68         else
69         {
70             this.digester = null;
71         }
72 
73         if (isDirectSignature)
74         {
75             this.sAttrGen = null;
76             this.unsAttrGen = null;
77         }
78         else
79         {
80             this.sAttrGen = new DefaultSignedAttributeTableGenerator();
81             this.unsAttrGen = null;
82         }
83 
84         this.sigEncAlgFinder = sigEncAlgFinder;
85     }
86 
SignerInfoGenerator( SignerInfoGenerator original, CMSAttributeTableGenerator sAttrGen, CMSAttributeTableGenerator unsAttrGen)87     public SignerInfoGenerator(
88         SignerInfoGenerator original,
89         CMSAttributeTableGenerator sAttrGen,
90         CMSAttributeTableGenerator unsAttrGen)
91     {
92         this.signerIdentifier = original.signerIdentifier;
93         this.signer = original.signer;
94         this.digester = original.digester;
95         this.sigEncAlgFinder = original.sigEncAlgFinder;
96         this.sAttrGen = sAttrGen;
97         this.unsAttrGen = unsAttrGen;
98     }
99 
SignerInfoGenerator( SignerIdentifier signerIdentifier, ContentSigner signer, DigestCalculatorProvider digesterProvider, CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder, CMSAttributeTableGenerator sAttrGen, CMSAttributeTableGenerator unsAttrGen)100     SignerInfoGenerator(
101         SignerIdentifier signerIdentifier,
102         ContentSigner signer,
103         DigestCalculatorProvider digesterProvider,
104         CMSSignatureEncryptionAlgorithmFinder sigEncAlgFinder,
105         CMSAttributeTableGenerator sAttrGen,
106         CMSAttributeTableGenerator unsAttrGen)
107         throws OperatorCreationException
108     {
109         this.signerIdentifier = signerIdentifier;
110         this.signer = signer;
111 
112         if (digesterProvider != null)
113         {
114             this.digester = digesterProvider.get(digAlgFinder.find(signer.getAlgorithmIdentifier()));
115         }
116         else
117         {
118             this.digester = null;
119         }
120 
121         this.sAttrGen = sAttrGen;
122         this.unsAttrGen = unsAttrGen;
123         this.sigEncAlgFinder = sigEncAlgFinder;
124     }
125 
getSID()126     public SignerIdentifier getSID()
127     {
128         return signerIdentifier;
129     }
130 
getGeneratedVersion()131     public int getGeneratedVersion()
132     {
133         return signerIdentifier.isTagged() ? 3 : 1;
134     }
135 
hasAssociatedCertificate()136     public boolean hasAssociatedCertificate()
137     {
138         return certHolder != null;
139     }
140 
getAssociatedCertificate()141     public X509CertificateHolder getAssociatedCertificate()
142     {
143         return certHolder;
144     }
145 
getDigestAlgorithm()146     public AlgorithmIdentifier getDigestAlgorithm()
147     {
148         if (digester != null)
149         {
150             return digester.getAlgorithmIdentifier();
151         }
152 
153         return digAlgFinder.find(signer.getAlgorithmIdentifier());
154     }
155 
getCalculatingOutputStream()156     public OutputStream getCalculatingOutputStream()
157     {
158         if (digester != null)
159         {
160             if (sAttrGen == null)
161             {
162                 return new TeeOutputStream(digester.getOutputStream(), signer.getOutputStream());
163             }
164             return digester.getOutputStream();
165         }
166         else
167         {
168             return signer.getOutputStream();
169         }
170     }
171 
generate(ASN1ObjectIdentifier contentType)172     public SignerInfo generate(ASN1ObjectIdentifier contentType)
173         throws CMSException
174     {
175         try
176         {
177             /* RFC 3852 5.4
178              * The result of the message digest calculation process depends on
179              * whether the signedAttrs field is present.  When the field is absent,
180              * the result is just the message digest of the content as described
181              *
182              * above.  When the field is present, however, the result is the message
183              * digest of the complete DER encoding of the SignedAttrs value
184              * contained in the signedAttrs field.
185              */
186             ASN1Set signedAttr = null;
187 
188             AlgorithmIdentifier digestEncryptionAlgorithm = sigEncAlgFinder.findEncryptionAlgorithm(signer.getAlgorithmIdentifier());
189 
190             AlgorithmIdentifier digestAlg = null;
191 
192             if (sAttrGen != null)
193             {
194                 digestAlg = digester.getAlgorithmIdentifier();
195                 calculatedDigest = digester.getDigest();
196                 Map parameters = getBaseParameters(contentType, digester.getAlgorithmIdentifier(), digestEncryptionAlgorithm, calculatedDigest);
197                 AttributeTable signed = sAttrGen.getAttributes(Collections.unmodifiableMap(parameters));
198 
199                 signedAttr = getAttributeSet(signed);
200 
201                 // sig must be composed from the DER encoding.
202                 OutputStream sOut = signer.getOutputStream();
203 
204                 sOut.write(signedAttr.getEncoded(ASN1Encoding.DER));
205 
206                 sOut.close();
207             }
208             else
209             {
210                 if (digester != null)
211                 {
212                     digestAlg = digester.getAlgorithmIdentifier();
213                     calculatedDigest = digester.getDigest();
214                 }
215                 else
216                 {
217                     digestAlg = digAlgFinder.find(signer.getAlgorithmIdentifier());
218                     calculatedDigest = null;
219                 }
220             }
221 
222             byte[] sigBytes = signer.getSignature();
223 
224             ASN1Set unsignedAttr = null;
225             if (unsAttrGen != null)
226             {
227                 Map parameters = getBaseParameters(contentType, digestAlg, digestEncryptionAlgorithm, calculatedDigest);
228                 parameters.put(CMSAttributeTableGenerator.SIGNATURE, Arrays.clone(sigBytes));
229 
230                 AttributeTable unsigned = unsAttrGen.getAttributes(Collections.unmodifiableMap(parameters));
231 
232                 unsignedAttr = getAttributeSet(unsigned);
233             }
234 
235             if (sAttrGen == null)
236             {
237                 // BEGIN Android-removed: Unsupported algorithms
238                 /*
239                 // RFC 8419, Section 3.2 - needs to be shake-256, not shake-256-len
240                 if (EdECObjectIdentifiers.id_Ed448.equals(digestEncryptionAlgorithm.getAlgorithm()))
241                 {
242                     digestAlg = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256);
243                 }
244                 */
245                 // END Android-removed: Unsupported algorithms
246             }
247 
248             return new SignerInfo(signerIdentifier, digestAlg,
249                 signedAttr, digestEncryptionAlgorithm, new DEROctetString(sigBytes), unsignedAttr);
250         }
251         catch (IOException e)
252         {
253             throw new CMSException("encoding error.", e);
254         }
255     }
256 
setAssociatedCertificate(X509CertificateHolder certHolder)257     void setAssociatedCertificate(X509CertificateHolder certHolder)
258     {
259         this.certHolder = certHolder;
260     }
261 
getAttributeSet( AttributeTable attr)262     private ASN1Set getAttributeSet(
263         AttributeTable attr)
264     {
265         if (attr != null)
266         {
267             return new DERSet(attr.toASN1EncodableVector());
268         }
269 
270         return null;
271     }
272 
getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, AlgorithmIdentifier sigAlgId, byte[] hash)273     private Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, AlgorithmIdentifier sigAlgId, byte[] hash)
274     {
275         Map param = new HashMap();
276 
277         if (contentType != null)
278         {
279             param.put(CMSAttributeTableGenerator.CONTENT_TYPE, contentType);
280         }
281 
282         param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId);
283         param.put(CMSAttributeTableGenerator.SIGNATURE_ALGORITHM_IDENTIFIER, sigAlgId);
284         param.put(CMSAttributeTableGenerator.DIGEST,  Arrays.clone(hash));
285 
286         return param;
287     }
288 
getCalculatedDigest()289     public byte[] getCalculatedDigest()
290     {
291         if (calculatedDigest != null)
292         {
293             return Arrays.clone(calculatedDigest);
294         }
295 
296         return null;
297     }
298 
getSignedAttributeTableGenerator()299     public CMSAttributeTableGenerator getSignedAttributeTableGenerator()
300     {
301         return sAttrGen;
302     }
303 
getUnsignedAttributeTableGenerator()304     public CMSAttributeTableGenerator getUnsignedAttributeTableGenerator()
305     {
306         return unsAttrGen;
307     }
308 }
309