001 /*
002 * Copyright 2007-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 UnboundID Corp.
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 */
021 package com.unboundid.asn1;
022
023
024
025 import java.io.InputStream;
026 import java.io.IOException;
027 import java.io.OutputStream;
028 import java.io.Serializable;
029 import java.util.Arrays;
030
031 import com.unboundid.util.ByteStringBuffer;
032
033 import static com.unboundid.asn1.ASN1Constants.*;
034 import static com.unboundid.asn1.ASN1Messages.*;
035 import static com.unboundid.util.Debug.*;
036 import static com.unboundid.util.StaticUtils.*;
037
038
039
040 /**
041 * This class defines a generic ASN.1 BER element, which has a type and value.
042 * It provides a framework for encoding and decoding BER elements, both as
043 * generic elements and more specific subtypes.
044 */
045 public class ASN1Element
046 implements Serializable
047 {
048 /**
049 * The serial version UID for this serializable class.
050 */
051 private static final long serialVersionUID = -1871166128693521335L;
052
053
054
055 // The BER type for this element.
056 private final byte type;
057
058 // The encoded value for this element.
059 private final byte[] value;
060
061 // The cached hashCode for this element.
062 private int hashCode = -1;
063
064 // The number of bytes contained in the value.
065 private final int valueLength;
066
067 // The offset within the value array at which the value begins.
068 private final int valueOffset;
069
070
071
072 /**
073 * Creates a new ASN.1 BER element with the specified type and no value.
074 *
075 * @param type The BER type for this element.
076 */
077 public ASN1Element(final byte type)
078 {
079 this.type = type;
080 value = NO_VALUE;
081 valueOffset = 0;
082 valueLength = 0;
083 }
084
085
086
087 /**
088 * Creates a new ASN1 BER element with the specified type and value.
089 *
090 * @param type The BER type for this element.
091 * @param value The encoded value for this element.
092 */
093 public ASN1Element(final byte type, final byte[] value)
094 {
095 this.type = type;
096
097 if (value == null)
098 {
099 this.value = NO_VALUE;
100 }
101 else
102 {
103 this.value = value;
104 }
105
106 valueOffset = 0;
107 valueLength = this.value.length;
108 }
109
110
111
112 /**
113 * Creates a new ASN1 BER element with the specified type and value.
114 *
115 * @param type The BER type for this element.
116 * @param value The array containing the encoded value for this element.
117 * It must not be {@code null}.
118 * @param offset The offset within the array at which the value begins.
119 * @param length The number of bytes contained in the value.
120 */
121 public ASN1Element(final byte type, final byte[] value, final int offset,
122 final int length)
123 {
124 this.type = type;
125 this.value = value;
126
127 valueOffset = offset;
128 valueLength = length;
129 }
130
131
132
133 /**
134 * Retrieves the BER type for this element.
135 *
136 * @return The BER type for this element.
137 */
138 public final byte getType()
139 {
140 return type;
141 }
142
143
144
145 /**
146 * Retrieves the array containing the value. The returned array may be
147 * larger than the actual value, so it must be used in conjunction with the
148 * values returned by the {@code getValueOffset} and {@code getValueLength}
149 * methods.
150 *
151 * @return The array containing the value.
152 */
153 byte[] getValueArray()
154 {
155 return value;
156 }
157
158
159
160 /**
161 * Retrieves the position in the value array at which the value actually
162 * begins.
163 *
164 * @return The position in the value array at which the value actually
165 * begins.
166 */
167 int getValueOffset()
168 {
169 return valueOffset;
170 }
171
172
173
174 /**
175 * Retrieves the number of bytes contained in the value.
176 *
177 * @return The number of bytes contained in the value.
178 */
179 public int getValueLength()
180 {
181 return valueLength;
182 }
183
184
185
186 /**
187 * Retrieves the encoded value for this element.
188 *
189 * @return The encoded value for this element.
190 */
191 public byte[] getValue()
192 {
193 if ((valueOffset == 0) && (valueLength == value.length))
194 {
195 return value;
196 }
197 else
198 {
199 final byte[] returnValue = new byte[valueLength];
200 System.arraycopy(value, valueOffset, returnValue, 0, valueLength);
201 return returnValue;
202 }
203 }
204
205
206
207 /**
208 * Encodes this ASN.1 element to a byte array.
209 *
210 * @return A byte array containing the encoded representation of this ASN.1
211 * element.
212 */
213 public final byte[] encode()
214 {
215 final byte[] valueArray = getValueArray();
216 final int length = getValueLength();
217 final int offset = getValueOffset();
218
219 if (length == 0)
220 {
221 return new byte[] { type, 0x00 };
222 }
223
224 final byte[] lengthBytes = encodeLength(length);
225 final byte[] elementBytes = new byte[1 + lengthBytes.length + length];
226
227 elementBytes[0] = type;
228 System.arraycopy(lengthBytes, 0, elementBytes, 1, lengthBytes.length);
229 System.arraycopy(valueArray, offset, elementBytes, 1+lengthBytes.length,
230 length);
231
232 return elementBytes;
233 }
234
235
236
237 /**
238 * Encodes the provided length to the given buffer.
239 *
240 * @param length The length to be encoded.
241 * @param buffer The buffer to which the length should be appended.
242 */
243 static void encodeLengthTo(final int length, final ByteStringBuffer buffer)
244 {
245 if ((length & 0x7F) == length)
246 {
247 buffer.append((byte) length);
248 }
249 else if ((length & 0xFF) == length)
250 {
251 buffer.append((byte) 0x81);
252 buffer.append((byte) (length & 0xFF));
253 }
254 else if ((length & 0xFFFF) == length)
255 {
256 buffer.append((byte) 0x82);
257 buffer.append((byte) ((length >> 8) & 0xFF));
258 buffer.append((byte) (length & 0xFF));
259 }
260 else if ((length & 0xFFFFFF) == length)
261 {
262 buffer.append((byte) 0x83);
263 buffer.append((byte) ((length >> 16) & 0xFF));
264 buffer.append((byte) ((length >> 8) & 0xFF));
265 buffer.append((byte) (length & 0xFF));
266 }
267 else
268 {
269 buffer.append((byte) 0x84);
270 buffer.append((byte) ((length >> 24) & 0xFF));
271 buffer.append((byte) ((length >> 16) & 0xFF));
272 buffer.append((byte) ((length >> 8) & 0xFF));
273 buffer.append((byte) (length & 0xFF));
274 }
275 }
276
277
278
279 /**
280 * Appends an encoded representation of this ASN.1 element to the provided
281 * buffer.
282 *
283 * @param buffer The buffer to which the encoded representation should be
284 * appended.
285 */
286 public void encodeTo(final ByteStringBuffer buffer)
287 {
288 final byte[] valueArray = getValueArray();
289 final int length = getValueLength();
290 final int offset = getValueOffset();
291
292 buffer.append(type);
293 if (length == 0)
294 {
295 buffer.append((byte) 0x00);
296 }
297 else
298 {
299 encodeLengthTo(length, buffer);
300 buffer.append(valueArray, offset, length);
301 }
302 }
303
304
305
306 /**
307 * Encodes the provided length to a byte array.
308 *
309 * @param length The length to be encoded.
310 *
311 * @return A byte array containing the encoded length.
312 */
313 public static byte[] encodeLength(final int length)
314 {
315 switch (length)
316 {
317 case 0: return LENGTH_0;
318 case 1: return LENGTH_1;
319 case 2: return LENGTH_2;
320 case 3: return LENGTH_3;
321 case 4: return LENGTH_4;
322 case 5: return LENGTH_5;
323 case 6: return LENGTH_6;
324 case 7: return LENGTH_7;
325 case 8: return LENGTH_8;
326 case 9: return LENGTH_9;
327 case 10: return LENGTH_10;
328 case 11: return LENGTH_11;
329 case 12: return LENGTH_12;
330 case 13: return LENGTH_13;
331 case 14: return LENGTH_14;
332 case 15: return LENGTH_15;
333 case 16: return LENGTH_16;
334 case 17: return LENGTH_17;
335 case 18: return LENGTH_18;
336 case 19: return LENGTH_19;
337 case 20: return LENGTH_20;
338 case 21: return LENGTH_21;
339 case 22: return LENGTH_22;
340 case 23: return LENGTH_23;
341 case 24: return LENGTH_24;
342 case 25: return LENGTH_25;
343 case 26: return LENGTH_26;
344 case 27: return LENGTH_27;
345 case 28: return LENGTH_28;
346 case 29: return LENGTH_29;
347 case 30: return LENGTH_30;
348 case 31: return LENGTH_31;
349 case 32: return LENGTH_32;
350 case 33: return LENGTH_33;
351 case 34: return LENGTH_34;
352 case 35: return LENGTH_35;
353 case 36: return LENGTH_36;
354 case 37: return LENGTH_37;
355 case 38: return LENGTH_38;
356 case 39: return LENGTH_39;
357 case 40: return LENGTH_40;
358 case 41: return LENGTH_41;
359 case 42: return LENGTH_42;
360 case 43: return LENGTH_43;
361 case 44: return LENGTH_44;
362 case 45: return LENGTH_45;
363 case 46: return LENGTH_46;
364 case 47: return LENGTH_47;
365 case 48: return LENGTH_48;
366 case 49: return LENGTH_49;
367 case 50: return LENGTH_50;
368 case 51: return LENGTH_51;
369 case 52: return LENGTH_52;
370 case 53: return LENGTH_53;
371 case 54: return LENGTH_54;
372 case 55: return LENGTH_55;
373 case 56: return LENGTH_56;
374 case 57: return LENGTH_57;
375 case 58: return LENGTH_58;
376 case 59: return LENGTH_59;
377 case 60: return LENGTH_60;
378 case 61: return LENGTH_61;
379 case 62: return LENGTH_62;
380 case 63: return LENGTH_63;
381 case 64: return LENGTH_64;
382 case 65: return LENGTH_65;
383 case 66: return LENGTH_66;
384 case 67: return LENGTH_67;
385 case 68: return LENGTH_68;
386 case 69: return LENGTH_69;
387 case 70: return LENGTH_70;
388 case 71: return LENGTH_71;
389 case 72: return LENGTH_72;
390 case 73: return LENGTH_73;
391 case 74: return LENGTH_74;
392 case 75: return LENGTH_75;
393 case 76: return LENGTH_76;
394 case 77: return LENGTH_77;
395 case 78: return LENGTH_78;
396 case 79: return LENGTH_79;
397 case 80: return LENGTH_80;
398 case 81: return LENGTH_81;
399 case 82: return LENGTH_82;
400 case 83: return LENGTH_83;
401 case 84: return LENGTH_84;
402 case 85: return LENGTH_85;
403 case 86: return LENGTH_86;
404 case 87: return LENGTH_87;
405 case 88: return LENGTH_88;
406 case 89: return LENGTH_89;
407 case 90: return LENGTH_90;
408 case 91: return LENGTH_91;
409 case 92: return LENGTH_92;
410 case 93: return LENGTH_93;
411 case 94: return LENGTH_94;
412 case 95: return LENGTH_95;
413 case 96: return LENGTH_96;
414 case 97: return LENGTH_97;
415 case 98: return LENGTH_98;
416 case 99: return LENGTH_99;
417 case 100: return LENGTH_100;
418 case 101: return LENGTH_101;
419 case 102: return LENGTH_102;
420 case 103: return LENGTH_103;
421 case 104: return LENGTH_104;
422 case 105: return LENGTH_105;
423 case 106: return LENGTH_106;
424 case 107: return LENGTH_107;
425 case 108: return LENGTH_108;
426 case 109: return LENGTH_109;
427 case 110: return LENGTH_110;
428 case 111: return LENGTH_111;
429 case 112: return LENGTH_112;
430 case 113: return LENGTH_113;
431 case 114: return LENGTH_114;
432 case 115: return LENGTH_115;
433 case 116: return LENGTH_116;
434 case 117: return LENGTH_117;
435 case 118: return LENGTH_118;
436 case 119: return LENGTH_119;
437 case 120: return LENGTH_120;
438 case 121: return LENGTH_121;
439 case 122: return LENGTH_122;
440 case 123: return LENGTH_123;
441 case 124: return LENGTH_124;
442 case 125: return LENGTH_125;
443 case 126: return LENGTH_126;
444 case 127: return LENGTH_127;
445 }
446
447 if ((length & 0x000000FF) == length)
448 {
449 return new byte[]
450 {
451 (byte) 0x81,
452 (byte) (length & 0xFF)
453 };
454 }
455 else if ((length & 0x0000FFFF) == length)
456 {
457 return new byte[]
458 {
459 (byte) 0x82,
460 (byte) ((length >> 8) & 0xFF),
461 (byte) (length & 0xFF)
462 };
463 }
464 else if ((length & 0x00FFFFFF) == length)
465 {
466 return new byte[]
467 {
468 (byte) 0x83,
469 (byte) ((length >> 16) & 0xFF),
470 (byte) ((length >> 8) & 0xFF),
471 (byte) (length & 0xFF)
472 };
473 }
474 else
475 {
476 return new byte[]
477 {
478 (byte) 0x84,
479 (byte) ((length >> 24) & 0xFF),
480 (byte) ((length >> 16) & 0xFF),
481 (byte) ((length >> 8) & 0xFF),
482 (byte) (length & 0xFF)
483 };
484 }
485 }
486
487
488
489 /**
490 * Decodes the content in the provided byte array as an ASN.1 element.
491 *
492 * @param elementBytes The byte array containing the data to decode.
493 *
494 * @return The decoded ASN.1 BER element.
495 *
496 * @throws ASN1Exception If the provided byte array does not represent a
497 * valid ASN.1 element.
498 */
499 public static ASN1Element decode(final byte[] elementBytes)
500 throws ASN1Exception
501 {
502 try
503 {
504 int valueStartPos = 2;
505 int length = (elementBytes[1] & 0x7F);
506 if (length != elementBytes[1])
507 {
508 final int numLengthBytes = length;
509
510 length = 0;
511 for (int i=0; i < numLengthBytes; i++)
512 {
513 length <<= 8;
514 length |= (elementBytes[valueStartPos++] & 0xFF);
515 }
516 }
517
518 if ((elementBytes.length - valueStartPos) != length)
519 {
520 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
521 (elementBytes.length - valueStartPos)));
522 }
523
524 final byte[] value = new byte[length];
525 System.arraycopy(elementBytes, valueStartPos, value, 0, length);
526 return new ASN1Element(elementBytes[0], value);
527 }
528 catch (final ASN1Exception ae)
529 {
530 debugException(ae);
531 throw ae;
532 }
533 catch (final Exception e)
534 {
535 debugException(e);
536 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
537 }
538 }
539
540
541
542 /**
543 * Decodes this ASN.1 element as a Boolean element.
544 *
545 * @return The decoded Boolean element.
546 *
547 * @throws ASN1Exception If this element cannot be decoded as a Boolean
548 * element.
549 */
550 public final ASN1Boolean decodeAsBoolean()
551 throws ASN1Exception
552 {
553 return ASN1Boolean.decodeAsBoolean(this);
554 }
555
556
557
558 /**
559 * Decodes this ASN.1 element as an enumerated element.
560 *
561 * @return The decoded enumerated element.
562 *
563 * @throws ASN1Exception If this element cannot be decoded as an enumerated
564 * element.
565 */
566 public final ASN1Enumerated decodeAsEnumerated()
567 throws ASN1Exception
568 {
569 return ASN1Enumerated.decodeAsEnumerated(this);
570 }
571
572
573
574 /**
575 * Decodes this ASN.1 element as an integer element.
576 *
577 * @return The decoded integer element.
578 *
579 * @throws ASN1Exception If this element cannot be decoded as an integer
580 * element.
581 */
582 public final ASN1Integer decodeAsInteger()
583 throws ASN1Exception
584 {
585 return ASN1Integer.decodeAsInteger(this);
586 }
587
588
589
590 /**
591 * Decodes this ASN.1 element as a long element.
592 *
593 * @return The decoded long element.
594 *
595 * @throws ASN1Exception If this element cannot be decoded as a long
596 * element.
597 */
598 public final ASN1Long decodeAsLong()
599 throws ASN1Exception
600 {
601 return ASN1Long.decodeAsLong(this);
602 }
603
604
605
606 /**
607 * Decodes this ASN.1 element as a null element.
608 *
609 * @return The decoded null element.
610 *
611 * @throws ASN1Exception If this element cannot be decoded as a null
612 * element.
613 */
614 public final ASN1Null decodeAsNull()
615 throws ASN1Exception
616 {
617 return ASN1Null.decodeAsNull(this);
618 }
619
620
621
622 /**
623 * Decodes this ASN.1 element as an octet string element.
624 *
625 * @return The decoded octet string element.
626 */
627 public final ASN1OctetString decodeAsOctetString()
628 {
629 return ASN1OctetString.decodeAsOctetString(this);
630 }
631
632
633
634 /**
635 * Decodes this ASN.1 element as a sequence element.
636 *
637 * @return The decoded sequence element.
638 *
639 * @throws ASN1Exception If this element cannot be decoded as a sequence
640 * element.
641 */
642 public final ASN1Sequence decodeAsSequence()
643 throws ASN1Exception
644 {
645 return ASN1Sequence.decodeAsSequence(this);
646 }
647
648
649
650 /**
651 * Decodes this ASN.1 element as a set element.
652 *
653 * @return The decoded set element.
654 *
655 * @throws ASN1Exception If this element cannot be decoded as a set
656 * element.
657 */
658 public final ASN1Set decodeAsSet()
659 throws ASN1Exception
660 {
661 return ASN1Set.decodeAsSet(this);
662 }
663
664
665
666 /**
667 * Reads an ASN.1 element from the provided input stream.
668 *
669 * @param inputStream The input stream from which to read the element.
670 *
671 * @return The element read from the input stream, or {@code null} if the end
672 * of the input stream is reached without reading any data.
673 *
674 * @throws IOException If a problem occurs while attempting to read from the
675 * input stream.
676 *
677 * @throws ASN1Exception If a problem occurs while attempting to decode the
678 * element.
679 */
680 public static ASN1Element readFrom(final InputStream inputStream)
681 throws IOException, ASN1Exception
682 {
683 return readFrom(inputStream, -1);
684 }
685
686
687
688 /**
689 * Reads an ASN.1 element from the provided input stream.
690 *
691 * @param inputStream The input stream from which to read the element.
692 * @param maxSize The maximum value size in bytes that will be allowed.
693 * A value less than or equal to zero indicates that no
694 * maximum size should be enforced. An attempt to read
695 * an element with a value larger than this will cause an
696 * {@code ASN1Exception} to be thrown.
697 *
698 * @return The element read from the input stream, or {@code null} if the end
699 * of the input stream is reached without reading any data.
700 *
701 * @throws IOException If a problem occurs while attempting to read from the
702 * input stream.
703 *
704 * @throws ASN1Exception If a problem occurs while attempting to decode the
705 * element.
706 */
707 public static ASN1Element readFrom(final InputStream inputStream,
708 final int maxSize)
709 throws IOException, ASN1Exception
710 {
711 final int typeInt = inputStream.read();
712 if (typeInt < 0)
713 {
714 return null;
715 }
716
717 final byte type = (byte) typeInt;
718
719 int length = inputStream.read();
720 if (length < 0)
721 {
722 throw new ASN1Exception(ERR_READ_END_BEFORE_FIRST_LENGTH.get());
723 }
724 else if (length > 127)
725 {
726 final int numLengthBytes = length & 0x7F;
727 length = 0;
728 if ((numLengthBytes < 1) || (numLengthBytes > 4))
729 {
730 throw new ASN1Exception(ERR_READ_LENGTH_TOO_LONG.get(numLengthBytes));
731 }
732
733 for (int i=0; i < numLengthBytes; i++)
734 {
735 final int lengthInt = inputStream.read();
736 if (lengthInt < 0)
737 {
738 throw new ASN1Exception(ERR_READ_END_BEFORE_LENGTH_END.get());
739 }
740
741 length <<= 8;
742 length |= (lengthInt & 0xFF);
743 }
744 }
745
746 if ((length < 0) || ((maxSize > 0) && (length > maxSize)))
747 {
748 throw new ASN1Exception(ERR_READ_LENGTH_EXCEEDS_MAX.get(length, maxSize));
749 }
750
751 int totalBytesRead = 0;
752 int bytesRemaining = length;
753 final byte[] value = new byte[length];
754 while (totalBytesRead < length)
755 {
756 final int bytesRead =
757 inputStream.read(value, totalBytesRead, bytesRemaining);
758 if (bytesRead < 0)
759 {
760 throw new ASN1Exception(ERR_READ_END_BEFORE_VALUE_END.get());
761 }
762
763 totalBytesRead += bytesRead;
764 bytesRemaining -= bytesRead;
765 }
766
767 final ASN1Element e = new ASN1Element(type, value);
768 debugASN1Read(e);
769 return e;
770 }
771
772
773
774 /**
775 * Writes an encoded representation of this ASN.1 element to the provided
776 * output stream.
777 *
778 * @param outputStream The output stream to which the element should be
779 * written.
780 *
781 * @return The total number of bytes written to the output stream.
782 *
783 * @throws IOException If a problem occurs while attempting to write to the
784 * provided output stream.
785 *
786 * @see ASN1Writer#writeElement(ASN1Element,OutputStream)
787 */
788 public final int writeTo(final OutputStream outputStream)
789 throws IOException
790 {
791 debugASN1Write(this);
792
793 final ByteStringBuffer buffer = new ByteStringBuffer();
794 encodeTo(buffer);
795 buffer.write(outputStream);
796 return buffer.length();
797 }
798
799
800
801 /**
802 * Retrieves a hash code for this ASN.1 BER element.
803 *
804 * @return A hash code for this ASN.1 BER element.
805 */
806 @Override()
807 public final int hashCode()
808 {
809 if (hashCode == -1)
810 {
811 int hash = 0;
812 for (final byte b : getValue())
813 {
814 hash = hash * 31 + b;
815 }
816 hashCode = hash;
817 }
818
819 return hashCode;
820 }
821
822
823
824 /**
825 * Indicates whether the provided object is equal to this ASN.1 BER element.
826 * The object will only be considered equal to this ASN.1 element if it is a
827 * non-null ASN.1 element with the same type and value as this element.
828 *
829 * @param o The object for which to make the determination.
830 *
831 * @return {@code true} if the provided object is considered equal to this
832 * ASN.1 element, or {@code false} if not.
833 */
834 @Override()
835 public final boolean equals(final Object o)
836 {
837 if (o == null)
838 {
839 return false;
840 }
841
842 if (o == this)
843 {
844 return true;
845 }
846
847 try
848 {
849 final ASN1Element e = (ASN1Element) o;
850 return ((type == e.getType()) && Arrays.equals(getValue(), e.getValue()));
851 }
852 catch (final Exception e)
853 {
854 debugException(e);
855 return false;
856 }
857 }
858
859
860
861 /**
862 * Indicates whether the provided ASN.1 element is equal to this element,
863 * ignoring any potential difference in the BER type.
864 *
865 * @param element The ASN.1 BER element for which to make the determination.
866 *
867 * @return {@code true} if the provided ASN.1 element is considered equal to
868 * this element (ignoring type differences), or {@code false} if not.
869 */
870 public final boolean equalsIgnoreType(final ASN1Element element)
871 {
872 if (element == null)
873 {
874 return false;
875 }
876
877 if (element == this)
878 {
879 return true;
880 }
881
882 return Arrays.equals(getValue(), element.getValue());
883 }
884
885
886
887 /**
888 * Retrieves a string representation of the value for ASN.1 element.
889 *
890 * @return A string representation of the value for this ASN.1 element.
891 */
892 @Override()
893 public final String toString()
894 {
895 final StringBuilder buffer = new StringBuilder();
896 toString(buffer);
897 return buffer.toString();
898 }
899
900
901
902 /**
903 * Appends a string representation of the value for this ASN.1 element to the
904 * provided buffer.
905 *
906 * @param buffer The buffer to which to append the information.
907 */
908 public void toString(final StringBuilder buffer)
909 {
910 final byte[] v = getValue();
911 buffer.append("ASN1Element(type=");
912 toHex(type, buffer);
913 buffer.append(", valueLength=");
914 buffer.append(v.length);
915 buffer.append(", valueBytes='");
916 toHex(v, buffer);
917 buffer.append("')");
918 }
919 }