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