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