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