TOP

ASN.1 Tags


Summary

This page covers the tags that are used for TLV (Tag-Length-Value) based encodings (BER, DER, or CER).

  • Every defined type is assigned a tag either automatically or manually (inline in the schema).
  • AUTOMATIC tagging allows you to avoid assigning tags manually.
  • UNIVERSAL tags are the default.
  • Types may have multiple tags.
  • EXPLICIT tags are added to the existing tags.
  • IMPLICIT tags override the existing tags.
  • If a module contains no indication of whether tags are IMPLICIT or EXPLICIT, that module's user-defined tags default to EXPLICIT.
  • Tags are not necessarily unique (you can assign the same tag to two or more different types).

What is an ASN.1 Tag?

To ensure that encodings are not ambiguous, every ASN.1 type is associated with a tag. A tag consists of two parts: the class and the number. The following classes are defined:

  • UNIVERSAL. This class is assigned to tags defined in the ASN.1 standard.
  • APPLICATION. Application class tags were intended to uniquely identify a type within a particular application. Some application layer standards use these tags extensively to name their types.
  • PRIVATE. A particular company, for example, may choose to define several types with private class tags for use in a number of their common applications.
  • Context-specific. Tags of this class are used with types that need to be identified only within some specific, well-defined context. For example, a type that needs to be uniquely identifiable within a sequence of other types might be assigned a context-specific tag.

Tag-Length-Value encoding

  • You can assign the same tag to two (or more) different types. To avoid ambiguity, the context in which an instance of the type occurs must be sufficient to allow unique identification.
  • AUTOMATIC tagging allows you to write an ASN.1 module without having to specify any tags, however, there are special rules to follow to determine which tags will be used when encoding.
  • Type-length-value encodings may be recursive. One value can consist of one or more other values, each encoded with its own type and length. No maximum level of nesting is defined, so complex structures can be created. For more information on how tags are encoded using BER, DER, or CER, see the Basic Encoding Rules, Distinguished Encoding Rules, or Canonical Encoding Rules section.

The following table lists the ASN.1 types and their UNIVERSAL class tags in alphabetical order:


Specifying Tags

When you define a new type derived from one of the types that have predefined tags, the tag associated with the new type is identical to that of the original. With tagged types, you can determine exactly what tag should be assigned to a newly defined type.

To define a tagged type, you need to precede the name of a type with a tag wrapped in square brackets and select a class and number. Note that ASN.1 tags can be used to identify a type as well as a field (for example, if some components of a SEQUENCE type are optional, tags can be used to detect whether the optional components are absent or present).

Example

In the following example, a type called BinaryFile is defined, based on OCTET STRING. This type can be used only for OCTET STRING values, however, a new tag (class APPLICATION, number 13) is prepended to each:

BinaryFile ::= [APPLICATION 13] OCTET STRING

In the second example, a tag with class PRIVATE, number 1 is assigned to identify values of type IDNumber1, even though they are still really integers:

IDNumber1 ::=  [PRIVATE 1] INTEGER

In the third example, a tag with number 1 is added to BOOLEAN to identify a new type, Present. No class is specified for this new tag. When only a number appears inside the brackets, the tag's class defaults to context-specific. The original tag may or may not be present in the encoded value, depending on the presence of the word "IMPLICIT". If IMPLICIT is present, the original tag will not appear in an encoded value, otherwise both the newly defined tag and the original tag will appear in an encoded value.

Present ::= [1] BOOLEAN

The type IDNumber2 is defined in the following example using the IMPLICIT option. A value of this type would be encoded just like one of type IDNumber1, except that the INTEGER tag would be missing. However, IDNumber2 may contain only integer values.

IDNumber2 ::=  [PRIVATE 1] IMPLICIT INTEGER

If the tag for INTEGER is omitted, how does the receiver know that this type contains integer values? Recall that both sender and receiver must agree on a schema before data transfer begins. Both know that the tag with class PRIVATE, number 1 is assigned to the type IDNumber2. The writer must make sure that this tag is recognizable in all contexts in which it may occur during use of that syntax.

Tagging Modes: EXPLICIT, IMPLICIT, and AUTOMATIC Tagging

  • Tags are added when they are EXPLICIT (in addition to the existing tag).
    ExpSample ::= [15] EXPLICIT INTEGER   -- tag of context-specific 15 in addition to universal 2
  • Tags override when they are IMPLICIT (instead of the existing tag).
    ImpSample ::= [15] IMPLICIT INTEGER   -- tag of context-specific 15 instead of universal 2
  • A module definition may indicate whether the default should be IMPLICIT or EXPLICIT tagging.
  • EXPLICIT tags can be used even in a module where IMPLICIT tagging is the default. If a module contains no indication of whether tags are IMPLICIT or EXPLICIT, that module's user-defined tags default to EXPLICIT.
  • You can use AUTOMATIC TAGS to omit the tags. The use of AUTOMATIC TAGS results in the first element getting a tag of [0], the second [1], and the third [2].
  • The presence of a tag on one or more elements of a SEQUENCE disables AUTOMATIC TAGS for all of the elements of a given SEQUENCE; other SEQUENCEs, possibly nested ones, are unaffected.
