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