Home → ASN.1

ASN.1 Basics

ASN.1 stands for Abstract Syntax Notation One.

ASN.1 allows to describe complex data structures independently of any particular programming language. The ASN.1 compiler would take these ASN.1 specifications and produce a set of target language (C, C++, Java) files which would contain the native type definitions for these abstractly specified structures, and also generate a code which would perform the conversions of these structures into/from a series of bytes (serialization/deserialization), (presumably, these routines would be useful if the structure is going to be transferred over the network or written to an external media).

There are multiple data encodings developed for ASN.1. The most widely used ones are BER (Basic Encoding Rules), CER (Canonical-), DER (Distinguished Encoding Rules), PER (Packed Encoding Rules) and XER (XML Encoding Rules).

Consider the following example. Suppose, you want to transmit a certain structure between computers. This structure would include a string tag, a couple of integer values (one of them optional), and a set of floating-point values. The structure can be described using ASN.1 notation as follows:

        CertainStructure ::= SEQUENCE {
                tag     VisibleString,
                val1    INTEGER,
                val2    INTEGER   OPTIONAL,
                reals   SET OF REAL
        }
This specification can be fed into the asn1c compiler (), which would produce the C language files with headers containing something like that:
        typedef struct CertainStructure {
                VisibleString_t  tag;
                int              val1;
                int             *val2;        /* OPTIONAL */
                A_SET_OF(double) reals;
        } CertainStructure_t;
The contents of a variable of this type may be directly manipulated. But the most important thing, the serialization and deserialization process to convert this complex structure into (from) a series of bytes, becomes a snap.

Here is how such structure may be received from the network, edited, and then converted back into the compact binary encoding:

        CertainStructure_t *cs = 0;
        ber_decode(0, &asn_DEF_CertainStructure, &cs, buffer, buffer_length);
        cs->val1 = 123;        /* Modify the contents */
        der_encode(&asn_DEF_CertainStructure, cs, write_handle, 0);
(The meaning of write_handle() is described in the asn1c compiler's usage guide, check the Documentation).

And here's how easy the contents of this structure can be printed out in XML format:

        xer_fprint(stdout, &asn_DEF_CertainStructure, cs);
Here's an example of what xer_fprint() might generate:
        <CertainStructure>
                <tag>This is a random tag</tag>
                <val1>123</val1>
                <reals>
                        <REAL>3.14159265</REAL>
                        <REAL><MINUS-INFINITY/></REAL>
                        <REAL>2.7182818284</REAL>
                </reals>
        </CertainStructure>
The ASN.1 notation is extensively used in telecom industry (examples include cell networks' MMS (multimedia services) and telecom equipment CDR (Call Data Records), TAP3 (Transferred Account Procedure)), security protocols and data formats (PKIX/X.509) and other high-profile applications. If you are using SSL (HTTPS) to access a bank or email account, be sure the ASN.1 is involved too; it describes the structure of the server's identity certificate for verification by your Internet browser.

The question is: why not every programmer developing the network protocols and/or data formats is using the ASN.1? One of the answers is that the cost of commercial ASN.1 compiler is often prohibitive for small-to-medium sized projects.

This page describes the free one.

Open Source ASN.1 Compiler

The asn1c is a free, open source compiler of ASN.1 specifications into C source code. It supports a range of ASN.1 syntaxes, including ISO/IEC/ITU ASN.1 1988, '94, '97, 2002 and later amendments. The supported sets of encoding rules are

  • BER: ITU-T Rec. X.690 | ISO/IEC 8825-1 (2002) (BER/DER/CER)
  • PER: X.691|8825-2 (2002) (PER).
  • XER: X.693|8825-3 (2001) (BASIC-XER/CXER).

The compiler was written specifically to address security concerns while providing streaming decoding capabilities.

Featureasn1c
Restartable/stream decoding1YES, for BER and XER families
BER (Basic Encoding Rules)YES
DER (a canonical BER subset)YES
CER (another canonical BER subset)yes, read-only2
BASIC-XER (XML Encoding Rules)YES
CXER ("Canonical" XER)YES
EXTENDED-XERno
PER (Packed Encoding Rules)yes, read-only2
Subtype constraintsYES3
Information Object Classesbasic support
C target languageYES
C++ target languageYES4
Java target languageno
Compiled code portability  LP64: Linux/alpha, Linux/amd64
ILP32: MacOS X/powerpc (big-endian), Solaris 9/sparc (big-endian);
   Solaris/x86, FreeBSD/x86, OpenBSD/x86, NetBSD/x86, Linux/x86
(consistency for above platforms is ensured by automated daily testing)
ILP32: Windows-CYGWIN, Windows-MSVC++
(minor manual tweaking required for MS platforms)
EBCDIC supportprovisioned5
LicenseBSD
Cost$0
1) A decoder does not have to have the whole data sequence to start parsing. If it receives less data then required, it will process as much as possible and may be invoked again later, when the next chunk of data becomes available.
2) Encoding has not been required so far. Please ask for support.
3) The code generator automatically generates constraints checking procedures for PER-visible constraints.
4) C++ compatible C code. No OOP yet.
5) Code has been designed to support EBCDIC charset, but no formal testing has been made yet.

