1package org.bouncycastle.asn1;
2
3import java.io.ByteArrayInputStream;
4import java.io.IOException;
5import java.io.InputStream;
6
7import org.bouncycastle.util.Arrays;
8import org.bouncycastle.util.Strings;
9import org.bouncycastle.util.encoders.Hex;
10
11/**
12 * Abstract base for the ASN.1 OCTET STRING data type
13 * <p>
14 * This supports BER, and DER forms of the data.
15 * </p><p>
16 * DER form is always primitive single OCTET STRING, while
17 * BER support includes the constructed forms.
18 * </p>
19 * <hr>
20 * <p><b>X.690</b></p>
21 * <p><b>8: Basic encoding rules</b></p>
22 * <p><b>8.7 Encoding of an octetstring value</b></p>
23 * <p>
24 * <b>8.7.1</b> The encoding of an octetstring value shall be
25 * either primitive or constructed at the option of the sender.
26 * <blockquote>
27 * NOTE &mdash; Where it is necessary to transfer part of an octet string
28 * before the entire OCTET STRING is available, the constructed encoding
29 * is used.
30 * </blockquote>
31 * <p>
32 * <b>8.7.2</b> The primitive encoding contains zero,
33 * one or more contents octets equal in value to the octets
34 * in the data value, in the order they appear in the data value,
35 * and with the most significant bit of an octet of the data value
36 * aligned with the most significant bit of an octet of the contents octets.
37 * </p>
38 * <p>
39 * <b>8.7.3</b> The contents octets for the constructed encoding shall consist
40 * of zero, one, or more encodings.
41 * <blockquote>
42 * NOTE &mdash; Each such encoding includes identifier, length, and contents octets,
43 * and may include end-of-contents octets if it is constructed.
44 * </blockquote>
45 * </p>
46 * <p>
47 * <b>8.7.3.1</b> To encode an octetstring value in this way,
48 * it is segmented. Each segment shall consist of a series of
49 * consecutive octets of the value. There shall be no significance
50 * placed on the segment boundaries.
51 * <blockquote>
52 * NOTE &mdash; A segment may be of size zero, i.e. contain no octets.
53 * </blockquote>
54 * </p>
55 * <p>
56 * <b>8.7.3.2</b> Each encoding in the contents octets shall represent
57 * a segment of the overall octetstring, the encoding arising from
58 * a recursive application of this subclause.
59 * In this recursive application, each segment is treated as if it were
60 * a octetstring value. The encodings of the segments shall appear in the contents
61 * octets in the order in which their octets appear in the overall value.
62 * <blockquote>
63 * NOTE 1 &mdash; As a consequence of this recursion,
64 * each encoding in the contents octets may itself
65 * be primitive or constructed.
66 * However, such encodings will usually be primitive.
67 * <br />
68 * NOTE 2 &mdash; In particular, the tags in the contents octets are always universal class, number 4.
69 * </blockquote>
70 * </p>
71 * <p><b>9: Canonical encoding rules</b></p>
72 * <p><b>9.1 Length forms</b></p>
73 * <p>
74 * If the encoding is constructed, it shall employ the indefinite-length form.
75 * If the encoding is primitive, it shall include the fewest length octets necessary.
76 * [Contrast with 8.1.3.2 b).]
77 * </p>
78 * <p><b>9.2 String encoding forms</b></p>
79 * <p>
80 * BIT STRING, OCTET STRING,and restricted character string
81 * values shall be encoded with a primitive encoding if they would
82 * require no more than 1000 contents octets, and as a constructed
83 * encoding otherwise. The string fragments contained in
84 * the constructed encoding shall be encoded with a primitive encoding.
85 * The encoding of each fragment, except possibly
86 * the last, shall have 1000 contents octets. (Contrast with 8.21.6.)
87 * </p><p>
88 * <b>10: Distinguished encoding rules</b>
89 * </p><p>
90 * <b>10.1 Length forms</b>
91 * The definite form of length encoding shall be used,
92 * encoded in the minimum number of octets.
93 * [Contrast with 8.1.3.2 b).]
94 * </p><p>
95 * <b>10.2 String encoding forms</b>
96 * For BIT STRING, OCTET STRING and restricted character string types,
97 * the constructed form of encoding shall not be used.
98 * (Contrast with 8.21.6.)
99 * </p>
100 */
101public abstract class ASN1OctetString
102    extends ASN1Primitive
103    implements ASN1OctetStringParser
104{
105    byte[]  string;
106
107    /**
108     * return an Octet String from a tagged object.
109     *
110     * @param obj the tagged object holding the object we want.
111     * @param explicit true if the object is meant to be explicitly
112     *              tagged false otherwise.
113     * @exception IllegalArgumentException if the tagged object cannot
114     *              be converted.
115     */
116    public static ASN1OctetString getInstance(
117        ASN1TaggedObject    obj,
118        boolean             explicit)
119    {
120        ASN1Primitive o = obj.getObject();
121
122        if (explicit || o instanceof ASN1OctetString)
123        {
124            return getInstance(o);
125        }
126        else
127        {
128            return BEROctetString.fromSequence(ASN1Sequence.getInstance(o));
129        }
130    }
131
132    /**
133     * return an Octet String from the given object.
134     *
135     * @param obj the object we want converted.
136     * @exception IllegalArgumentException if the object cannot be converted.
137     */
138    public static ASN1OctetString getInstance(
139        Object  obj)
140    {
141        if (obj == null || obj instanceof ASN1OctetString)
142        {
143            return (ASN1OctetString)obj;
144        }
145        else if (obj instanceof byte[])
146        {
147            try
148            {
149                return ASN1OctetString.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
150            }
151            catch (IOException e)
152            {
153                throw new IllegalArgumentException("failed to construct OCTET STRING from byte[]: " + e.getMessage());
154            }
155        }
156        else if (obj instanceof ASN1Encodable)
157        {
158            ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
159
160            if (primitive instanceof ASN1OctetString)
161            {
162                return (ASN1OctetString)primitive;
163            }
164        }
165
166        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
167    }
168
169    /**
170     * Base constructor.
171     *
172     * @param string the octets making up the octet string.
173     */
174    public ASN1OctetString(
175        byte[]  string)
176    {
177        if (string == null)
178        {
179            throw new NullPointerException("string cannot be null");
180        }
181        this.string = string;
182    }
183
184    /**
185     * Return the content of the OCTET STRING as an InputStream.
186     *
187     * @return an InputStream representing the OCTET STRING's content.
188     */
189    public InputStream getOctetStream()
190    {
191        return new ByteArrayInputStream(string);
192    }
193
194    /**
195     * Return the parser associated with this object.
196     *
197     * @return a parser based on this OCTET STRING
198     */
199    public ASN1OctetStringParser parser()
200    {
201        return this;
202    }
203
204    /**
205     * Return the content of the OCTET STRING as a byte array.
206     *
207     * @return the byte[] representing the OCTET STRING's content.
208     */
209    public byte[] getOctets()
210    {
211        return string;
212    }
213
214    public int hashCode()
215    {
216        return Arrays.hashCode(this.getOctets());
217    }
218
219    boolean asn1Equals(
220        ASN1Primitive o)
221    {
222        if (!(o instanceof ASN1OctetString))
223        {
224            return false;
225        }
226
227        ASN1OctetString  other = (ASN1OctetString)o;
228
229        return Arrays.areEqual(string, other.string);
230    }
231
232    public ASN1Primitive getLoadedObject()
233    {
234        return this.toASN1Primitive();
235    }
236
237    ASN1Primitive toDERObject()
238    {
239        return new DEROctetString(string);
240    }
241
242    ASN1Primitive toDLObject()
243    {
244        return new DEROctetString(string);
245    }
246
247    abstract void encode(ASN1OutputStream out)
248        throws IOException;
249
250    public String toString()
251    {
252      return "#"+ Strings.fromByteArray(Hex.encode(string));
253    }
254}
255