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