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