001package org.apache.commons.ssl.org.bouncycastle.asn1.cms;
002
003import java.util.Enumeration;
004
005import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1OctetString;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Set;
012import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
013import org.apache.commons.ssl.org.bouncycastle.asn1.BERSequence;
014import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject;
015import org.apache.commons.ssl.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
016
017/**
018 * <a href="http://tools.ietf.org/html/rfc5652#section-9.1">RFC 5652</a> section 9.1:
019 * The AuthenticatedData carries AuthAttributes and other data
020 * which define what really is being signed.
021 * <p>
022 * <pre>
023 * AuthenticatedData ::= SEQUENCE {
024 *       version CMSVersion,
025 *       originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
026 *       recipientInfos RecipientInfos,
027 *       macAlgorithm MessageAuthenticationCodeAlgorithm,
028 *       digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
029 *       encapContentInfo EncapsulatedContentInfo,
030 *       authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
031 *       mac MessageAuthenticationCode,
032 *       unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
033 *
034 * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
035 *
036 * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
037 *
038 * MessageAuthenticationCode ::= OCTET STRING
039 * </pre>
040 */
041public class AuthenticatedData
042    extends ASN1Object
043{
044    private ASN1Integer version;
045    private OriginatorInfo originatorInfo;
046    private ASN1Set recipientInfos;
047    private AlgorithmIdentifier macAlgorithm;
048    private AlgorithmIdentifier digestAlgorithm;
049    private ContentInfo encapsulatedContentInfo;
050    private ASN1Set authAttrs;
051    private ASN1OctetString mac;
052    private ASN1Set unauthAttrs;
053
054    public AuthenticatedData(
055        OriginatorInfo originatorInfo,
056        ASN1Set recipientInfos,
057        AlgorithmIdentifier macAlgorithm,
058        AlgorithmIdentifier digestAlgorithm,
059        ContentInfo encapsulatedContent,
060        ASN1Set authAttrs,
061        ASN1OctetString mac,
062        ASN1Set unauthAttrs)
063    {
064        if (digestAlgorithm != null || authAttrs != null)
065        {
066            if (digestAlgorithm == null || authAttrs == null)
067            {
068                throw new IllegalArgumentException("digestAlgorithm and authAttrs must be set together");
069            }
070        }
071
072        version = new ASN1Integer(calculateVersion(originatorInfo));
073        
074        this.originatorInfo = originatorInfo;
075        this.macAlgorithm = macAlgorithm;
076        this.digestAlgorithm = digestAlgorithm;
077        this.recipientInfos = recipientInfos;
078        this.encapsulatedContentInfo = encapsulatedContent;
079        this.authAttrs = authAttrs;
080        this.mac = mac;
081        this.unauthAttrs = unauthAttrs;
082    }
083
084    /**
085     * @deprecated use getInstance()
086     */
087    public AuthenticatedData(
088        ASN1Sequence seq)
089    {
090        int index = 0;
091
092        version = (ASN1Integer)seq.getObjectAt(index++);
093
094        Object tmp = seq.getObjectAt(index++);
095
096        if (tmp instanceof ASN1TaggedObject)
097        {
098            originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false);
099            tmp = seq.getObjectAt(index++);
100        }
101
102        recipientInfos = ASN1Set.getInstance(tmp);
103        macAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++));
104
105        tmp = seq.getObjectAt(index++);
106
107        if (tmp instanceof ASN1TaggedObject)
108        {
109            digestAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)tmp, false);
110            tmp = seq.getObjectAt(index++);
111        }
112
113        encapsulatedContentInfo = ContentInfo.getInstance(tmp);
114
115        tmp = seq.getObjectAt(index++);
116
117        if (tmp instanceof ASN1TaggedObject)
118        {
119            authAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false);
120            tmp = seq.getObjectAt(index++);
121        }
122
123        mac = ASN1OctetString.getInstance(tmp);
124        
125        if (seq.size() > index)
126        {
127            unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false);
128        }
129    }
130
131    /**
132     * Return an AuthenticatedData object from a tagged object.
133     *
134     * @param obj      the tagged object holding the object we want.
135     * @param explicit true if the object is meant to be explicitly
136     *                 tagged false otherwise.
137     * @throws IllegalArgumentException if the object held by the
138     *                                  tagged object cannot be converted.
139     */
140    public static AuthenticatedData getInstance(
141        ASN1TaggedObject obj,
142        boolean explicit)
143    {
144        return getInstance(ASN1Sequence.getInstance(obj, explicit));
145    }
146
147    /**
148     * Return an AuthenticatedData object from the given object.
149     * <p>
150     * Accepted inputs:
151     * <ul>
152     * <li> null &rarr; null
153     * <li> {@link AuthenticatedData} object
154     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with AuthenticatedData structure inside
155     * </ul>
156     *
157     * @param obj the object we want converted.
158     * @throws IllegalArgumentException if the object cannot be converted.
159     */
160    public static AuthenticatedData getInstance(
161        Object obj)
162    {
163        if (obj == null || obj instanceof AuthenticatedData)
164        {
165            return (AuthenticatedData)obj;
166        }
167
168        if (obj instanceof ASN1Sequence)
169        {
170            return new AuthenticatedData((ASN1Sequence)obj);
171        }
172
173        throw new IllegalArgumentException("Invalid AuthenticatedData: " + obj.getClass().getName());
174    }
175
176    public ASN1Integer getVersion()
177    {
178        return version;
179    }
180
181    public OriginatorInfo getOriginatorInfo()
182    {
183        return originatorInfo;
184    }
185
186    public ASN1Set getRecipientInfos()
187    {
188        return recipientInfos;
189    }
190
191    public AlgorithmIdentifier getMacAlgorithm()
192    {
193        return macAlgorithm;
194    }
195
196    public AlgorithmIdentifier getDigestAlgorithm()
197    {
198        return digestAlgorithm;
199    }
200
201    public ContentInfo getEncapsulatedContentInfo()
202    {
203        return encapsulatedContentInfo;
204    }
205
206    public ASN1Set getAuthAttrs()
207    {
208        return authAttrs;
209    }
210
211    public ASN1OctetString getMac()
212    {
213        return mac;
214    }
215
216    public ASN1Set getUnauthAttrs()
217    {
218        return unauthAttrs;
219    }
220
221    /**
222     * Produce an object suitable for an ASN1OutputStream.
223     */
224    public ASN1Primitive toASN1Primitive()
225    {
226        ASN1EncodableVector v = new ASN1EncodableVector();
227
228        v.add(version);
229
230        if (originatorInfo != null)
231        {
232            v.add(new DERTaggedObject(false, 0, originatorInfo));
233        }
234
235        v.add(recipientInfos);
236        v.add(macAlgorithm);
237
238        if (digestAlgorithm != null)
239        {
240            v.add(new DERTaggedObject(false, 1, digestAlgorithm));
241        }
242
243        v.add(encapsulatedContentInfo);
244
245        if (authAttrs != null)
246        {
247            v.add(new DERTaggedObject(false, 2, authAttrs));
248        }
249
250        v.add(mac);
251
252        if (unauthAttrs != null)
253        {
254            v.add(new DERTaggedObject(false, 3, unauthAttrs));
255        }
256
257        return new BERSequence(v);
258    }
259
260    public static int calculateVersion(OriginatorInfo origInfo)
261    {
262        if (origInfo == null)
263        {
264            return 0;
265        }
266        else
267        {
268            int ver = 0;
269
270            for (Enumeration e = origInfo.getCertificates().getObjects(); e.hasMoreElements();)
271            {
272                Object obj = e.nextElement();
273
274                if (obj instanceof ASN1TaggedObject)
275                {
276                    ASN1TaggedObject tag = (ASN1TaggedObject)obj;
277
278                    if (tag.getTagNo() == 2)
279                    {
280                        ver = 1;
281                    }
282                    else if (tag.getTagNo() == 3)
283                    {
284                        ver = 3;
285                        break;
286                    }
287                }
288            }
289
290            if (origInfo.getCRLs() != null)
291            {
292                for (Enumeration e = origInfo.getCRLs().getObjects(); e.hasMoreElements();)
293                {
294                    Object obj = e.nextElement();
295
296                    if (obj instanceof ASN1TaggedObject)
297                    {
298                        ASN1TaggedObject tag = (ASN1TaggedObject)obj;
299
300                        if (tag.getTagNo() == 1)
301                        {
302                            ver = 3;
303                            break;
304                        }
305                    }
306                }
307            }
308
309            return ver;
310        }
311    }
312}