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