1 package org.bouncycastle.asn1; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.EOFException; 6 import java.io.FilterInputStream; 7 import java.io.IOException; 8 import java.io.InputStream; 9 import java.util.Vector; 10 11 /** 12 * a general purpose ASN.1 decoder - note: this class differs from the 13 * others in that it returns null after it has read the last object in 14 * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is 15 * returned. 16 */ 17 public class ASN1InputStream 18 extends FilterInputStream 19 implements DERTags 20 { 21 private DERObject END_OF_STREAM = new DERObject() 22 { 23 void encode( 24 DEROutputStream out) 25 throws IOException 26 { 27 throw new IOException("Eeek!"); 28 } 29 public int hashCode() 30 { 31 return 0; 32 } 33 public boolean equals( 34 Object o) 35 { 36 return o == this; 37 } 38 }; 39 40 boolean eofFound = false; 41 int limit = Integer.MAX_VALUE; 42 43 public ASN1InputStream( 44 InputStream is) 45 { 46 super(is); 47 } 48 49 /** 50 * Create an ASN1InputStream based on the input byte array. The length of DER objects in 51 * the stream is automatically limited to the length of the input array. 52 * 53 * @param input array containing ASN.1 encoded data. 54 */ 55 public ASN1InputStream( 56 byte[] input) 57 { 58 this(new ByteArrayInputStream(input), input.length); 59 } 60 61 /** 62 * Create an ASN1InputStream where no DER object will be longer than limit. 63 * 64 * @param input stream containing ASN.1 encoded data. 65 * @param limit maximum size of a DER encoded object. 66 */ 67 public ASN1InputStream( 68 InputStream input, 69 int limit) 70 { 71 super(input); 72 this.limit = limit; 73 } 74 75 protected int readLength() 76 throws IOException 77 { 78 int length = read(); 79 if (length < 0) 80 { 81 throw new IOException("EOF found when length expected"); 82 } 83 84 if (length == 0x80) 85 { 86 return -1; // indefinite-length encoding 87 } 88 89 if (length > 127) 90 { 91 int size = length & 0x7f; 92 93 if (size > 4) 94 { 95 throw new IOException("DER length more than 4 bytes"); 96 } 97 98 length = 0; 99 for (int i = 0; i < size; i++) 100 { 101 int next = read(); 102 103 if (next < 0) 104 { 105 throw new IOException("EOF found reading length"); 106 } 107 108 length = (length << 8) + next; 109 } 110 111 if (length < 0) 112 { 113 throw new IOException("corrupted steam - negative length found"); 114 } 115 116 if (length >= limit) // after all we must have read at least 1 byte 117 { 118 throw new IOException("corrupted steam - out of bounds length found"); 119 } 120 } 121 122 return length; 123 } 124 125 protected void readFully( 126 byte[] bytes) 127 throws IOException 128 { 129 int left = bytes.length; 130 int len; 131 132 if (left == 0) 133 { 134 return; 135 } 136 137 while ((len = read(bytes, bytes.length - left, left)) > 0) 138 { 139 if ((left -= len) == 0) 140 { 141 return; 142 } 143 } 144 145 if (left != 0) 146 { 147 throw new EOFException("EOF encountered in middle of object"); 148 } 149 } 150 151 /** 152 * build an object given its tag and a byte stream to construct it 153 * from. 154 */ 155 protected DERObject buildObject( 156 int tag, 157 int tagNo, 158 byte[] bytes) 159 throws IOException 160 { 161 if ((tag & APPLICATION) != 0) 162 { 163 return new DERApplicationSpecific(tag, bytes); 164 } 165 166 switch (tag) 167 { 168 case NULL: 169 // BEGIN android-changed 170 return DERNull.THE_ONE; 171 //END android-changed 172 case SEQUENCE | CONSTRUCTED: 173 ASN1InputStream aIn = new ASN1InputStream(bytes); 174 ASN1EncodableVector v = new ASN1EncodableVector(); 175 176 DERObject obj = aIn.readObject(); 177 178 while (obj != null) 179 { 180 v.add(obj); 181 obj = aIn.readObject(); 182 } 183 184 return new DERSequence(v); 185 case SET | CONSTRUCTED: 186 aIn = new ASN1InputStream(bytes); 187 v = new ASN1EncodableVector(); 188 189 obj = aIn.readObject(); 190 191 while (obj != null) 192 { 193 v.add(obj); 194 obj = aIn.readObject(); 195 } 196 197 return new DERSet(v, false); 198 case BOOLEAN: 199 // BEGIN android-changed 200 return DERBoolean.getInstance(bytes); 201 // END android-changed 202 case INTEGER: 203 return new DERInteger(bytes); 204 case ENUMERATED: 205 return new DEREnumerated(bytes); 206 case OBJECT_IDENTIFIER: 207 return new DERObjectIdentifier(bytes); 208 case BIT_STRING: 209 int padBits = bytes[0]; 210 byte[] data = new byte[bytes.length - 1]; 211 212 System.arraycopy(bytes, 1, data, 0, bytes.length - 1); 213 214 return new DERBitString(data, padBits); 215 case NUMERIC_STRING: 216 return new DERNumericString(bytes); 217 case UTF8_STRING: 218 return new DERUTF8String(bytes); 219 case PRINTABLE_STRING: 220 return new DERPrintableString(bytes); 221 case IA5_STRING: 222 return new DERIA5String(bytes); 223 case T61_STRING: 224 return new DERT61String(bytes); 225 case VISIBLE_STRING: 226 return new DERVisibleString(bytes); 227 case GENERAL_STRING: 228 return new DERGeneralString(bytes); 229 case UNIVERSAL_STRING: 230 return new DERUniversalString(bytes); 231 case BMP_STRING: 232 return new DERBMPString(bytes); 233 case OCTET_STRING: 234 return new DEROctetString(bytes); 235 case OCTET_STRING | CONSTRUCTED: 236 return buildDerConstructedOctetString(bytes); 237 case UTC_TIME: 238 return new DERUTCTime(bytes); 239 case GENERALIZED_TIME: 240 return new DERGeneralizedTime(bytes); 241 default: 242 // 243 // with tagged object tag number is bottom 5 bits 244 // 245 246 if ((tag & TAGGED) != 0) 247 { 248 if (bytes.length == 0) // empty tag! 249 { 250 if ((tag & CONSTRUCTED) == 0) 251 { 252 // BEGIN android-changed 253 return new DERTaggedObject(false, tagNo, DERNull.THE_ONE); 254 // END android-changed 255 } 256 else 257 { 258 return new DERTaggedObject(false, tagNo, new DERSequence()); 259 } 260 } 261 262 // 263 // simple type - implicit... return an octet string 264 // 265 if ((tag & CONSTRUCTED) == 0) 266 { 267 return new DERTaggedObject(false, tagNo, new DEROctetString(bytes)); 268 } 269 270 aIn = new ASN1InputStream(bytes); 271 272 DEREncodable dObj = aIn.readObject(); 273 274 // 275 // explicitly tagged (probably!) - if it isn't we'd have to 276 // tell from the context 277 // 278 if (aIn.available() == 0) 279 { 280 return new DERTaggedObject(tagNo, dObj); 281 } 282 283 // 284 // another implicit object, we'll create a sequence... 285 // 286 v = new ASN1EncodableVector(); 287 288 while (dObj != null) 289 { 290 v.add(dObj); 291 dObj = aIn.readObject(); 292 } 293 294 return new DERTaggedObject(false, tagNo, new DERSequence(v)); 295 } 296 297 return new DERUnknownTag(tag, bytes); 298 } 299 } 300 301 /** 302 * read a string of bytes representing an indefinite length object. 303 */ 304 private byte[] readIndefiniteLengthFully() 305 throws IOException 306 { 307 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 308 int b, b1; 309 310 b1 = read(); 311 312 while ((b = read()) >= 0) 313 { 314 if (b1 == 0 && b == 0) 315 { 316 break; 317 } 318 319 bOut.write(b1); 320 b1 = b; 321 } 322 323 return bOut.toByteArray(); 324 } 325 326 private BERConstructedOctetString buildConstructedOctetString() 327 throws IOException 328 { 329 Vector octs = new Vector(); 330 331 for (;;) 332 { 333 DERObject o = readObject(); 334 335 if (o == END_OF_STREAM) 336 { 337 break; 338 } 339 340 octs.addElement(o); 341 } 342 343 return new BERConstructedOctetString(octs); 344 } 345 346 // 347 // yes, people actually do this... 348 // 349 private BERConstructedOctetString buildDerConstructedOctetString(byte[] input) 350 throws IOException 351 { 352 Vector octs = new Vector(); 353 ASN1InputStream aIn = new ASN1InputStream(input); 354 DERObject o; 355 356 while ((o = aIn.readObject()) != null) 357 { 358 octs.addElement(o); 359 } 360 361 return new BERConstructedOctetString(octs); 362 } 363 364 public DERObject readObject() 365 throws IOException 366 { 367 int tag = read(); 368 if (tag == -1) 369 { 370 if (eofFound) 371 { 372 throw new EOFException("attempt to read past end of file."); 373 } 374 375 eofFound = true; 376 377 return null; 378 } 379 380 int tagNo = 0; 381 382 if ((tag & TAGGED) != 0) 383 { 384 tagNo = readTagNumber(tag); 385 } 386 387 int length = readLength(); 388 389 if (length < 0) // indefinite length method 390 { 391 switch (tag) 392 { 393 case NULL: 394 // BEGIN android-changed 395 return BERNull.THE_ONE; 396 // END android-changed 397 case SEQUENCE | CONSTRUCTED: 398 ASN1EncodableVector v = new ASN1EncodableVector(); 399 400 for (;;) 401 { 402 DERObject obj = readObject(); 403 404 if (obj == END_OF_STREAM) 405 { 406 break; 407 } 408 409 v.add(obj); 410 } 411 return new BERSequence(v); 412 case SET | CONSTRUCTED: 413 v = new ASN1EncodableVector(); 414 415 for (;;) 416 { 417 DERObject obj = readObject(); 418 419 if (obj == END_OF_STREAM) 420 { 421 break; 422 } 423 424 v.add(obj); 425 } 426 return new BERSet(v, false); 427 case OCTET_STRING | CONSTRUCTED: 428 return buildConstructedOctetString(); 429 default: 430 // 431 // with tagged object tag number is bottom 5 bits 432 // 433 if ((tag & TAGGED) != 0) 434 { 435 // 436 // simple type - implicit... return an octet string 437 // 438 if ((tag & CONSTRUCTED) == 0) 439 { 440 byte[] bytes = readIndefiniteLengthFully(); 441 442 return new BERTaggedObject(false, tagNo, new DEROctetString(bytes)); 443 } 444 445 // 446 // either constructed or explicitly tagged 447 // 448 DERObject dObj = readObject(); 449 450 if (dObj == END_OF_STREAM) // empty tag! 451 { 452 return new DERTaggedObject(tagNo); 453 } 454 455 DERObject next = readObject(); 456 457 // 458 // explicitly tagged (probably!) - if it isn't we'd have to 459 // tell from the context 460 // 461 if (next == END_OF_STREAM) 462 { 463 return new BERTaggedObject(tagNo, dObj); 464 } 465 466 // 467 // another implicit object, we'll create a sequence... 468 // 469 v = new ASN1EncodableVector(); 470 471 v.add(dObj); 472 473 do 474 { 475 v.add(next); 476 next = readObject(); 477 } 478 while (next != END_OF_STREAM); 479 480 return new BERTaggedObject(false, tagNo, new BERSequence(v)); 481 } 482 483 throw new IOException("unknown BER object encountered"); 484 } 485 } 486 else 487 { 488 if (tag == 0 && length == 0) // end of contents marker. 489 { 490 return END_OF_STREAM; 491 } 492 493 byte[] bytes = new byte[length]; 494 495 readFully(bytes); 496 497 return buildObject(tag, tagNo, bytes); 498 } 499 } 500 501 private int readTagNumber(int tag) 502 throws IOException 503 { 504 int tagNo = tag & 0x1f; 505 506 if (tagNo == 0x1f) 507 { 508 int b = read(); 509 510 tagNo = 0; 511 512 while ((b >= 0) && ((b & 0x80) != 0)) 513 { 514 tagNo |= (b & 0x7f); 515 tagNo <<= 7; 516 b = read(); 517 } 518 519 if (b < 0) 520 { 521 eofFound = true; 522 throw new EOFException("EOF found inside tag value."); 523 } 524 525 tagNo |= (b & 0x7f); 526 } 527 528 return tagNo; 529 } 530 } 531 532