001 /*
002 * Copyright (c) 2000 - 2006 The Legion Of The Bouncy Castle (http://www.bouncycastle.org)
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
005 * software and associated documentation files (the "Software"), to deal in the Software
006 * without restriction, including without limitation the rights to use, copy, modify,
007 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
008 * permit persons to whom the Software is furnished to do so, subject to the following
009 * conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in all copies
012 * or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
015 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
016 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
017 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
018 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
019 * DEALINGS IN THE SOFTWARE.
020 *
021 */
022
023 package org.apache.directory.shared.asn1.der;
024
025
026 import java.io.ByteArrayInputStream;
027 import java.io.ByteArrayOutputStream;
028 import java.io.EOFException;
029 import java.io.FilterInputStream;
030 import java.io.IOException;
031 import java.io.InputStream;
032 import java.nio.ByteBuffer;
033 import java.util.Vector;
034
035 import org.apache.directory.shared.i18n.I18n;
036
037
038 /**
039 * General purpose ASN.1 decoder.
040 */
041 public class ASN1InputStream extends FilterInputStream
042 {
043 private boolean EOF_FOUND = false;
044
045 private DERObject END_OF_STREAM = new DERObject( 0, null )
046 {
047 public void encode( ASN1OutputStream out ) throws IOException
048 {
049 throw new IOException( I18n.err( I18n.ERR_00016 ) );
050 }
051
052
053 /**
054 * Compute the instance hash code
055 * @return the instance's hashcode
056 */
057 public int hashCode()
058 {
059 return 0;
060 }
061
062
063 public boolean equals( Object o )
064 {
065 return o == this;
066 }
067 };
068
069
070 public ASN1InputStream(ByteBuffer in)
071 {
072 super( newInputStream( in ) );
073 }
074
075
076 public ASN1InputStream(byte[] input)
077 {
078 super( new ByteArrayInputStream( input ) );
079 }
080
081
082 private static InputStream newInputStream( final ByteBuffer buf )
083 {
084 return new InputStream()
085 {
086 public synchronized int read() throws IOException
087 {
088 if ( !buf.hasRemaining() )
089 {
090 return -1;
091 }
092
093 int result = buf.get() & 0x000000FF;
094
095 return result;
096 }
097
098
099 public synchronized int read( byte[] bytes, int off, int len ) throws IOException
100 {
101 // Read only what's left
102 len = Math.min( len, buf.remaining() );
103 buf.get( bytes, off, len );
104 return len;
105 }
106 };
107 }
108
109
110 protected int readLength() throws IOException
111 {
112 int length = read();
113 if ( length < 0 )
114 {
115 throw new IOException( I18n.err( I18n.ERR_00017 ) );
116 }
117
118 // Indefinite-length encoding.
119 if ( length == 0x80 )
120 {
121 return -1;
122 }
123
124 if ( length > 127 )
125 {
126 int size = length & 0x7f;
127
128 if ( size > 4 )
129 {
130 throw new IOException( I18n.err( I18n.ERR_00018 ) );
131 }
132
133 length = 0;
134 for ( int i = 0; i < size; i++ )
135 {
136 int next = read();
137
138 if ( next < 0 )
139 {
140 throw new IOException( I18n.err( I18n.ERR_00019 ) );
141 }
142
143 length = ( length << 8 ) + next;
144 }
145
146 if ( length < 0 )
147 {
148 throw new IOException( I18n.err( I18n.ERR_00020 ) );
149 }
150 }
151
152 return length;
153 }
154
155
156 protected void readFully( byte[] bytes ) throws IOException
157 {
158 int left = bytes.length;
159 int len;
160
161 if ( left == 0 )
162 {
163 return;
164 }
165
166 while ( ( len = read( bytes, bytes.length - left, left ) ) > 0 )
167 {
168 if ( ( left -= len ) == 0 )
169 {
170 return;
171 }
172 }
173
174 if ( left != 0 )
175 {
176 throw new EOFException( I18n.err( I18n.ERR_00021 ) );
177 }
178 }
179
180
181 /**
182 * Build an object given its tag and a byte stream.
183 */
184 protected DEREncodable buildObject( int tag, byte[] bytes ) throws IOException
185 {
186 if ( ( tag & DERObject.APPLICATION ) != 0 )
187 {
188 return new DERApplicationSpecific( tag, bytes );
189 }
190
191 switch ( tag )
192 {
193 case DERObject.NULL:
194 return new DERNull();
195 case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
196 ASN1InputStream ais = new ASN1InputStream( bytes );
197 DEREncodable obj = null;
198 DERSequence sequence = new DERSequence();
199
200 try
201 {
202 obj = ais.readObject();
203
204 while ( obj != null )
205 {
206 sequence.add( obj );
207 obj = ais.readObject();
208 }
209 }
210 finally
211 {
212 ais.close();
213 }
214
215 return sequence;
216 case DERObject.SET | DERObject.CONSTRUCTED:
217 ais = new ASN1InputStream( bytes );
218 DERSet set = new DERSet();
219
220 try
221 {
222 obj = ais.readObject();
223
224 while ( obj != null )
225 {
226 set.add( obj );
227 obj = ais.readObject();
228 }
229 }
230 finally
231 {
232 ais.close();
233 }
234
235 return set;
236 case DERObject.BOOLEAN:
237 return new DERBoolean( bytes );
238 case DERObject.INTEGER:
239 return new DERInteger( bytes );
240 case DERObject.ENUMERATED:
241 return new DEREnumerated( bytes );
242 case DERObject.OBJECT_IDENTIFIER:
243 return new DERObjectIdentifier( bytes );
244 case DERObject.BIT_STRING:
245 return new DERBitString( bytes );
246 case DERObject.NUMERIC_STRING:
247 return new DERNumericString( bytes );
248 case DERObject.UTF8_STRING:
249 return new DERUTF8String( bytes );
250 case DERObject.PRINTABLE_STRING:
251 return new DERPrintableString( bytes );
252 case DERObject.IA5_STRING:
253 return new DERIA5String( bytes );
254 case DERObject.T61_STRING:
255 return new DERTeletexString( bytes );
256 case DERObject.VISIBLE_STRING:
257 return new DERVisibleString( bytes );
258 case DERObject.GENERAL_STRING:
259 return new DERGeneralString( bytes );
260 case DERObject.UNIVERSAL_STRING:
261 return new DERUniversalString( bytes );
262 case DERObject.BMP_STRING:
263 return new DERBMPString( bytes );
264 case DERObject.OCTET_STRING:
265 return new DEROctetString( bytes );
266 case DERObject.UTC_TIME:
267 return new DERUTCTime( bytes );
268 case DERObject.GENERALIZED_TIME:
269 return new DERGeneralizedTime( bytes );
270 default:
271 // Tag number is bottom 5 bits.
272 if ( ( tag & DERObject.TAGGED ) != 0 )
273 {
274 int tagNo = tag & 0x1f;
275
276 if ( tagNo == 0x1f )
277 {
278 int idx = 0;
279
280 tagNo = 0;
281
282 while ( ( bytes[idx] & 0x80 ) != 0 )
283 {
284 tagNo |= ( bytes[idx++] & 0x7f );
285 tagNo <<= 7;
286 }
287
288 tagNo |= ( bytes[idx] & 0x7f );
289
290 byte[] tmp = bytes;
291
292 bytes = new byte[tmp.length - ( idx + 1 )];
293 System.arraycopy( tmp, idx + 1, bytes, 0, bytes.length );
294 }
295
296 // Empty tag.
297 if ( bytes.length == 0 )
298 {
299 if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
300 {
301 return new DERTaggedObject( tagNo, new DERNull() );
302 }
303
304 return new DERTaggedObject( false, tagNo, new DERSequence() );
305 }
306
307 // Simple type - implicit, return an octet string.
308 if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
309 {
310 return new DERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
311 }
312
313 ais = new ASN1InputStream( bytes );
314
315 try
316 {
317 DEREncodable encodable = ais.readObject();
318
319 // Explicitly tagged - if it isn't we'd have to tell from
320 // the context.
321 if ( ais.available() == 0 )
322 {
323 return new DERTaggedObject( true, tagNo, encodable, bytes );
324 }
325
326 // Another implicit object, create a sequence.
327 DERSequence derSequence = new DERSequence();
328
329 while ( encodable != null )
330 {
331 derSequence.add( encodable );
332 encodable = ais.readObject();
333 }
334
335 return new DERTaggedObject( false, tagNo, derSequence );
336 }
337 finally
338 {
339 ais.close();
340 }
341 }
342
343 return new DERUnknownTag( tag, bytes );
344 }
345 }
346
347
348 /**
349 * Read a string of bytes representing an indefinite length object.
350 */
351 private byte[] readIndefiniteLengthFully() throws IOException
352 {
353 ByteArrayOutputStream baos = new ByteArrayOutputStream();
354 int b, b1;
355
356 b1 = read();
357
358 while ( ( b = read() ) >= 0 )
359 {
360 if ( b1 == 0 && b == 0 )
361 {
362 break;
363 }
364
365 baos.write( b1 );
366 b1 = b;
367 }
368
369 return baos.toByteArray();
370 }
371
372
373 private BERConstructedOctetString buildConstructedOctetString() throws IOException
374 {
375 Vector<DEREncodable> octets = new Vector<DEREncodable>();
376
377 for ( ;; )
378 {
379 DEREncodable encodable = readObject();
380
381 if ( encodable == END_OF_STREAM )
382 {
383 break;
384 }
385
386 octets.addElement( encodable );
387 }
388
389 return new BERConstructedOctetString( octets );
390 }
391
392
393 public DEREncodable readObject() throws IOException
394 {
395 int tag = read();
396 if ( tag == -1 )
397 {
398 if ( EOF_FOUND )
399 {
400 throw new EOFException( I18n.err( I18n.ERR_00022 ) );
401 }
402
403 EOF_FOUND = true;
404
405 return null;
406 }
407
408 int length = readLength();
409
410 // Indefinite length method.
411 if ( length < 0 )
412 {
413 switch ( tag )
414 {
415 case DERObject.NULL:
416 return new BERNull();
417 case DERObject.SEQUENCE | DERObject.CONSTRUCTED:
418 BERSequence sequence = new BERSequence();
419
420 for ( ;; )
421 {
422 DEREncodable obj = readObject();
423
424 if ( obj == END_OF_STREAM )
425 {
426 break;
427 }
428
429 sequence.add( obj );
430 }
431 return sequence;
432 case DERObject.SET | DERObject.CONSTRUCTED:
433 BERSet set = new BERSet();
434
435 for ( ;; )
436 {
437 DEREncodable obj = readObject();
438
439 if ( obj == END_OF_STREAM )
440 {
441 break;
442 }
443
444 set.add( obj );
445 }
446 return set;
447 case DERObject.OCTET_STRING | DERObject.CONSTRUCTED:
448 return buildConstructedOctetString();
449 default:
450 // Tag number is bottom 5 bits.
451 if ( ( tag & DERObject.TAGGED ) != 0 )
452 {
453 int tagNo = tag & 0x1f;
454
455 if ( tagNo == 0x1f )
456 {
457 int b = read();
458
459 tagNo = 0;
460
461 while ( ( b >= 0 ) && ( ( b & 0x80 ) != 0 ) )
462 {
463 tagNo |= ( b & 0x7f );
464 tagNo <<= 7;
465 b = read();
466 }
467
468 tagNo |= ( b & 0x7f );
469 }
470
471 // Simple type - implicit, return an octet string.
472 if ( ( tag & DERObject.CONSTRUCTED ) == 0 )
473 {
474 byte[] bytes = readIndefiniteLengthFully();
475
476 return new BERTaggedObject( false, tagNo, new DEROctetString( bytes ) );
477 }
478
479 // Either constructed or explicitly tagged
480 DEREncodable dObj = readObject();
481
482 // Empty tag!
483 if ( dObj == END_OF_STREAM )
484 {
485 return new DERTaggedObject( tagNo );
486 }
487
488 DEREncodable next = readObject();
489
490 // Explicitly tagged.
491 if ( next == END_OF_STREAM )
492 {
493 return new BERTaggedObject( tagNo, dObj );
494 }
495
496 // Another implicit object, create a sequence.
497 BERSequence berSequence = new BERSequence();
498
499 berSequence.add( dObj );
500
501 do
502 {
503 berSequence.add( next );
504 next = readObject();
505 }
506 while ( next != END_OF_STREAM );
507
508 return new BERTaggedObject( false, tagNo, berSequence );
509 }
510
511 throw new IOException( I18n.err( I18n.ERR_00023 ) );
512 }
513 }
514
515 // End of contents marker.
516 if ( tag == 0 && length == 0 )
517 {
518 return END_OF_STREAM;
519 }
520
521 byte[] bytes = new byte[length];
522
523 readFully( bytes );
524
525 return buildObject( tag, bytes );
526 }
527 }