• 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(InputStream in)
17     {
18         this(in, StreamUtil.findLimit(in));
19     }
20 
ASN1StreamParser(byte[] encoding)21     public ASN1StreamParser(byte[] encoding)
22     {
23         this(new ByteArrayInputStream(encoding), encoding.length);
24     }
25 
ASN1StreamParser(InputStream in, int limit)26     public ASN1StreamParser(InputStream in, int limit)
27     {
28         this(in, limit, new byte[11][]);
29     }
30 
ASN1StreamParser(InputStream in, int limit, byte[][] tmpBuffers)31     ASN1StreamParser(InputStream in, int limit, byte[][] tmpBuffers)
32     {
33         this._in = in;
34         this._limit = limit;
35         this.tmpBuffers = tmpBuffers;
36     }
37 
readObject()38     public ASN1Encodable readObject() throws IOException
39     {
40         int tagHdr = _in.read();
41         if (tagHdr < 0)
42         {
43             return null;
44         }
45 
46         return implParseObject(tagHdr);
47     }
48 
implParseObject(int tagHdr)49     ASN1Encodable implParseObject(int tagHdr) throws IOException
50     {
51         //
52         // turn off looking for "00" while we resolve the tag
53         //
54         set00Check(false);
55 
56         //
57         // calculate tag number
58         //
59         int tagNo = ASN1InputStream.readTagNumber(_in, tagHdr);
60 
61         //
62         // calculate length
63         //
64         int length = ASN1InputStream.readLength(_in, _limit,
65             tagNo == BERTags.BIT_STRING || tagNo == BERTags.OCTET_STRING || tagNo == BERTags.SEQUENCE
66                 || tagNo == BERTags.SET || tagNo == BERTags.EXTERNAL);
67 
68         if (length < 0) // indefinite-length method
69         {
70             if (0 == (tagHdr & BERTags.CONSTRUCTED))
71             {
72                 throw new IOException("indefinite-length primitive encoding encountered");
73             }
74 
75             IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
76             ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit, tmpBuffers);
77 
78             int tagClass = tagHdr & BERTags.PRIVATE;
79             if (0 != tagClass)
80             {
81                 return new BERTaggedObjectParser(tagClass, tagNo, sp);
82             }
83 
84             return sp.parseImplicitConstructedIL(tagNo);
85         }
86         else
87         {
88             DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit);
89 
90             if (0 == (tagHdr & BERTags.FLAGS))
91             {
92                 return parseImplicitPrimitive(tagNo, defIn);
93             }
94 
95             ASN1StreamParser sp = new ASN1StreamParser(defIn, defIn.getLimit(), tmpBuffers);
96 
97             int tagClass = tagHdr & BERTags.PRIVATE;
98             if (0 != tagClass)
99             {
100                 boolean isConstructed = (tagHdr & BERTags.CONSTRUCTED) != 0;
101 
102                 return new DLTaggedObjectParser(tagClass, tagNo, isConstructed, sp);
103             }
104 
105             return sp.parseImplicitConstructedDL(tagNo);
106         }
107     }
108 
loadTaggedDL(int tagClass, int tagNo, boolean constructed)109     ASN1Primitive loadTaggedDL(int tagClass, int tagNo, boolean constructed) throws IOException
110     {
111         if (!constructed)
112         {
113             byte[] contentsOctets = ((DefiniteLengthInputStream) _in).toByteArray();
114             return ASN1TaggedObject.createPrimitive(tagClass, tagNo, contentsOctets);
115         }
116 
117         ASN1EncodableVector contentsElements = readVector();
118         return ASN1TaggedObject.createConstructedDL(tagClass, tagNo, contentsElements);
119     }
120 
loadTaggedIL(int tagClass, int tagNo)121     ASN1Primitive loadTaggedIL(int tagClass, int tagNo) throws IOException
122     {
123         ASN1EncodableVector contentsElements = readVector();
124         return ASN1TaggedObject.createConstructedIL(tagClass, tagNo, contentsElements);
125     }
126 
parseImplicitConstructedDL(int univTagNo)127     ASN1Encodable parseImplicitConstructedDL(int univTagNo) throws IOException
128     {
129         switch (univTagNo)
130         {
131         case BERTags.BIT_STRING:
132             // TODO[asn1] DLConstructedBitStringParser
133             return new BERBitStringParser(this);
134         case BERTags.EXTERNAL:
135             return new DERExternalParser(this);
136         case BERTags.OCTET_STRING:
137             // TODO[asn1] DLConstructedOctetStringParser
138             return new BEROctetStringParser(this);
139         case BERTags.SET:
140             return new DLSetParser(this);
141         case BERTags.SEQUENCE:
142             return new DLSequenceParser(this);
143         default:
144             // -DM toHexString
145             throw new ASN1Exception("unknown DL object encountered: 0x" + Integer.toHexString(univTagNo));
146         }
147     }
148 
parseImplicitConstructedIL(int univTagNo)149     ASN1Encodable parseImplicitConstructedIL(int univTagNo) throws IOException
150     {
151         switch (univTagNo)
152         {
153         case BERTags.BIT_STRING:
154             return new BERBitStringParser(this);
155         case BERTags.OCTET_STRING:
156             return new BEROctetStringParser(this);
157         case BERTags.EXTERNAL:
158             // TODO[asn1] BERExternalParser
159             return new DERExternalParser(this);
160         case BERTags.SEQUENCE:
161             return new BERSequenceParser(this);
162         case BERTags.SET:
163             return new BERSetParser(this);
164         default:
165             throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(univTagNo));
166         }
167     }
168 
parseImplicitPrimitive(int univTagNo)169     ASN1Encodable parseImplicitPrimitive(int univTagNo) throws IOException
170     {
171         return parseImplicitPrimitive(univTagNo, (DefiniteLengthInputStream)_in);
172     }
173 
parseImplicitPrimitive(int univTagNo, DefiniteLengthInputStream defIn)174     ASN1Encodable parseImplicitPrimitive(int univTagNo, DefiniteLengthInputStream defIn) throws IOException
175     {
176         // Some primitive encodings can be handled by parsers too...
177         switch (univTagNo)
178         {
179         case BERTags.BIT_STRING:
180             return new DLBitStringParser(defIn);
181         case BERTags.EXTERNAL:
182             throw new ASN1Exception("externals must use constructed encoding (see X.690 8.18)");
183         case BERTags.OCTET_STRING:
184             return new DEROctetStringParser(defIn);
185         case BERTags.SET:
186             throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
187         case BERTags.SEQUENCE:
188             throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
189         }
190 
191         try
192         {
193             return ASN1InputStream.createPrimitiveDERObject(univTagNo, defIn, tmpBuffers);
194         }
195         catch (IllegalArgumentException e)
196         {
197             throw new ASN1Exception("corrupted stream detected", e);
198         }
199     }
200 
parseObject(int univTagNo)201     ASN1Encodable parseObject(int univTagNo) throws IOException
202     {
203         if (univTagNo < 0 || univTagNo > 30)
204         {
205             throw new IllegalArgumentException("invalid universal tag number: " + univTagNo);
206         }
207 
208         int tagHdr = _in.read();
209         if (tagHdr < 0)
210         {
211             return null;
212         }
213 
214         if ((tagHdr & ~BERTags.CONSTRUCTED) != univTagNo)
215         {
216             throw new IOException("unexpected identifier encountered: " + tagHdr);
217         }
218 
219         return implParseObject(tagHdr);
220     }
221 
parseTaggedObject()222     ASN1TaggedObjectParser parseTaggedObject() throws IOException
223     {
224         int tagHdr = _in.read();
225         if (tagHdr < 0)
226         {
227             return null;
228         }
229 
230         int tagClass = tagHdr & BERTags.PRIVATE;
231         if (0 == tagClass)
232         {
233             throw new ASN1Exception("no tagged object found");
234         }
235 
236         return (ASN1TaggedObjectParser)implParseObject(tagHdr);
237     }
238 
239     // TODO[asn1] Prefer 'loadVector'
readVector()240     ASN1EncodableVector readVector() throws IOException
241     {
242         int tagHdr = _in.read();
243         if (tagHdr < 0)
244         {
245             return new ASN1EncodableVector(0);
246         }
247 
248         ASN1EncodableVector v = new ASN1EncodableVector();
249         do
250         {
251             ASN1Encodable obj = implParseObject(tagHdr);
252 
253             if (obj instanceof InMemoryRepresentable)
254             {
255                 v.add(((InMemoryRepresentable) obj).getLoadedObject());
256             }
257             else
258             {
259                 v.add(obj.toASN1Primitive());
260             }
261         }
262         while ((tagHdr = _in.read()) >= 0);
263         return v;
264     }
265 
set00Check(boolean enabled)266     private void set00Check(boolean enabled)
267     {
268         if (_in instanceof IndefiniteLengthInputStream)
269         {
270             ((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
271         }
272     }
273 }
274