Resources
This page covers the tags that are used for TLV (Tag-Length-Value) based encodings (BER, DER, or CER).
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:
The following table lists the ASN.1 types and their UNIVERSAL class tags. You can view them by tag number or by type name:
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).
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.
ExpSample ::= [15] EXPLICIT INTEGER -- tag of context-specific 15 in addition to universal 2
ImpSample ::= [15] IMPLICIT INTEGER -- tag of context-specific 15 instead of universal 2
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
|
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.
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