• 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 DERSetParser(this);
76                 case BERTags.SEQUENCE:
77                     return new DERSequenceParser(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 DERTaggedObject(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 DERTaggedObject(true, tag, v.get(0))
118             :   new DERTaggedObject(false, tag, DERFactory.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 
147         if (length < 0) // indefinite-length method
148         {
149             if (!isConstructed)
150             {
151                 throw new IOException("indefinite-length primitive encoding encountered");
152             }
153 
154             IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
155             ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
156 
157             if ((tag & BERTags.APPLICATION) != 0)
158             {
159                 return new BERApplicationSpecificParser(tagNo, sp);
160             }
161 
162             if ((tag & BERTags.TAGGED) != 0)
163             {
164                 return new BERTaggedObjectParser(true, tagNo, sp);
165             }
166 
167             return sp.readIndef(tagNo);
168         }
169         else
170         {
171             DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
172 
173             if ((tag & BERTags.APPLICATION) != 0)
174             {
175                 return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
176             }
177 
178             if ((tag & BERTags.TAGGED) != 0)
179             {
180                 return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));
181             }
182 
183             if (isConstructed)
184             {
185                 // TODO There are other tags that may be constructed (e.g. BIT_STRING)
186                 switch (tagNo)
187                 {
188                     case BERTags.OCTET_STRING:
189                         //
190                         // yes, people actually do this...
191                         //
192                         return new BEROctetStringParser(new ASN1StreamParser(defIn));
193                     case BERTags.SEQUENCE:
194                         return new DERSequenceParser(new ASN1StreamParser(defIn));
195                     case BERTags.SET:
196                         return new DERSetParser(new ASN1StreamParser(defIn));
197                     case BERTags.EXTERNAL:
198                         return new DERExternalParser(new ASN1StreamParser(defIn));
199                     default:
200                         throw new IOException("unknown tag " + tagNo + " encountered");
201                 }
202             }
203 
204             // Some primitive encodings can be handled by parsers too...
205             switch (tagNo)
206             {
207                 case BERTags.OCTET_STRING:
208                     return new DEROctetStringParser(defIn);
209             }
210 
211             try
212             {
213                 return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
214             }
215             catch (IllegalArgumentException e)
216             {
217                 throw new ASN1Exception("corrupted stream detected", e);
218             }
219         }
220     }
221 
set00Check(boolean enabled)222     private void set00Check(boolean enabled)
223     {
224         if (_in instanceof IndefiniteLengthInputStream)
225         {
226             ((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
227         }
228     }
229 
readVector()230     ASN1EncodableVector readVector() throws IOException
231     {
232         ASN1EncodableVector v = new ASN1EncodableVector();
233 
234         ASN1Encodable obj;
235         while ((obj = readObject()) != null)
236         {
237             if (obj instanceof InMemoryRepresentable)
238             {
239                 v.add(((InMemoryRepresentable)obj).getLoadedObject());
240             }
241             else
242             {
243                 v.add(obj.toASN1Primitive());
244             }
245         }
246 
247         return v;
248     }
249 }
250