1package org.bouncycastle.asn1.cms;
2
3import java.util.Enumeration;
4
5import org.bouncycastle.asn1.ASN1EncodableVector;
6import org.bouncycastle.asn1.ASN1Integer;
7import org.bouncycastle.asn1.ASN1Object;
8import org.bouncycastle.asn1.ASN1ObjectIdentifier;
9import org.bouncycastle.asn1.ASN1Primitive;
10import org.bouncycastle.asn1.ASN1Sequence;
11import org.bouncycastle.asn1.ASN1Set;
12import org.bouncycastle.asn1.ASN1TaggedObject;
13import org.bouncycastle.asn1.BERSequence;
14import org.bouncycastle.asn1.BERSet;
15import org.bouncycastle.asn1.BERTaggedObject;
16import org.bouncycastle.asn1.DERTaggedObject;
17
18/**
19 * a signed data object.
20 */
21public class SignedData
22    extends ASN1Object
23{
24    private ASN1Integer version;
25    private ASN1Set     digestAlgorithms;
26    private ContentInfo contentInfo;
27    private ASN1Set     certificates;
28    private ASN1Set     crls;
29    private ASN1Set     signerInfos;
30    private boolean certsBer;
31    private boolean        crlsBer;
32
33    public static SignedData getInstance(
34        Object  o)
35    {
36        if (o instanceof SignedData)
37        {
38            return (SignedData)o;
39        }
40        else if (o != null)
41        {
42            return new SignedData(ASN1Sequence.getInstance(o));
43        }
44
45        return null;
46    }
47
48    public SignedData(
49        ASN1Set     digestAlgorithms,
50        ContentInfo contentInfo,
51        ASN1Set     certificates,
52        ASN1Set     crls,
53        ASN1Set     signerInfos)
54    {
55        this.version = calculateVersion(contentInfo.getContentType(), certificates, crls, signerInfos);
56        this.digestAlgorithms = digestAlgorithms;
57        this.contentInfo = contentInfo;
58        this.certificates = certificates;
59        this.crls = crls;
60        this.signerInfos = signerInfos;
61        this.crlsBer = crls instanceof BERSet;
62        this.certsBer = certificates instanceof BERSet;
63    }
64
65
66    // RFC3852, section 5.1:
67    // IF ((certificates is present) AND
68    //    (any certificates with a type of other are present)) OR
69    //    ((crls is present) AND
70    //    (any crls with a type of other are present))
71    // THEN version MUST be 5
72    // ELSE
73    //    IF (certificates is present) AND
74    //       (any version 2 attribute certificates are present)
75    //    THEN version MUST be 4
76    //    ELSE
77    //       IF ((certificates is present) AND
78    //          (any version 1 attribute certificates are present)) OR
79    //          (any SignerInfo structures are version 3) OR
80    //          (encapContentInfo eContentType is other than id-data)
81    //       THEN version MUST be 3
82    //       ELSE version MUST be 1
83    //
84    private ASN1Integer calculateVersion(
85        ASN1ObjectIdentifier contentOid,
86        ASN1Set certs,
87        ASN1Set crls,
88        ASN1Set signerInfs)
89    {
90        boolean otherCert = false;
91        boolean otherCrl = false;
92        boolean attrCertV1Found = false;
93        boolean attrCertV2Found = false;
94
95        if (certs != null)
96        {
97            for (Enumeration en = certs.getObjects(); en.hasMoreElements();)
98            {
99                Object obj = en.nextElement();
100                if (obj instanceof ASN1TaggedObject)
101                {
102                    ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj);
103
104                    if (tagged.getTagNo() == 1)
105                    {
106                        attrCertV1Found = true;
107                    }
108                    else if (tagged.getTagNo() == 2)
109                    {
110                        attrCertV2Found = true;
111                    }
112                    else if (tagged.getTagNo() == 3)
113                    {
114                        otherCert = true;
115                    }
116                }
117            }
118        }
119
120        if (otherCert)
121        {
122            return new ASN1Integer(5);
123        }
124
125        if (crls != null)         // no need to check if otherCert is true
126        {
127            for (Enumeration en = crls.getObjects(); en.hasMoreElements();)
128            {
129                Object obj = en.nextElement();
130                if (obj instanceof ASN1TaggedObject)
131                {
132                    otherCrl = true;
133                }
134            }
135        }
136
137        if (otherCrl)
138        {
139            return new ASN1Integer(5);
140        }
141
142        if (attrCertV2Found)
143        {
144            return new ASN1Integer(4);
145        }
146
147        if (attrCertV1Found)
148        {
149            return new ASN1Integer(3);
150        }
151
152        if (checkForVersion3(signerInfs))
153        {
154            return new ASN1Integer(3);
155        }
156
157        if (!CMSObjectIdentifiers.data.equals(contentOid))
158        {
159            return new ASN1Integer(3);
160        }
161
162        return new ASN1Integer(1);
163    }
164
165    private boolean checkForVersion3(ASN1Set signerInfs)
166    {
167        for (Enumeration e = signerInfs.getObjects(); e.hasMoreElements();)
168        {
169            SignerInfo s = SignerInfo.getInstance(e.nextElement());
170
171            if (s.getVersion().getValue().intValue() == 3)
172            {
173                return true;
174            }
175        }
176
177        return false;
178    }
179
180    private SignedData(
181        ASN1Sequence seq)
182    {
183        Enumeration     e = seq.getObjects();
184
185        version = ASN1Integer.getInstance(e.nextElement());
186        digestAlgorithms = ((ASN1Set)e.nextElement());
187        contentInfo = ContentInfo.getInstance(e.nextElement());
188
189        while (e.hasMoreElements())
190        {
191            ASN1Primitive o = (ASN1Primitive)e.nextElement();
192
193            //
194            // an interesting feature of SignedData is that there appear
195            // to be varying implementations...
196            // for the moment we ignore anything which doesn't fit.
197            //
198            if (o instanceof ASN1TaggedObject)
199            {
200                ASN1TaggedObject tagged = (ASN1TaggedObject)o;
201
202                switch (tagged.getTagNo())
203                {
204                case 0:
205                    certsBer = tagged instanceof BERTaggedObject;
206                    certificates = ASN1Set.getInstance(tagged, false);
207                    break;
208                case 1:
209                    crlsBer = tagged instanceof BERTaggedObject;
210                    crls = ASN1Set.getInstance(tagged, false);
211                    break;
212                default:
213                    throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
214                }
215            }
216            else
217            {
218                signerInfos = (ASN1Set)o;
219            }
220        }
221    }
222
223    public ASN1Integer getVersion()
224    {
225        return version;
226    }
227
228    public ASN1Set getDigestAlgorithms()
229    {
230        return digestAlgorithms;
231    }
232
233    public ContentInfo getEncapContentInfo()
234    {
235        return contentInfo;
236    }
237
238    public ASN1Set getCertificates()
239    {
240        return certificates;
241    }
242
243    public ASN1Set getCRLs()
244    {
245        return crls;
246    }
247
248    public ASN1Set getSignerInfos()
249    {
250        return signerInfos;
251    }
252
253    /**
254     * Produce an object suitable for an ASN1OutputStream.
255     * <pre>
256     * SignedData ::= SEQUENCE {
257     *     version CMSVersion,
258     *     digestAlgorithms DigestAlgorithmIdentifiers,
259     *     encapContentInfo EncapsulatedContentInfo,
260     *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
261     *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
262     *     signerInfos SignerInfos
263     *   }
264     * </pre>
265     */
266    public ASN1Primitive toASN1Primitive()
267    {
268        ASN1EncodableVector  v = new ASN1EncodableVector();
269
270        v.add(version);
271        v.add(digestAlgorithms);
272        v.add(contentInfo);
273
274        if (certificates != null)
275        {
276            if (certsBer)
277            {
278                v.add(new BERTaggedObject(false, 0, certificates));
279            }
280            else
281            {
282                v.add(new DERTaggedObject(false, 0, certificates));
283            }
284        }
285
286        if (crls != null)
287        {
288            if (crlsBer)
289            {
290                v.add(new BERTaggedObject(false, 1, crls));
291            }
292            else
293            {
294                v.add(new DERTaggedObject(false, 1, crls));
295            }
296        }
297
298        v.add(signerInfos);
299
300        return new BERSequence(v);
301    }
302}
303