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