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