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