• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.asn1;
2 
3 import java.io.ByteArrayInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 
7 /**
8  * A parser for ASN.1 streams which also returns, where possible, parsers for the objects it encounters.
9  */
10 public class ASN1StreamParser
11 {
12     private final InputStream _in;
13     private final int         _limit;
14     private final byte[][] tmpBuffers;
15 
ASN1StreamParser( InputStream in)16     public ASN1StreamParser(
17         InputStream in)
18     {
19         this(in, StreamUtil.findLimit(in));
20     }
21 
ASN1StreamParser( InputStream in, int limit)22     public ASN1StreamParser(
23         InputStream in,
24         int         limit)
25     {
26         this._in = in;
27         this._limit = limit;
28 
29         this.tmpBuffers = new byte[11][];
30     }
31 
ASN1StreamParser( byte[] encoding)32     public ASN1StreamParser(
33         byte[] encoding)
34     {
35         this(new ByteArrayInputStream(encoding), encoding.length);
36     }
37 
readIndef(int tagValue)38     ASN1Encodable readIndef(int tagValue) throws IOException
39     {
40         // Note: INDEF => CONSTRUCTED
41 
42         // TODO There are other tags that may be constructed (e.g. BIT_STRING)
43         switch (tagValue)
44         {
45             case BERTags.EXTERNAL:
46                 return new DERExternalParser(this);
47             case BERTags.OCTET_STRING:
48                 return new BEROctetStringParser(this);
49             case BERTags.SEQUENCE:
50                 return new BERSequenceParser(this);
51             case BERTags.SET:
52                 return new BERSetParser(this);
53             default:
54                 throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue));
55         }
56     }
57 
readImplicit(boolean constructed, int tag)58     ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException
59     {
60         if (_in instanceof IndefiniteLengthInputStream)
61         {
62             if (!constructed)
63             {
64                 throw new IOException("indefinite-length primitive encoding encountered");
65             }
66 
67             return readIndef(tag);
68         }
69 
70         if (constructed)
71         {
72             switch (tag)
73             {
74                 case BERTags.SET:
75                     return new DLSetParser(this);
76                 case BERTags.SEQUENCE:
77                     return new DLSequenceParser(this);
78                 case BERTags.OCTET_STRING:
79                     return new BEROctetStringParser(this);
80             }
81         }
82         else
83         {
84             switch (tag)
85             {
86                 case BERTags.SET:
87                     throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
88                 case BERTags.SEQUENCE:
89                     throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
90                 case BERTags.OCTET_STRING:
91                     return new DEROctetStringParser((DefiniteLengthInputStream)_in);
92             }
93         }
94 
95         throw new ASN1Exception("implicit tagging not implemented");
96     }
97 
readTaggedObject(boolean constructed, int tag)98     ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException
99     {
100         if (!constructed)
101         {
102             // Note: !CONSTRUCTED => IMPLICIT
103             DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
104             return new DLTaggedObject(false, tag, new DEROctetString(defIn.toByteArray()));
105         }
106 
107         ASN1EncodableVector v = readVector();
108 
109         if (_in instanceof IndefiniteLengthInputStream)
110         {
111             return v.size() == 1
112                 ?   new BERTaggedObject(true, tag, v.get(0))
113                 :   new BERTaggedObject(false, tag, BERFactory.createSequence(v));
114         }
115 
116         return v.size() == 1
117             ?   new DLTaggedObject(true, tag, v.get(0))
118             :   new DLTaggedObject(false, tag, DLFactory.createSequence(v));
119     }
120 
readObject()121     public ASN1Encodable readObject()
122         throws IOException
123     {
124         int tag = _in.read();
125         if (tag == -1)
126         {
127             return null;
128         }
129 
130         //
131         // turn of looking for "00" while we resolve the tag
132         //
133         set00Check(false);
134 
135         //
136         // calculate tag number
137         //
138         int tagNo = ASN1InputStream.readTagNumber(_in, tag);
139 
140         boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0;
141 
142         //
143         // calculate length
144         //
145         int length = ASN1InputStream.readLength(_in, _limit,
146             tagNo == BERTags.OCTET_STRING || tagNo == BERTags.SEQUENCE || tagNo == BERTags.SET || tagNo == BERTags.EXTERNAL);
147 
148         if (length < 0) // indefinite-length method
149         {
150             if (!isConstructed)
151             {
152                 throw new IOException("indefinite-length primitive encoding encountered");
153             }
154 
155             IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
156             ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
157 
158             if ((tag & BERTags.APPLICATION) != 0)
159             {
160                 return new BERApplicationSpecificParser(tagNo, sp);
161             }
162 
163             if ((tag & BERTags.TAGGED) != 0)
164             {
165                 return new BERTaggedObjectParser(true, tagNo, sp);
166             }
167 
168             return sp.readIndef(tagNo);
169         }
170         else
171         {
172             DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit);
173 
174             if ((tag & BERTags.APPLICATION) != 0)
175             {
176                 return new DLApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
177             }
178 
179             if ((tag & BERTags.TAGGED) != 0)
180             {
181                 return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));
182             }
183 
184             if (isConstructed)
185             {
186                 // TODO There are other tags that may be constructed (e.g. BIT_STRING)
187                 switch (tagNo)
188                 {
189                     case BERTags.OCTET_STRING:
190                         //
191                         // yes, people actually do this...
192                         //
193                         return new BEROctetStringParser(new ASN1StreamParser(defIn));
194                     case BERTags.SEQUENCE:
195                         return new DLSequenceParser(new ASN1StreamParser(defIn));
196                     case BERTags.SET:
197                         return new DLSetParser(new ASN1StreamParser(defIn));
198                     case BERTags.EXTERNAL:
199                         return new DERExternalParser(new ASN1StreamParser(defIn));
200                     default:
201                         throw new IOException("unknown tag " + tagNo + " encountered");
202                 }
203             }
204 
205             // Some primitive encodings can be handled by parsers too...
206             switch (tagNo)
207             {
208                 case BERTags.OCTET_STRING:
209                     return new DEROctetStringParser(defIn);
210             }
211 
212             try
213             {
214                 return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
215             }
216             catch (IllegalArgumentException e)
217             {
218                 throw new ASN1Exception("corrupted stream detected", e);
219             }
220         }
221     }
222 
set00Check(boolean enabled)223     private void set00Check(boolean enabled)
224     {
225         if (_in instanceof IndefiniteLengthInputStream)
226         {
227             ((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
228         }
229     }
230 
readVector()231     ASN1EncodableVector readVector() throws IOException
232     {
233         ASN1Encodable obj = readObject();
234         if (null == obj)
235         {
236             return new ASN1EncodableVector(0);
237         }
238 
239         ASN1EncodableVector v = new ASN1EncodableVector();
240         do
241         {
242             if (obj instanceof InMemoryRepresentable)
243             {
244                 v.add(((InMemoryRepresentable)obj).getLoadedObject());
245             }
246             else
247             {
248                 v.add(obj.toASN1Primitive());
249             }
250         }
251         while ((obj = readObject()) != null);
252         return v;
253     }
254 }
255