1package org.bouncycastle.cms;
2
3import java.io.IOException;
4import java.io.InputStream;
5import java.io.OutputStream;
6import java.security.NoSuchAlgorithmException;
7import java.security.NoSuchProviderException;
8import java.security.Provider;
9import java.security.cert.CertStore;
10import java.security.cert.CertStoreException;
11import java.util.ArrayList;
12import java.util.Collection;
13import java.util.Iterator;
14import java.util.List;
15import java.util.Map;
16
17import org.bouncycastle.asn1.ASN1EncodableVector;
18import org.bouncycastle.asn1.ASN1InputStream;
19import org.bouncycastle.asn1.ASN1ObjectIdentifier;
20import org.bouncycastle.asn1.ASN1OctetString;
21import org.bouncycastle.asn1.ASN1Sequence;
22import org.bouncycastle.asn1.ASN1Set;
23import org.bouncycastle.asn1.BERSequence;
24import org.bouncycastle.asn1.DERSet;
25import org.bouncycastle.asn1.cms.ContentInfo;
26import org.bouncycastle.asn1.cms.SignedData;
27import org.bouncycastle.asn1.cms.SignerInfo;
28// BEGIN android-removed
29// import org.bouncycastle.cert.jcajce.JcaCertStoreBuilder;
30// END android-removed
31import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
32import org.bouncycastle.operator.OperatorCreationException;
33import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder;
34import org.bouncycastle.util.Store;
35import org.bouncycastle.x509.NoSuchStoreException;
36import org.bouncycastle.x509.X509Store;
37
38/**
39 * general class for handling a pkcs7-signature message.
40 *
41 * A simple example of usage - note, in the example below the validity of
42 * the certificate isn't verified, just the fact that one of the certs
43 * matches the given signer...
44 *
45 * <pre>
46 *  Store                   certStore = s.getCertificates();
47 *  SignerInformationStore  signers = s.getSignerInfos();
48 *  Collection              c = signers.getSigners();
49 *  Iterator                it = c.iterator();
50 *
51 *  while (it.hasNext())
52 *  {
53 *      SignerInformation   signer = (SignerInformation)it.next();
54 *      Collection          certCollection = certStore.getMatches(signer.getSID());
55 *
56 *      Iterator              certIt = certCollection.iterator();
57 *      X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
58 *
59 *      if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert)))
60 *      {
61 *          verified++;
62 *      }
63 *  }
64 * </pre>
65 */
66public class CMSSignedData
67{
68    private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE;
69
70    SignedData              signedData;
71    ContentInfo             contentInfo;
72    CMSTypedData            signedContent;
73    SignerInformationStore  signerInfoStore;
74    X509Store               attributeStore;
75    X509Store               certificateStore;
76    X509Store               crlStore;
77    private Map             hashes;
78
79    private CMSSignedData(
80        CMSSignedData   c)
81    {
82        this.signedData = c.signedData;
83        this.contentInfo = c.contentInfo;
84        this.signedContent = c.signedContent;
85        this.signerInfoStore = c.signerInfoStore;
86    }
87
88    public CMSSignedData(
89        byte[]      sigBlock)
90        throws CMSException
91    {
92        this(CMSUtils.readContentInfo(sigBlock));
93    }
94
95    public CMSSignedData(
96        CMSProcessable  signedContent,
97        byte[]          sigBlock)
98        throws CMSException
99    {
100        this(signedContent, CMSUtils.readContentInfo(sigBlock));
101    }
102
103    /**
104     * Content with detached signature, digests precomputed
105     *
106     * @param hashes a map of precomputed digests for content indexed by name of hash.
107     * @param sigBlock the signature object.
108     */
109    public CMSSignedData(
110        Map     hashes,
111        byte[]  sigBlock)
112        throws CMSException
113    {
114        this(hashes, CMSUtils.readContentInfo(sigBlock));
115    }
116
117    /**
118     * base constructor - content with detached signature.
119     *
120     * @param signedContent the content that was signed.
121     * @param sigData the signature object.
122     */
123    public CMSSignedData(
124        CMSProcessable  signedContent,
125        InputStream     sigData)
126        throws CMSException
127    {
128        this(signedContent, CMSUtils.readContentInfo(new ASN1InputStream(sigData)));
129    }
130
131    /**
132     * base constructor - with encapsulated content
133     */
134    public CMSSignedData(
135        InputStream sigData)
136        throws CMSException
137    {
138        this(CMSUtils.readContentInfo(sigData));
139    }
140
141    public CMSSignedData(
142        final CMSProcessable  signedContent,
143        ContentInfo     sigData)
144        throws CMSException
145    {
146        if (signedContent instanceof CMSTypedData)
147        {
148            this.signedContent = (CMSTypedData)signedContent;
149        }
150        else
151        {
152            this.signedContent = new CMSTypedData()
153            {
154                public ASN1ObjectIdentifier getContentType()
155                {
156                    return signedData.getEncapContentInfo().getContentType();
157                }
158
159                public void write(OutputStream out)
160                    throws IOException, CMSException
161                {
162                    signedContent.write(out);
163                }
164
165                public Object getContent()
166                {
167                    return signedContent.getContent();
168                }
169            };
170        }
171
172        this.contentInfo = sigData;
173        this.signedData = getSignedData();
174    }
175
176    public CMSSignedData(
177        Map             hashes,
178        ContentInfo     sigData)
179        throws CMSException
180    {
181        this.hashes = hashes;
182        this.contentInfo = sigData;
183        this.signedData = getSignedData();
184    }
185
186    public CMSSignedData(
187        ContentInfo sigData)
188        throws CMSException
189    {
190        this.contentInfo = sigData;
191        this.signedData = getSignedData();
192
193        //
194        // this can happen if the signed message is sent simply to send a
195        // certificate chain.
196        //
197        if (signedData.getEncapContentInfo().getContent() != null)
198        {
199            this.signedContent = new CMSProcessableByteArray(signedData.getEncapContentInfo().getContentType(),
200                    ((ASN1OctetString)(signedData.getEncapContentInfo()
201                                                .getContent())).getOctets());
202        }
203        else
204        {
205            this.signedContent = null;
206        }
207    }
208
209    private SignedData getSignedData()
210        throws CMSException
211    {
212        try
213        {
214            return SignedData.getInstance(contentInfo.getContent());
215        }
216        catch (ClassCastException e)
217        {
218            throw new CMSException("Malformed content.", e);
219        }
220        catch (IllegalArgumentException e)
221        {
222            throw new CMSException("Malformed content.", e);
223        }
224    }
225
226    /**
227     * Return the version number for this object
228     */
229    public int getVersion()
230    {
231        return signedData.getVersion().getValue().intValue();
232    }
233
234    /**
235     * return the collection of signers that are associated with the
236     * signatures for the message.
237     */
238    public SignerInformationStore getSignerInfos()
239    {
240        if (signerInfoStore == null)
241        {
242            ASN1Set         s = signedData.getSignerInfos();
243            List            signerInfos = new ArrayList();
244            SignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
245
246            for (int i = 0; i != s.size(); i++)
247            {
248                SignerInfo info = SignerInfo.getInstance(s.getObjectAt(i));
249                ASN1ObjectIdentifier contentType = signedData.getEncapContentInfo().getContentType();
250
251                if (hashes == null)
252                {
253                    signerInfos.add(new SignerInformation(info, contentType, signedContent, null));
254                }
255                else
256                {
257                    Object obj = hashes.keySet().iterator().next();
258                    byte[] hash = (obj instanceof String) ? (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm().getId()) : (byte[])hashes.get(info.getDigestAlgorithm().getAlgorithm());
259
260                    signerInfos.add(new SignerInformation(info, contentType, null, hash));
261                }
262            }
263
264            signerInfoStore = new SignerInformationStore(signerInfos);
265        }
266
267        return signerInfoStore;
268    }
269
270    /**
271     * return a X509Store containing the attribute certificates, if any, contained
272     * in this message.
273     *
274     * @param type type of store to create
275     * @param provider name of provider to use
276     * @return a store of attribute certificates
277     * @exception NoSuchProviderException if the provider requested isn't available.
278     * @exception NoSuchStoreException if the store type isn't available.
279     * @exception CMSException if a general exception prevents creation of the X509Store
280     * @deprecated use base Store returning method
281     */
282    public X509Store getAttributeCertificates(
283        String type,
284        String provider)
285        throws NoSuchStoreException, NoSuchProviderException, CMSException
286    {
287        return getAttributeCertificates(type, CMSUtils.getProvider(provider));
288    }
289
290    /**
291     * return a X509Store containing the attribute certificates, if any, contained
292     * in this message.
293     *
294     * @param type type of store to create
295     * @param provider provider to use
296     * @return a store of attribute certificates
297     * @exception NoSuchStoreException if the store type isn't available.
298     * @exception CMSException if a general exception prevents creation of the X509Store
299     * @deprecated use base Store returning method
300     */
301    public X509Store getAttributeCertificates(
302        String type,
303        Provider provider)
304        throws NoSuchStoreException, CMSException
305    {
306        if (attributeStore == null)
307        {
308            attributeStore = HELPER.createAttributeStore(type, provider, this.getAttributeCertificates());
309        }
310
311        return attributeStore;
312    }
313
314    // BEGIN android-removed
315    // /**
316    //  * return a X509Store containing the public key certificates, if any, contained
317    //  * in this message.
318    //  *
319    //  * @param type type of store to create
320    //  * @param provider name of provider to use
321    //  * @return a store of public key certificates
322    //  * @exception NoSuchProviderException if the provider requested isn't available.
323    //  * @exception NoSuchStoreException if the store type isn't available.
324    //  * @exception CMSException if a general exception prevents creation of the X509Store
325    //  * @deprecated use base Store returning method
326    //  */
327    // public X509Store getCertificates(
328    //     String type,
329    //     String provider)
330    //     throws NoSuchStoreException, NoSuchProviderException, CMSException
331    // {
332    //     return getCertificates(type, CMSUtils.getProvider(provider));
333    // }
334    //
335    // /**
336    //  * return a X509Store containing the public key certificates, if any, contained
337    //  * in this message.
338    //  *
339    //  * @param type type of store to create
340    //  * @param provider provider to use
341    //  * @return a store of public key certificates
342    //  * @exception NoSuchStoreException if the store type isn't available.
343    //  * @exception CMSException if a general exception prevents creation of the X509Store
344    //  * @deprecated use base Store returning method
345    //  */
346    // public X509Store getCertificates(
347    //     String type,
348    //     Provider provider)
349    //     throws NoSuchStoreException, CMSException
350    // {
351    //     if (certificateStore == null)
352    //     {
353    //         certificateStore = HELPER.createCertificateStore(type, provider, this.getCertificates());
354    //     }
355    //
356    //     return certificateStore;
357    // }
358    //
359    // /**
360    //  * return a X509Store containing CRLs, if any, contained
361    //  * in this message.
362    //  *
363    //  * @param type type of store to create
364    //  * @param provider name of provider to use
365    //  * @return a store of CRLs
366    //  * @exception NoSuchProviderException if the provider requested isn't available.
367    //  * @exception NoSuchStoreException if the store type isn't available.
368    //  * @exception CMSException if a general exception prevents creation of the X509Store
369    //  * @deprecated use base Store returning method
370    //  */
371    // public X509Store getCRLs(
372    //     String type,
373    //     String provider)
374    //     throws NoSuchStoreException, NoSuchProviderException, CMSException
375    // {
376    //     return getCRLs(type, CMSUtils.getProvider(provider));
377    // }
378    //
379    // /**
380    //  * return a X509Store containing CRLs, if any, contained
381    //  * in this message.
382    //  *
383    //  * @param type type of store to create
384    //  * @param provider provider to use
385    //  * @return a store of CRLs
386    //  * @exception NoSuchStoreException if the store type isn't available.
387    //  * @exception CMSException if a general exception prevents creation of the X509Store
388    //  * @deprecated use base Store returning method
389    //  */
390    // public X509Store getCRLs(
391    //     String type,
392    //     Provider provider)
393    //     throws NoSuchStoreException, CMSException
394    // {
395    //     if (crlStore == null)
396    //     {
397    //         crlStore = HELPER.createCRLsStore(type, provider, getCRLs());
398    //     }
399    //
400    //     return crlStore;
401    // }
402    //
403    // /**
404    //  * return a CertStore containing the certificates and CRLs associated with
405    //  * this message.
406    //  *
407    //  * @exception NoSuchProviderException if the provider requested isn't available.
408    //  * @exception NoSuchAlgorithmException if the cert store isn't available.
409    //  * @exception CMSException if a general exception prevents creation of the CertStore
410    //  * @deprecated use base Store returning method and org.bouncycastle.cert.jcajce.JcaCertStoreBuilder
411    //  */
412    // public CertStore getCertificatesAndCRLs(
413    //     String  type,
414    //     String  provider)
415    //     throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
416    // {
417    //     return getCertificatesAndCRLs(type, CMSUtils.getProvider(provider));
418    // }
419    //
420    // /**
421    //  * return a CertStore containing the certificates and CRLs associated with
422    //  * this message.
423    //  *
424    //  * @exception NoSuchAlgorithmException if the cert store isn't available.
425    //  * @exception CMSException if a general exception prevents creation of the CertStore
426    //  * @deprecated use base Store returning method and org.bouncycastle.cert.jcajce.JcaCertStoreBuilder
427    //  */
428    // public CertStore getCertificatesAndCRLs(
429    //     String  type,
430    //     Provider  provider)
431    //     throws NoSuchAlgorithmException, CMSException
432    // {
433    //     try
434    //     {
435    //         JcaCertStoreBuilder certStoreBuilder = new JcaCertStoreBuilder().setType(type);
436    //
437    //         if (provider != null)
438    //         {
439    //             certStoreBuilder.setProvider(provider);
440    //         }
441    //
442    //         certStoreBuilder.addCertificates(this.getCertificates());
443    //         certStoreBuilder.addCRLs(this.getCRLs());
444    //
445    //         return certStoreBuilder.build();
446    //     }
447    //     catch (NoSuchAlgorithmException e)
448    //     {
449    //         throw e;
450    //     }
451    //     catch (Exception e)
452    //     {
453    //         throw new CMSException("exception creating CertStore: " + e.getMessage(), e);
454    //     }
455    // }
456    // END android-removed
457
458    /**
459     * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects.
460     *
461     * @return a Store of X509CertificateHolder objects.
462     */
463    public Store getCertificates()
464    {
465        return HELPER.getCertificates(signedData.getCertificates());
466    }
467
468    /**
469     * Return any X.509 CRL objects in this SignedData structure as a Store of X509CRLHolder objects.
470     *
471     * @return a Store of X509CRLHolder objects.
472     */
473    public Store getCRLs()
474    {
475        return HELPER.getCRLs(signedData.getCRLs());
476    }
477
478    /**
479     * Return any X.509 attribute certificate objects in this SignedData structure as a Store of X509AttributeCertificateHolder objects.
480     *
481     * @return a Store of X509AttributeCertificateHolder objects.
482     */
483    public Store getAttributeCertificates()
484    {
485        return HELPER.getAttributeCertificates(signedData.getCertificates());
486    }
487
488    // BEGIN android-removed
489    // /**
490    //  * Return any OtherRevocationInfo OtherRevInfo objects of the type indicated by otherRevocationInfoFormat in
491    //  * this SignedData structure.
492    //  *
493    //  * @param otherRevocationInfoFormat OID of the format type been looked for.
494    //  *
495    //  * @return a Store of ASN1Encodable objects representing any objects of otherRevocationInfoFormat found.
496    //  */
497    // public Store getOtherRevocationInfo(ASN1ObjectIdentifier otherRevocationInfoFormat)
498    // {
499    //     return HELPER.getOtherRevocationInfo(otherRevocationInfoFormat, signedData.getCRLs());
500    // }
501    // END android-removed
502
503    /**
504     * Return the a string representation of the OID associated with the
505     * encapsulated content info structure carried in the signed data.
506     *
507     * @return the OID for the content type.
508     */
509    public String getSignedContentTypeOID()
510    {
511        return signedData.getEncapContentInfo().getContentType().getId();
512    }
513
514    public CMSTypedData getSignedContent()
515    {
516        return signedContent;
517    }
518
519    /**
520     * return the ContentInfo
521     * @deprecated use toASN1Structure()
522     */
523    public ContentInfo getContentInfo()
524    {
525        return contentInfo;
526    }
527
528    /**
529     * return the ContentInfo
530     */
531    public ContentInfo toASN1Structure()
532    {
533        return contentInfo;
534    }
535
536    /**
537     * return the ASN.1 encoded representation of this object.
538     */
539    public byte[] getEncoded()
540        throws IOException
541    {
542        return contentInfo.getEncoded();
543    }
544
545    // BEGIN android-removed
546    // /**
547    //  * Verify all the SignerInformation objects and their associated counter signatures attached
548    //  * to this CMS SignedData object.
549    //  *
550    //  * @param verifierProvider  a provider of SignerInformationVerifier objects.
551    //  * @return true if all verify, false otherwise.
552    //  * @throws CMSException  if an exception occurs during the verification process.
553    //  */
554    // public boolean verifySignatures(SignerInformationVerifierProvider verifierProvider)
555    //     throws CMSException
556    // {
557    //     return verifySignatures(verifierProvider, false);
558    // }
559    //
560    // /**
561    //  * Verify all the SignerInformation objects and optionally their associated counter signatures attached
562    //  * to this CMS SignedData object.
563    //  *
564    //  * @param verifierProvider  a provider of SignerInformationVerifier objects.
565    //  * @param ignoreCounterSignatures if true don't check counter signatures. If false check counter signatures as well.
566    //  * @return true if all verify, false otherwise.
567    //  * @throws CMSException  if an exception occurs during the verification process.
568    //  */
569    // public boolean verifySignatures(SignerInformationVerifierProvider verifierProvider, boolean ignoreCounterSignatures)
570    //     throws CMSException
571    // {
572    //     Collection signers = this.getSignerInfos().getSigners();
573    //
574    //     for (Iterator it = signers.iterator(); it.hasNext();)
575    //     {
576    //         SignerInformation signer = (SignerInformation)it.next();
577    //
578    //         try
579    //         {
580    //             SignerInformationVerifier verifier = verifierProvider.get(signer.getSID());
581    //
582    //             if (!signer.verify(verifier))
583    //             {
584    //                 return false;
585    //             }
586    //
587    //             if (!ignoreCounterSignatures)
588    //             {
589    //                 Collection counterSigners = signer.getCounterSignatures().getSigners();
590    //
591    //                 for  (Iterator cIt = counterSigners.iterator(); cIt.hasNext();)
592    //                 {
593    //                     SignerInformation counterSigner = (SignerInformation)cIt.next();
594    //                     SignerInformationVerifier counterVerifier = verifierProvider.get(signer.getSID());
595    //
596    //                     if (!counterSigner.verify(counterVerifier))
597    //                     {
598    //                         return false;
599    //                     }
600    //                 }
601    //             }
602    //         }
603    //         catch (OperatorCreationException e)
604    //         {
605    //             throw new CMSException("failure in verifier provider: " + e.getMessage(), e);
606    //         }
607    //     }
608    //
609    //     return true;
610    // }
611    // END android-removed
612
613    /**
614     * Replace the SignerInformation store associated with this
615     * CMSSignedData object with the new one passed in. You would
616     * probably only want to do this if you wanted to change the unsigned
617     * attributes associated with a signer, or perhaps delete one.
618     *
619     * @param signedData the signed data object to be used as a base.
620     * @param signerInformationStore the new signer information store to use.
621     * @return a new signed data object.
622     */
623    public static CMSSignedData replaceSigners(
624        CMSSignedData           signedData,
625        SignerInformationStore  signerInformationStore)
626    {
627        //
628        // copy
629        //
630        CMSSignedData   cms = new CMSSignedData(signedData);
631
632        //
633        // replace the store
634        //
635        cms.signerInfoStore = signerInformationStore;
636
637        //
638        // replace the signers in the SignedData object
639        //
640        ASN1EncodableVector digestAlgs = new ASN1EncodableVector();
641        ASN1EncodableVector vec = new ASN1EncodableVector();
642
643        Iterator    it = signerInformationStore.getSigners().iterator();
644        while (it.hasNext())
645        {
646            SignerInformation signer = (SignerInformation)it.next();
647            digestAlgs.add(CMSSignedHelper.INSTANCE.fixAlgID(signer.getDigestAlgorithmID()));
648            vec.add(signer.toASN1Structure());
649        }
650
651        ASN1Set             digests = new DERSet(digestAlgs);
652        ASN1Set             signers = new DERSet(vec);
653        ASN1Sequence        sD = (ASN1Sequence)signedData.signedData.toASN1Primitive();
654
655        vec = new ASN1EncodableVector();
656
657        //
658        // signers are the last item in the sequence.
659        //
660        vec.add(sD.getObjectAt(0)); // version
661        vec.add(digests);
662
663        for (int i = 2; i != sD.size() - 1; i++)
664        {
665            vec.add(sD.getObjectAt(i));
666        }
667
668        vec.add(signers);
669
670        cms.signedData = SignedData.getInstance(new BERSequence(vec));
671
672        //
673        // replace the contentInfo with the new one
674        //
675        cms.contentInfo = new ContentInfo(cms.contentInfo.getContentType(), cms.signedData);
676
677        return cms;
678    }
679
680    /**
681     * Replace the certificate and CRL information associated with this
682     * CMSSignedData object with the new one passed in.
683     *
684     * @param signedData the signed data object to be used as a base.
685     * @param certsAndCrls the new certificates and CRLs to be used.
686     * @return a new signed data object.
687     * @exception CMSException if there is an error processing the CertStore
688     * @deprecated use method taking Store arguments.
689     */
690    public static CMSSignedData replaceCertificatesAndCRLs(
691        CMSSignedData   signedData,
692        CertStore       certsAndCrls)
693        throws CMSException
694    {
695        //
696        // copy
697        //
698        CMSSignedData   cms = new CMSSignedData(signedData);
699
700        //
701        // replace the certs and crls in the SignedData object
702        //
703        ASN1Set             certs = null;
704        ASN1Set             crls = null;
705
706        try
707        {
708            ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCertificatesFromStore(certsAndCrls));
709
710            if (set.size() != 0)
711            {
712                certs = set;
713            }
714        }
715        catch (CertStoreException e)
716        {
717            throw new CMSException("error getting certs from certStore", e);
718        }
719
720        try
721        {
722            ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(certsAndCrls));
723
724            if (set.size() != 0)
725            {
726                crls = set;
727            }
728        }
729        catch (CertStoreException e)
730        {
731            throw new CMSException("error getting crls from certStore", e);
732        }
733
734        //
735        // replace the CMS structure.
736        //
737        cms.signedData = new SignedData(signedData.signedData.getDigestAlgorithms(),
738                                   signedData.signedData.getEncapContentInfo(),
739                                   certs,
740                                   crls,
741                                   signedData.signedData.getSignerInfos());
742
743        //
744        // replace the contentInfo with the new one
745        //
746        cms.contentInfo = new ContentInfo(cms.contentInfo.getContentType(), cms.signedData);
747
748        return cms;
749    }
750
751    /**
752     * Replace the certificate and CRL information associated with this
753     * CMSSignedData object with the new one passed in.
754     *
755     * @param signedData the signed data object to be used as a base.
756     * @param certificates the new certificates to be used.
757     * @param attrCerts the new attribute certificates to be used.
758     * @param crls the new CRLs to be used.
759     * @return a new signed data object.
760     * @exception CMSException if there is an error processing the CertStore
761     */
762    public static CMSSignedData replaceCertificatesAndCRLs(
763        CMSSignedData   signedData,
764        Store           certificates,
765        Store           attrCerts,
766        Store           crls)
767        throws CMSException
768    {
769        //
770        // copy
771        //
772        CMSSignedData   cms = new CMSSignedData(signedData);
773
774        //
775        // replace the certs and crls in the SignedData object
776        //
777        ASN1Set certSet = null;
778        ASN1Set crlSet = null;
779
780        if (certificates != null || attrCerts != null)
781        {
782            List certs = new ArrayList();
783
784            if (certificates != null)
785            {
786                certs.addAll(CMSUtils.getCertificatesFromStore(certificates));
787            }
788            if (attrCerts != null)
789            {
790                certs.addAll(CMSUtils.getAttributeCertificatesFromStore(attrCerts));
791            }
792
793            ASN1Set set = CMSUtils.createBerSetFromList(certs);
794
795            if (set.size() != 0)
796            {
797                certSet = set;
798            }
799        }
800
801        if (crls != null)
802        {
803            ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(crls));
804
805            if (set.size() != 0)
806            {
807                crlSet = set;
808            }
809        }
810
811        //
812        // replace the CMS structure.
813        //
814        cms.signedData = new SignedData(signedData.signedData.getDigestAlgorithms(),
815                                   signedData.signedData.getEncapContentInfo(),
816                                   certSet,
817                                   crlSet,
818                                   signedData.signedData.getSignerInfos());
819
820        //
821        // replace the contentInfo with the new one
822        //
823        cms.contentInfo = new ContentInfo(cms.contentInfo.getContentType(), cms.signedData);
824
825        return cms;
826    }
827}
828