001/* 002 * Copyright 2009-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2009-2018 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.asn1; 022 023 024 025import java.io.BufferedInputStream; 026import java.io.ByteArrayInputStream; 027import java.io.Closeable; 028import java.io.InputStream; 029import java.io.IOException; 030import java.math.BigInteger; 031import java.net.SocketTimeoutException; 032import java.util.Date; 033import java.util.logging.Level; 034import javax.security.sasl.SaslClient; 035 036import com.unboundid.util.Mutable; 037import com.unboundid.util.ThreadSafety; 038import com.unboundid.util.ThreadSafetyLevel; 039 040import static com.unboundid.asn1.ASN1Messages.*; 041import static com.unboundid.util.Debug.*; 042import static com.unboundid.util.StaticUtils.*; 043 044 045 046/** 047 * This class provides a mechanism for ASN.1 elements (including sequences and 048 * sets) from an input stream in a manner that allows the data to be decoded on 049 * the fly without constructing {@link ASN1Element} objects if they are not 050 * needed. If any method in this class throws an {@code IOException}, then the 051 * caller must close this reader and must not attempt to use it any more. 052 * {@code ASN1StreamReader} instances are not threadsafe and must not be 053 * accessed concurrently by multiple threads. 054 */ 055@Mutable() 056@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 057public final class ASN1StreamReader 058 implements Closeable 059{ 060 // Indicates whether socket timeout exceptions should be ignored for the 061 // initial read of an element. 062 private boolean ignoreInitialSocketTimeout; 063 064 // Indicates whether socket timeout exceptions should be ignored for 065 // subsequent reads of an element. 066 private boolean ignoreSubsequentSocketTimeout; 067 068 // The input stream that will be used for reading data after it has been 069 // unwrapped by SASL processing. 070 private volatile ByteArrayInputStream saslInputStream; 071 072 // The input stream from which data will be read. 073 private final InputStream inputStream; 074 075 // The maximum element size that will be allowed. 076 private final int maxElementSize; 077 078 // The total number of bytes read from the underlying input stream. 079 private long totalBytesRead; 080 081 // The SASL client that will be used to unwrap any data read over this 082 // stream reader. 083 private volatile SaslClient saslClient; 084 085 086 087 /** 088 * Creates a new ASN.1 stream reader that will read data from the provided 089 * input stream. It will use a maximum element size of 090 * {@code Integer.MAX_VALUE}. 091 * 092 * @param inputStream The input stream from which data should be read. If 093 * the provided input stream does not support the use of 094 * the {@code mark} and {@code reset} methods, then it 095 * will be wrapped with a {@code BufferedInputStream}. 096 */ 097 public ASN1StreamReader(final InputStream inputStream) 098 { 099 this(inputStream, Integer.MAX_VALUE); 100 } 101 102 103 104 /** 105 * Creates a new ASN.1 stream reader that will read data from the provided 106 * input stream. It will use a maximum element size of 107 * {@code Integer.MAX_VALUE}. 108 * 109 * @param inputStream The input stream from which data should be read. 110 * If the provided input stream does not support the 111 * use of the {@code mark} and {@code reset} methods, 112 * then it will be wrapped with a 113 * {@code BufferedInputStream}. 114 * @param maxElementSize The maximum size in bytes of an ASN.1 element that 115 * may be read. A value less than or equal to zero 116 * will be interpreted as {@code Integer.MAX_VALUE}. 117 */ 118 public ASN1StreamReader(final InputStream inputStream, 119 final int maxElementSize) 120 { 121 if (inputStream.markSupported()) 122 { 123 this.inputStream = inputStream; 124 } 125 else 126 { 127 this.inputStream = new BufferedInputStream(inputStream); 128 } 129 130 if (maxElementSize > 0) 131 { 132 this.maxElementSize = maxElementSize; 133 } 134 else 135 { 136 this.maxElementSize = Integer.MAX_VALUE; 137 } 138 139 totalBytesRead = 0L; 140 ignoreInitialSocketTimeout = false; 141 ignoreSubsequentSocketTimeout = false; 142 saslClient = null; 143 saslInputStream = null; 144 } 145 146 147 148 /** 149 * Closes this ASN.1 stream reader and the underlying input stream. This 150 * reader must not be used after it has been closed. 151 * 152 * @throws IOException If a problem occurs while closing the underlying 153 * input stream. 154 */ 155 public void close() 156 throws IOException 157 { 158 inputStream.close(); 159 } 160 161 162 163 /** 164 * Retrieves the total number of bytes read so far from the underlying input 165 * stream. 166 * 167 * @return The total number of bytes read so far from the underlying input 168 * stream. 169 */ 170 long getTotalBytesRead() 171 { 172 return totalBytesRead; 173 } 174 175 176 177 /** 178 * Indicates whether to ignore {@code java.net.SocketTimeoutException} 179 * exceptions that may be caught during processing. 180 * 181 * @return {@code true} if {@code SocketTimeoutException} exceptions should 182 * be ignored, or {@code false} if they should not be ignored and 183 * should be propagated to the caller. 184 * 185 * @deprecated Use the {@link #ignoreInitialSocketTimeoutException()} and 186 * {@link #ignoreSubsequentSocketTimeoutException()} methods 187 * instead. 188 */ 189 @Deprecated() 190 public boolean ignoreSocketTimeoutException() 191 { 192 return ignoreInitialSocketTimeout; 193 } 194 195 196 197 /** 198 * Indicates whether to ignore {@code java.net.SocketTimeoutException} 199 * exceptions that may be caught while trying to read the first byte of an 200 * element. 201 * 202 * @return {@code true} if {@code SocketTimeoutException} exceptions should 203 * be ignored while trying to read the first byte of an element, or 204 * {@code false} if they should not be ignored and should be 205 * propagated to the caller. 206 */ 207 public boolean ignoreInitialSocketTimeoutException() 208 { 209 return ignoreInitialSocketTimeout; 210 } 211 212 213 214 /** 215 * Indicates whether to ignore {@code java.net.SocketTimeoutException} 216 * exceptions that may be caught while trying to read subsequent bytes of an 217 * element (after one or more bytes have already been read for that element). 218 * 219 * @return {@code true} if {@code SocketTimeoutException} exceptions should 220 * be ignored while trying to read subsequent bytes of an element, or 221 * {@code false} if they should not be ignored and should be 222 * propagated to the caller. 223 */ 224 public boolean ignoreSubsequentSocketTimeoutException() 225 { 226 return ignoreSubsequentSocketTimeout; 227 } 228 229 230 231 /** 232 * Indicates whether to ignore {@code java.net.SocketTimeoutException} 233 * exceptions that may be caught during processing. 234 * 235 * @param ignoreSocketTimeout Indicates whether to ignore 236 * {@code SocketTimeoutException} exceptions that 237 * may be caught during processing. 238 * 239 * @deprecated Use the {@link #setIgnoreSocketTimeout(boolean,boolean)} 240 * method instead. 241 */ 242 @Deprecated() 243 public void setIgnoreSocketTimeout(final boolean ignoreSocketTimeout) 244 { 245 ignoreInitialSocketTimeout = ignoreSocketTimeout; 246 ignoreSubsequentSocketTimeout = ignoreSocketTimeout; 247 } 248 249 250 251 /** 252 * Indicates whether to ignore {@code java.net.SocketTimeoutException} 253 * exceptions that may be caught during processing. 254 * 255 * @param ignoreInitialSocketTimeout Indicates whether to ignore 256 * {@code SocketTimeoutException} 257 * exceptions that may be caught while 258 * trying to read the first byte of an 259 * element. 260 * @param ignoreSubsequentSocketTimeout Indicates whether to ignore 261 * {@code SocketTimeoutException} 262 * exceptions that may be caught while 263 * reading beyond the first byte of an 264 * element. 265 */ 266 public void setIgnoreSocketTimeout(final boolean ignoreInitialSocketTimeout, 267 final boolean ignoreSubsequentSocketTimeout) 268 { 269 this.ignoreInitialSocketTimeout = ignoreInitialSocketTimeout; 270 this.ignoreSubsequentSocketTimeout = ignoreSubsequentSocketTimeout; 271 } 272 273 274 275 /** 276 * Peeks at the next byte to be read from the input stream without actually 277 * consuming it. 278 * 279 * @return An integer value encapsulating the BER type of the next element in 280 * the input stream, or -1 if the end of the input stream has been 281 * reached and there is no data to be read. If a value of -1 is 282 * returned, then the input stream will not have been closed since 283 * this method is not intended to have any impact on the underlying 284 * input stream. 285 * 286 * @throws IOException If a problem occurs while reading from the input 287 * stream. 288 */ 289 public int peek() 290 throws IOException 291 { 292 final InputStream is; 293 if (saslClient == null) 294 { 295 is = inputStream; 296 } 297 else 298 { 299 if (saslInputStream == null) 300 { 301 readAndDecodeSASLData(-1); 302 } 303 304 is = saslInputStream; 305 } 306 307 is.mark(1); 308 final int byteRead = read(true); 309 is.reset(); 310 311 return byteRead; 312 } 313 314 315 316 /** 317 * Reads the BER type of the next element from the input stream. This may not 318 * be called if a previous element has been started but not yet completed. 319 * 320 * @return An integer value encapsulating the BER type of the next element in 321 * the input stream, or -1 if the end of the input stream has been 322 * reached and there is no data to be read. If a value of -1 is 323 * returned, then the input stream will have been closed. 324 * 325 * @throws IOException If a problem occurs while reading from the input 326 * stream. 327 */ 328 private int readType() 329 throws IOException 330 { 331 final int typeInt = read(true); 332 if (typeInt < 0) 333 { 334 close(); 335 } 336 else 337 { 338 totalBytesRead++; 339 } 340 return typeInt; 341 } 342 343 344 345 /** 346 * Reads the length of the next element from the input stream. This may only 347 * be called after reading the BER type. 348 * 349 * @return The length of the next element from the input stream. 350 * 351 * @throws IOException If a problem occurs while reading from the input 352 * stream, if the end of the stream has been reached, or 353 * if the decoded length is greater than the maximum 354 * allowed length. 355 */ 356 private int readLength() 357 throws IOException 358 { 359 int length = read(false); 360 if (length < 0) 361 { 362 throw new IOException(ERR_READ_END_BEFORE_FIRST_LENGTH.get()); 363 } 364 365 totalBytesRead++; 366 if (length > 127) 367 { 368 final int numLengthBytes = length & 0x7F; 369 length = 0; 370 if ((numLengthBytes < 1) || (numLengthBytes > 4)) 371 { 372 throw new IOException(ERR_READ_LENGTH_TOO_LONG.get(numLengthBytes)); 373 } 374 375 for (int i=0; i < numLengthBytes; i++) 376 { 377 final int lengthInt = read(false); 378 if (lengthInt < 0) 379 { 380 throw new IOException(ERR_READ_END_BEFORE_LENGTH_END.get()); 381 } 382 383 length <<= 8; 384 length |= (lengthInt & 0xFF); 385 } 386 387 totalBytesRead += numLengthBytes; 388 } 389 390 if ((length < 0) || ((maxElementSize > 0) && (length > maxElementSize))) 391 { 392 throw new IOException(ERR_READ_LENGTH_EXCEEDS_MAX.get(length, 393 maxElementSize)); 394 } 395 396 return length; 397 } 398 399 400 401 /** 402 * Skips over the specified number of bytes. 403 * 404 * @param numBytes The number of bytes to skip. 405 * 406 * @throws IOException If a problem occurs while reading from the input 407 * stream, or if the end of the stream is reached before 408 * having skipped the specified number of bytes. 409 */ 410 private void skip(final int numBytes) 411 throws IOException 412 { 413 if (numBytes <= 0) 414 { 415 return; 416 } 417 418 if (saslClient != null) 419 { 420 int skippedSoFar = 0; 421 final byte[] skipBuffer = new byte[numBytes]; 422 while (true) 423 { 424 final int bytesRead = read(skipBuffer, skippedSoFar, 425 (numBytes - skippedSoFar)); 426 if (bytesRead < 0) 427 { 428 // We unexpectedly hit the end of the stream. We'll just return since 429 // we clearly can't skip any more, and subsequent read attempts will 430 // fail. 431 return; 432 } 433 434 skippedSoFar += bytesRead; 435 totalBytesRead += bytesRead; 436 if (skippedSoFar >= numBytes) 437 { 438 return; 439 } 440 } 441 } 442 443 long totalBytesSkipped = inputStream.skip(numBytes); 444 while (totalBytesSkipped < numBytes) 445 { 446 final long bytesSkipped = inputStream.skip(numBytes - totalBytesSkipped); 447 if (bytesSkipped <= 0) 448 { 449 while (totalBytesSkipped < numBytes) 450 { 451 final int byteRead = read(false); 452 if (byteRead < 0) 453 { 454 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 455 } 456 totalBytesSkipped++; 457 } 458 } 459 else 460 { 461 totalBytesSkipped += bytesSkipped; 462 } 463 } 464 465 totalBytesRead += numBytes; 466 } 467 468 469 470 /** 471 * Reads a complete ASN.1 element from the input stream. 472 * 473 * @return The ASN.1 element read from the input stream, or {@code null} if 474 * the end of the input stream was reached before any data could be 475 * read. If {@code null} is returned, then the input stream will 476 * have been closed. 477 * 478 * @throws IOException If a problem occurs while reading from the input 479 * stream, if the end of the input stream is reached in 480 * the middle of the element, or or if an attempt is 481 * made to read an element larger than the maximum 482 * allowed size. 483 */ 484 public ASN1Element readElement() 485 throws IOException 486 { 487 final int type = readType(); 488 if (type < 0) 489 { 490 return null; 491 } 492 493 final int length = readLength(); 494 495 int valueBytesRead = 0; 496 int bytesRemaining = length; 497 final byte[] value = new byte[length]; 498 while (valueBytesRead < length) 499 { 500 final int bytesRead = read(value, valueBytesRead, bytesRemaining); 501 if (bytesRead < 0) 502 { 503 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 504 } 505 506 valueBytesRead += bytesRead; 507 bytesRemaining -= bytesRead; 508 } 509 510 totalBytesRead += length; 511 final ASN1Element e = new ASN1Element((byte) type, value); 512 debugASN1Read(e); 513 return e; 514 } 515 516 517 518 /** 519 * Reads an ASN.1 Boolean element from the input stream and returns the value 520 * as a {@code Boolean}. 521 * 522 * @return The {@code Boolean} value of the ASN.1 Boolean element read, or 523 * {@code null} if the end of the input stream was reached before any 524 * data could be read. If {@code null} is returned, then the input 525 * stream will have been closed. 526 * 527 * @throws IOException If a problem occurs while reading from the input 528 * stream, if the end of the input stream is reached in 529 * the middle of the element, or or if an attempt is 530 * made to read an element larger than the maximum 531 * allowed size. 532 * 533 * @throws ASN1Exception If the data read cannot be parsed as an ASN.1 534 * Boolean element. 535 */ 536 public Boolean readBoolean() 537 throws IOException, ASN1Exception 538 { 539 final int type = readType(); 540 if (type < 0) 541 { 542 return null; 543 } 544 545 final int length = readLength(); 546 547 if (length == 1) 548 { 549 final int value = read(false); 550 if (value < 0) 551 { 552 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 553 } 554 555 totalBytesRead++; 556 557 final Boolean booleanValue = (value != 0x00); 558 debugASN1Read(Level.INFO, "Boolean", type, 1, booleanValue); 559 return booleanValue; 560 } 561 else 562 { 563 skip(length); 564 throw new ASN1Exception(ERR_BOOLEAN_INVALID_LENGTH.get()); 565 } 566 } 567 568 569 570 /** 571 * Reads an ASN.1 enumerated element from the input stream and returns the 572 * value as an {@code Integer}. 573 * 574 * @return The {@code Integer} value of the ASN.1 enumerated element read, or 575 * {@code null} if the end of the input stream was reached before any 576 * data could be read. If {@code null} is returned, then the input 577 * stream will have been closed. 578 * 579 * @throws IOException If a problem occurs while reading from the input 580 * stream, if the end of the input stream is reached in 581 * the middle of the element, or or if an attempt is 582 * made to read an element larger than the maximum 583 * allowed size. 584 * 585 * @throws ASN1Exception If the data read cannot be parsed as an ASN.1 586 * enumerated element. 587 */ 588 public Integer readEnumerated() 589 throws IOException, ASN1Exception 590 { 591 return readInteger(); 592 } 593 594 595 596 /** 597 * Reads an ASN.1 generalized time element from the input stream and returns 598 * the value as a {@code Date}. 599 * 600 * @return The {@code Date} value of the ASN.1 generalized time element read, 601 * or {@code null} if the end of the input stream was reached before 602 * any data could be read. If {@code null} is returned, then the 603 * input stream will have been closed. 604 * 605 * @throws IOException If a problem occurs while reading from the input 606 * stream, if the end of the input stream is reached in 607 * the middle of the element, or or if an attempt is 608 * made to read an element larger than the maximum 609 * allowed size. 610 * 611 * @throws ASN1Exception If the data read cannot be parsed as an ASN.1 612 * generalized time element. 613 */ 614 public Date readGeneralizedTime() 615 throws IOException, ASN1Exception 616 { 617 final int type = readType(); 618 if (type < 0) 619 { 620 return null; 621 } 622 623 final int length = readLength(); 624 625 int valueBytesRead = 0; 626 int bytesRemaining = length; 627 final byte[] value = new byte[length]; 628 while (valueBytesRead < length) 629 { 630 final int bytesRead = read(value, valueBytesRead, bytesRemaining); 631 if (bytesRead < 0) 632 { 633 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 634 } 635 636 valueBytesRead += bytesRead; 637 bytesRemaining -= bytesRead; 638 } 639 640 totalBytesRead += length; 641 642 final String timestamp = toUTF8String(value); 643 final Date date = 644 new Date(ASN1GeneralizedTime.decodeTimestamp(timestamp)); 645 debugASN1Read(Level.INFO, "GeneralizedTime", type, length, timestamp); 646 return date; 647 } 648 649 650 651 /** 652 * Reads an ASN.1 integer element from the input stream and returns the value 653 * as an {@code Integer}. 654 * 655 * @return The {@code Integer} value of the ASN.1 integer element read, or 656 * {@code null} if the end of the input stream was reached before any 657 * data could be read. If {@code null} is returned, then the input 658 * stream will have been closed. 659 * 660 * @throws IOException If a problem occurs while reading from the input 661 * stream, if the end of the input stream is reached in 662 * the middle of the element, or or if an attempt is 663 * made to read an element larger than the maximum 664 * allowed size. 665 * 666 * @throws ASN1Exception If the data read cannot be parsed as an ASN.1 667 * integer element. 668 */ 669 public Integer readInteger() 670 throws IOException, ASN1Exception 671 { 672 final int type = readType(); 673 if (type < 0) 674 { 675 return null; 676 } 677 678 final int length = readLength(); 679 if ((length == 0) || (length > 4)) 680 { 681 skip(length); 682 throw new ASN1Exception(ERR_INTEGER_INVALID_LENGTH.get(length)); 683 } 684 685 boolean negative = false; 686 int intValue = 0; 687 for (int i=0; i < length; i++) 688 { 689 final int byteRead = read(false); 690 if (byteRead < 0) 691 { 692 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 693 } 694 695 if (i == 0) 696 { 697 negative = ((byteRead & 0x80) != 0x00); 698 } 699 700 intValue <<= 8; 701 intValue |= (byteRead & 0xFF); 702 } 703 704 if (negative) 705 { 706 switch (length) 707 { 708 case 1: 709 intValue |= 0xFFFFFF00; 710 break; 711 case 2: 712 intValue |= 0xFFFF0000; 713 break; 714 case 3: 715 intValue |= 0xFF000000; 716 break; 717 } 718 } 719 720 totalBytesRead += length; 721 debugASN1Read(Level.INFO, "Integer", type, length, intValue); 722 return intValue; 723 } 724 725 726 727 /** 728 * Reads an ASN.1 integer element from the input stream and returns the value 729 * as a {@code Long}. 730 * 731 * @return The {@code Long} value of the ASN.1 integer element read, or 732 * {@code null} if the end of the input stream was reached before any 733 * data could be read. If {@code null} is returned, then the input 734 * stream will have been closed. 735 * 736 * @throws IOException If a problem occurs while reading from the input 737 * stream, if the end of the input stream is reached in 738 * the middle of the element, or or if an attempt is 739 * made to read an element larger than the maximum 740 * allowed size. 741 * 742 * @throws ASN1Exception If the data read cannot be parsed as an ASN.1 743 * integer element. 744 */ 745 public Long readLong() 746 throws IOException, ASN1Exception 747 { 748 final int type = readType(); 749 if (type < 0) 750 { 751 return null; 752 } 753 754 final int length = readLength(); 755 if ((length == 0) || (length > 8)) 756 { 757 skip(length); 758 throw new ASN1Exception(ERR_LONG_INVALID_LENGTH.get(length)); 759 } 760 761 boolean negative = false; 762 long longValue = 0; 763 for (int i=0; i < length; i++) 764 { 765 final int byteRead = read(false); 766 if (byteRead < 0) 767 { 768 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 769 } 770 771 if (i == 0) 772 { 773 negative = ((byteRead & 0x80) != 0x00); 774 } 775 776 longValue <<= 8; 777 longValue |= (byteRead & 0xFFL); 778 } 779 780 if (negative) 781 { 782 switch (length) 783 { 784 case 1: 785 longValue |= 0xFFFFFFFFFFFFFF00L; 786 break; 787 case 2: 788 longValue |= 0xFFFFFFFFFFFF0000L; 789 break; 790 case 3: 791 longValue |= 0xFFFFFFFFFF000000L; 792 break; 793 case 4: 794 longValue |= 0xFFFFFFFF00000000L; 795 break; 796 case 5: 797 longValue |= 0xFFFFFF0000000000L; 798 break; 799 case 6: 800 longValue |= 0xFFFF000000000000L; 801 break; 802 case 7: 803 longValue |= 0xFF00000000000000L; 804 break; 805 } 806 } 807 808 totalBytesRead += length; 809 debugASN1Read(Level.INFO, "Long", type, length, longValue); 810 return longValue; 811 } 812 813 814 815 /** 816 * Reads an ASN.1 integer element from the input stream and returns the value 817 * as a {@code BigInteger}. 818 * 819 * @return The {@code BigInteger} value of the ASN.1 integer element read, or 820 * {@code null} if the end of the input stream was reached before any 821 * data could be read. If {@code null} is returned, then the input 822 * stream will have been closed. 823 * 824 * @throws IOException If a problem occurs while reading from the input 825 * stream, if the end of the input stream is reached in 826 * the middle of the element, or or if an attempt is 827 * made to read an element larger than the maximum 828 * allowed size. 829 * 830 * @throws ASN1Exception If the data read cannot be parsed as an ASN.1 831 * integer element. 832 */ 833 public BigInteger readBigInteger() 834 throws IOException, ASN1Exception 835 { 836 final int type = readType(); 837 if (type < 0) 838 { 839 return null; 840 } 841 842 final int length = readLength(); 843 if (length == 0) 844 { 845 throw new ASN1Exception(ERR_BIG_INTEGER_DECODE_EMPTY_VALUE.get()); 846 } 847 848 final byte[] valueBytes = new byte[length]; 849 for (int i=0; i < length; i++) 850 { 851 final int byteRead = read(false); 852 if (byteRead < 0) 853 { 854 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 855 } 856 857 valueBytes[i] = (byte) byteRead; 858 } 859 860 final BigInteger bigIntegerValue = new BigInteger(valueBytes); 861 862 totalBytesRead += length; 863 debugASN1Read(Level.INFO, "BigInteger", type, length, bigIntegerValue); 864 return bigIntegerValue; 865 } 866 867 868 869 /** 870 * Reads an ASN.1 null element from the input stream. No value will be 871 * returned but the null element will be consumed. 872 * 873 * @throws IOException If a problem occurs while reading from the input 874 * stream, if the end of the input stream is reached in 875 * the middle of the element, or or if an attempt is 876 * made to read an element larger than the maximum 877 * allowed size. 878 * 879 * @throws ASN1Exception If the data read cannot be parsed as an ASN.1 null 880 * element. 881 */ 882 public void readNull() 883 throws IOException, ASN1Exception 884 { 885 final int type = readType(); 886 if (type < 0) 887 { 888 return; 889 } 890 891 final int length = readLength(); 892 893 if (length != 0) 894 { 895 skip(length); 896 throw new ASN1Exception(ERR_NULL_HAS_VALUE.get()); 897 } 898 debugASN1Read(Level.INFO, "Null", type, 0, null); 899 } 900 901 902 903 /** 904 * Reads an ASN.1 octet string element from the input stream and returns the 905 * value as a byte array. 906 * 907 * @return The byte array value of the ASN.1 octet string element read, or 908 * {@code null} if the end of the input stream was reached before any 909 * data could be read. If {@code null} is returned, then the input 910 * stream will have been closed. 911 * 912 * @throws IOException If a problem occurs while reading from the input 913 * stream, if the end of the input stream is reached in 914 * the middle of the element, or or if an attempt is 915 * made to read an element larger than the maximum 916 * allowed size. 917 */ 918 public byte[] readBytes() 919 throws IOException 920 { 921 final int type = readType(); 922 if (type < 0) 923 { 924 return null; 925 } 926 927 final int length = readLength(); 928 929 int valueBytesRead = 0; 930 int bytesRemaining = length; 931 final byte[] value = new byte[length]; 932 while (valueBytesRead < length) 933 { 934 final int bytesRead = read(value, valueBytesRead, bytesRemaining); 935 if (bytesRead < 0) 936 { 937 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 938 } 939 940 valueBytesRead += bytesRead; 941 bytesRemaining -= bytesRead; 942 } 943 944 totalBytesRead += length; 945 debugASN1Read(Level.INFO, "byte[]", type, length, value); 946 return value; 947 } 948 949 950 951 /** 952 * Reads an ASN.1 octet string element from the input stream and returns the 953 * value as a {@code String} using the UTF-8 encoding. 954 * 955 * @return The {@code String} value of the ASN.1 octet string element read, 956 * or {@code null} if the end of the input stream was reached before 957 * any data could be read. If {@code null} is returned, then the 958 * input stream will have been closed. 959 * 960 * @throws IOException If a problem occurs while reading from the input 961 * stream, if the end of the input stream is reached in 962 * the middle of the element, or or if an attempt is 963 * made to read an element larger than the maximum 964 * allowed size. 965 */ 966 public String readString() 967 throws IOException 968 { 969 final int type = readType(); 970 if (type < 0) 971 { 972 return null; 973 } 974 975 final int length = readLength(); 976 977 int valueBytesRead = 0; 978 int bytesRemaining = length; 979 final byte[] value = new byte[length]; 980 while (valueBytesRead < length) 981 { 982 final int bytesRead = read(value, valueBytesRead, bytesRemaining); 983 if (bytesRead < 0) 984 { 985 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 986 } 987 988 valueBytesRead += bytesRead; 989 bytesRemaining -= bytesRead; 990 } 991 992 totalBytesRead += length; 993 994 final String s = toUTF8String(value); 995 debugASN1Read(Level.INFO, "String", type, length, s); 996 return s; 997 } 998 999 1000 1001 /** 1002 * Reads an ASN.1 UTC time element from the input stream and returns the value 1003 * as a {@code Date}. 1004 * 1005 * @return The {@code Date} value of the ASN.1 UTC time element read, or 1006 * {@code null} if the end of the input stream was reached before any 1007 * data could be read. If {@code null} is returned, then the input 1008 * stream will have been closed. 1009 * 1010 * @throws IOException If a problem occurs while reading from the input 1011 * stream, if the end of the input stream is reached in 1012 * the middle of the element, or or if an attempt is 1013 * made to read an element larger than the maximum 1014 * allowed size. 1015 * 1016 * @throws ASN1Exception If the data read cannot be parsed as an ASN.1 UTC 1017 * time element. 1018 */ 1019 public Date readUTCTime() 1020 throws IOException, ASN1Exception 1021 { 1022 final int type = readType(); 1023 if (type < 0) 1024 { 1025 return null; 1026 } 1027 1028 final int length = readLength(); 1029 1030 int valueBytesRead = 0; 1031 int bytesRemaining = length; 1032 final byte[] value = new byte[length]; 1033 while (valueBytesRead < length) 1034 { 1035 final int bytesRead = read(value, valueBytesRead, bytesRemaining); 1036 if (bytesRead < 0) 1037 { 1038 throw new IOException(ERR_READ_END_BEFORE_VALUE_END.get()); 1039 } 1040 1041 valueBytesRead += bytesRead; 1042 bytesRemaining -= bytesRead; 1043 } 1044 1045 totalBytesRead += length; 1046 1047 final String timestamp = toUTF8String(value); 1048 final Date date = new Date(ASN1UTCTime.decodeTimestamp(timestamp)); 1049 debugASN1Read(Level.INFO, "UTCTime", type, length, timestamp); 1050 return date; 1051 } 1052 1053 1054 1055 /** 1056 * Reads the beginning of an ASN.1 sequence from the input stream and 1057 * returns a value that can be used to determine when the end of the sequence 1058 * has been reached. Elements which are part of the sequence may be read from 1059 * this ASN.1 stream reader until the 1060 * {@link ASN1StreamReaderSequence#hasMoreElements} method returns 1061 * {@code false}. 1062 * 1063 * @return An object which may be used to determine when the end of the 1064 * sequence has been reached, or {@code null} if the end of the input 1065 * stream was reached before any data could be read. If {@code null} 1066 * is returned, then the input stream will have been closed. 1067 * 1068 * @throws IOException If a problem occurs while reading from the input 1069 * stream, if the end of the input stream is reached in 1070 * the middle of the element, or or if an attempt is 1071 * made to read an element larger than the maximum 1072 * allowed size. 1073 */ 1074 public ASN1StreamReaderSequence beginSequence() 1075 throws IOException 1076 { 1077 final int type = readType(); 1078 if (type < 0) 1079 { 1080 return null; 1081 } 1082 1083 final int length = readLength(); 1084 1085 debugASN1Read(Level.INFO, "Sequence Header", type, length, null); 1086 return new ASN1StreamReaderSequence(this, (byte) type, length); 1087 } 1088 1089 1090 1091 /** 1092 * Reads the beginning of an ASN.1 set from the input stream and returns a 1093 * value that can be used to determine when the end of the set has been 1094 * reached. Elements which are part of the set may be read from this ASN.1 1095 * stream reader until the {@link ASN1StreamReaderSet#hasMoreElements} method 1096 * returns {@code false}. 1097 * 1098 * @return An object which may be used to determine when the end of the set 1099 * has been reached, or {@code null} if the end of the input stream 1100 * was reached before any data could be read. If {@code null} is 1101 * returned, then the input stream will have been closed. 1102 * 1103 * @throws IOException If a problem occurs while reading from the input 1104 * stream, if the end of the input stream is reached in 1105 * the middle of the element, or or if an attempt is 1106 * made to read an element larger than the maximum 1107 * allowed size. 1108 */ 1109 public ASN1StreamReaderSet beginSet() 1110 throws IOException 1111 { 1112 final int type = readType(); 1113 if (type < 0) 1114 { 1115 return null; 1116 } 1117 1118 final int length = readLength(); 1119 1120 debugASN1Read(Level.INFO, "Set Header", type, length, null); 1121 return new ASN1StreamReaderSet(this, (byte) type, length); 1122 } 1123 1124 1125 1126 /** 1127 * Reads a byte of data from the underlying input stream, optionally ignoring 1128 * socket timeout exceptions. 1129 * 1130 * @param initial Indicates whether this is the initial read for an element. 1131 * 1132 * @return The byte read from the input stream, or -1 if the end of the 1133 * input stream was reached. 1134 * 1135 * @throws IOException If a problem occurs while reading data. 1136 */ 1137 private int read(final boolean initial) 1138 throws IOException 1139 { 1140 if (saslClient != null) 1141 { 1142 if (saslInputStream != null) 1143 { 1144 final int b = saslInputStream.read(); 1145 if (b >= 0) 1146 { 1147 return b; 1148 } 1149 } 1150 1151 readAndDecodeSASLData(-1); 1152 return saslInputStream.read(); 1153 } 1154 1155 try 1156 { 1157 final int b = inputStream.read(); 1158 if ((saslClient == null) || (b < 0)) 1159 { 1160 return b; 1161 } 1162 else 1163 { 1164 // This should only happen the first time after the SASL client has been 1165 // installed. 1166 readAndDecodeSASLData(b); 1167 return saslInputStream.read(); 1168 } 1169 } 1170 catch (final SocketTimeoutException ste) 1171 { 1172 debugException(Level.FINEST, ste); 1173 1174 if ((initial && ignoreInitialSocketTimeout) || 1175 ((! initial) && ignoreSubsequentSocketTimeout)) 1176 { 1177 while (true) 1178 { 1179 try 1180 { 1181 return inputStream.read(); 1182 } 1183 catch (final SocketTimeoutException ste2) 1184 { 1185 debugException(Level.FINEST, ste2); 1186 } 1187 } 1188 } 1189 else 1190 { 1191 throw ste; 1192 } 1193 } 1194 } 1195 1196 1197 1198 /** 1199 * Reads data from the underlying input stream, optionally ignoring socket 1200 * timeout exceptions. 1201 * 1202 * @param buffer The buffer into which the data should be read. 1203 * @param offset The position at which to start placing the data that was 1204 * read. 1205 * @param length The maximum number of bytes to read. 1206 * 1207 * @return The number of bytes read, or -1 if the end of the input stream 1208 * was reached. 1209 * 1210 * @throws IOException If a problem occurs while reading data. 1211 */ 1212 private int read(final byte[] buffer, final int offset, final int length) 1213 throws IOException 1214 { 1215 if (saslClient != null) 1216 { 1217 if (saslInputStream != null) 1218 { 1219 final int bytesRead = saslInputStream.read(buffer, offset, length); 1220 if (bytesRead > 0) 1221 { 1222 return bytesRead; 1223 } 1224 } 1225 1226 readAndDecodeSASLData(-1); 1227 return saslInputStream.read(buffer, offset, length); 1228 } 1229 1230 try 1231 { 1232 return inputStream.read(buffer, offset, length); 1233 } 1234 catch (final SocketTimeoutException ste) 1235 { 1236 debugException(Level.FINEST, ste); 1237 if (ignoreSubsequentSocketTimeout) 1238 { 1239 while (true) 1240 { 1241 try 1242 { 1243 return inputStream.read(buffer, offset, length); 1244 } 1245 catch (final SocketTimeoutException ste2) 1246 { 1247 debugException(Level.FINEST, ste2); 1248 } 1249 } 1250 } 1251 else 1252 { 1253 throw ste; 1254 } 1255 } 1256 } 1257 1258 1259 1260 /** 1261 * Sets the SASL client to use to unwrap any data read over this ASN.1 stream 1262 * reader. 1263 * 1264 * @param saslClient The SASL client to use to unwrap any data read over 1265 * this ASN.1 stream reader. 1266 */ 1267 void setSASLClient(final SaslClient saslClient) 1268 { 1269 this.saslClient = saslClient; 1270 } 1271 1272 1273 1274 /** 1275 * Reads data from the underlying input stream, unwraps it using the 1276 * configured SASL client, and makes the result available in a byte array 1277 * input stream that will be used for subsequent reads. 1278 * 1279 * @param firstByte The first byte that has already been read. This should 1280 * only be used if the value is greater than or equal to 1281 * zero. 1282 * 1283 * @throws IOException If a problem is encountered while reading from the 1284 * underlying input stream or decoding the data that 1285 * has been read. 1286 */ 1287 private void readAndDecodeSASLData(final int firstByte) 1288 throws IOException 1289 { 1290 // The first four bytes must be the number of bytes of data to unwrap. 1291 int numWrappedBytes = 0; 1292 int numLengthBytes = 4; 1293 if (firstByte >= 0) 1294 { 1295 numLengthBytes = 3; 1296 numWrappedBytes = firstByte; 1297 } 1298 1299 for (int i=0; i < numLengthBytes; i++) 1300 { 1301 final int b = inputStream.read(); 1302 if (b < 0) 1303 { 1304 if ((i == 0) && (firstByte < 0)) 1305 { 1306 // This means that we hit the end of the input stream without 1307 // reading any data. This is fine and just means that the end of 1308 // the input stream has been reached. 1309 saslInputStream = new ByteArrayInputStream(NO_BYTES); 1310 } 1311 else 1312 { 1313 // This means that we hit the end of the input stream after having 1314 // read a portion of the number of wrapped bytes. This is an error. 1315 throw new IOException( 1316 ERR_STREAM_READER_EOS_READING_SASL_LENGTH.get(i)); 1317 } 1318 } 1319 else 1320 { 1321 numWrappedBytes = (numWrappedBytes << 8) | (b & 0xFF); 1322 } 1323 } 1324 1325 if ((maxElementSize > 0) && (numWrappedBytes > maxElementSize)) 1326 { 1327 throw new IOException(ERR_READ_SASL_LENGTH_EXCEEDS_MAX.get( 1328 numWrappedBytes, maxElementSize)); 1329 } 1330 1331 int wrappedDataPos = 0; 1332 final byte[] wrappedData = new byte[numWrappedBytes]; 1333 while (true) 1334 { 1335 final int numBytesRead = inputStream.read(wrappedData, wrappedDataPos, 1336 (numWrappedBytes - wrappedDataPos)); 1337 if (numBytesRead < 0) 1338 { 1339 throw new IOException(ERR_STREAM_READER_EOS_READING_SASL_DATA.get( 1340 wrappedDataPos, numWrappedBytes)); 1341 } 1342 1343 wrappedDataPos += numBytesRead; 1344 if (wrappedDataPos >= numWrappedBytes) 1345 { 1346 break; 1347 } 1348 } 1349 1350 final byte[] unwrappedData = 1351 saslClient.unwrap(wrappedData, 0, numWrappedBytes); 1352 saslInputStream = new ByteArrayInputStream(unwrappedData, 0, 1353 unwrappedData.length); 1354 } 1355}