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 }