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 }