ffasn1c ASN.1 Compiler

Table of Contents

1 Introduction

ffasn1c compiles ASN.1 source and generate C code to manipulate, encode and decode the corresponding ASN.1 messages.

The generated C code is made of a header defining the ASN.1 types and a source defining an internal binary representation of the ASN.1 types.

The library libffasn1 (source code in libffasn1/) contains the functions to allocate, encode, decode and free ASN.1 messages.

2 Installation

The compiler ffasn1c does not need a specific installation. The ffasn1c executable does not need any other file so you can copy it anywhere (for example in /usr/local/bin on a Linux system).

3 Quick Start

In the examples directory you can build the asn1convert example.

ffasn1c is invoked to generate simpletest.h and simpletest.c from the ASN.1 source simpletest.asn.

asn1convert is a simple tool to convert messages of type ObjectList from any ASN.1 encoding to any encoding. You can try:

./asn1convert ber gser simpletest.der a.gser

a.gser contains the GSER (i.e. text) representation of the DER encoded message stored in simpletest.der.

4 Invocation

Usage:

ffasn1c [options] inputfile...

There can be several input files. Each input file defines one or more ASN.1 modules.

Options:

-h

show the help

-o outfile

set the output filename (extension replaced by .c or .h)

-fforce-int32

force 32 bit integers for INTEGER type. By default the compiler stores the integers on the C int or uint32_t type only if the PER-visible contraints tells that it can fit. Otherwise, large integers are used (ASN1Integer C type).

-fno-type-names

do not generate type name information. It saves space if XER encoding is not needed. Type name information is only necessary for XER encoding or for debugging.

-fallow-dup-int-ident

Allow duplicate integer value identifiers (not standard, useful to compile some invalid ASN.1 sources)

-fprefix=name

Add the prefix name to all public C identifiers.

-fdefine-int-values

Export as C defines all ASN.1 integer values (useful for example for LTE S1AP/X2AP identifiers).

-fshort-enums

The ffasn1c runtime requires that the enum type in the generated headers has a size of 32 bits. It is the case with most toolchains. If it is not the case (for example if the GCC option -fshort-enums is used), then this option should be used. It forces ffasn1c to generate an additional dummy definition in each enum to force its size to 32 bits.

Debug options: these options are useful if you want to know if the compiler really understood what you meant.

-fdump-parse-tree

dump the modules just after they are parsed.

-fdump-expanded-tree

dump the modules after the parametrized types and values are expanded.

-E

dump the modules after the values are evaluated.

-fdump-per

same as -E but with the PER-visible constraints as comments.

5 Compliance

The compiler implements the following standards:

The ANY type is supported to be able to compile older ASN.1 sources (X.208 specification).

The runtime library implements the following standards:

Known limitations and rationale:

6 Useful types

A few useful types are predefined by the compiler in a built-in UsefulDefinitions module. The types are:

7 Runtime C/C++ API

7.1 Memory allocation

The user must provide the 3 following functions so that the library can allocate, reallocate and free memory:

void *asn1_malloc(size_t size);
void *asn1_realloc(void *ptr, size_t size);
void asn1_free(void *ptr);

Note: asn1_malloc() must return a non NULL pointer when size = 0.

7.2 Managing ASN.1 types and values

The ASN.1 types are compiled into an opaque C type: ASN1CType *. All the API uses this type to manipulate ASN.1 types.

The ASN.1 values of the corresponding types are represented in memory using the structures, unions and other types defined in the C header generated by the compiler. A flat representation is used for SEQUENCE/SET and CHOICE to minimize the cost of memory allocations. Pointer indirections are used for SEQUENCE/SET OF and for recursive types.

The following functions are defined to manage ASN.1 types and values:

asn1_ssize_t asn1_get_size(const ASN1CType *p);

Return the size (in bytes) of an ASN1 type.

void *asn1_mallocz_value(const ASN1CType *p);

Allocate a value of the ASN1 type p. All fields are set to zero.

void asn1_free_value(const ASN1CType *p, void *data);

Free the value data of the ASN1 type p.

int asn1_cmp_value(const ASN1CType *p, const void *data1, const void *data2);

Compare the two ASN1 values data1 and data2 of type p. Return < 0 for less than, == 0 for equal, or > 0 for larger than. For composite values, a lexicographical ordering is assumed.

int asn1_copy_value(const ASN1CType *p, void *data1, const void *data2);

