001package org.apache.commons.ssl.org.bouncycastle.asn1.cms;
002
003import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Choice;
004import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Encodable;
005import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Integer;
006import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
010import org.apache.commons.ssl.org.bouncycastle.asn1.DERTaggedObject;
011
012/**
013 * <a href="http://tools.ietf.org/html/rfc5652#section-6.2">RFC 5652</a>:
014 * Content encryption key delivery mechanisms.
015 * <p>
016 * <pre>
017 * RecipientInfo ::= CHOICE {
018 *     ktri      KeyTransRecipientInfo,
019 *     kari  [1] KeyAgreeRecipientInfo,
020 *     kekri [2] KEKRecipientInfo,
021 *     pwri  [3] PasswordRecipientInfo,
022 *     ori   [4] OtherRecipientInfo }
023 * </pre>
024 */
025public class RecipientInfo
026    extends ASN1Object
027    implements ASN1Choice
028{
029    ASN1Encodable    info;
030
031    public RecipientInfo(
032        KeyTransRecipientInfo info)
033    {
034        this.info = info;
035    }
036
037    public RecipientInfo(
038        KeyAgreeRecipientInfo info)
039    {
040        this.info = new DERTaggedObject(false, 1, info);
041    }
042
043    public RecipientInfo(
044        KEKRecipientInfo info)
045    {
046        this.info = new DERTaggedObject(false, 2, info);
047    }
048
049    public RecipientInfo(
050        PasswordRecipientInfo info)
051    {
052        this.info = new DERTaggedObject(false, 3, info);
053    }
054
055    public RecipientInfo(
056        OtherRecipientInfo info)
057    {
058        this.info = new DERTaggedObject(false, 4, info);
059    }
060
061    public RecipientInfo(
062        ASN1Primitive   info)
063    {
064        this.info = info;
065    }
066
067    /**
068     * Return a RecipientInfo object from the given object.
069     * <p>
070     * Accepted inputs:
071     * <ul>
072     * <li> null &rarr; null
073     * <li> {@link RecipientInfo} object
074     * <li> {@link org.bouncycastle.asn1.ASN1Sequence#getInstance(java.lang.Object) ASN1Sequence} input formats with RecipientInfo structure inside
075     * <li> {@link org.bouncycastle.asn1.ASN1TaggedObject#getInstance(java.lang.Object) ASN1TaggedObject} input formats with RecipientInfo structure inside
076     * </ul>
077     *
078     * @param o the object we want converted.
079     * @exception IllegalArgumentException if the object cannot be converted.
080     */
081    public static RecipientInfo getInstance(
082        Object  o)
083    {
084        if (o == null || o instanceof RecipientInfo)
085        {
086            return (RecipientInfo)o;
087        }
088        else if (o instanceof ASN1Sequence)
089        {
090            return new RecipientInfo((ASN1Sequence)o);
091        }
092        else if (o instanceof ASN1TaggedObject)
093        {
094            return new RecipientInfo((ASN1TaggedObject)o);
095        }
096
097        throw new IllegalArgumentException("unknown object in factory: "
098                                                    + o.getClass().getName());
099    }
100
101    public ASN1Integer getVersion()
102    {
103        if (info instanceof ASN1TaggedObject)
104        {
105            ASN1TaggedObject o = (ASN1TaggedObject)info;
106
107            switch (o.getTagNo())
108            {
109            case 1:
110                return KeyAgreeRecipientInfo.getInstance(o, false).getVersion();
111            case 2:
112                return getKEKInfo(o).getVersion();
113            case 3:
114                return PasswordRecipientInfo.getInstance(o, false).getVersion();
115            case 4:
116                return new ASN1Integer(0);    // no syntax version for OtherRecipientInfo
117            default:
118                throw new IllegalStateException("unknown tag");
119            }
120        }
121
122        return KeyTransRecipientInfo.getInstance(info).getVersion();
123    }
124
125    public boolean isTagged()
126    {
127        return (info instanceof ASN1TaggedObject);
128    }
129
130    public ASN1Encodable getInfo()
131    {
132        if (info instanceof ASN1TaggedObject)
133        {
134            ASN1TaggedObject o = (ASN1TaggedObject)info;
135
136            switch (o.getTagNo())
137            {
138            case 1:
139                return KeyAgreeRecipientInfo.getInstance(o, false);
140            case 2:
141                return getKEKInfo(o);
142            case 3:
143                return PasswordRecipientInfo.getInstance(o, false);
144            case 4:
145                return OtherRecipientInfo.getInstance(o, false);
146            default:
147                throw new IllegalStateException("unknown tag");
148            }
149        }
150
151        return KeyTransRecipientInfo.getInstance(info);
152    }
153
154    private KEKRecipientInfo getKEKInfo(ASN1TaggedObject o)
155    {
156        if (o.isExplicit())
157        {                        // compatibilty with erroneous version
158            return KEKRecipientInfo.getInstance(o, true);
159        }
160        else
161        {
162            return KEKRecipientInfo.getInstance(o, false);
163        }
164    }
165
166    /**
167     * Produce an object suitable for an ASN1OutputStream.
168     */
169    public ASN1Primitive toASN1Primitive()
170    {
171        return info.toASN1Primitive();
172    }
173}