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.ASN1Primitive;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Set;
011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
012import org.apache.commons.ssl.org.bouncycastle.asn1.BERSequence;
013import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject;
014
015/**
016 * <a href="http://tools.ietf.org/html/rfc5652#section-6.1">RFC 5652</a> EnvelopedData object.
017 * <pre>
018 * EnvelopedData ::= SEQUENCE {
019 *     version CMSVersion,
020 *     originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
021 *     recipientInfos RecipientInfos,
022 *     encryptedContentInfo EncryptedContentInfo,
023 *     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL 
024 * }
025 * </pre>
026 */
027public class EnvelopedData
028    extends ASN1Object
029{
030    private ASN1Integer              version;
031    private OriginatorInfo          originatorInfo;
032    private ASN1Set                 recipientInfos;
033    private EncryptedContentInfo    encryptedContentInfo;
034    private ASN1Set                 unprotectedAttrs;
035
036    public EnvelopedData(
037        OriginatorInfo          originatorInfo,
038        ASN1Set                 recipientInfos,
039        EncryptedContentInfo    encryptedContentInfo,
040        ASN1Set                 unprotectedAttrs)
041    {
042        version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, unprotectedAttrs));
043
044        this.originatorInfo = originatorInfo;
045        this.recipientInfos = recipientInfos;
046        this.encryptedContentInfo = encryptedContentInfo;
047        this.unprotectedAttrs = unprotectedAttrs;
048    }
049
050    public EnvelopedData(
051        OriginatorInfo          originatorInfo,
052        ASN1Set                 recipientInfos,
053        EncryptedContentInfo    encryptedContentInfo,
054        Attributes              unprotectedAttrs)
055    {
056        version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, ASN1Set.getInstance(unprotectedAttrs)));
057
058        this.originatorInfo = originatorInfo;
059        this.recipientInfos = recipientInfos;
060        this.encryptedContentInfo = encryptedContentInfo;
061        this.unprotectedAttrs = ASN1Set.getInstance(unprotectedAttrs);
062    }
063
064    /**
065     * @deprecated use getInstance()
066     */
067    public EnvelopedData(
068        ASN1Sequence seq)
069    {
070        int     index = 0;
071        
072        version = (ASN1Integer)seq.getObjectAt(index++);
073        
074        Object  tmp = seq.getObjectAt(index++);
075
076        if (tmp instanceof ASN1TaggedObject)
077        {
078            originatorInfo = OriginatorInfo.getInstance((ASN1TaggedObject)tmp, false);
079            tmp = seq.getObjectAt(index++);
080        }
081
082        recipientInfos = ASN1Set.getInstance(tmp);
083        
084        encryptedContentInfo = EncryptedContentInfo.getInstance(seq.getObjectAt(index++));
085        
086        if(seq.size() > index)
087        {
088            unprotectedAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false);
089        }
090    }
091    
092    /**
093     * Return an EnvelopedData object from a tagged object.
094     *
095     * @param obj the tagged object holding the object we want.
096     * @param explicit true if the object is meant to be explicitly
097     *              tagged false otherwise.
098     * @exception IllegalArgumentException if the object held by the
099     *          tagged object cannot be converted.
100     */
101    public static EnvelopedData getInstance(
102        ASN1TaggedObject obj,
103        boolean explicit)
104    {
105        return getInstance(ASN1Sequence.getInstance(obj, explicit));
106    }
107    
108    /**
109     * Return an EnvelopedData object from the given object.
110     * <p>
111     * Accepted inputs:
112     * <ul>
113     * <li> null &rarr; null
114     * <li> {@link EnvelopedData} object
115     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with EnvelopedData structure inside
116     * </ul>
117     *
118     * @param obj the object we want converted.
119     * @exception IllegalArgumentException if the object cannot be converted.
120     */
121    public static EnvelopedData getInstance(
122        Object obj)
123    {
124        if (obj instanceof EnvelopedData)
125        {
126            return (EnvelopedData)obj;
127        }
128        
129        if (obj != null)
130        {
131            return new EnvelopedData(ASN1Sequence.getInstance(obj));
132        }
133        
134        return null;
135    }
136
137    public ASN1Integer getVersion()
138    {
139        return version;
140    }
141    
142    public OriginatorInfo getOriginatorInfo()
143    {
144        return originatorInfo;
145    }
146
147    public ASN1Set getRecipientInfos()
148    {
149        return recipientInfos;
150    }
151
152    public EncryptedContentInfo getEncryptedContentInfo()
153    {
154        return encryptedContentInfo;
155    }
156
157    public ASN1Set getUnprotectedAttrs()
158    {
159        return unprotectedAttrs;
160    }
161
162    /** 
163     * Produce an object suitable for an ASN1OutputStream.
164     */
165    public ASN1Primitive toASN1Primitive()
166    {
167        ASN1EncodableVector  v = new ASN1EncodableVector();
168        
169        v.add(version);
170
171        if (originatorInfo != null)
172        {
173            v.add(new DERTaggedObject(false, 0, originatorInfo));
174        }
175
176        v.add(recipientInfos);
177        v.add(encryptedContentInfo);
178
179        if (unprotectedAttrs != null)
180        {
181            v.add(new DERTaggedObject(false, 1, unprotectedAttrs));
182        }
183        
184        return new BERSequence(v);
185    }
186
187    public static int calculateVersion(OriginatorInfo originatorInfo, ASN1Set recipientInfos, ASN1Set unprotectedAttrs)
188    {
189        int version;
190
191        if (originatorInfo != null || unprotectedAttrs != null)
192        {
193            version = 2;
194        }
195        else
196        {
197            version = 0;
198
199            Enumeration e = recipientInfos.getObjects();
200
201            while (e.hasMoreElements())
202            {
203                RecipientInfo   ri = RecipientInfo.getInstance(e.nextElement());
204
205                if (ri.getVersion().getValue().intValue() != version)
206                {
207                    version = 2;
208                    break;
209                }
210            }
211        }
212
213        return version;
214    }
215}