001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.protocols.asn1;
028 import org.opends.messages.Message;
029
030
031
032 import java.io.Serializable;
033 import java.util.ArrayList;
034 import java.util.Arrays;
035
036 import org.opends.server.api.ProtocolElement;
037 import org.opends.server.types.ByteString;
038
039 import static org.opends.messages.ProtocolMessages.*;
040 import static org.opends.server.protocols.asn1.ASN1Constants.*;
041 import static org.opends.server.util.ServerConstants.*;
042 import static org.opends.server.util.StaticUtils.*;
043
044
045
046 /**
047 * This class defines the data structures and methods to use when interacting
048 * with generic ASN.1 elements. Subclasses may provide more specific
049 * functionality for individual element types.
050 */
051 @org.opends.server.types.PublicAPI(
052 stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
053 mayInstantiate=true,
054 mayExtend=false,
055 mayInvoke=true)
056 public class ASN1Element
057 implements ProtocolElement, Serializable
058 {
059 /**
060 * The serial version identifier required to satisfy the compiler because this
061 * class implements the <CODE>java.io.Serializable</CODE> interface. This
062 * value was generated using the <CODE>serialver</CODE> command-line utility
063 * included with the Java SDK.
064 */
065 private static final long serialVersionUID = -6085322427222358963L;
066
067
068
069 // The BER type for this element.
070 private byte type;
071
072 // The encoded value for this element.
073 private byte[] value;
074
075
076
077 /**
078 * Creates a new ASN.1 element with the specified type and no value.
079 *
080 * @param type The BER type for this ASN.1 element.
081 */
082 public ASN1Element(byte type)
083 {
084 this.type = type;
085 this.value = NO_VALUE;
086 }
087
088
089
090 /**
091 * Creates a new ASN.1 element with the specified type and value.
092 *
093 * @param type The BER type for this ASN.1 element.
094 * @param value The encoded value for this ASN.1 element.
095 */
096 public ASN1Element(byte type, byte[] value)
097 {
098 this.type = type;
099
100 if (value == null)
101 {
102 this.value = NO_VALUE;
103 }
104 else
105 {
106 this.value = value;
107 }
108 }
109
110
111
112 /**
113 * Retrieves the BER type for this ASN.1 element.
114 *
115 * @return The BER type for this ASN.1 element.
116 */
117 public final byte getType()
118 {
119 return type;
120 }
121
122
123
124 /**
125 * Specifies the BER type for this ASN.1 element.
126 *
127 * @param type The BER type for this ASN.1 element.
128 */
129 public final void setType(byte type)
130 {
131 this.type = type;
132 }
133
134
135
136 /**
137 * Indicates whether this ASN.1 element is in the universal class.
138 *
139 * @return <CODE>true</CODE> if this ASN.1 element is in the universal class,
140 * or <CODE>false</CODE> if not.
141 */
142 public final boolean isUniversal()
143 {
144 return ((type & TYPE_MASK_ALL_BUT_CLASS) == TYPE_MASK_UNIVERSAL);
145 }
146
147
148
149 /**
150 * Indicates whether this ASN.1 element is in the application-specific class.
151 *
152 * @return <CODE>true</CODE> if this ASN.1 element is in the
153 * application-specific class, or <CODE>false</CODE> if not.
154 */
155 public final boolean isApplicationSpecific()
156 {
157 return ((type & TYPE_MASK_ALL_BUT_CLASS) == TYPE_MASK_APPLICATION);
158 }
159
160
161
162 /**
163 * Indicates whether this ASN.1 element is in the context-specific class.
164 *
165 * @return <CODE>true</CODE> if this ASN.1 element is in the context-specific
166 * class, or <CODE>false</CODE> if not.
167 */
168 public final boolean isContextSpecific()
169 {
170 return ((type & TYPE_MASK_ALL_BUT_CLASS) == TYPE_MASK_CONTEXT);
171 }
172
173
174
175 /**
176 * Indicates whether this ASN.1 element is in the private class.
177 *
178 * @return <CODE>true</CODE> if this ASN.1 element is in the private class,
179 * or <CODE>false</CODE> if not.
180 */
181 public final boolean isPrivate()
182 {
183 return ((type & TYPE_MASK_ALL_BUT_CLASS) == TYPE_MASK_PRIVATE);
184 }
185
186
187
188 /**
189 * Indicates whether this ASN.1 element has a primitive value.
190 *
191 * @return <CODE>true</CODE> if this ASN.1 element has a primitive value, or
192 * <CODE>false</CODE> if it is constructed.
193 */
194 public final boolean isPrimitive()
195 {
196 return ((type & TYPE_MASK_ALL_BUT_PC) == TYPE_MASK_PRIMITIVE);
197 }
198
199
200
201 /**
202 * Indicates whether this ASN.1 element has a constructed value.
203 *
204 * @return <CODE>true</CODE> if this ASN.1 element has a constructed value,
205 * or <CODE>false</CODE> if it is primitive.
206 */
207 public final boolean isConstructed()
208 {
209 return ((type & TYPE_MASK_ALL_BUT_PC) == TYPE_MASK_CONSTRUCTED);
210 }
211
212
213
214 /**
215 * Retrieves the encoded value for this ASN.1 element.
216 *
217 * @return The encoded value for this ASN.1 element.
218 */
219 public final byte[] value()
220 {
221 return value;
222 }
223
224
225
226 /**
227 * Specifies the encoded value for this ASN.1 element.
228 *
229 * @param value The encoded value for this ASN.1 element.
230 *
231 * @throws ASN1Exception If the provided value is not appropriate for this
232 * type of ASN.1 element.
233 */
234 public void setValue(byte[] value)
235 throws ASN1Exception
236 {
237 if (value == null)
238 {
239 this.value = NO_VALUE;
240 }
241 else
242 {
243 this.value = value;
244 }
245 }
246
247
248
249 /**
250 * Specifies the value to use for this ASN.1 element, but without performing
251 * any validity checks. This should only be used by subclasses and they must
252 * ensure that it is non-null and conforms to the appropriate requirements of
253 * the underlying type.
254 *
255 * @param value The encoded value for this ASN.1 element.
256 */
257 protected final void setValueInternal(byte[] value)
258 {
259 this.value = value;
260 }
261
262
263
264 /**
265 * Encodes the provided value for use as the length of an ASN.1 element.
266 *
267 * @param length The length to encode for use in an ASN.1 element.
268 *
269 * @return The byte array containing the encoded length.
270 */
271 public static byte[] encodeLength(int length)
272 {
273 if (length < 128)
274 {
275 return new byte[] { (byte) length };
276 }
277
278 if ((length & 0x000000FF) == length)
279 {
280 return new byte[]
281 {
282 (byte) 0x81,
283 (byte) (length & 0xFF)
284 };
285 }
286 else if ((length & 0x0000FFFF) == length)
287 {
288 return new byte[]
289 {
290 (byte) 0x82,
291 (byte) ((length >> 8) & 0xFF),
292 (byte) (length & 0xFF)
293 };
294 }
295 else if ((length & 0x00FFFFFF) == length)
296 {
297 return new byte[]
298 {
299 (byte) 0x83,
300 (byte) ((length >> 16) & 0xFF),
301 (byte) ((length >> 8) & 0xFF),
302 (byte) (length & 0xFF)
303 };
304 }
305 else
306 {
307 return new byte[]
308 {
309 (byte) 0x84,
310 (byte) ((length >> 24) & 0xFF),
311 (byte) ((length >> 16) & 0xFF),
312 (byte) ((length >> 8) & 0xFF),
313 (byte) (length & 0xFF)
314 };
315 }
316 }
317
318
319
320 /**
321 * Encodes this ASN.1 element to a byte array.
322 *
323 * @return The byte array containing the encoded ASN.1 element.
324 */
325 public final byte[] encode()
326 {
327 if (value.length == 0)
328 {
329 return new byte[] { type, 0x00 };
330 }
331 else if (value.length < 128)
332 {
333 byte[] encodedElement = new byte[value.length + 2];
334
335 encodedElement[0] = type;
336 encodedElement[1] = (byte) value.length;
337 System.arraycopy(value, 0, encodedElement, 2, value.length);
338
339 return encodedElement;
340 }
341 else
342 {
343 byte[] encodedLength = encodeLength(value.length);
344 byte[] encodedElement = new byte[1 + value.length + encodedLength.length];
345
346 encodedElement[0] = type;
347 System.arraycopy(encodedLength, 0, encodedElement, 1,
348 encodedLength.length);
349 System.arraycopy(value, 0, encodedElement, 1+encodedLength.length,
350 value.length);
351
352 return encodedElement;
353 }
354 }
355
356
357
358 /**
359 * Retrieves a byte array containing the encoded representation of the
360 * provided boolean value.
361 *
362 * @param booleanValue The boolean value to encode.
363 *
364 * @return A byte array containing the encoded representation of the provided
365 * boolean value.
366 */
367 public static byte[] encodeValue(boolean booleanValue)
368 {
369 return (booleanValue ? BOOLEAN_VALUE_TRUE : BOOLEAN_VALUE_FALSE);
370 }
371
372
373
374 /**
375 * Retrieves a byte array containing the encoded representation of the
376 * provided integer value.
377 *
378 * @param intValue The integer value to encode.
379 *
380 * @return A byte array containing the encoded representation of the provided
381 * integer value.
382 */
383 public static byte[] encodeValue(int intValue)
384 {
385 if ((intValue & 0x0000007F) == intValue)
386 {
387 return new byte[]
388 {
389 (byte) (intValue & 0xFF)
390 };
391 }
392 else if ((intValue & 0x00007FFF) == intValue)
393 {
394 return new byte[]
395 {
396 (byte) ((intValue >> 8) & 0xFF),
397 (byte) (intValue & 0xFF)
398 };
399 }
400 else if ((intValue & 0x007FFFFF) == intValue)
401 {
402 return new byte[]
403 {
404 (byte) ((intValue >> 16) & 0xFF),
405 (byte) ((intValue >> 8) & 0xFF),
406 (byte) (intValue & 0xFF)
407 };
408 }
409 else
410 {
411 return new byte[]
412 {
413 (byte) ((intValue >> 24) & 0xFF),
414 (byte) ((intValue >> 16) & 0xFF),
415 (byte) ((intValue >> 8) & 0xFF),
416 (byte) (intValue & 0xFF)
417 };
418 }
419 }
420
421
422
423 /**
424 * Retrieves a byte array containing the encoded representation of the
425 * provided long value.
426 *
427 * @param longValue The long value to encode.
428 *
429 * @return A byte array containing the encoded representation of the provided
430 * long value.
431 */
432 public static byte[] encodeLongValue(long longValue)
433 {
434 if ((longValue & 0x000000000000007FL) == longValue)
435 {
436 return new byte[]
437 {
438 (byte) (longValue & 0xFF)
439 };
440 }
441 else if ((longValue & 0x0000000000007FFFL) == longValue)
442 {
443 return new byte[]
444 {
445 (byte) ((longValue >> 8) & 0xFF),
446 (byte) (longValue & 0xFF)
447 };
448 }
449 else if ((longValue & 0x00000000007FFFFFL) == longValue)
450 {
451 return new byte[]
452 {
453 (byte) ((longValue >> 16) & 0xFF),
454 (byte) ((longValue >> 8) & 0xFF),
455 (byte) (longValue & 0xFF)
456 };
457 }
458 else if ((longValue & 0x000000007FFFFFFFL) == longValue)
459 {
460 return new byte[]
461 {
462 (byte) ((longValue >> 24) & 0xFF),
463 (byte) ((longValue >> 16) & 0xFF),
464 (byte) ((longValue >> 8) & 0xFF),
465 (byte) (longValue & 0xFF)
466 };
467 }
468 else if ((longValue & 0x0000007FFFFFFFFFL) == longValue)
469 {
470 return new byte[]
471 {
472 (byte) ((longValue >> 32) & 0xFF),
473 (byte) ((longValue >> 24) & 0xFF),
474 (byte) ((longValue >> 16) & 0xFF),
475 (byte) ((longValue >> 8) & 0xFF),
476 (byte) (longValue & 0xFF)
477 };
478 }
479 else if ((longValue & 0x00007FFFFFFFFFFFL) == longValue)
480 {
481 return new byte[]
482 {
483 (byte) ((longValue >> 40) & 0xFF),
484 (byte) ((longValue >> 32) & 0xFF),
485 (byte) ((longValue >> 24) & 0xFF),
486 (byte) ((longValue >> 16) & 0xFF),
487 (byte) ((longValue >> 8) & 0xFF),
488 (byte) (longValue & 0xFF)
489 };
490 }
491 else if ((longValue & 0x007FFFFFFFFFFFFFL) == longValue)
492 {
493 return new byte[]
494 {
495 (byte) ((longValue >> 48) & 0xFF),
496 (byte) ((longValue >> 40) & 0xFF),
497 (byte) ((longValue >> 32) & 0xFF),
498 (byte) ((longValue >> 24) & 0xFF),
499 (byte) ((longValue >> 16) & 0xFF),
500 (byte) ((longValue >> 8) & 0xFF),
501 (byte) (longValue & 0xFF)
502 };
503 }
504 else
505 {
506 return new byte[]
507 {
508 (byte) ((longValue >> 56) & 0xFF),
509 (byte) ((longValue >> 48) & 0xFF),
510 (byte) ((longValue >> 40) & 0xFF),
511 (byte) ((longValue >> 32) & 0xFF),
512 (byte) ((longValue >> 24) & 0xFF),
513 (byte) ((longValue >> 16) & 0xFF),
514 (byte) ((longValue >> 8) & 0xFF),
515 (byte) (longValue & 0xFF)
516 };
517 }
518 }
519
520
521
522 /**
523 * Retrieves a byte array containing the encoded representation of the
524 * provided set of ASN.1 elements.
525 *
526 * @param elements The set of ASN.1 elements to encode into the value.
527 *
528 * @return A byte array containing the encoded representation of the
529 * provided set of ASN.1 elements.
530 */
531 public static byte[] encodeValue(ArrayList<ASN1Element> elements)
532 {
533 if (elements == null)
534 {
535 return NO_VALUE;
536 }
537
538
539 int totalLength = 0;
540 byte[][] encodedElements = new byte[elements.size()][];
541 for (int i=0; i < encodedElements.length; i++)
542 {
543 encodedElements[i] = elements.get(i).encode();
544 totalLength += encodedElements[i].length;
545 }
546
547 byte[] encodedValue = new byte[totalLength];
548 int startPos = 0;
549 for (byte[] b : encodedElements)
550 {
551 System.arraycopy(b, 0, encodedValue, startPos, b.length);
552 startPos += b.length;
553 }
554
555 return encodedValue;
556 }
557
558
559
560 /**
561 * Decodes the contents of the provided byte array as an ASN.1 element.
562 *
563 * @param encodedElement The byte array containing the ASN.1 element to
564 * decode.
565 *
566 * @return The decoded ASN.1 element.
567 *
568 * @throws ASN1Exception If a problem occurs while attempting to decode the
569 * byte array as an ASN.1 element.
570 */
571 public static ASN1Element decode(byte[] encodedElement)
572 throws ASN1Exception
573 {
574 // First make sure that the array is not null and long enough to contain
575 // a valid ASN.1 element.
576 if (encodedElement == null)
577 {
578 Message message = ERR_ASN1_NULL_ELEMENT.get();
579 throw new ASN1Exception(message);
580 }
581 else if (encodedElement.length < 2)
582 {
583 Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
584 throw new ASN1Exception(message);
585 }
586
587
588 // Next, decode the length. This allows multi-byte lengths with up to four
589 // bytes used to indicate how many bytes are in the length.
590 byte type = encodedElement[0];
591 int length = (encodedElement[1] & 0x7F);
592 int valueStartPos = 2;
593 if (length != encodedElement[1])
594 {
595 int numLengthBytes = length;
596 if (numLengthBytes > 4)
597 {
598 Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
599 throw new ASN1Exception(message);
600 }
601 else if (encodedElement.length < (2 + numLengthBytes))
602 {
603 Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
604 throw new ASN1Exception(message);
605 }
606
607 length = 0x00;
608 valueStartPos = 2 + numLengthBytes;
609 for (int i=0; i < numLengthBytes; i++)
610 {
611 length = (length << 8) | (encodedElement[i+2] & 0xFF);
612 }
613 }
614
615
616 // Make sure that the number of bytes left is equal to the number of bytes
617 // in the value.
618 if ((encodedElement.length - valueStartPos) != length)
619 {
620 Message message = ERR_ASN1_LENGTH_MISMATCH.get(
621 length, (encodedElement.length - valueStartPos));
622 throw new ASN1Exception(message);
623 }
624
625
626 // Copy the value and construct the element to return.
627 byte[] value = new byte[length];
628 System.arraycopy(encodedElement, valueStartPos, value, 0, length);
629 return new ASN1Element(type, value);
630 }
631
632
633
634 /**
635 * Decodes the specified portion of the provided byte array as an ASN.1
636 * element.
637 *
638 * @param encodedElement The byte array containing the ASN.1 element to
639 * decode.
640 * @param startPos The position in the provided array at which to
641 * start decoding.
642 * @param length The number of bytes in the set of data to decode as
643 * an ASN.1 element.
644 *
645 * @return The decoded ASN.1 element.
646 *
647 * @throws ASN1Exception If a problem occurs while attempting to decode the
648 * byte array as an ASN.1 element.
649 */
650 public static ASN1Element decode(byte[] encodedElement, int startPos,
651 int length)
652 throws ASN1Exception
653 {
654 // First make sure that the array is not null and long enough to contain
655 // a valid ASN.1 element.
656 if (encodedElement == null)
657 {
658 Message message = ERR_ASN1_NULL_ELEMENT.get();
659 throw new ASN1Exception(message);
660 }
661 else if ((startPos < 0) || (startPos+length > encodedElement.length) ||
662 (length < 2))
663 {
664 Message message = ERR_ASN1_SHORT_ELEMENT.get(encodedElement.length);
665 throw new ASN1Exception(message);
666 }
667
668
669 // Next, decode the length. This allows multi-byte lengths with up to four
670 // bytes used to indicate how many bytes are in the length.
671 byte type = encodedElement[startPos];
672 int elementLength = (encodedElement[startPos+1] & 0x7F);
673 int valueStartPos = startPos + 2;
674 if (elementLength != encodedElement[startPos+1])
675 {
676 int numLengthBytes = elementLength;
677 if (numLengthBytes > 4)
678 {
679 Message message = ERR_ASN1_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
680 throw new ASN1Exception(message);
681 }
682 else if (startPos+length < (2 + numLengthBytes))
683 {
684 Message message = ERR_ASN1_TRUNCATED_LENGTH.get(numLengthBytes);
685 throw new ASN1Exception(message);
686 }
687
688 elementLength = 0x00;
689 valueStartPos = startPos + 2 + numLengthBytes;
690 for (int i=0; i < numLengthBytes; i++)
691 {
692 elementLength = (elementLength << 8) | (encodedElement[i+2] & 0xFF);
693 }
694 }
695
696
697 // Make sure that the number of bytes left is equal to the number of bytes
698 // in the value.
699 if ((startPos+length - valueStartPos) != elementLength)
700 {
701 Message message = ERR_ASN1_LENGTH_MISMATCH.get(
702 elementLength, (startPos+length - valueStartPos));
703 throw new ASN1Exception(message);
704 }
705
706
707 // Copy the value and construct the element to return.
708 byte[] value = new byte[elementLength];
709 System.arraycopy(encodedElement, valueStartPos, value, 0, elementLength);
710 return new ASN1Element(type, value);
711 }
712
713
714
715 /**
716 * Decodes this ASN.1 element as an ASN.1 Boolean element.
717 *
718 * @return The ASN.1 Boolean element decoded from this element.
719 *
720 * @throws ASN1Exception If a problem occurs while attempting to decode this
721 * element as an ASN.1 Boolean element.
722 */
723 public final ASN1Boolean decodeAsBoolean()
724 throws ASN1Exception
725 {
726 return ASN1Boolean.decodeAsBoolean(this);
727 }
728
729
730
731 /**
732 * Decodes this ASN.1 element as an ASN.1 enumerated element.
733 *
734 * @return The ASN.1 enumerated element decoded from this element.
735 *
736 * @throws ASN1Exception If a problem occurs while attempting to decode this
737 * element as an ASN.1 enumerated element.
738 */
739 public final ASN1Enumerated decodeAsEnumerated()
740 throws ASN1Exception
741 {
742 return ASN1Enumerated.decodeAsEnumerated(this);
743 }
744
745
746
747 /**
748 * Decodes this ASN.1 element as an ASN.1 integer element.
749 *
750 * @return The ASN.1 integer element decoded from this element.
751 *
752 * @throws ASN1Exception If a problem occurs while attempting to decode this
753 * element as an ASN.1 integer element.
754 */
755 public final ASN1Integer decodeAsInteger()
756 throws ASN1Exception
757 {
758 return ASN1Integer.decodeAsInteger(this);
759 }
760
761
762
763 /**
764 * Decodes this ASN.1 element as an ASN.1 long element.
765 *
766 * @return The ASN.1 long element decoded from this element.
767 *
768 * @throws ASN1Exception If a problem occurs while attempting to decode this
769 * element as an ASN.1 long element.
770 */
771 public final ASN1Long decodeAsLong()
772 throws ASN1Exception
773 {
774 return ASN1Long.decodeAsLong(this);
775 }
776
777
778
779 /**
780 * Decodes this ASN.1 element as an ASN.1 null element.
781 *
782 * @return The ASN.1 null element decoded from this element.
783 *
784 * @throws ASN1Exception If a problem occurs while attempting to decode this
785 * element as an ASN.1 null element.
786 */
787 public final ASN1Null decodeAsNull()
788 throws ASN1Exception
789 {
790 return ASN1Null.decodeAsNull(this);
791 }
792
793
794
795 /**
796 * Decodes this ASN.1 element as an ASN.1 octet string element.
797 *
798 * @return The ASN.1 octet string element decoded from this element.
799 *
800 * @throws ASN1Exception If a problem occurs while attempting to decode this
801 * element as an ASN.1 octet string element.
802 */
803 public final ASN1OctetString decodeAsOctetString()
804 throws ASN1Exception
805 {
806 return ASN1OctetString.decodeAsOctetString(this);
807 }
808
809
810
811 /**
812 * Decodes this ASN.1 element as an ASN.1 sequence element.
813 *
814 * @return The ASN.1 sequence element decoded from this element.
815 *
816 * @throws ASN1Exception If a problem occurs while attempting to decode this
817 * element as an ASN.1 sequence element.
818 */
819 public final ASN1Sequence decodeAsSequence()
820 throws ASN1Exception
821 {
822 return ASN1Sequence.decodeAsSequence(this);
823 }
824
825
826
827 /**
828 * Decodes this ASN.1 element as an ASN.1 set element.
829 *
830 * @return The ASN.1 set element decoded from this element.
831 *
832 * @throws ASN1Exception If a problem occurs while attempting to decode this
833 * element as an ASN.1 set element.
834 */
835 public final ASN1Set decodeAsSet()
836 throws ASN1Exception
837 {
838 return ASN1Set.decodeAsSet(this);
839 }
840
841
842
843 /**
844 * Decodes the provided byte array as a collection of ASN.1 elements as would
845 * be found in the value of a sequence or set.
846 *
847 * @param encodedElements The byte array containing the data to decode.
848 *
849 * @return The set of decoded ASN.1 elements.
850 *
851 * @throws ASN1Exception If a problem occurs while attempting to decode the
852 * set of ASN.1 elements from the provided byte array.
853 */
854 public static ArrayList<ASN1Element> decodeElements(byte[] encodedElements)
855 throws ASN1Exception
856 {
857 // Make sure that the element array is not null.
858 if (encodedElements == null)
859 {
860 Message message = ERR_ASN1_ELEMENT_SET_NULL.get();
861 throw new ASN1Exception(message);
862 }
863
864
865 // Iterate through the array and keep reading elements until the end is
866 // reached.
867 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>();
868 int startPos = 0;
869 while (startPos < encodedElements.length)
870 {
871 byte type = encodedElements[startPos++];
872 if (startPos >= encodedElements.length)
873 {
874 Message message = ERR_ASN1_ELEMENT_SET_NO_LENGTH.get();
875 throw new ASN1Exception(message);
876 }
877
878
879 byte firstLengthByte = encodedElements[startPos++];
880 int length = (byte) (firstLengthByte & 0x7F);
881 if (length != firstLengthByte)
882 {
883 int numLengthBytes = length;
884 if (numLengthBytes > 4)
885 {
886 Message message =
887 ERR_ASN1_ELEMENT_SET_INVALID_NUM_LENGTH_BYTES.get(numLengthBytes);
888 throw new ASN1Exception(message);
889 }
890
891 if (numLengthBytes > encodedElements.length - startPos)
892 {
893 Message message =
894 ERR_ASN1_ELEMENT_SET_TRUNCATED_LENGTH.get(numLengthBytes);
895 throw new ASN1Exception(message);
896 }
897
898 length = 0x00;
899 for (int i=0; i < numLengthBytes; i++)
900 {
901 length = (length << 8) | (encodedElements[startPos++] & 0xFF);
902 }
903 }
904
905
906 // Make sure that there are at least enough bytes to hold the value.
907 if (length > encodedElements.length - startPos)
908 {
909 Message message = ERR_ASN1_ELEMENT_SET_TRUNCATED_VALUE.get(
910 length, (encodedElements.length-startPos));
911 throw new ASN1Exception(message);
912 }
913
914
915 // Create the element and add it to the list.
916 byte[] value = new byte[length];
917 System.arraycopy(encodedElements, startPos, value, 0, length);
918 elements.add(new ASN1Element(type, value));
919 startPos += length;
920 }
921
922
923 return elements;
924 }
925
926
927
928 /**
929 * Retrieves the name of the protocol associated with this protocol element.
930 *
931 * @return The name of the protocol associated with this protocol element.
932 */
933 public final String getProtocolElementName()
934 {
935 return "ASN.1";
936 }
937
938
939
940 /**
941 * Indicates whether the provided object is equal to this ASN.1 element.
942 *
943 * @param o The object for which to make the determination.
944 *
945 * @return <CODE>true</CODE> if the provided object is an ASN.1 element that
946 * is equal to this element, or <CODE>false</CODE> if not. The
947 * object will be considered equal if it is an ASN.1 element (or a
948 * subclass) with the same type and encoded value.
949 */
950 public final boolean equals(Object o)
951 {
952 if (this == o)
953 {
954 return true;
955 }
956
957 if ((o == null) || (! (o instanceof ASN1Element)))
958 {
959 return false;
960 }
961
962 ASN1Element e = (ASN1Element) o;
963 return ((type == e.type) && Arrays.equals(value, e.value));
964 }
965
966
967
968 /**
969 * Indicates whether the provided ASN.1 element has a value that is equal to
970 * the value of this ASN.1 element.
971 *
972 * @param element The ASN.1 element whose value should be compared against
973 * the value of this element.
974 *
975 * @return <CODE>true</CODE> if the values of the elements are equal, or
976 * <CODE>false</CODE> if not.
977 */
978 public final boolean equalsIgnoreType(ASN1Element element)
979 {
980 return Arrays.equals(value, element.value);
981 }
982
983
984
985 /**
986 * Indicates whether the provided byte string has a value that is equal to
987 * the value of this ASN.1 element.
988 *
989 * @param byteString The byte string whose value should be compared against
990 * the value of this element.
991 *
992 * @return <CODE>true</CODE> if the values are equal, or <CODE>false</CODE>
993 * if not.
994 */
995 public final boolean equalsIgnoreType(ByteString byteString)
996 {
997 return Arrays.equals(value, byteString.value());
998 }
999
1000
1001
1002 /**
1003 * Indicates whether the provided ASN.1 element is equal to this element.
1004 *
1005 * @param e The ASN.1 element for which to make the determination.
1006 *
1007 * @return <CODE>true</CODE> ASN.1 element is equal to this element,
1008 * or <CODE>false</CODE> if not. The elements will be considered
1009 * equal if they have the same type and encoded value.
1010 */
1011 public final boolean equalsElement(ASN1Element e)
1012 {
1013 if (this == e)
1014 {
1015 return true;
1016 }
1017
1018 if (e == null)
1019 {
1020 return false;
1021 }
1022
1023 return ((type == e.type) && Arrays.equals(value, e.value));
1024 }
1025
1026
1027
1028 /**
1029 * Retrieves the hash code for this ASN.1 element. It will be constructed
1030 * from the sum of the type and up to the first twenty bytes of the value.
1031 *
1032 * @return The hash code for this ASN.1 element.
1033 */
1034 public final int hashCode()
1035 {
1036 int hashCode = type;
1037 int length = Math.min(20, value.length);
1038 for (int i=0; i < length; i++)
1039 {
1040 hashCode += value[i];
1041 }
1042
1043 return hashCode;
1044 }
1045
1046
1047
1048 /**
1049 * Retrieves a string representation of this ASN.1 element.
1050 *
1051 * @return A string representation of this ASN.1 element.
1052 */
1053 public final String toString()
1054 {
1055 StringBuilder buffer = new StringBuilder();
1056 toString(buffer);
1057 return buffer.toString();
1058 }
1059
1060
1061
1062 /**
1063 * Appends a string representation of this ASN.1 element to the provided
1064 * buffer.
1065 *
1066 * @param buffer The buffer to which the information should be appended.
1067 */
1068 public void toString(StringBuilder buffer)
1069 {
1070 buffer.append("ASN1Element(type=");
1071 buffer.append(byteToHex(type));
1072 buffer.append(", length=");
1073 buffer.append(value.length);
1074 buffer.append(")");
1075 }
1076
1077
1078
1079 /**
1080 * Appends a string representation of this protocol element to the provided
1081 * buffer.
1082 *
1083 * @param buffer The buffer into which the string representation should be
1084 * written.
1085 * @param indent The number of spaces that should be used to indent the
1086 * resulting string representation.
1087 */
1088 public void toString(StringBuilder buffer, int indent)
1089 {
1090 StringBuilder indentBuf = new StringBuilder(indent);
1091 for (int i=0 ; i < indent; i++)
1092 {
1093 indentBuf.append(' ');
1094 }
1095
1096 buffer.append(indentBuf);
1097 buffer.append("ASN.1 Element");
1098 buffer.append(EOL);
1099
1100 buffer.append(indentBuf);
1101 buffer.append(" BER Type: ");
1102 buffer.append(byteToHex(type));
1103 buffer.append(EOL);
1104
1105 buffer.append(indentBuf);
1106 buffer.append(" Value (");
1107 buffer.append(value.length);
1108 buffer.append(" bytes)");
1109 buffer.append(EOL);
1110
1111 byteArrayToHexPlusAscii(buffer, value, indent+2);
1112 }
1113 }
1114