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.IOException;
026import java.io.OutputStream;
027import java.io.Serializable;
028import java.math.BigInteger;
029import java.nio.ByteBuffer;
030import java.util.Date;
031import java.util.concurrent.atomic.AtomicBoolean;
032
033import com.unboundid.util.ByteStringBuffer;
034import com.unboundid.util.DebugType;
035import com.unboundid.util.Mutable;
036import com.unboundid.util.ThreadSafety;
037import com.unboundid.util.ThreadSafetyLevel;
038
039import static com.unboundid.util.Debug.*;
040
041
042
043/**
044 * This class provides a mechanism for writing one or more ASN.1 elements into a
045 * byte string buffer.  It may be cleared and re-used any number of times, and
046 * the contents may be written to an {@code OutputStream} or {@code ByteBuffer},
047 * or copied to a byte array.  {@code ASN1Buffer} instances are not threadsafe
048 * and should not be accessed concurrently by multiple threads.
049 */
050@Mutable()
051@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
052public final class ASN1Buffer
053       implements Serializable
054{
055  /**
056   * The default maximum buffer size.
057   */
058  private static final int DEFAULT_MAX_BUFFER_SIZE = 1048576;
059
060
061
062  /**
063   * An array that will be inserted when completing a sequence whose
064   * multi-byte length should be encoded with one byte for the header and one
065   * byte for the number of value bytes.
066   */
067  private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_ONE =
068       { (byte) 0x81, (byte) 0x00 };
069
070
071
072  /**
073   * An array that will be inserted when completing a sequence whose
074   * multi-byte length should be encoded with one byte for the header and two
075   * bytes for the number of value bytes.
076   */
077  private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_TWO =
078       { (byte) 0x82, (byte) 0x00, (byte) 0x00 };
079
080
081
082  /**
083   * An array that will be inserted when completing a sequence whose
084   * multi-byte length should be encoded with one byte for the header and three
085   * bytes for the number of value bytes.
086   */
087  private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_THREE =
088       { (byte) 0x83, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
089
090
091
092  /**
093   * An array that will be inserted when completing a sequence whose
094   * multi-byte length should be encoded with one byte for the header and four
095   * bytes for the number of value bytes.
096   */
097  private static final byte[] MULTIBYTE_LENGTH_HEADER_PLUS_FOUR =
098       { (byte) 0x84, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
099
100
101
102  /**
103   * The serial version UID for this serializable class.
104   */
105  private static final long serialVersionUID = -4898230771376551562L;
106
107
108
109  // Indicates whether to zero out the contents of the buffer the next time it
110  // is cleared in order to wipe out any sensitive data it may contain.
111  private final AtomicBoolean zeroBufferOnClear;
112
113  // The buffer to which all data will be written.
114  private final ByteStringBuffer buffer;
115
116  // The maximum buffer size that should be retained.
117  private final int maxBufferSize;
118
119
120
121  /**
122   * Creates a new instance of this ASN.1 buffer.
123   */
124  public ASN1Buffer()
125  {
126    this(DEFAULT_MAX_BUFFER_SIZE);
127  }
128
129
130
131  /**
132   * Creates a new instance of this ASN.1 buffer with an optional maximum
133   * retained size.  If a maximum size is defined, then this buffer may be used
134   * to hold elements larger than that, but when the buffer is cleared it will
135   * be shrunk to the maximum size.
136   *
137   * @param  maxBufferSize  The maximum buffer size that will be retained by
138   *                        this ASN.1 buffer.  A value less than or equal to
139   *                        zero indicates that no maximum size should be
140   *                        enforced.
141   */
142  public ASN1Buffer(final int maxBufferSize)
143  {
144    this.maxBufferSize = maxBufferSize;
145
146    buffer            = new ByteStringBuffer();
147    zeroBufferOnClear = new AtomicBoolean(false);
148  }
149
150
151
152  /**
153   * Indicates whether the content of the buffer should be zeroed out the next
154   * time it is cleared in order to wipe any sensitive information it may
155   * contain.
156   *
157   * @return  {@code true} if the content of the buffer should be zeroed out the
158   *          next time it is cleared, or {@code false} if not.
159   */
160  public boolean zeroBufferOnClear()
161  {
162    return zeroBufferOnClear.get();
163  }
164
165
166
167  /**
168   * Specifies that the content of the buffer should be zeroed out the next time
169   * it is cleared in order to wipe any sensitive information it may contain.
170   */
171  public void setZeroBufferOnClear()
172  {
173    zeroBufferOnClear.set(true);
174  }
175
176
177
178  /**
179   * Clears the contents of this buffer.  If there are any outstanding sequences
180   * or sets that have been created but not closed, then they must no longer be
181   * used and any attempt to do so may yield unpredictable results.
182   */
183  public void clear()
184  {
185    buffer.clear(zeroBufferOnClear.getAndSet(false));
186
187    if ((maxBufferSize > 0) && (buffer.capacity() > maxBufferSize))
188    {
189      buffer.setCapacity(maxBufferSize);
190    }
191  }
192
193
194
195  /**
196   * Retrieves the current length of this buffer in bytes.
197   *
198   * @return  The current length of this buffer in bytes.
199   */
200  public int length()
201  {
202    return buffer.length();
203  }
204
205
206
207  /**
208   * Adds the provided ASN.1 element to this ASN.1 buffer.
209   *
210   * @param  element  The element to be added.  It must not be {@code null}.
211   */
212  public void addElement(final ASN1Element element)
213  {
214    element.encodeTo(buffer);
215  }
216
217
218
219  /**
220   * Adds a Boolean element to this ASN.1 buffer using the default BER type.
221   *
222   * @param  booleanValue  The value to use for the Boolean element.
223   */
224  public void addBoolean(final boolean booleanValue)
225  {
226    addBoolean(ASN1Constants.UNIVERSAL_BOOLEAN_TYPE, booleanValue);
227  }
228
229
230
231  /**
232   * Adds a Boolean element to this ASN.1 buffer using the provided BER type.
233   *
234   * @param  type          The BER type to use for the Boolean element.
235   * @param  booleanValue  The value to use for the Boolean element.
236   */
237  public void addBoolean(final byte type, final boolean booleanValue)
238  {
239    buffer.append(type);
240    buffer.append((byte) 0x01);
241
242    if (booleanValue)
243    {
244      buffer.append((byte) 0xFF);
245    }
246    else
247    {
248      buffer.append((byte) 0x00);
249    }
250  }
251
252
253
254  /**
255   * Adds an enumerated element to this ASN.1 buffer using the default BER type.
256   *
257   * @param  intValue  The value to use for the enumerated element.
258   */
259  public void addEnumerated(final int intValue)
260  {
261    addInteger(ASN1Constants.UNIVERSAL_ENUMERATED_TYPE, intValue);
262  }
263
264
265
266  /**
267   * Adds an enumerated element to this ASN.1 buffer using the provided BER
268   * type.
269   *
270   * @param  type      The BER type to use for the enumerated element.
271   * @param  intValue  The value to use for the enumerated element.
272   */
273  public void addEnumerated(final byte type, final int intValue)
274  {
275    addInteger(type, intValue);
276  }
277
278
279
280  /**
281   * Adds a generalized time element to this ASN.1 buffer using the default BER
282   * type.
283   *
284   * @param  date  The date value that specifies the time to represent.  This
285   *               must not be {@code null}.
286   */
287  public void addGeneralizedTime(final Date date)
288  {
289    addGeneralizedTime(date.getTime());
290  }
291
292
293
294  /**
295   * Adds a generalized time element to this ASN.1 buffer using the provided BER
296   * type.
297   *
298   * @param  type  The BER type to use for the generalized time element.
299   * @param  date  The date value that specifies the time to represent.  This
300   *               must not be {@code null}.
301   */
302  public void addGeneralizedTime(final byte type, final Date date)
303  {
304    addGeneralizedTime(type, date.getTime());
305  }
306
307
308
309  /**
310   * Adds a generalized time element to this ASN.1 buffer using the default BER
311   * type.
312   *
313   * @param  time  The time to represent.  This must be expressed in
314   *               milliseconds since the epoch (the same format used by
315   *               {@code System.currentTimeMillis()} and
316   *               {@code Date.getTime()}).
317   */
318  public void addGeneralizedTime(final long time)
319  {
320    addGeneralizedTime(ASN1Constants.UNIVERSAL_GENERALIZED_TIME_TYPE, time);
321  }
322
323
324
325  /**
326   * Adds a generalized time element to this ASN.1 buffer using the provided BER
327   * type.
328   *
329   * @param  type  The BER type to use for the generalized time element.
330   * @param  time  The time to represent.  This must be expressed in
331   *               milliseconds since the epoch (the same format used by
332   *               {@code System.currentTimeMillis()} and
333   *               {@code Date.getTime()}).
334   */
335  public void addGeneralizedTime(final byte type, final long time)
336  {
337    buffer.append(type);
338
339    final String timestamp = ASN1GeneralizedTime.encodeTimestamp(time, true);
340    ASN1Element.encodeLengthTo(timestamp.length(), buffer);
341    buffer.append(timestamp);
342  }
343
344
345
346  /**
347   * Adds an integer element to this ASN.1 buffer using the default BER type.
348   *
349   * @param  intValue  The value to use for the integer element.
350   */
351  public void addInteger(final int intValue)
352  {
353    addInteger(ASN1Constants.UNIVERSAL_INTEGER_TYPE, intValue);
354  }
355
356
357
358  /**
359   * Adds an integer element to this ASN.1 buffer using the provided BER type.
360   *
361   * @param  type      The BER type to use for the integer element.
362   * @param  intValue  The value to use for the integer element.
363   */
364  public void addInteger(final byte type, final int intValue)
365  {
366    buffer.append(type);
367
368    if (intValue < 0)
369    {
370      if ((intValue & 0xFFFFFF80) == 0xFFFFFF80)
371      {
372        buffer.append((byte) 0x01);
373        buffer.append((byte) (intValue & 0xFF));
374      }
375      else if ((intValue & 0xFFFF8000) == 0xFFFF8000)
376      {
377        buffer.append((byte) 0x02);
378        buffer.append((byte) ((intValue >> 8) & 0xFF));
379        buffer.append((byte) (intValue & 0xFF));
380      }
381      else if ((intValue & 0xFF800000) == 0xFF800000)
382      {
383        buffer.append((byte) 0x03);
384        buffer.append((byte) ((intValue >> 16) & 0xFF));
385        buffer.append((byte) ((intValue >> 8) & 0xFF));
386        buffer.append((byte) (intValue & 0xFF));
387      }
388      else
389      {
390        buffer.append((byte) 0x04);
391        buffer.append((byte) ((intValue >> 24) & 0xFF));
392        buffer.append((byte) ((intValue >> 16) & 0xFF));
393        buffer.append((byte) ((intValue >> 8) & 0xFF));
394        buffer.append((byte) (intValue & 0xFF));
395      }
396    }
397    else
398    {
399      if ((intValue & 0x0000007F) == intValue)
400      {
401        buffer.append((byte) 0x01);
402        buffer.append((byte) (intValue & 0x7F));
403      }
404      else if ((intValue & 0x00007FFF) == intValue)
405      {
406        buffer.append((byte) 0x02);
407        buffer.append((byte) ((intValue >> 8) & 0x7F));
408        buffer.append((byte) (intValue & 0xFF));
409      }
410      else if ((intValue & 0x007FFFFF) == intValue)
411      {
412        buffer.append((byte) 0x03);
413        buffer.append((byte) ((intValue >> 16) & 0x7F));
414        buffer.append((byte) ((intValue >> 8) & 0xFF));
415        buffer.append((byte) (intValue & 0xFF));
416      }
417      else
418      {
419        buffer.append((byte) 0x04);
420        buffer.append((byte) ((intValue >> 24) & 0x7F));
421        buffer.append((byte) ((intValue >> 16) & 0xFF));
422        buffer.append((byte) ((intValue >> 8) & 0xFF));
423        buffer.append((byte) (intValue & 0xFF));
424      }
425    }
426  }
427
428
429
430  /**
431   * Adds an integer element to this ASN.1 buffer using the default BER type.
432   *
433   * @param  longValue  The value to use for the integer element.
434   */
435  public void addInteger(final long longValue)
436  {
437    addInteger(ASN1Constants.UNIVERSAL_INTEGER_TYPE, longValue);
438  }
439
440
441
442  /**
443   * Adds an integer element to this ASN.1 buffer using the provided BER type.
444   *
445   * @param  type       The BER type to use for the integer element.
446   * @param  longValue  The value to use for the integer element.
447   */
448  public void addInteger(final byte type, final long longValue)
449  {
450    buffer.append(type);
451
452    if (longValue < 0)
453    {
454      if ((longValue & 0xFFFFFFFFFFFFFF80L) == 0xFFFFFFFFFFFFFF80L)
455      {
456        buffer.append((byte) 0x01);
457        buffer.append((byte) (longValue & 0xFFL));
458      }
459      else if ((longValue & 0xFFFFFFFFFFFF8000L) == 0xFFFFFFFFFFFF8000L)
460      {
461        buffer.append((byte) 0x02);
462        buffer.append((byte) ((longValue >> 8) & 0xFFL));
463        buffer.append((byte) (longValue & 0xFFL));
464      }
465      else if ((longValue & 0xFFFFFFFFFF800000L) == 0xFFFFFFFFFF800000L)
466      {
467        buffer.append((byte) 0x03);
468        buffer.append((byte) ((longValue >> 16) & 0xFFL));
469        buffer.append((byte) ((longValue >> 8) & 0xFFL));
470        buffer.append((byte) (longValue & 0xFFL));
471      }
472      else if ((longValue & 0xFFFFFFFF80000000L) == 0xFFFFFFFF80000000L)
473      {
474        buffer.append((byte) 0x04);
475        buffer.append((byte) ((longValue >> 24) & 0xFFL));
476        buffer.append((byte) ((longValue >> 16) & 0xFFL));
477        buffer.append((byte) ((longValue >> 8) & 0xFFL));
478        buffer.append((byte) (longValue & 0xFFL));
479      }
480      else if ((longValue & 0xFFFFFF8000000000L) == 0xFFFFFF8000000000L)
481      {
482        buffer.append((byte) 0x05);
483        buffer.append((byte) ((longValue >> 32) & 0xFFL));
484        buffer.append((byte) ((longValue >> 24) & 0xFFL));
485        buffer.append((byte) ((longValue >> 16) & 0xFFL));
486        buffer.append((byte) ((longValue >> 8) & 0xFFL));
487        buffer.append((byte) (longValue & 0xFFL));
488      }
489      else if ((longValue & 0xFFFF800000000000L) == 0xFFFF800000000000L)
490      {
491        buffer.append((byte) 0x06);
492        buffer.append((byte) ((longValue >> 40) & 0xFFL));
493        buffer.append((byte) ((longValue >> 32) & 0xFFL));
494        buffer.append((byte) ((longValue >> 24) & 0xFFL));
495        buffer.append((byte) ((longValue >> 16) & 0xFFL));
496        buffer.append((byte) ((longValue >> 8) & 0xFFL));
497        buffer.append((byte) (longValue & 0xFFL));
498      }
499      else if ((longValue & 0xFF80000000000000L) == 0xFF80000000000000L)
500      {
501        buffer.append((byte) 0x07);
502        buffer.append((byte) ((longValue >> 48) & 0xFFL));
503        buffer.append((byte) ((longValue >> 40) & 0xFFL));
504        buffer.append((byte) ((longValue >> 32) & 0xFFL));
505        buffer.append((byte) ((longValue >> 24) & 0xFFL));
506        buffer.append((byte) ((longValue >> 16) & 0xFFL));
507        buffer.append((byte) ((longValue >> 8) & 0xFFL));
508        buffer.append((byte) (longValue & 0xFFL));
509      }
510      else
511      {
512        buffer.append((byte) 0x08);
513        buffer.append((byte) ((longValue >> 56) & 0xFFL));
514        buffer.append((byte) ((longValue >> 48) & 0xFFL));
515        buffer.append((byte) ((longValue >> 40) & 0xFFL));
516        buffer.append((byte) ((longValue >> 32) & 0xFFL));
517        buffer.append((byte) ((longValue >> 24) & 0xFFL));
518        buffer.append((byte) ((longValue >> 16) & 0xFFL));
519        buffer.append((byte) ((longValue >> 8) & 0xFFL));
520        buffer.append((byte) (longValue & 0xFFL));
521      }
522    }
523    else
524    {
525      if ((longValue & 0x000000000000007FL) == longValue)
526      {
527        buffer.append((byte) 0x01);
528        buffer.append((byte) (longValue & 0x7FL));
529      }
530      else if ((longValue & 0x0000000000007FFFL) == longValue)
531      {
532        buffer.append((byte) 0x02);
533        buffer.append((byte) ((longValue >> 8) & 0x7FL));
534        buffer.append((byte) (longValue & 0xFFL));
535      }
536      else if ((longValue & 0x00000000007FFFFFL) == longValue)
537      {
538        buffer.append((byte) 0x03);
539        buffer.append((byte) ((longValue >> 16) & 0x7FL));
540        buffer.append((byte) ((longValue >> 8) & 0xFFL));
541        buffer.append((byte) (longValue & 0xFFL));
542      }
543      else if ((longValue & 0x000000007FFFFFFFL) == longValue)
544      {
545        buffer.append((byte) 0x04);
546        buffer.append((byte) ((longValue >> 24) & 0x7FL));
547        buffer.append((byte) ((longValue >> 16) & 0xFFL));
548        buffer.append((byte) ((longValue >> 8) & 0xFFL));
549        buffer.append((byte) (longValue & 0xFFL));
550      }
551      else if ((longValue & 0x0000007FFFFFFFFFL) == longValue)
552      {
553        buffer.append((byte) 0x05);
554        buffer.append((byte) ((longValue >> 32) & 0x7FL));
555        buffer.append((byte) ((longValue >> 24) & 0xFFL));
556        buffer.append((byte) ((longValue >> 16) & 0xFFL));
557        buffer.append((byte) ((longValue >> 8) & 0xFFL));
558        buffer.append((byte) (longValue & 0xFFL));
559      }
560      else if ((longValue & 0x00007FFFFFFFFFFFL) == longValue)
561      {
562        buffer.append((byte) 0x06);
563        buffer.append((byte) ((longValue >> 40) & 0x7FL));
564        buffer.append((byte) ((longValue >> 32) & 0xFFL));
565        buffer.append((byte) ((longValue >> 24) & 0xFFL));
566        buffer.append((byte) ((longValue >> 16) & 0xFFL));
567        buffer.append((byte) ((longValue >> 8) & 0xFFL));
568        buffer.append((byte) (longValue & 0xFFL));
569      }
570      else if ((longValue & 0x007FFFFFFFFFFFFFL) == longValue)
571      {
572        buffer.append((byte) 0x07);
573        buffer.append((byte) ((longValue >> 48) & 0x7FL));
574        buffer.append((byte) ((longValue >> 40) & 0xFFL));
575        buffer.append((byte) ((longValue >> 32) & 0xFFL));
576        buffer.append((byte) ((longValue >> 24) & 0xFFL));
577        buffer.append((byte) ((longValue >> 16) & 0xFFL));
578        buffer.append((byte) ((longValue >> 8) & 0xFFL));
579        buffer.append((byte) (longValue & 0xFFL));
580      }
581      else
582      {
583        buffer.append((byte) 0x08);
584        buffer.append((byte) ((longValue >> 56) & 0x7FL));
585        buffer.append((byte) ((longValue >> 48) & 0xFFL));
586        buffer.append((byte) ((longValue >> 40) & 0xFFL));
587        buffer.append((byte) ((longValue >> 32) & 0xFFL));
588        buffer.append((byte) ((longValue >> 24) & 0xFFL));
589        buffer.append((byte) ((longValue >> 16) & 0xFFL));
590        buffer.append((byte) ((longValue >> 8) & 0xFFL));
591        buffer.append((byte) (longValue & 0xFFL));
592      }
593    }
594  }
595
596
597
598  /**
599   * Adds an integer element to this ASN.1 buffer using the default BER type.
600   *
601   * @param  value  The value to use for the integer element.  It must not be
602   *                {@code null}.
603   */
604  public void addInteger(final BigInteger value)
605  {
606    addInteger(ASN1Constants.UNIVERSAL_INTEGER_TYPE, value);
607  }
608
609
610
611  /**
612   * Adds an integer element to this ASN.1 buffer using the provided BER type.
613   *
614   * @param  type   The BER type to use for the integer element.
615   * @param  value  The value to use for the integer element.  It must not be
616   *                {@code null}.
617   */
618  public void addInteger(final byte type, final BigInteger value)
619  {
620    buffer.append(type);
621
622    final byte[] valueBytes = value.toByteArray();
623    ASN1Element.encodeLengthTo(valueBytes.length, buffer);
624    buffer.append(valueBytes);
625  }
626
627
628
629  /**
630   * Adds a null element to this ASN.1 buffer using the default BER type.
631   */
632  public void addNull()
633  {
634    addNull(ASN1Constants.UNIVERSAL_NULL_TYPE);
635  }
636
637
638
639  /**
640   * Adds a null element to this ASN.1 buffer using the provided BER type.
641   *
642   * @param  type  The BER type to use for the null element.
643   */
644  public void addNull(final byte type)
645  {
646    buffer.append(type);
647    buffer.append((byte) 0x00);
648  }
649
650
651
652  /**
653   * Adds an octet string element to this ASN.1 buffer using the default BER
654   * type and no value.
655   */
656  public void addOctetString()
657  {
658    addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
659  }
660
661
662
663  /**
664   * Adds an octet string element to this ASN.1 buffer using the provided BER
665   * type and no value.
666   *
667   * @param  type  The BER type to use for the octet string element.
668   */
669  public void addOctetString(final byte type)
670  {
671    buffer.append(type);
672    buffer.append((byte) 0x00);
673  }
674
675
676
677  /**
678   * Adds an octet string element to this ASN.1 buffer using the default BER
679   * type.
680   *
681   * @param  value  The value to use for the octet string element.
682   */
683  public void addOctetString(final byte[] value)
684  {
685    addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, value);
686  }
687
688
689
690  /**
691   * Adds an octet string element to this ASN.1 buffer using the default BER
692   * type.
693   *
694   * @param  value  The value to use for the octet string element.
695   */
696  public void addOctetString(final CharSequence value)
697  {
698    if (value == null)
699    {
700      addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);
701    }
702    else
703    {
704      addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE,
705                     value.toString());
706    }
707  }
708
709
710
711  /**
712   * Adds an octet string element to this ASN.1 buffer using the default BER
713   * type.
714   *
715   * @param  value  The value to use for the octet string element.
716   */
717  public void addOctetString(final String value)
718  {
719    addOctetString(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE, value);
720  }
721
722
723
724  /**
725   * Adds an octet string element to this ASN.1 buffer using the provided BER
726   * type.
727   *
728   * @param  type   The BER type to use for the octet string element.
729   * @param  value  The value to use for the octet string element.
730   */
731  public void addOctetString(final byte type, final byte[] value)
732  {
733    buffer.append(type);
734
735    if (value == null)
736    {
737      buffer.append((byte) 0x00);
738    }
739    else
740    {
741      ASN1Element.encodeLengthTo(value.length, buffer);
742      buffer.append(value);
743    }
744  }
745
746
747
748  /**
749   * Adds an octet string element to this ASN.1 buffer using the provided BER
750   * type.
751   *
752   * @param  type   The BER type to use for the octet string element.
753   * @param  value  The value to use for the octet string element.
754   */
755  public void addOctetString(final byte type, final CharSequence value)
756  {
757    if (value == null)
758    {
759      addOctetString(type);
760    }
761    else
762    {
763      addOctetString(type, value.toString());
764    }
765  }
766
767
768
769  /**
770   * Adds an octet string element to this ASN.1 buffer using the provided BER
771   * type.
772   *
773   * @param  type   The BER type to use for the octet string element.
774   * @param  value  The value to use for the octet string element.
775   */
776  public void addOctetString(final byte type, final String value)
777  {
778    buffer.append(type);
779
780    if (value == null)
781    {
782      buffer.append((byte) 0x00);
783    }
784    else
785    {
786      // We'll assume that the string contains only ASCII characters and
787      // therefore the number of bytes will equal the number of characters.
788      // However, save the position in case we're wrong and need to re-encode.
789      final int lengthStartPos = buffer.length();
790      ASN1Element.encodeLengthTo(value.length(), buffer);
791
792      final int valueStartPos = buffer.length();
793      buffer.append(value);
794
795      if (buffer.length() != (valueStartPos + value.length()))
796      {
797        final byte[] valueBytes = new byte[buffer.length() - valueStartPos];
798        System.arraycopy(buffer.getBackingArray(), valueStartPos, valueBytes, 0,
799                         valueBytes.length);
800
801        buffer.setLength(lengthStartPos);
802        ASN1Element.encodeLengthTo(valueBytes.length, buffer);
803        buffer.append(valueBytes);
804      }
805    }
806  }
807
808
809
810  /**
811   * Adds a UTC time element to this ASN.1 buffer using the default BER type.
812   *
813   * @param  date  The date value that specifies the time to represent.  This
814   *               must not be {@code null}.
815   */
816  public void addUTCTime(final Date date)
817  {
818    addUTCTime(date.getTime());
819  }
820
821
822
823  /**
824   * Adds a UTC time element to this ASN.1 buffer using the provided BER type.
825   *
826   * @param  type  The BER type to use for the UTC time element.
827   * @param  date  The date value that specifies the time to represent.  This
828   *               must not be {@code null}.
829   */
830  public void addUTCTime(final byte type, final Date date)
831  {
832    addUTCTime(type, date.getTime());
833  }
834
835
836
837  /**
838   * Adds a UTC time element to this ASN.1 buffer using the default BER type.
839   *
840   * @param  time  The time to represent.  This must be expressed in
841   *               milliseconds since the epoch (the same format used by
842   *               {@code System.currentTimeMillis()} and
843   *               {@code Date.getTime()}).
844   */
845  public void addUTCTime(final long time)
846  {
847    addUTCTime(ASN1Constants.UNIVERSAL_UTC_TIME_TYPE, time);
848  }
849
850
851
852  /**
853   * Adds a UTC time element to this ASN.1 buffer using the provided BER type.
854   *
855   * @param  type  The BER type to use for the UTC time element.
856   * @param  time  The time to represent.  This must be expressed in
857   *               milliseconds since the epoch (the same format used by
858   *               {@code System.currentTimeMillis()} and
859   *               {@code Date.getTime()}).
860   */
861  public void addUTCTime(final byte type, final long time)
862  {
863    buffer.append(type);
864
865    final String timestamp = ASN1UTCTime.encodeTimestamp(time);
866    ASN1Element.encodeLengthTo(timestamp.length(), buffer);
867    buffer.append(timestamp);
868  }
869
870
871
872  /**
873   * Begins adding elements to an ASN.1 sequence using the default BER type.
874   *
875   * @return  An object that may be used to indicate when the end of the
876   *          sequence has been reached.  Once all embedded sequence elements
877   *          have been added, then the {@link ASN1BufferSequence#end} method
878   *          MUST be called to ensure that the sequence is properly encoded.
879   */
880  public ASN1BufferSequence beginSequence()
881  {
882    return beginSequence(ASN1Constants.UNIVERSAL_SEQUENCE_TYPE);
883  }
884
885
886
887  /**
888   * Begins adding elements to an ASN.1 sequence using the provided BER type.
889   *
890   * @param  type  The BER type to use for the sequence.
891   *
892   * @return  An object that may be used to indicate when the end of the
893   *          sequence has been reached.  Once all embedded sequence elements
894   *          have been added, then the {@link ASN1BufferSequence#end} method
895   *          MUST be called to ensure that the sequence is properly encoded.
896   */
897  public ASN1BufferSequence beginSequence(final byte type)
898  {
899    buffer.append(type);
900    return new ASN1BufferSequence(this);
901  }
902
903
904
905  /**
906   * Begins adding elements to an ASN.1 set using the default BER type.
907   *
908   * @return  An object that may be used to indicate when the end of the set has
909   *          been reached.  Once all embedded set elements have been added,
910   *          then the {@link ASN1BufferSet#end} method MUST be called to ensure
911   *          that the set is properly encoded.
912   */
913  public ASN1BufferSet beginSet()
914  {
915    return beginSet(ASN1Constants.UNIVERSAL_SET_TYPE);
916  }
917
918
919
920  /**
921   * Begins adding elements to an ASN.1 set using the provided BER type.
922   *
923   * @param  type  The BER type to use for the set.
924   *
925   * @return  An object that may be used to indicate when the end of the set has
926   *          been reached.  Once all embedded set elements have been added,
927   *          then the {@link ASN1BufferSet#end} method MUST be called to ensure
928   *          that the set is properly encoded.
929   */
930  public ASN1BufferSet beginSet(final byte type)
931  {
932    buffer.append(type);
933    return new ASN1BufferSet(this);
934  }
935
936
937
938  /**
939   * Ensures that the appropriate length is inserted into the internal buffer
940   * after all elements in a sequence or set have been added.
941   *
942   * @param  valueStartPos  The position in which the first value was added.
943   */
944  void endSequenceOrSet(final int valueStartPos)
945  {
946    final int length = buffer.length() - valueStartPos;
947    if (length == 0)
948    {
949      buffer.append((byte) 0x00);
950      return;
951    }
952
953    if ((length & 0x7F) == length)
954    {
955      buffer.insert(valueStartPos, (byte) length);
956    }
957    else if ((length & 0xFF) == length)
958    {
959      buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_ONE);
960
961      final byte[] backingArray = buffer.getBackingArray();
962      backingArray[valueStartPos+1] = (byte) (length & 0xFF);
963    }
964    else if ((length & 0xFFFF) == length)
965    {
966      buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_TWO);
967
968      final byte[] backingArray = buffer.getBackingArray();
969      backingArray[valueStartPos+1] = (byte) ((length >> 8) & 0xFF);
970      backingArray[valueStartPos+2] = (byte) (length & 0xFF);
971    }
972    else if ((length & 0xFFFFFF) == length)
973    {
974      buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_THREE);
975
976      final byte[] backingArray = buffer.getBackingArray();
977      backingArray[valueStartPos+1] = (byte) ((length >> 16) & 0xFF);
978      backingArray[valueStartPos+2] = (byte) ((length >> 8) & 0xFF);
979      backingArray[valueStartPos+3] = (byte) (length & 0xFF);
980    }
981    else
982    {
983      buffer.insert(valueStartPos, MULTIBYTE_LENGTH_HEADER_PLUS_FOUR);
984
985      final byte[] backingArray = buffer.getBackingArray();
986      backingArray[valueStartPos+1] = (byte) ((length >> 24) & 0xFF);
987      backingArray[valueStartPos+2] = (byte) ((length >> 16) & 0xFF);
988      backingArray[valueStartPos+3] = (byte) ((length >> 8) & 0xFF);
989      backingArray[valueStartPos+4] = (byte) (length & 0xFF);
990    }
991  }
992
993
994
995  /**
996   * Writes the contents of this buffer to the provided output stream.
997   *
998   * @param  outputStream  The output stream to which the data should be
999   *                       written.
1000   *
1001   * @throws  IOException  If a problem occurs while writing to the provided
1002   *                       output stream.
1003   */
1004  public void writeTo(final OutputStream outputStream)
1005         throws IOException
1006  {
1007    if (debugEnabled(DebugType.ASN1))
1008    {
1009      debugASN1Write(this);
1010    }
1011
1012    buffer.write(outputStream);
1013  }
1014
1015
1016
1017  /**
1018   * Retrieves a byte array containing the contents of this ASN.1 buffer.
1019   *
1020   * @return  A byte array containing the contents of this ASN.1 buffer.
1021   */
1022  public byte[] toByteArray()
1023  {
1024    return buffer.toByteArray();
1025  }
1026
1027
1028
1029  /**
1030   * Retrieves a byte buffer that wraps the data associated with this ASN.1
1031   * buffer.  The position will be set to the beginning of the data, and the
1032   * limit will be set to one byte after the end of the data.  The contents
1033   * of the returned byte buffer must not be altered in any way, and the
1034   * contents of this ASN.1 buffer must not be altered until the
1035   * {@code ByteBuffer} is no longer needed.
1036   *
1037   * @return  A byte buffer that wraps the data associated with this ASN.1
1038   *          buffer.
1039   */
1040  public ByteBuffer asByteBuffer()
1041  {
1042    return ByteBuffer.wrap(buffer.getBackingArray(), 0, buffer.length());
1043  }
1044}