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