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