001package org.apache.commons.ssl.org.bouncycastle.asn1;
002
003import java.io.ByteArrayOutputStream;
004import java.io.IOException;
005
006/**
007 * Class representing the DER-type External
008 */
009public class DERExternal
010    extends ASN1Primitive
011{
012    private ASN1ObjectIdentifier directReference;
013    private ASN1Integer indirectReference;
014    private ASN1Primitive dataValueDescriptor;
015    private int encoding;
016    private ASN1Primitive externalContent;
017    
018    public DERExternal(ASN1EncodableVector vector)
019    {
020        int offset = 0;
021
022        ASN1Primitive enc = getObjFromVector(vector, offset);
023        if (enc instanceof ASN1ObjectIdentifier)
024        {
025            directReference = (ASN1ObjectIdentifier)enc;
026            offset++;
027            enc = getObjFromVector(vector, offset);
028        }
029        if (enc instanceof ASN1Integer)
030        {
031            indirectReference = (ASN1Integer) enc;
032            offset++;
033            enc = getObjFromVector(vector, offset);
034        }
035        if (!(enc instanceof DERTaggedObject))
036        {
037            dataValueDescriptor = (ASN1Primitive) enc;
038            offset++;
039            enc = getObjFromVector(vector, offset);
040        }
041
042        if (vector.size() != offset + 1)
043        {
044            throw new IllegalArgumentException("input vector too large");
045        }
046
047        if (!(enc instanceof DERTaggedObject))
048        {
049            throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External");
050        }
051        DERTaggedObject obj = (DERTaggedObject)enc;
052        setEncoding(obj.getTagNo());
053        externalContent = obj.getObject();
054    }
055
056    private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index)
057    {
058        if (v.size() <= index)
059        {
060            throw new IllegalArgumentException("too few objects in input vector");
061        }
062
063        return v.get(index).toASN1Primitive();
064    }
065    /**
066     * Creates a new instance of DERExternal
067     * See X.690 for more informations about the meaning of these parameters
068     * @param directReference The direct reference or <code>null</code> if not set.
069     * @param indirectReference The indirect reference or <code>null</code> if not set.
070     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
071     * @param externalData The external data in its encoded form.
072     */
073    public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)
074    {
075        this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());
076    }
077
078    /**
079     * Creates a new instance of DERExternal.
080     * See X.690 for more informations about the meaning of these parameters
081     * @param directReference The direct reference or <code>null</code> if not set.
082     * @param indirectReference The indirect reference or <code>null</code> if not set.
083     * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
084     * @param encoding The encoding to be used for the external data
085     * @param externalData The external data
086     */
087    public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)
088    {
089        setDirectReference(directReference);
090        setIndirectReference(indirectReference);
091        setDataValueDescriptor(dataValueDescriptor);
092        setEncoding(encoding);
093        setExternalContent(externalData.toASN1Primitive());
094    }
095
096    /* (non-Javadoc)
097     * @see java.lang.Object#hashCode()
098     */
099    public int hashCode()
100    {
101        int ret = 0;
102        if (directReference != null)
103        {
104            ret = directReference.hashCode();
105        }
106        if (indirectReference != null)
107        {
108            ret ^= indirectReference.hashCode();
109        }
110        if (dataValueDescriptor != null)
111        {
112            ret ^= dataValueDescriptor.hashCode();
113        }
114        ret ^= externalContent.hashCode();
115        return ret;
116    }
117
118    boolean isConstructed()
119    {
120        return true;
121    }
122
123    int encodedLength()
124        throws IOException
125    {
126        return this.getEncoded().length;
127    }
128
129    /* (non-Javadoc)
130     * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
131     */
132    void encode(ASN1OutputStream out)
133        throws IOException
134    {
135        ByteArrayOutputStream baos = new ByteArrayOutputStream();
136        if (directReference != null)
137        {
138            baos.write(directReference.getEncoded(ASN1Encoding.DER));
139        }
140        if (indirectReference != null)
141        {
142            baos.write(indirectReference.getEncoded(ASN1Encoding.DER));
143        }
144        if (dataValueDescriptor != null)
145        {
146            baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DER));
147        }
148        DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent);
149        baos.write(obj.getEncoded(ASN1Encoding.DER));
150        out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray());
151    }
152
153    /* (non-Javadoc)
154     * @see org.bouncycastle.asn1.ASN1Primitive#asn1Equals(org.bouncycastle.asn1.ASN1Primitive)
155     */
156    boolean asn1Equals(ASN1Primitive o)
157    {
158        if (!(o instanceof DERExternal))
159        {
160            return false;
161        }
162        if (this == o)
163        {
164            return true;
165        }
166        DERExternal other = (DERExternal)o;
167        if (directReference != null)
168        {
169            if (other.directReference == null || !other.directReference.equals(directReference))  
170            {
171                return false;
172            }
173        }
174        if (indirectReference != null)
175        {
176            if (other.indirectReference == null || !other.indirectReference.equals(indirectReference))
177            {
178                return false;
179            }
180        }
181        if (dataValueDescriptor != null)
182        {
183            if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor))
184            {
185                return false;
186            }
187        }
188        return externalContent.equals(other.externalContent);
189    }
190
191    /**
192     * Returns the data value descriptor
193     * @return The descriptor
194     */
195    public ASN1Primitive getDataValueDescriptor()
196    {
197        return dataValueDescriptor;
198    }
199
200    /**
201     * Returns the direct reference of the external element
202     * @return The reference
203     */
204    public ASN1ObjectIdentifier getDirectReference()
205    {
206        return directReference;
207    }
208
209    /**
210     * Returns the encoding of the content. Valid values are
211     * <ul>
212     * <li><code>0</code> single-ASN1-type</li>
213     * <li><code>1</code> OCTET STRING</li>
214     * <li><code>2</code> BIT STRING</li>
215     * </ul>
216     * @return The encoding
217     */
218    public int getEncoding()
219    {
220        return encoding;
221    }
222    
223    /**
224     * Returns the content of this element
225     * @return The content
226     */
227    public ASN1Primitive getExternalContent()
228    {
229        return externalContent;
230    }
231    
232    /**
233     * Returns the indirect reference of this element
234     * @return The reference
235     */
236    public ASN1Integer getIndirectReference()
237    {
238        return indirectReference;
239    }
240    
241    /**
242     * Sets the data value descriptor
243     * @param dataValueDescriptor The descriptor
244     */
245    private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor)
246    {
247        this.dataValueDescriptor = dataValueDescriptor;
248    }
249
250    /**
251     * Sets the direct reference of the external element
252     * @param directReferemce The reference
253     */
254    private void setDirectReference(ASN1ObjectIdentifier directReferemce)
255    {
256        this.directReference = directReferemce;
257    }
258    
259    /**
260     * Sets the encoding of the content. Valid values are
261     * <ul>
262     * <li><code>0</code> single-ASN1-type</li>
263     * <li><code>1</code> OCTET STRING</li>
264     * <li><code>2</code> BIT STRING</li>
265     * </ul>
266     * @param encoding The encoding
267     */
268    private void setEncoding(int encoding)
269    {
270        if (encoding < 0 || encoding > 2)
271        {
272            throw new IllegalArgumentException("invalid encoding value: " + encoding);
273        }
274        this.encoding = encoding;
275    }
276    
277    /**
278     * Sets the content of this element
279     * @param externalContent The content
280     */
281    private void setExternalContent(ASN1Primitive externalContent)
282    {
283        this.externalContent = externalContent;
284    }
285    
286    /**
287     * Sets the indirect reference of this element
288     * @param indirectReference The reference
289     */
290    private void setIndirectReference(ASN1Integer indirectReference)
291    {
292        this.indirectReference = indirectReference;
293    }
294}