The OSS ASN.1 Tools fully support the Distinguished Encoding Rules and the Canonical Encoding Rules.
The following illustrates how to DER encode a value of a SET. The peculiarity of the SET data type is that its components are not ordered (can occur in any order), which means that the same value can be encoded in a variety of ways.
Having:
Name ::= SET { first [3] FirstName, middle [1] MiddleName, last [2] LastName }
one can encode the value name
Name ::= {first "John", middle "J", last "Smith"}
as John followed by J followed by Smith or Smith followed by J followed by John and so on.
Canonical encoding rules, like DER, require one-to-one mapping between the values and encodings. For this reason, DER restricts the above variations to only one alternative: encode the components of SET in the canonical order. The canonical order is the order in which each component has the tag that is greater than the tag of the previous component. For example, for the Name type that is defined above the canonical order of components is middle, last, first.
In most cases the canonical order is static for a given type (that is, the same for all values of this type). But there is an exception: if the SET type happens to contain a nested untagged choice, the canonical order can vary from one value to another. Namely, DER specifies that one should use the tag of the current selection of this untagged CHOICE in order to position the corresponding component in the ordered list.
Let's explain the above on a real example. Here are definitions that are extracted from MTSAbstractService (X.400 series):
-- This is an extract from the MTSAbstractService -- {joint-iso-itu-t mhs(6) mts(3) modules(0) mts-abstract-service(1) -- version-1999(1)} MTSAbstractService-Fragment DEFINITIONS IMPLICIT TAGS ::= BEGIN RefusedOperation ::= SET { refused-argument CHOICE { built-in-argument [1] RefusedArgument, refused-extension EXTENSION.&id }, refusal-reason [2] RefusalReason } RefusedArgument ::= INTEGER { user-name (0), user-address (1), encoded-information-types-constraints (2), deliverable-content-types (3), deliverable-maximum-content-length (4), deliverable-security-labels (5), recipient-assigned-redirections (6), restricted-delivery (7), retrieve-registrations (8), -- value 9 reserved for possible -- future extension to Register -- arguments restrict (10), permissible-operations (11), permissible-lowest-priority (12), permissible-encoded-information-types (13), permissible-content-types (14), permissible-maximum-content-length (15), permissible-security-context (16) } (0..ub-integer-options) RefusalReason ::= INTEGER { facility-unavailable (0), facility-not-subscribed (1), parameter-unacceptable (2) } (0..ub-integer-options) EXTENSION ::= CLASS { &id ExtensionType, &Type OPTIONAL, &absent & Type OPTIONAL, &recommended Criticality DEFAULT { } } WITH SYNTAX { [&Type [IF ABSENT &absent],] [RECOMMENDED CRITICALITY &recommended,] IDENTIFIED BY &id } ExtensionType ::= CHOICE { standard-extension [0] INTEGER (0..ub-extension-types), private-extension [3] OBJECT IDENTIFIER } Criticality ::= BIT STRING { for-submission (0), for-transfer (1), for-delivery (2) } (SIZE (0..ub-bit-options)) -- critical 'one', -- non-critical 'zero' -- Upper bounds ub-bit-options INTEGER ::= 16 ub-integer-options INTEGER ::= 256 ub-extension-types INTEGER ::= 256 -- Sample value refusedOperation1 RefusedOperation ::= { refused-argument refused-extension : built-in-argument : restrict, refusal-reason parameter-unacceptable } refusedOperation2 RefusedOperation ::= { refused-argument refused-extension : private-extension : {1 2 3 4 5}, refusal-reason parameter-unacceptable } END
Note, that the refused-argument component of the RefusedOperation is an untagged CHOICE. How does one construct DER compliant encodings of refusedOperation1 and refusedOperation2?
First, let's look at the first value:
refuseOperation1 : RefusedOperation ::= SET { refused-argument CHOICE { built-in-argument [1] RefusedArgument, refused-extension EXTENSION.&id }, refusal-reason [2] RefusalReason } refusedOperation1 RefusedOperation ::= { refused-argument refused-extension : built-in-argument : restrict, refusal-reason parameter-unacceptable }
The refusal-reason component has the tag [2]. In order to decide whether the refused-argument should be put before or after refusal-reason, one should compute its tag. Since refused-argument is defined as the untagged CHOICE and the CHOICE has the 'built-in-argument' alternative selected, the tag to use for canonical ordering is [1] and a DER compliant encoder should encode the components in the order: refused-argument, refusal-reason: RefusedOperation SET: tag = [UNIVERSAL 17] constructed; length = 6 refused-argument CHOICE built-in-argument RefusedArgument INTEGER: tag = [1] primitive; length = 1 10 refusal-reason RefusalReason INTEGER: tag = [2] primitive; length = 1 2 PDU successfully encoded, in 8 bytes: 31 06 - tag and length of the RefusedOperation (SET) 81 01 0A - encoded 'refused-argument' 82 01 02 - encoded 'refusal-reason'.
Now let's see what will happen for the second value of the same type - for the refusedOperation2 value: RefusedOperation ::= SET { refused-argument CHOICE { built-in-argument [1] RefusedArgument, refused-extension EXTENSION.&id }, refusal-reason [2] RefusalReason } refusedOperation2 RefusedOperation ::= { refused-argument refused-extension : private-extension : {1 2 3 4 5}, refusal-reason parameter-unacceptable }
This time the refused-argument component has another alternative selected - refused-extension, that has the EXTENSION.&id type. Looking at the definition of the EXTENSION information object class one will find that the notation EXTENSION.&id specifies the type: ExtensionType ::= CHOICE { standard-extension [0] INTEGER (0..ub-extension-types), private-extension [3] OBJECT IDENTIFIER }.
That is, another untagged CHOICE. So finally the tag, that identifies the position of refused-argument in the canonically ordered list of components, is the tag of the private-extension alternative or [3]. Which means that for refusedOperation2 the components have to be encoded in reverse order: the encoding of refused-argument must follow the encoding of refusal-reason: RefusedOperation SET: tag = [UNIVERSAL 17] constructed; length = 9 refusal-reason RefusalReason INTEGER: tag = [2] primitive; length = 1 2 refused-argument CHOICE refused-extension ExtensionType CHOICE private-extension OBJECT IDENTIFIER: tag = [3] primitive; length = 4 { 1 2 3 4 5 } PDU successfully encoded, in 11 bytes: 31 09 - tag and length of theRefusedOperation (SET) 82 01 02 - encoded 'refusal-reason' 83 04 2A030405 - encoded 'refused-argument'.
You can easily check whether your tool implements DER correctly by compiling the mts.asn file attached and attempting to encode the sample values. For instance, if you are using OSS Nokalva Java tools, you can run this sample as follows:
java mts.Test
To make it easier for you to run the example from the command line, two scripts are included, a Unix .sh and a Windows .bat.
To run it on a Unix platform, cd to the derset directory and type:
./run.sh
To run it on Windows, cd to the derset directory and type:
run
To do a cleanup on Unix, type:
./run.sh cleanup
To do a cleanup on Windows, type:
run cleanup
To download, click on the file below:
The samples included with some of the Knowledge Center answers are meant for your general understanding of the OSS products. Different versions of the products might produce slightly different outputs. Consult the products documentation and samples for the most up-to-date products information and code examples.
Test drive the OSS Nokalva ASN.1, LTE, and XML Tools now! Your trial includes complete software, documentation, sample programs, free 24x7 technical support and more.
Our expert personnel can help you learn ASN.1!
We offer 4-day ASN.1 courses at our headquarters or your premises.