Examples

This section presents a few unrelated examples of some aspects of asn1c usage.
[Example requested by Eyal Carmi]

Using the asn1c generated structures

Let's suppose we need to employ the following ASN.1 module:
MyModule.asn1
MyModule DEFINITIONS ::= BEGIN MyTypes ::= SEQUENCE { myObjectId OBJECT IDENTIFIER, mySeqOf SEQUENCE OF MyInt, myBitString BIT STRING { muxToken(0), modemToken(1) } } MyInt ::= INTEGER (0..65535) END
1. Compile this module into a set of .c and .h files with the following command line:
> asn1c MyModule.asn1
2. Create a .c file with the following contents:
my-program.c
#include <stdio.h> /* for stdout */ #include <stdlib.h> /* for malloc() */ #include <assert.h> /* for run-time control */ #include "MyTypes.h" /* Include MyTypes definition */ int main() { /* Define an OBJECT IDENTIFIER value */ int oid[] = { 1, 3, 6, 1, 4, 1, 9363, 1, 5, 0 }; /* or whatever */ /* Declare a pointer to a new instance of MyTypes type */ MyTypes_t *myType; /* Declare a pointer to a MyInt type */ MyInt_t *myInt; /* Temporary return value */ int ret; /* Allocate an instance of MyTypes */ myType = calloc(1, sizeof *myType); assert(myType); /* Assume infinite memory */ /* * Fill in myObjectId */ ret = OBJECT_IDENTIFIER_set_arcs(&myType->myObjectId, oid, sizeof(oid[0]), sizeof(oid) / sizeof(oid[0])); assert(ret == 0); /* * Fill in mySeqOf with a couple of integers. */ /* Prepare a certain INTEGER */ myInt = calloc(1, sizeof *myInt); assert(myInt); *myInt = 123; /* Set integer value */ /* Fill in mySeqOf with the prepared INTEGER */ ret = ASN_SEQUENCE_ADD(&myType->mySeqOf, myInt); assert(ret == 0); /* Prepare another integer */ myInt = calloc(1, sizeof *myInt); assert(myInt); *myInt = 111222333; /* Set integer value */ /* Append another INTEGER into mySeqOf */ ret = ASN_SEQUENCE_ADD(&myType->mySeqOf, myInt); assert(ret == 0); /* * Fill in myBitString */ /* Allocate some space for bitmask */ myType->myBitString.buf = calloc(1, 1); assert(myType->myBitString.buf); myType->myBitString.size = 1; /* 1 byte */ /* Set the value of muxToken */ myType->myBitString.buf[0] |= 1 << (7 - myBitString_muxToken); /* Also set the value of modemToken */ myType->myBitString.buf[0] |= 1 << (7 - myBitString_modemToken); /* Trim unused bits (optional) */ myType->myBitString.bits_unused = 6; /* * Print the resulting structure as XER (XML) */ xer_fprint(stdout, &asn_DEF_MyTypes, myType); return 0; }
3. Compile every .c file together:
> cc -o my-program.exe -I. *.c
4. Run it:
> ./my-program.exe
<MyTypes>
    <myObjectId>1.3.6.1.4.1.9363.1.5.0</myObjectId>
    <mySeqOf>
        <MyInt>123</MyInt>
        <MyInt>111222333</MyInt>
    </mySeqOf>
    <myBitString>11</myBitString>
</MyTypes>
[Reverse example requested by Eyal Carmi]

Fetching information from XER encoded data

Suppose we need to decode the XER data from the previous example and place its contents into a specific C types.

1. Compile the ASN.1 module from the previous example into a set of .c and .h files with the following command line:

