1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.asn1.der;
19
20 import java.io.ByteArrayInputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.EOFException;
23 import java.io.FilterInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.nio.ByteBuffer;
27 import java.util.Vector;
28
29 /***
30 * General purpose ASN.1 decoder.
31 */
32 public class ASN1InputStream extends FilterInputStream
33 {
34 private boolean EOF_FOUND = false;
35
36 private DERObject END_OF_STREAM = new DERObject( 0, null ) {
37 public void encode( ASN1OutputStream out )
38 throws IOException
39 {
40 throw new IOException("End of stream.");
41 }
42 public int hashCode()
43 {
44 return 0;
45 }
46 public boolean equals( Object o )
47 {
48 return o == this;
49 }
50 };
51
52 public ASN1InputStream( ByteBuffer in )
53 {
54 super( newInputStream( in ) );
55 }
56
57 public ASN1InputStream( byte[] input )
58 {
59 super( new ByteArrayInputStream( input ) );
60 }
61
62 private static InputStream newInputStream( final ByteBuffer buf )
63 {
64 return new InputStream()
65 {
66 public synchronized int read() throws IOException
67 {
68 if ( !buf.hasRemaining() )
69 {
70 return -1;
71 }
72
73 int result = buf.get() & 0x000000FF;
74
75 return result;
76 }
77
78 public synchronized int read( byte[] bytes, int off, int len ) throws IOException
79 {
80
81 len = Math.min( len, buf.remaining() );
82 buf.get( bytes, off, len );
83 return len;
84 }
85 };
86 }
87
88 protected int readLength()
89 throws IOException
90 {
91 int length = read();
92 if ( length < 0 )
93 {
94 throw new IOException( "EOF found when length expected." );
95 }
96
97
98 if ( length == 0x80 )
99 {
100 return -1;
101 }
102
103 if ( length > 127 )
104 {
105 int size = length & 0x7f;
106
107 if ( size > 4 )
108 {
109 throw new IOException( "DER length more than 4 bytes." );
110 }
111
112 length = 0;
113 for ( int i = 0; i < size; i++ )
114 {
115 int next = read();
116
117 if ( next < 0 )
118 {
119 throw new IOException( "EOF found reading length." );
120 }
121
122 length = ( length << 8 ) + next;
123 }
124
125 if ( length < 0 )
126 {
127 throw new IOException( "Corrupted steam - negative length found." );
128 }
129 }
130
131 return length;
132 }
133
134 protected void readFully( byte[] bytes )
135 throws IOException
136 {
137 int left = bytes.length;
138 int len;
139
140 if ( left == 0 )
141 {
142 return;
143 }
144
145 while ( ( len = read( bytes, bytes.length - left, left ) ) > 0 )
146 {
147 if ( ( left -= len ) == 0 )
148 {
149 return;
150 }
151 }
152
153 if ( left != 0 )
154 {
155 throw new EOFException( "EOF encountered in middle of object." );
156 }
157 }
158
159 /***
160 * Build an object given its tag and a byte stream.
161 */
162 protected DEREncodable buildObject( int tag, byte[] bytes )
163 throws IOException
164 {
165 if ( ( tag & DERObject.APPLICATION ) != 0 )
166 {
167 return new DERApplicationSpecific( tag, bytes );
168 }
169
170 switch ( tag )
171 {
172 case DERObject.NULL:
173 return new DERNull();
174 case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
175 ASN1InputStream ais = new ASN1InputStream( bytes );
176
177 DERSequence sequence = new DERSequence();
178
179 DEREncodable obj = ais.readObject();
180
181 while ( obj != null )
182 {
183 sequence.add( obj );
184 obj = ais.readObject();
185 }
186
187 return sequence;
188 case DERObject.SET | DERObject.CONSTRUCTED:
189 ais = new ASN1InputStream( bytes );
190 DERSet set = new DERSet();
191
192 obj = ais.readObject();
193
194 while ( obj != null )
195 {
196 set.add( obj );
197 obj = ais.readObject();
198 }
199
200 return set;
201 case DERObject.BOOLEAN:
202 return new DERBoolean( bytes );
203 case DERObject.INTEGER:
204 return new DERInteger( bytes );
205 case DERObject.ENUMERATED:
206 return new DEREnumerated( bytes );
207 case DERObject.OBJECT_IDENTIFIER:
208 return new DERObjectIdentifier( bytes );
209 case DERObject.BIT_STRING:
210 return new DERBitString( bytes );
211 case DERObject.NUMERIC_STRING:
212 return new DERNumericString( bytes );
213 case DERObject.UTF8_STRING:
214 return new DERUTF8String( bytes );
215 case DERObject.PRINTABLE_STRING:
216 return new DERPrintableString( bytes );
217 case DERObject.IA5_STRING:
218 return new DERIA5String( bytes );
219 case DERObject.T61_STRING:
220 return new DERTeletexString( bytes );
221 case DERObject.VISIBLE_STRING:
222 return new DERVisibleString( bytes );
223 case DERObject.GENERAL_STRING:
224 return new DERGeneralString( bytes );
225 case DERObject.UNIVERSAL_STRING:
226 return new DERUniversalString( bytes );
227 case DERObject.BMP_STRING:
228 return new DERBMPString( bytes );
229 case DERObject.OCTET_STRING:
230 return new DEROctetString( bytes );
231 case DERObject.UTC_TIME:
232 return new DERUTCTime( bytes );
233 case DERObject.GENERALIZED_TIME:
234 return new DERGeneralizedTime( bytes );
235 default:
236
237 if ( ( tag & DERObject.TAGGED ) != 0 )
238 {
239 int tagNo = tag & 0x1f;
240
241 if ( tagNo == 0x1f )
242 {
243 int idx = 0;
244
245 tagNo = 0;
246
247 while ( ( bytes[ idx ] & 0x80 ) != 0 )
248 {
249 tagNo |= ( bytes[ idx++ ] & 0x7f );
250 tagNo <<= 7;
251 }
252
253 tagNo |= ( bytes[ idx ] & 0x7f );
254
255 byte[] tmp = bytes;
256
257 bytes = new byte[ tmp.length - ( idx + 1 ) ];
258 System.arraycopy( tmp, idx + 1, bytes, 0, bytes.length );
259 }
260
261
262 if ( bytes.length == 0 )
263 {
264 if ( ( tag & DERObject.CONSTRUCTED ) == 0)
265 {
266 return new DERTaggedObject( tagNo, new DERNull() );
267 }
268
269 return new DERTaggedObject( false, tagNo, new DERSequence() );
270 }
271
272
273 if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
274 {
275 return new DERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
276 }
277
278 ais = new ASN1InputStream( bytes );
279
280 DEREncodable encodable = ais.readObject();
281
282
283 if ( ais.available() == 0 )
284 {
285 return new DERTaggedObject( true, tagNo, encodable, bytes );
286 }
287
288
289 DERSequence derSequence = new DERSequence();
290
291 while ( encodable != null )
292 {
293 derSequence.add( encodable );
294 encodable = ais.readObject();
295 }
296
297 return new DERTaggedObject( false, tagNo, derSequence );
298 }
299
300 return new DERUnknownTag( tag, bytes );
301 }
302 }
303
304 /***
305 * Read a string of bytes representing an indefinite length object.
306 */
307 private byte[] readIndefiniteLengthFully()
308 throws IOException
309 {
310 ByteArrayOutputStream baos = new ByteArrayOutputStream();
311 int b, b1;
312
313 b1 = read();
314
315 while ( ( b = read() ) >= 0 )
316 {
317 if ( b1 == 0 && b == 0 )
318 {
319 break;
320 }
321
322 baos.write( b1 );
323 b1 = b;
324 }
325
326 return baos.toByteArray();
327 }
328
329 private BERConstructedOctetString buildConstructedOctetString()
330 throws IOException
331 {
332 Vector octets = new Vector();
333
334 for (;;)
335 {
336 DEREncodable encodable = readObject();
337
338 if ( encodable == END_OF_STREAM )
339 {
340 break;
341 }
342
343 octets.addElement( encodable );
344 }
345
346 return new BERConstructedOctetString( octets );
347 }
348
349 public DEREncodable readObject()
350 throws IOException
351 {
352 int tag = read();
353 if ( tag == -1 )
354 {
355 if ( EOF_FOUND )
356 {
357 throw new EOFException( "Attempt to read past end of file." );
358 }
359
360 EOF_FOUND = true;
361
362 return null;
363 }
364
365 int length = readLength();
366
367
368 if ( length < 0 )
369 {
370 switch ( tag )
371 {
372 case DERObject.NULL:
373 return new BERNull();
374 case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
375 BERSequence sequence = new BERSequence();
376
377 for (;;)
378 {
379 DEREncodable obj = readObject();
380
381 if ( obj == END_OF_STREAM )
382 {
383 break;
384 }
385
386 sequence.add( obj );
387 }
388 return sequence;
389 case DERObject.SET | DERObject.CONSTRUCTED:
390 BERSet set = new BERSet();
391
392 for (;;)
393 {
394 DEREncodable obj = readObject();
395
396 if ( obj == END_OF_STREAM )
397 {
398 break;
399 }
400
401 set.add( obj );
402 }
403 return set;
404 case DERObject.OCTET_STRING | DERObject.CONSTRUCTED:
405 return buildConstructedOctetString();
406 default:
407
408 if ( ( tag & DERObject.TAGGED ) != 0 )
409 {
410 int tagNo = tag & 0x1f;
411
412 if ( tagNo == 0x1f )
413 {
414 int b = read();
415
416 tagNo = 0;
417
418 while ( ( b >= 0 ) && ( ( b & 0x80 ) != 0 ) )
419 {
420 tagNo |= ( b & 0x7f );
421 tagNo <<= 7;
422 b = read();
423 }
424
425 tagNo |= ( b & 0x7f );
426 }
427
428
429 if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
430 {
431 byte[] bytes = readIndefiniteLengthFully();
432
433 return new BERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
434 }
435
436
437 DEREncodable dObj = readObject();
438
439
440 if ( dObj == END_OF_STREAM )
441 {
442 return new DERTaggedObject( tagNo );
443 }
444
445 DEREncodable next = readObject();
446
447
448 if ( next == END_OF_STREAM )
449 {
450 return new BERTaggedObject( tagNo, dObj );
451 }
452
453
454 BERSequence berSequence = new BERSequence();
455
456 berSequence.add( dObj );
457
458 do
459 {
460 berSequence.add( next );
461 next = readObject();
462 }
463 while ( next != END_OF_STREAM );
464
465 return new BERTaggedObject( false, tagNo, berSequence );
466 }
467
468 throw new IOException( "Unknown BER object encountered." );
469 }
470 }
471
472
473 if ( tag == 0 && length == 0 )
474 {
475 return END_OF_STREAM;
476 }
477
478 byte[] bytes = new byte[ length ];
479
480 readFully( bytes );
481
482 return buildObject( tag, bytes );
483 }
484 }
485