1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /** 19 * @author Vladimir N. Molotkov, Stepan M. Mishura 20 * @version $Revision$ 21 */ 22 23 package org.apache.harmony.security.asn1; 24 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.util.ArrayList; 28 29 30 /** 31 * Decodes ASN.1 types encoded with BER (X.690) 32 * 33 * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a> 34 */ 35 36 public class BerInputStream { 37 38 /** 39 * Associated <code>InputStream</code> 40 */ 41 protected InputStream in; 42 43 /** 44 * Internal buffer for storing encoded array 45 */ 46 protected byte[] buffer; 47 48 /** 49 * The position in the buffer. 50 * 51 * Next read must place data into the buffer from this offset 52 */ 53 protected int offset = 0; 54 55 // The buffer increment size. 56 // Must be reasonable big to reallocate memory not to often. 57 // Primary is used for decoding indefinite length encoding 58 private static final int BUF_INCREASE_SIZE = 1024 * 16; 59 60 /** 61 * Indicates indefinite length of the current type 62 */ 63 protected static final int INDEFINIT_LENGTH = -1; 64 65 /** 66 * Creates stream for decoding. 67 * 68 * @param encoded - bytes array to be decoded 69 * @throws IOException - if an error occurs 70 */ 71 public BerInputStream(byte[] encoded) throws IOException { 72 this(encoded, 0, encoded.length); 73 } 74 75 /** 76 * Creates stream for decoding. 77 * 78 * @param encoded - 79 * bytes array to be decoded 80 * @param offset - 81 * the encoding offset 82 * @param expectedLength - 83 * expected length of full encoding, this includes identifier, 84 * length an content octets 85 * @throws IOException - 86 * if an error occurs 87 */ 88 public BerInputStream(byte[] encoded, int offset, int expectedLength) 89 throws IOException { 90 91 this.buffer = encoded; 92 this.offset = offset; 93 94 next(); 95 96 // compare expected and decoded length 97 if (length != INDEFINIT_LENGTH 98 && (offset + expectedLength) != (this.offset + this.length)) { 99 throw new ASN1Exception("Wrong content length"); 100 } 101 } 102 103 /** 104 * Creates stream for decoding. 105 * 106 * Allocates initial buffer of default size 107 * 108 * @param is associated <code>InputStream</code> 109 */ 110 public BerInputStream(InputStream in) throws IOException { 111 this(in, BUF_INCREASE_SIZE); 112 } 113 114 /** 115 * Creates stream for decoding. 116 * 117 * Allocates initial buffer of <code>initialSize</code> size 118 * 119 * @param initialSize the internal buffer initial size 120 * @param is associated <code>InputStream</code> 121 */ 122 public BerInputStream(InputStream in, int initialSize) throws IOException { 123 124 this.in = in; 125 buffer = new byte[initialSize]; 126 127 next(); 128 129 if (length != INDEFINIT_LENGTH) { 130 // input stream has definite length encoding 131 // check allocated length to avoid further reallocations 132 if (buffer.length < (length + offset)) { 133 byte[] newBuffer = new byte[length + offset]; 134 System.arraycopy(buffer, 0, newBuffer, 0, offset); 135 buffer = newBuffer; 136 } 137 } else { 138 isIndefinedLength = true; 139 throw new ASN1Exception("Decoding indefinite length encoding is not supported"); 140 } 141 } 142 143 /** 144 * Resets this stream to initial state. 145 * 146 * @param encoded - a new bytes array to be decoded 147 * @throws IOException - if an error occurs 148 */ 149 public final void reset(byte[] encoded) throws IOException { 150 buffer = encoded; 151 152 next(); 153 } 154 155 /** 156 * Current decoded tag 157 */ 158 public int tag; 159 160 /** 161 * Current decoded length 162 */ 163 protected int length; 164 165 /** 166 * Current decoded content 167 */ 168 public Object content; 169 170 /** 171 * Current decoded tag offset 172 */ 173 protected int tagOffset; 174 175 /** 176 * Current decoded content offset 177 */ 178 protected int contentOffset; 179 180 /** 181 * Decodes next encoded type. 182 * Initializes tag, length, tagOffset and contentOffset variables 183 * 184 * @return next decoded tag 185 * @throws IOException - if error occured 186 */ 187 public int next() throws IOException { 188 189 tagOffset = offset; 190 191 // read tag 192 tag = read(); 193 194 // read length 195 length = read(); 196 if (length != 0x80) { // definite form 197 // long or short length form 198 if ((length & 0x80) != 0) { // long form 199 int numOctets = length & 0x7F; 200 201 if (numOctets > 5) { 202 throw new ASN1Exception("Too long encoding at [" + tagOffset + "]"); //FIXME message 203 } 204 205 // collect this value length 206 length = read(); 207 for (int i = 1; i < numOctets; i++) { 208 int ch = read(); 209 length = (length << 8) + ch;//read(); 210 } 211 212 if (length > 0xFFFFFF) { 213 throw new ASN1Exception("Too long encoding at [" + tagOffset + "]"); //FIXME message 214 } 215 } 216 } else { //indefinite form 217 length = INDEFINIT_LENGTH; 218 } 219 contentOffset = offset; 220 221 return tag; 222 } 223 224 /** 225 * Returns the length of the encoding 226 */ 227 public static int getLength(byte[] encoding) { 228 int length = encoding[1] & 0xFF; 229 int numOctets = 0; 230 if ((length & 0x80) != 0) { // long form 231 numOctets = length & 0x7F; 232 233 // collect this value length 234 length = encoding[2] & 0xFF; 235 for (int i = 3; i < numOctets + 2; i++) { 236 length = (length << 8) + (encoding[i] & 0xFF); 237 } 238 } 239 // tag length long_form content 240 return 1 + 1 + numOctets + length; 241 } 242 243 /** 244 * Decodes ASN.1 bitstring type 245 * 246 * @throws IOException - if error occured 247 */ 248 public void readBitString() throws IOException { 249 250 if (tag == ASN1Constants.TAG_BITSTRING) { 251 252 if (length == 0) { 253 throw new ASN1Exception("ASN.1 Bitstring: wrong length. Tag at [" + tagOffset + "]"); 254 } 255 256 readContent(); 257 258 // content: check unused bits 259 if (buffer[contentOffset] > 7) { 260 throw new ASN1Exception("ASN.1 Bitstring: wrong content at [" + contentOffset + "]. A number of unused bits MUST be in range 0 to 7"); 261 } 262 263 if (length == 1 && buffer[contentOffset] != 0) { 264 throw new ASN1Exception("ASN.1 Bitstring: wrong content at [" + contentOffset + "]. For empty string unused bits MUST be 0"); 265 } 266 267 } else if (tag == ASN1Constants.TAG_C_BITSTRING) { 268 throw new ASN1Exception("Decoding constructed ASN.1 bitstring type is not provided"); 269 } else { 270 throw expected("bitstring"); 271 } 272 } 273 274 /** 275 * Decodes ASN.1 Enumerated type 276 * 277 * @throws IOException - if error occured 278 */ 279 public void readEnumerated() throws IOException { 280 281 if (tag != ASN1Constants.TAG_ENUM) { 282 throw expected("enumerated"); 283 } 284 285 // 286 // all checks are the same as for ASN.1 integer type 287 // 288 289 // check encoded length 290 if (length == 0) { 291 throw new ASN1Exception("ASN.1 enumerated: wrong length for identifier at [" + tagOffset + "]"); 292 } 293 294 readContent(); 295 296 // check encoded content 297 if (length > 1) { 298 299 int bits = buffer[contentOffset] & 0xFF; 300 if (buffer[contentOffset + 1] < 0) { 301 bits += 0x100; 302 } 303 304 if (bits == 0 || bits == 0x1FF) { 305 throw new ASN1Exception("ASN.1 enumerated: wrong content at [" + contentOffset + "]. An integer MUST be encoded in minimum number of octets"); 306 } 307 } 308 } 309 310 /** 311 * Decodes ASN.1 boolean type 312 * 313 * @throws IOException - if error occured 314 */ 315 public void readBoolean() throws IOException { 316 317 if (tag != ASN1Constants.TAG_BOOLEAN) { 318 throw expected("boolean"); 319 } 320 321 // check encoded length 322 if (length != 1) { 323 throw new ASN1Exception("Wrong length for ASN.1 boolean at [" + tagOffset + "]"); 324 } 325 326 readContent(); 327 } 328 329 /** 330 * The last choice index 331 */ 332 public int choiceIndex; 333 334 /** 335 * Keeps last decoded: year, month, day, hour, minute, second, millisecond 336 */ 337 public int[] times; 338 339 /** 340 * Decodes ASN.1 GeneralizedTime type 341 * 342 * @throws IOException - if error occured 343 */ 344 public void readGeneralizedTime() throws IOException { 345 346 if (tag == ASN1Constants.TAG_GENERALIZEDTIME) { 347 348 // FIXME: any other optimizations? 349 readContent(); 350 // FIXME store string somewhere to allow a custom time type perform 351 // additional checks 352 353 // check syntax: the last char MUST be Z 354 if (buffer[offset - 1] != 'Z') { 355 // FIXME support only format that is acceptable for DER 356 throw new ASN1Exception("ASN.1 GeneralizedTime: encoded format is not implemented"); 357 } 358 359 // check syntax: MUST be YYYYMMDDHHMMSS[(./,)DDD]'Z' 360 if (length != 15 && (length < 17 || length > 19)) // invalid 361 // length 362 { 363 throw new ASN1Exception("ASN.1 GeneralizedTime wrongly encoded at [" + contentOffset + "]"); 364 } 365 366 // check content: milliseconds 367 if (length > 16) { 368 byte char14 = buffer[contentOffset + 14]; 369 if (char14 != '.' && char14 != ',') { 370 throw new ASN1Exception("ASN.1 GeneralizedTime wrongly encoded at [" + contentOffset + "]"); 371 } 372 } 373 374 if (times == null) { 375 times = new int[7]; 376 } 377 times[0] = strToInt(contentOffset, 4); // year 378 times[1] = strToInt(contentOffset + 4, 2); // month 379 times[2] = strToInt(contentOffset + 6, 2); // day 380 times[3] = strToInt(contentOffset + 8, 2); // hour 381 times[4] = strToInt(contentOffset + 10, 2); // minute 382 times[5] = strToInt(contentOffset + 12, 2); // second 383 384 if (length > 16) { 385 // FIXME optimize me 386 times[6] = strToInt(contentOffset + 15, length - 16); 387 388 if (length == 17) { 389 times[6] = times[6] * 100; 390 } else if (length == 18) { 391 times[6] = times[6] * 10; 392 } 393 } 394 395 // FIXME check all values for valid numbers!!! 396 } else if (tag == ASN1Constants.TAG_C_GENERALIZEDTIME) { 397 throw new ASN1Exception("Decoding constructed ASN.1 GeneralizedTime type is not supported"); 398 } else { 399 throw expected("GeneralizedTime"); 400 } 401 } 402 403 /** 404 * Decodes ASN.1 UTCTime type 405 * 406 * @throws IOException - if an I/O error occurs or the end of the stream is reached 407 */ 408 public void readUTCTime() throws IOException { 409 410 if (tag == ASN1Constants.TAG_UTCTIME) { 411 412 switch (length) { 413 case ASN1UTCTime.UTC_HM: 414 case ASN1UTCTime.UTC_HMS: 415 break; 416 case ASN1UTCTime.UTC_LOCAL_HM: 417 case ASN1UTCTime.UTC_LOCAL_HMS: 418 // FIXME only coordinated universal time formats are supported 419 throw new ASN1Exception("ASN.1 UTCTime: local time format is not supported"); 420 default: 421 throw new ASN1Exception("ASN.1 UTCTime: wrong length, identifier at " + tagOffset); 422 } 423 424 // FIXME: any other optimizations? 425 readContent(); 426 427 // FIXME store string somewhere to allow a custom time type perform 428 // additional checks 429 430 // check syntax: the last char MUST be Z 431 if (buffer[offset - 1] != 'Z') { 432 throw new ASN1Exception("ASN.1 UTCTime wrongly encoded at [" 433 + contentOffset + ']'); 434 } 435 436 if (times == null) { 437 times = new int[7]; 438 } 439 440 times[0] = strToInt(contentOffset, 2); // year 441 if (times[0] > 49) { 442 times[0] += 1900; 443 } else { 444 times[0] += 2000; 445 } 446 447 times[1] = strToInt(contentOffset + 2, 2); // month 448 times[2] = strToInt(contentOffset + 4, 2); // day 449 times[3] = strToInt(contentOffset + 6, 2); // hour 450 times[4] = strToInt(contentOffset + 8, 2); // minute 451 452 if (length == ASN1UTCTime.UTC_HMS) { 453 times[5] = strToInt(contentOffset + 10, 2); // second 454 } 455 456 // FIXME check all time values for valid numbers!!! 457 } else if (tag == ASN1Constants.TAG_C_UTCTIME) { 458 throw new ASN1Exception("Decoding constructed ASN.1 UTCTime type is not supported"); 459 } else { 460 throw expected("UTCTime"); 461 } 462 } 463 464 //TODO comment me 465 private int strToInt(int off, int count) throws ASN1Exception { 466 467 //FIXME works only with buffer 468 469 int c; 470 int result = 0; 471 for (int i = off, end = off + count; i < end; i++) { 472 c = buffer[i] - 48; 473 if (c < 0 || c > 9) { 474 throw new ASN1Exception("Time encoding has invalid char"); 475 } 476 result = result * 10 + c; 477 } 478 return result; 479 } 480 481 /** 482 * Decodes ASN.1 Integer type 483 * 484 * @throws IOException - if error occured 485 */ 486 public void readInteger() throws IOException { 487 488 if (tag != ASN1Constants.TAG_INTEGER) { 489 throw expected("integer"); 490 } 491 492 // check encoded length 493 if (length < 1) { 494 throw new ASN1Exception("Wrong length for ASN.1 integer at [" + tagOffset + "]"); 495 } 496 497 readContent(); 498 499 // check encoded content 500 if (length > 1) { 501 502 byte firstByte = buffer[offset - length]; 503 byte secondByte = (byte) (buffer[offset - length + 1] & 0x80); 504 505 if (firstByte == 0 && secondByte == 0 || firstByte == (byte) 0xFF 506 && secondByte == (byte) 0x80) { 507 throw new ASN1Exception("Wrong content for ASN.1 integer at [" + (offset - length) + "]. An integer MUST be encoded in minimum number of octets"); 508 } 509 } 510 } 511 512 /** 513 * Decodes ASN.1 Octetstring type 514 * 515 * @throws IOException - if error occured 516 */ 517 public void readOctetString() throws IOException { 518 519 if (tag == ASN1Constants.TAG_OCTETSTRING) { 520 readContent(); 521 } else if (tag == ASN1Constants.TAG_C_OCTETSTRING) { 522 throw new ASN1Exception("Decoding constructed ASN.1 octet string type is not supported"); 523 } else { 524 throw expected("octetstring"); 525 } 526 } 527 528 private ASN1Exception expected(String what) throws ASN1Exception { 529 throw new ASN1Exception("ASN.1 " + what + " identifier expected at [" + tagOffset + "], got " + Integer.toHexString(tag)); 530 } 531 532 //FIXME comment me 533 public int oidElement; 534 535 /** 536 * Decodes ASN.1 ObjectIdentifier type 537 * 538 * @throws IOException - if error occured 539 */ 540 public void readOID() throws IOException { 541 542 if (tag != ASN1Constants.TAG_OID) { 543 throw expected("OID"); 544 } 545 546 // check encoded length 547 if (length < 1) { 548 throw new ASN1Exception("Wrong length for ASN.1 object identifier at [" + tagOffset + "]"); 549 } 550 551 readContent(); 552 553 // check content: last encoded byte (8th bit MUST be zero) 554 if ((buffer[offset - 1] & 0x80) != 0) { 555 throw new ASN1Exception("Wrong encoding at [" + (offset - 1) + "]"); 556 } 557 558 oidElement = 1; 559 for (int i = 0; i < length; i++, ++oidElement) { 560 561 // According to ASN.1 BER spec: 562 // leading octet of subidentifier MUST not be 0x80 563 // This assertion is not verified 564 // 565 //if (buffer[contentOffset + i] == (byte)0x80) { 566 // throw new ASN1Exception( 567 // "Wrong content for ASN.1 object identifier at [" 568 // + contentOffset 569 // + "]. Subidentifier MUST be encoded in minimum number of octets"); 570 //} 571 572 while ((buffer[contentOffset + i] & 0x80) == 0x80) { 573 i++; 574 } 575 } 576 } 577 578 /** 579 * Decodes ASN.1 Sequence type 580 * 581 * @param sequence - ASN.1 sequence to be decoded 582 * @throws IOException - if error occured 583 */ 584 public void readSequence(ASN1Sequence sequence) throws IOException { 585 586 if (tag != ASN1Constants.TAG_C_SEQUENCE) { 587 throw expected("sequence"); 588 } 589 590 int begOffset = offset; 591 int endOffset = begOffset + length; 592 593 ASN1Type[] type = sequence.type; 594 595 int i = 0; 596 597 if (isVerify) { 598 599 for (; (offset < endOffset) && (i < type.length); i++) { 600 601 next(); 602 while (!type[i].checkTag(tag)) { 603 // check whether it is optional component or not 604 if (!sequence.OPTIONAL[i] || (i == type.length - 1)) { 605 throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]"); 606 } 607 i++; 608 } 609 610 type[i].decode(this); 611 } 612 613 // check the rest of components 614 for (; i < type.length; i++) { 615 if (!sequence.OPTIONAL[i]) { 616 throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]"); 617 } 618 } 619 620 } else { 621 622 int seqTagOffset = tagOffset; //store tag offset 623 624 Object[] values = new Object[type.length]; 625 for (; (offset < endOffset) && (i < type.length); i++) { 626 627 next(); 628 while (!type[i].checkTag(tag)) { 629 // check whether it is optional component or not 630 if (!sequence.OPTIONAL[i] || (i == type.length - 1)) { 631 throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]"); 632 } 633 634 // sets default value 635 if (sequence.DEFAULT[i] != null) { 636 values[i] = sequence.DEFAULT[i]; 637 } 638 i++; 639 } 640 values[i] = type[i].decode(this); 641 } 642 643 // check the rest of components 644 for (; i < type.length; i++) { 645 if (!sequence.OPTIONAL[i]) { 646 throw new ASN1Exception("ASN.1 Sequence: mandatory value is missing at [" + tagOffset + "]"); 647 } 648 if (sequence.DEFAULT[i] != null) { 649 values[i] = sequence.DEFAULT[i]; 650 } 651 } 652 content = values; 653 654 tagOffset = seqTagOffset; //retrieve tag offset 655 } 656 657 if (offset != endOffset) { 658 throw new ASN1Exception("Wrong encoding at [" + begOffset + "]. Content's length and encoded length are not the same"); 659 } 660 } 661 662 /** 663 * Decodes ASN.1 SequenceOf type 664 * 665 * @param sequenceOf - ASN.1 sequence to be decoded 666 * @throws IOException - if error occured 667 */ 668 public void readSequenceOf(ASN1SequenceOf sequenceOf) throws IOException { 669 670 if (tag != ASN1Constants.TAG_C_SEQUENCEOF) { 671 throw expected("sequenceOf"); 672 } 673 674 decodeValueCollection(sequenceOf); 675 } 676 677 /** 678 * Decodes ASN.1 Set type 679 * 680 * @param set - ASN.1 set to be decoded 681 * @throws IOException - if error occured 682 */ 683 public void readSet(ASN1Set set) throws IOException { 684 685 if (tag != ASN1Constants.TAG_C_SET) { 686 throw expected("set"); 687 } 688 689 throw new ASN1Exception("Decoding ASN.1 Set type is not supported"); 690 } 691 692 /** 693 * Decodes ASN.1 SetOf type 694 * 695 * @param set - ASN.1 set to be decoded 696 * @throws IOException - if error occured 697 */ 698 public void readSetOf(ASN1SetOf setOf) throws IOException { 699 700 if (tag != ASN1Constants.TAG_C_SETOF) { 701 throw expected("setOf"); 702 } 703 704 decodeValueCollection(setOf); 705 } 706 707 private final void decodeValueCollection(ASN1ValueCollection collection) 708 throws IOException { 709 710 int begOffset = offset; 711 int endOffset = begOffset + length; 712 713 ASN1Type type = collection.type; 714 715 if (isVerify) { 716 while (endOffset > offset) { 717 next(); 718 type.decode(this); 719 } 720 } else { 721 722 int seqTagOffset = tagOffset; //store tag offset 723 724 ArrayList values = new ArrayList(); 725 while (endOffset > offset) { 726 next(); 727 values.add(type.decode(this)); 728 } 729 730 content = values; 731 732 tagOffset = seqTagOffset; //retrieve tag offset 733 } 734 735 if (offset != endOffset) { 736 throw new ASN1Exception("Wrong encoding at [" + begOffset + "]. Content's length and encoded length are not the same"); 737 } 738 } 739 740 /** 741 * Decodes ASN.1 String type 742 * 743 * @throws IOException - if an I/O error occurs or the end of the stream is reached 744 */ 745 public void readString(ASN1StringType type) throws IOException { 746 747 //FIXME check string content 748 if (tag == type.id) { 749 readContent(); 750 } else if (tag == type.constrId) { 751 throw new ASN1Exception("Decoding constructed ASN.1 string type is not provided"); 752 } else { 753 throw expected("string"); 754 } 755 } 756 757 /** 758 * Returns encoded array. 759 * 760 * MUST be invoked after decoding corresponding ASN.1 notation 761 */ 762 public byte[] getEncoded() { 763 byte[] encoded = new byte[offset - tagOffset]; 764 System.arraycopy(buffer, tagOffset, encoded, 0, encoded.length); 765 return encoded; 766 } 767 768 /** 769 * Returns internal buffer used for decoding 770 * 771 * @return - buffer 772 */ 773 public final byte[] getBuffer() { 774 return buffer; 775 } 776 777 /** 778 * Returns length of the current content for decoding 779 * 780 * @return - length of content 781 */ 782 public final int getLength() { 783 return length; 784 } 785 786 /** 787 * Returns the current offset 788 * 789 * @return - offset 790 */ 791 public final int getOffset() { 792 return offset; 793 } 794 795 /** 796 * Returns end offset for the current encoded type 797 * 798 * @return - offset 799 */ 800 public final int getEndOffset() { 801 return offset + length; 802 } 803 804 /** 805 * Returns start offset for the current encoded type 806 * 807 * @return - offset 808 */ 809 public final int getTagOffset() { 810 return tagOffset; 811 } 812 813 public final int getContentOffset() { 814 return contentOffset; 815 } 816 817 /** 818 * Indicates verify or store mode. 819 * 820 * In store mode a decoded content is stored in a newly allocated 821 * appropriate object. The <code>content</code> variable holds 822 * a reference to the last created object. 823 * 824 * In verify mode a decoded content is not stored. 825 */ 826 // FIXME it is used only for one case 827 // decoding PCKS#8 Private Key Info notation 828 // remove this option because it does decoding more complex 829 protected boolean isVerify; 830 831 /** 832 * Sets verify mode. 833 */ 834 public final void setVerify() { 835 isVerify = true; 836 } 837 838 /** 839 * Indicates defined or indefined reading mode for associated InputStream. 840 * 841 * This mode is defined by reading a length 842 * for a first ASN.1 type from InputStream. 843 */ 844 protected boolean isIndefinedLength; 845 846 /** 847 * Reads the next encoded byte from the encoded input stream. 848 * 849 * @return the next encoded byte 850 * @throws IOException - if error occured 851 */ 852 protected int read() throws IOException { 853 854 if (offset == buffer.length) { 855 throw new ASN1Exception("Unexpected end of encoding"); 856 } 857 858 if (in == null) { 859 return buffer[offset++] & 0xFF; 860 } else { 861 int octet = in.read(); 862 if (octet == -1) { 863 throw new ASN1Exception("Unexpected end of encoding"); 864 } 865 866 buffer[offset++] = (byte) octet; 867 868 return octet; 869 } 870 } 871 872 /** 873 * Reads the next encoded content from the encoded input stream. 874 * The method MUST be used for reading a primitive encoded content. 875 * 876 * @throws IOException - if error occured 877 */ 878 public void readContent() throws IOException { 879 if (offset + length > buffer.length) { 880 throw new ASN1Exception("Unexpected end of encoding"); 881 } 882 883 if (in == null) { 884 offset += length; 885 } else { 886 int bytesRead = in.read(buffer, offset, length); 887 888 if (bytesRead != length) { 889 // if input stream didn't return all data at once 890 // try to read it in several blocks 891 int c = bytesRead; 892 do { 893 if (c < 1 || bytesRead > length) { 894 throw new ASN1Exception("Failed to read encoded content"); 895 } 896 c = in.read(buffer, offset + bytesRead, length - bytesRead); 897 bytesRead += c; 898 } while (bytesRead != length); 899 } 900 901 offset += length; 902 } 903 } 904 905 // // reallocates internal buffer for indefined reading mode 906 // private void reallocateBuffer(int n) { 907 // int newSize; 908 // for (newSize = buffer.length * 2; newSize < buffer.length + n; newSize = newSize * 2) 909 // ; 910 // byte[] newBuffer = new byte[newSize]; 911 // System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); 912 // buffer = newBuffer; 913 // } 914 915 /** 916 * Reallocates the buffer in order to make it 917 * exactly the size of data it contains 918 */ 919 public void compactBuffer() { 920 if (offset != buffer.length) { 921 byte[] newBuffer = new byte[offset]; 922 // restore buffer content 923 System.arraycopy(buffer, 0, newBuffer, 0, offset); 924 // set new buffer 925 buffer = newBuffer; 926 } 927 } 928 929 // 930 // 931 // 932 // 933 // 934 935 private Object[][] pool; 936 937 public void put(Object key, Object entry) { 938 939 if (pool == null) { 940 pool = new Object[2][10]; 941 } 942 943 int i = 0; 944 for (; i < pool[0].length && pool[0][i] != null; i++) { 945 if (pool[0][i] == key) { 946 pool[1][i] = entry; 947 return; 948 } 949 } 950 951 if (i == pool[0].length) { 952 Object[][] newPool = new Object[pool[0].length * 2][2]; 953 System.arraycopy(pool[0], 0, newPool[0], 0, pool[0].length); 954 System.arraycopy(pool[1], 0, newPool[1], 0, pool[0].length); 955 pool = newPool; 956 } else { 957 pool[0][i] = key; 958 pool[1][i] = entry; 959 } 960 } 961 962 public Object get(Object key) { 963 964 if (pool == null) { 965 return null; 966 } 967 968 for (int i = 0; i < pool[0].length; i++) { 969 if (pool[0][i] == key) { 970 return pool[1][i]; 971 } 972 } 973 return null; 974 } 975 } 976