Copy data2 to data1 assuming data1 is allocated. All referenced data inside data1 is allocated. Return 0 if OK, < 0 if error.

void *asn1_clone_value(const ASN1CType *p, const void *data);

Clone the value data of type p (equivalent to asn1_mallocz_value() followed by asn1_copy_value()). Return NULL if error.

void *asn1_random(const ASN1CType *p, int seed);

Generate a random ASN1 value of type p (useful for testing). seed is used to initialize the random generator.

7.3 Encoding of ASN.1 values

asn1_ssize_t asn1_uper_encode(uint8_t **pbuf, const ASN1CType *p, const void *data);

Encode the value data of ASN.1 type p using unaligned PER encoding. Return the allocated value bytes at *pbuf and its length in bytes. The value can be freed with asn1_free().

asn1_ssize_t asn1_aper_encode(uint8_t **pbuf, const ASN1CType *p, const void *data);

Same for aligned PER encoding.

asn1_ssize_t asn1_der_encode(uint8_t **pbuf, const ASN1CType *p, const void *data);

Same for DER encoding.

asn1_ssize_t asn1_ber_encode(uint8_t **pbuf, const ASN1CType *p, const void *data, const ASN1BERParams *params);

Same for generic BER encoding with options specified in params. This function is normally only used to generate specific BER constructs to test BER decoders.

asn1_ssize_t asn1_gser_encode(uint8_t **pbuf, const ASN1CType *p, const void *data);

Same for GSER encoding.

asn1_ssize_t asn1_gser_encode2(uint8_t **pbuf, const ASN1CType *p, const void *data, const ASN1GSERParams *params);

Same for GSER encoding with formatting parameters.

asn1_ssize_t asn1_xer_encode(uint8_t **pbuf, const ASN1CType *p, const void *data);

Same for XER encoding.

asn1_ssize_t asn1_xer_encode2(uint8_t **pbuf, const ASN1CType *p, const void *data, const ASN1XERParams *params);

Same for XER encoding with formatting parameters.

asn1_ssize_t asn1_oer_encode(uint8_t **pbuf, const ASN1CType *p, const void *data);

Same for OER encoding. The encoding corresponds to canonical OER.

asn1_ssize_t asn1_jer_encode(uint8_t **pbuf, const ASN1CType *p, const void *data);

Same for JER encoding.

asn1_ssize_t asn1_jer_encode2(uint8_t **pbuf, const ASN1CType *p, const void *data, const ASN1JERParams *params);

Same for JER encoding with formatting parameters.

7.4 Decoding of ASN.1 values

asn1_ssize_t asn1_uper_decode(void **pdata, const ASN1CType *p, const uint8_t *buf, size_t buf_len, ASN1Error *err);

Decode the value of buf_len bytes contained in buf using the unaligned PER encoding. Return the number of consumed bytes or < 0 if error. *pdata contains the decoded value or NULL if there was an error. The decoded value can be freed with asn1_free_value(). In case of error, more information about the error is returned in err.

asn1_ssize_t asn1_aper_decode(void **pdata, const ASN1CType *p, const uint8_t *buf, size_t buf_len, ASN1Error *err);

Same for aligned PER decoding.

asn1_ssize_t asn1_ber_decode(void **pdata, const ASN1CType *p, const uint8_t *buf, size_t buf_len, ASN1Error *err);

Same for BER decoding.

asn1_ssize_t asn1_gser_decode(void **pdata, const ASN1CType *p, const uint8_t *buf, size_t buf_len, ASN1Error *err);

Same for GSER decoding.

asn1_ssize_t asn1_xer_decode(void **pdata, const ASN1CType *p, const uint8_t *buf, size_t buf_len, ASN1Error *err);

Same for XER decoding.

asn1_ssize_t asn1_oer_decode(void **pdata, const ASN1CType *p, const uint8_t *buf, size_t buf_len, ASN1Error *err);

Same for OER decoding.

asn1_ssize_t asn1_jer_decode(void **pdata, const ASN1CType *p, const uint8_t *buf, size_t buf_len, ASN1Error *err);

Same for JER decoding.

7.5 Constraint check

BOOL asn1_check_constraints(const ASN1CType *p, const void *data, char *msg_buf, size_t msg_buf_size);

Return TRUE if the constraints are satisfied. Otherwise return FALSE and put an informative message string in msg_buf of maximum size msg_buf_size.

8 License

ffasn1c and its runtime library is copyright 2011-2023 Fabrice Bellard.

ffasn1c and its associated runtime library is available without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software.