> asn1c MyModule.asn1
2. Create a .c file with the following contents:
my-program.c
#include <stdio.h> /* for stdout */ #include <stdlib.h> /* for malloc() */ #include <assert.h> /* for run-time control */ #include "MyTypes.h" /* Include MyTypes definition */ int main(int argc, char *argv[]) { char buf[1024]; /* Hope, sufficiently large buffer */ MyTypes_t *myType = 0; asn_dec_rval_t rval; char *filename; size_t size; FILE *f; /* * Target variables. */ int *oid_array; /* holds myObjectId */ int oid_size; int *int_array; /* holds mySeqOf */ int int_size; int muxToken_set; /* holds single bit */ int modemToken_set; /* holds single bit */ /* * Read in the input file. */ assert(argc == 2); filename = argv[1]; f = fopen(filename, "r"); assert(f); size = fread(buf, 1, sizeof buf, f); if(size == 0 || size == sizeof buf) { fprintf(stderr, "%s: Too large input\n", filename); exit(1); } /* * Decode the XER buffer. */ rval = xer_decode(0, &asn_DEF_MyTypes, &myType, buf, size); assert(rval.code == RC_OK); /* * Convert the OBJECT IDENTIFIER into oid_array/oid_size pair. */ /* Figure out the number of arcs inside OBJECT IDENTIFIER */ oid_size = OBJECT_IDENTIFIER_get_arcs(&myType->myObjectId, 0, sizeof(oid_array[0]), 0); assert(oid_size >= 0); /* Create the array of arcs and fill it in */ oid_array = malloc(oid_size * sizeof(oid_array[0])); assert(oid_array); (void)OBJECT_IDENTIFIER_get_arcs(&myType->myObjectId, oid_array, sizeof(oid_array[0]), oid_size); /* * Convert the sequence of integers into array of integers. */ int_size = myType->mySeqOf.list.count; int_array = malloc(int_size * sizeof(int_array[0])); assert(oid_array); for(int_size = 0; int_size < myType->mySeqOf.list.count; int_size++) int_array[int_size] = *myType->mySeqOf.list.array[int_size]; if(myType->myBitString.buf) { muxToken_set = myType->myBitString.buf[0] & (1 << (7 - myBitString_muxToken)); modemToken_set = myType->myBitString.buf[0] & (1 << (7 - myBitString_modemToken)); } else { muxToken_set = modemToken_set = 0; /* Nothing is set */ } return 0; }
3. Compile every .c file together:
> cc -o my-program.exe -I. *.c
4. Save the XER output from the step #4 of the previous example, and run the newly created binary against it:
> ./my-program.exe file.xer

Download

⇒ Use Online ASN.1 compiler, experimental version 0.9.21

The online version of asn1c compiler makes the following possible:
  • Compile ASN.1 modules into cross-platform C code
  • Decode MHEG-5 (BER) into XML representation
  • Decode X.509 (DER) certificate into XML
  • Decode GSM TAP3 (BER) files into XML
  • Decode 3GPP RRC (PER) files into XML
  • Convert any BER/CER/DER data into XML representation

∇ Download the ASN.1 compiler release:

  • Source code: asn1c-0.9.20.tar.gz (2006-Mar-06), see ChangeLog and License
    Notes:
    0. The code generated by the ASN.1 compiler is cross-platform and not compiler dependent, unlike asn1c itself.
    1. Requires GCC compiler under unix-like environment (FreeBSD, Linux, Solaris, HP-UX, whatelse...).
    2. Windows/CYGWIN users: please ignore GeneralizedTime failure during `make check`.
  • Windows installer: asn1c-0.9.20+.exe (2006-Mar-18)
    Notes:
    0. You must pay $24 in order to enjoy the pre-compiled installation.
    1. If in doubt, use Online ASN.1 compiler instead. Read privacy note.
Hosted on SourceForge:
http://sourceforge.net/projects/asn1c
SourceForge.net Logo

Δ Sync up with the bleeding edge:

  • Use CVS to fetch the latest development branch (0.9.21+):
    # Note: this may not work with certain firewall settings
    export CVS_RSH=ssh	# or "setenv", depending on your shell
    cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/asn1c login	# log in
    [press enter in the password prompt]
    cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/asn1c co asn1c	# checkout
    

Quotes...

What industrial users say about asn1c compiler and complimentary free support:

"Thanks so much for your help! asn1c is a life saver, good work!"
John Arthur, T-Mobile USA

"We've played with a few different free H.248 stub compilers in both C and Java, and yours is definitely the best we've seen."
Jason Walton, Alcatel, USA

"I have a positive story about asn1c for anyone who asks"
Lixin Zhou, Ph.D., Human genome projects

"Thanks again for this REALLY good product."
Alain Brunet, Alcatel, France


The ASN.1 Compiler Copyright © 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>