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