1 package org.bouncycastle.asn1.cms;
2 
3 import java.util.Enumeration;
4 
5 import org.bouncycastle.asn1.ASN1EncodableVector;
6 import org.bouncycastle.asn1.ASN1Integer;
7 import org.bouncycastle.asn1.ASN1Object;
8 import org.bouncycastle.asn1.ASN1OctetString;
9 import org.bouncycastle.asn1.ASN1Primitive;
10 import org.bouncycastle.asn1.ASN1Sequence;
11 import org.bouncycastle.asn1.ASN1Set;
12 import org.bouncycastle.asn1.ASN1TaggedObject;
13 import org.bouncycastle.asn1.BERSequence;
14 import org.bouncycastle.asn1.DERTaggedObject;
15 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
16 
17 /**
18  * <a href="https://tools.ietf.org/html/rfc5652#section-9.1">RFC 5652</a> section 9.1:
19  * The AuthenticatedData carries AuthAttributes and other data
20  * which define what really is being signed.
21  * <pre>
22  * AuthenticatedData ::= SEQUENCE {
23  *       version CMSVersion,
24  *       originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
25  *       recipientInfos RecipientInfos,
26  *       macAlgorithm MessageAuthenticationCodeAlgorithm,
27  *       digestAlgorithm [1] DigestAlgorithmIdentifier OPTIONAL,
28  *       encapContentInfo EncapsulatedContentInfo,
29  *       authAttrs [2] IMPLICIT AuthAttributes OPTIONAL,
30  *       mac MessageAuthenticationCode,
31  *       unauthAttrs [3] IMPLICIT UnauthAttributes OPTIONAL }
32  *
33  * AuthAttributes ::= SET SIZE (1..MAX) OF Attribute
34  *
35  * UnauthAttributes ::= SET SIZE (1..MAX) OF Attribute
36  *
37  * MessageAuthenticationCode ::= OCTET STRING
38  * </pre>
39  */
40 public class AuthenticatedData
41     extends ASN1Object
42 {
43     private ASN1Integer version;
44     private OriginatorInfo originatorInfo;
45     private ASN1Set recipientInfos;
46     private AlgorithmIdentifier macAlgorithm;
47     private AlgorithmIdentifier digestAlgorithm;
48     private ContentInfo encapsulatedContentInfo;
49     private ASN1Set authAttrs;
50     private ASN1OctetString mac;
51     private ASN1Set unauthAttrs;
52 
AuthenticatedData( OriginatorInfo originatorInfo, ASN1Set recipientInfos, AlgorithmIdentifier macAlgorithm, AlgorithmIdentifier digestAlgorithm, ContentInfo encapsulatedContent, ASN1Set authAttrs, ASN1OctetString mac, ASN1Set unauthAttrs)53     public AuthenticatedData(
54         OriginatorInfo originatorInfo,
55         ASN1Set recipientInfos,
56         AlgorithmIdentifier macAlgorithm,
57         AlgorithmIdentifier digestAlgorithm,
58         ContentInfo encapsulatedContent,
59         ASN1Set authAttrs,
60         ASN1OctetString mac,
61         ASN1Set unauthAttrs)
62     {
63         if (digestAlgorithm != null || authAttrs != null)
64         {
65             if (digestAlgorithm == null || authAttrs == null)
66             {
67                 throw new IllegalArgumentException("digestAlgorithm and authAttrs must be set together");
68             }
69         }
70 
71         version = new ASN1Integer(calculateVersion(originatorInfo));
72 
73         this.originatorInfo = originatorInfo;
74         this.macAlgorithm = macAlgorithm;
75         this.digestAlgorithm = digestAlgorithm;
76         this.recipientInfos = recipientInfos;
77         this.encapsulatedContentInfo = encapsulatedContent;
78         this.authAttrs = authAttrs;
79         this.mac = mac;
80         this.unauthAttrs = unauthAttrs;
81     }
82 
AuthenticatedData( ASN1Sequence seq)83     private AuthenticatedData(
84         ASN1Sequence seq)
85     {
86         int index = 0;
87 
88         version = (ASN1Integer)seq.getObjectAt(index++);
89 
90         Object tmp = seq.getObjectAt(index++);
91 
92         if (tmp instanceof ASN1TaggedObject)
93         {
94             originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false);
95             tmp = seq.getObjectAt(index++);
96         }
97 
98         recipientInfos = ASN1Set.getInstance(tmp);
99         macAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++));
100 
101         tmp = seq.getObjectAt(index++);
102 
103         if (tmp instanceof ASN1TaggedObject)
104         {
105             digestAlgorithm = AlgorithmIdentifier.getInstance((ASN1TaggedObject)tmp, false);
106             tmp = seq.getObjectAt(index++);
107         }
108 
109         encapsulatedContentInfo = ContentInfo.getInstance(tmp);
110 
111         tmp = seq.getObjectAt(index++);
112 
113         if (tmp instanceof ASN1TaggedObject)
114         {
115             authAttrs = ASN1Set.getInstance((ASN1TaggedObject)tmp, false);
116             tmp = seq.getObjectAt(index++);
117         }
118 
119         mac = ASN1OctetString.getInstance(tmp);
120 
121         if (seq.size() > index)
122         {
123             unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false);
124         }
125     }
126 
127     /**
128      * Return an AuthenticatedData object from a tagged object.
129      *
130      * @param obj      the tagged object holding the object we want.
131      * @param explicit true if the object is meant to be explicitly
132      *                 tagged false otherwise.
133      * @return a reference that can be assigned to AuthenticatedData (may be null)
134      * @throws IllegalArgumentException if the object held by the
135      *                                  tagged object cannot be converted.
136      */
getInstance( ASN1TaggedObject obj, boolean explicit)137     public static AuthenticatedData getInstance(
138         ASN1TaggedObject obj,
139         boolean explicit)
140     {
141         return getInstance(ASN1Sequence.getInstance(obj, explicit));
142     }
143 
144     /**
145      * Return an AuthenticatedData object from the given object.
146      * <p>
147      * Accepted inputs:
148      * <ul>
149      * <li> null &rarr; null
150      * <li> {@link AuthenticatedData} object
151      * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with AuthenticatedData structure inside
152      * </ul>
153      *
154      * @param obj the object we want converted.
155      * @return a reference that can be assigned to AuthenticatedData (may be null)
156      * @throws IllegalArgumentException if the object cannot be converted.
157      */
getInstance( Object obj)158     public static AuthenticatedData getInstance(
159         Object obj)
160     {
161         if (obj instanceof AuthenticatedData)
162         {
163             return (AuthenticatedData)obj;
164         }
165         else if (obj != null)
166         {
167             return new AuthenticatedData(ASN1Sequence.getInstance(obj));
168         }
169 
170         return null;
171     }
172 
getVersion()173     public ASN1Integer getVersion()
174     {
175         return version;
176     }
177 
getOriginatorInfo()178     public OriginatorInfo getOriginatorInfo()
179     {
180         return originatorInfo;
181     }
182 
getRecipientInfos()183     public ASN1Set getRecipientInfos()
184     {
185         return recipientInfos;
186     }
187 
getMacAlgorithm()188     public AlgorithmIdentifier getMacAlgorithm()
189     {
190         return macAlgorithm;
191     }
192 
getDigestAlgorithm()193     public AlgorithmIdentifier getDigestAlgorithm()
194     {
195         return digestAlgorithm;
196     }
197 
getEncapsulatedContentInfo()198     public ContentInfo getEncapsulatedContentInfo()
199     {
200         return encapsulatedContentInfo;
201     }
202 
getAuthAttrs()203     public ASN1Set getAuthAttrs()
204     {
205         return authAttrs;
206     }
207 
getMac()208     public ASN1OctetString getMac()
209     {
210         return mac;
211     }
212 
getUnauthAttrs()213     public ASN1Set getUnauthAttrs()
214     {
215         return unauthAttrs;
216     }
217 
218     /**
219      * Produce an object suitable for an ASN1OutputStream.
220      */
toASN1Primitive()221     public ASN1Primitive toASN1Primitive()
222     {
223         ASN1EncodableVector v = new ASN1EncodableVector(9);
224 
225         v.add(version);
226 
227         if (originatorInfo != null)
228         {
229             v.add(new DERTaggedObject(false, 0, originatorInfo));
230         }
231 
232         v.add(recipientInfos);
233         v.add(macAlgorithm);
234 
235         if (digestAlgorithm != null)
236         {
237             v.add(new DERTaggedObject(false, 1, digestAlgorithm));
238         }
239 
240         v.add(encapsulatedContentInfo);
241 
242         if (authAttrs != null)
243         {
244             v.add(new DERTaggedObject(false, 2, authAttrs));
245         }
246 
247         v.add(mac);
248 
249         if (unauthAttrs != null)
250         {
251             v.add(new DERTaggedObject(false, 3, unauthAttrs));
252         }
253 
254         return new BERSequence(v);
255     }
256 
calculateVersion(OriginatorInfo origInfo)257     public static int calculateVersion(OriginatorInfo origInfo)
258     {
259         if (origInfo == null)
260         {
261             return 0;
262         }
263         else
264         {
265             int ver = 0;
266 
267             for (Enumeration e = origInfo.getCertificates().getObjects(); e.hasMoreElements();)
268             {
269                 Object obj = e.nextElement();
270 
271                 if (obj instanceof ASN1TaggedObject)
272                 {
273                     ASN1TaggedObject tag = (ASN1TaggedObject)obj;
274 
275                     if (tag.getTagNo() == 2)
276                     {
277                         ver = 1;
278                     }
279                     else if (tag.getTagNo() == 3)
280                     {
281                         ver = 3;
282                         break;
283                     }
284                 }
285             }
286 
287             if (origInfo.getCRLs() != null)
288             {
289                 for (Enumeration e = origInfo.getCRLs().getObjects(); e.hasMoreElements();)
290                 {
291                     Object obj = e.nextElement();
292 
293                     if (obj instanceof ASN1TaggedObject)
294                     {
295                         ASN1TaggedObject tag = (ASN1TaggedObject)obj;
296 
297                         if (tag.getTagNo() == 1)
298                         {
299                             ver = 3;
300                             break;
301                         }
302                     }
303                 }
304             }
305 
306             return ver;
307         }
308     }
309 }
310