AUTOMATIC IMPLICIT EXPLICIT
Auto DEFINITIONS
 AUTOMATIC TAGS ::= BEGIN
PersonnelRecord ::= SEQUENCE {
       name     UTF8String,       
       age      INTEGER 
       }

name PersonnelRecord ::= {
       name "John",
       age  25       
       }
END
Impl DEFINITIONS  ::= BEGIN
PersonnelRecord ::=
 [0] IMPLICIT SEQUENCE {
       name      UTF8String,       
       age       INTEGER 
       }

name PersonnelRecord ::= {
       name "John",
       age  25       
       }
END
Expl DEFINITIONS
 EXPLICIT TAGS ::= BEGIN
PersonnelRecord ::= 
               [0] SEQUENCE { 
       name      UTF8String,       
       age       INTEGER 
       }
name PersonnelRecord ::= {
       name "John",
       age  25       
       }
END
30 09
   80 04 4A6F686E
   81 01 19
 A0 09
    0C 04 4A6F686E
    02 01 19
 A0 0B
    30 09
     0C 04 4A6F686E
     02 01 19

Identifiers on SEQUENCE Elements

Ambiguous tags:

PersonnelRecord ::= SEQUENCE {
      name     OCTET STRING,
      location INTEGER {home(0), field(1), roving(2)}
                       OPTIONAL,
      age      INTEGER OPTIONAL}

No longer ambiguous tags:

PersonnelRecord ::= SEQUENCE {
     name     [0] OCTET STRING,
     location [1] INTEGER {home(0), field(1), roving(2)}
                          OPTIONAL,
     age      [2] INTEGER OPTIONAL}

The problem is that both location and age are INTEGERs. Both, therefore, have UNIVERSAL 2 tags. If both are optional, then either one may appear, or both, or neither in any given value of type PersonnelRecord. Since both elements have the same tag, if only one appears, there is no way with BER for a receiver to know which it is; it could be either location or age. The type definition is ambiguous.

To avoid this problem, we assign tags. The tag [1] is assigned to location, and [2] to age. Since no class is specified, both tags default to context-specific. With this change, the ambiguity is removed, and a receiver can correctly determine which elements are present. Whenever optional elements are present, tags must be added as necessary to ensure that the type definition is not ambiguous.

A more complex example is shown below. Before defining the RequestPDU type, the supporting type RequestID is defined. RequestID contains integer values, but replaces INTEGER's UNIVERSAL 2 tag with PRIVATE 14. The sequence type called RequestPDU is defined next. This type is representative of what has so far been the most common use of ASN.1: describing PDUs for application layer protocols. Rather than leave the generic UNIVERSAL 16 tag assigned to SEQUENCE, this definition replaces it with a PRIVATE 3 tag. If several PDUs were defined, each would probably begin with its own unique tag.

RequestID ::= [PRIVATE 14] IMPLICIT INTEGER

RequestPDU ::= [PRIVATE 3] IMPLICIT SEQUENCE {
       responseRequired BOOLEAN,
       requestID RequestID,
       parameters SEQUENCE {
            request BIT STRING {
                 startup(0), shutdown(1),
                 status(2), echo(3) },
                 -- startup and shutdown may not both be specified
            priority INTEGER DEFAULT 0
},
moreInformation OCTET STRING OPTIONAL}

The first element in the SEQUENCE is a BOOLEAN called responseRequired. This field in the PDU might be used to indicate whether a response was needed to this request. Next is an element of the type RequestID, defined earlier. This element could also be defined as [PRIVATE 14] IMPLICIT INTEGER, and the encoding of a value for this element will remain unchanged. Which choice is made is a matter of programming style, although the element's purpose in the application should always be made clear.

Next appears another SEQUENCE, containing request, a BIT STRING with a named number bit, and priority, an INTEGER. Note the comment after request; it specifies a requirement for this element, and would not have been ignored by previous versions of the standard. Note also the word DEFAULT after priority. This indicates that this element is optional, and that, if it does not appear, its value defaults to 0. The SEQUENCE ends with a final optional parameter, an OCTET STRING for which no default value is provided, called moreInformation.

Encoding Tagged Types

A tagged type can use either a primitive or constructed encoding. If the IMPLICIT option is not used, the encoding is always constructed. If IMPLICIT is specified, the encoding is that of the underlying type, either primitive or constructed.

In the following example, the type Present is defined by prepending a context-specific 1 tag to BOOLEAN. When encoding a value of this type (status in the example), the newly added tag appears as the value's encoded identifier. This identifier is followed by octets encoding the value's length and contents. The contents octets of tagged types completely encode the value of the type being tagged. In this case, the value TRUE is encoded as a BOOLEAN, complete with BOOLEAN's tag and its own length field.

Present ::= [1] BOOLEAN
status Present ::= TRUE     
            -- 81 01 FF

Related Topics