/*

  silcasn1.h

  Author: Pekka Riikonen <priikone@silcnet.org>

  Copyright (C) 2003 - 2007 Pekka Riikonen

  The contents of this file are subject to one of the Licenses specified 
  in the COPYING file;  You may not use this file except in compliance 
  with the License.

  The software distributed under the License is distributed on an "AS IS"
  basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
  KIND, either expressed or implied.  See the COPYING file for more
  information.

*/

/****h* silcasn1/ASN.1 Interface
 *
 * DESCRIPTION
 *
 * Efficient Abstract Syntax Notation One (ASN.1) implementation.  This
 * interface provides simple and efficient ASN.1 encoder and decoder.
 * The encoder directly encodes BER encoded data blocks from variable
 * argument list of ASN.1 types.  Multiple trees can be encoded at once
 * and multiple nodes can be encoded into the tree at once.  By default
 * encoder does not allocate any memory during encoding but a pre-allocated
 * SilcStack is used as memory.
 *
 * The decoder directly decodes BER encoded data blocks into the correct
 * types dictated by the variable argument list of ASN.1 types.  By
 * default decoder does not allocate any memory during decoding but a
 * pre-allocated SilcStack is used as memory.
 *
 * The encoding and decoding interface is simple.  silc_asn1_encode is used
 * to encode and silc_asn1_decode to decode.  The actual ASN.1 is defined
 * as variable argument list to the function.  Various macros can be used
 * to encode and decode different ASN.1 types.  All types may also be used
 * to encode and decode with various options (such as implicit and explicit
 * tagging and defining specific class option).
 *
 * The implementation supports all the common ASN.1 types.  This
 * implementation does not support advanced ASN.1 features like macros.
 *
 * References: ITU-T X.680 - X.693
 * http://www.itu.int/ITU-T/studygroups/com17/languages/
 *
 ***/

#ifndef SILCASN1_H
#define SILCASN1_H

/****s* silcasn1/SilcASN1API/SilcAsn1
 *
 * NAME
 *
 *    typedef struct SilcAsn1Object *SilcAsn1;
 *
 * DESCRIPTION
 *
 *    This context is the actual ASN.1 encoder/decoder and is allocated
 *    by silc_asn1_alloc and given as argument to all silc_asn1_*
 *    functions.  It is freed by the silc_asn1_free function.  It is
 *    also possible to use pre-allocated ASN.1 context by using the
 *    SilcAsn1Struct instead of SilcAsn1.
 *
 ***/
typedef struct SilcAsn1Object *SilcAsn1;

/****s* silcasn1/SilcASN1API/SilcAsn1Struct
 *
 * NAME
 *
 *    typedef struct SilcAsn1Object SilcAsn1Struct;
 *
 * DESCRIPTION
 *
 *    This context is the actual ASN.1 encoder/decoder and can be
 *    used as pre-allocated ASN.1 context instead of SilcAsn1 context.
 *    This context is initialized with silc_asn1_init and uninitialized
 *    with silc_asn1_uninit.
 *
 ***/
typedef struct SilcAsn1Object SilcAsn1Struct;

/****d* silcasn1/SilcASN1API/SilcAsn1Options
 *
 * NAME
 *
 *    typedef enum { ... } SilcAsn1Options;
 *
 * DESCRIPTION
 *
 *    Options for ASN.1 encoder and decoder.  The ASN.1 options can be
 *    given to the SILC_ASN1_*_T macros and/or SILC_ASN1_OPTS macro.
 *
 * NOTES
 *
 *    The SILC_ASN1_ALLOC and SILC_ASN1_ACCUMUL flags can be given only
 *    with SILC_ASN1_OPTS macro.  Other options can be given with various
 *    SILC_ASN1_*_T macros.
 *
 * EXAMPLE
 *
 *    // Encodes boolean value with explicit tag and private class, and
 *    // the result is allocated into `dest'.
 *    silc_asn1_encode(asn1, &dest,
 *                     SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
 *                     SILC_ASN1_BOOLEAN_T(SILC_ASN1_PRIVATE |
 *                                         SILC_ASN1_EXPLICIT, 100, boolval),
 *                     SILC_ASN1_END);
 *
 * SOURCE
 */
typedef enum {
  /* Default. If only this is set then defaults are implied. */
  SILC_ASN1_DEFAULT      = 0x0000,

  /* Class options.  User does not need to set these unless specificly
     wanted to do so.  If SILC_ASN1_DEFAULT is set the SILC_ASN1_CONTEXT is
     implied if any of the tag options are set.  Otherwise SILC_ASN1_UNIVERSAL
     is implied. Only one of these can bet set at once. */
  SILC_ASN1_UNIVERSAL    = 0x0001,       /* Universal class (default) */
  SILC_ASN1_APP          = 0x0002,	 /* Application specific class */
  SILC_ASN1_CONTEXT      = 0x0003,	 /* Context specific class */
  SILC_ASN1_PRIVATE      = 0x0004,	 /* Private class */

  /* Tag options (bitmask) */
  SILC_ASN1_IMPLICIT     = 0x0010,       /* Tag is implicit (default) */
  SILC_ASN1_EXPLICIT     = 0x0020,	 /* Tag is explicit */
  SILC_ASN1_DEFINITE     = 0x0040,       /* Length is definite (default) */
  SILC_ASN1_INDEFINITE   = 0x0080,	 /* Length is indefinite */

  /* Decoding options (bitmask) */
  SILC_ASN1_OPTIONAL     = 0x0100,	 /* Zero or more may be found.  The
					    argument must be pointer to the
					    type pointer so that NULL can be
					    returned if type is not found. */

  /* ASN.1 encoder/decoder options (bitmask).  These can be given
     only with SILC_ASN1_OPTS macro at the start of encoding/decoding. */
  SILC_ASN1_ALLOC        = 0x0400,       /* Dynamically allocate results */
  SILC_ASN1_ACCUMUL      = 0x0800,       /* Accumulate memory for results,
					    next call to silc_asn1_decode
					    will not cancel old results. */
} SilcAsn1Options;
/***/

/****d* silcasn1/SilcASN1API/SilcAsn1Tag
 *
 * NAME
 *
 *    typedef enum { ... } SilcAsn1Tag;
 *
 * DESCRIPTION
 *
 *    Universal ASN.1 tags.  Usually these tags are given automatically
 *    to the silc_asn1_encode and silc_asn1_decode by using the various
 *    macros (such as SILC_ASN1_BOOLEAN).  Some macros may take the tag
 *    as additional argument.
 *
 * SOURCE
 */
typedef enum {
  SILC_ASN1_TAG_BOOLEAN               = 1,  /* SILC_ASN1_BOOLEAN */
  SILC_ASN1_TAG_INTEGER               = 2,  /* SILC_ASN1_INT */
  SILC_ASN1_TAG_BIT_STRING            = 3,  /* SILC_ASN1_BIT_STRING */
  SILC_ASN1_TAG_OCTET_STRING          = 4,  /* SILC_ASN1_OCTET_STRING */
  SILC_ASN1_TAG_NULL                  = 5,  /* SILC_ASN1_NULL */
  SILC_ASN1_TAG_OID                   = 6,  /* SILC_ASN1_OID */
  SILC_ASN1_TAG_ODE                   = 7,  /* not supported */
  SILC_ASN1_TAG_ETI                   = 8,  /* not supported */
  SILC_ASN1_TAG_REAL                  = 9,  /* not supported */
  SILC_ASN1_TAG_ENUM                  = 10, /* SILC_ASN1_ENUM */
  SILC_ASN1_TAG_EMBEDDED              = 11, /* not supported */
  SILC_ASN1_TAG_UTF8_STRING           = 12, /* SILC_ASN1_UTF8_STRING */
  SILC_ASN1_TAG_ROI                   = 13, /* not supported */
  SILC_ASN1_TAG_SEQUENCE              = 16, /* SILC_ASN1_SEQUENCE */
  SILC_ASN1_TAG_SET                   = 17, /* SILC_ASN1_SET */
  SILC_ASN1_TAG_NUMERIC_STRING        = 18, /* SILC_ASN1_NUMERIC_STRING */
  SILC_ASN1_TAG_PRINTABLE_STRING      = 19, /* SILC_ASN1_PRINTABLE_STRING */
  SILC_ASN1_TAG_TELETEX_STRING        = 20, /* SILC_ASN1_TELETEX_STRING */
  SILC_ASN1_TAG_VIDEOTEX_STRING       = 21, /* not supported */
  SILC_ASN1_TAG_IA5_STRING            = 22, /* SILC_ASN1_IA5_STRING */
  SILC_ASN1_TAG_UTC_TIME              = 23, /* SILC_ASN1_UTC_TIME */
  SILC_ASN1_TAG_GENERALIZED_TIME      = 24, /* SILC_ASN1_GENERAL_STRING */
  SILC_ASN1_TAG_GRAPHIC_STRING        = 25, /* not supported */
  SILC_ASN1_TAG_VISIBLE_STRING        = 26, /* SILC_ASN1_VISIBLE_STRING */
  SILC_ASN1_TAG_GENERAL_STRING        = 27, /* SILC_ASN1_GENERAL_STRING */
  SILC_ASN1_TAG_UNIVERSAL_STRING      = 28, /* SILC_ASN1_UNIVERSAL_STRING */
  SILC_ASN1_TAG_UNRESTRICTED_STRING   = 29, /* SILC_ASN1_UNRESTRICTED_STRING */
  SILC_ASN1_TAG_BMP_STRING            = 30, /* SILC_ASN1_BMP_STRING */
} SilcAsn1Tag;
/***/

#include "silcasn1_i.h"

/****f* silcasn1/SilcASN1API/silc_asn1_alloc
 *
 * SYNOPSIS
 *
 *    SilcAsn1 silc_asn1_alloc(void);
 *
 * DESCRIPTION
 *
 *    Allocates and initializes ASN.1 encoder/decoder and returns SilcAsn1
 *    context or NULL on error.  This context can be used with both
 *    silc_asn1_encode and silc_asn1_decode functions.
 *
 *    Usually SilcAsn1 is allocated when encoder or decoder is needed,
 *    however it is also possible to allocate long-lasting SilcAsn1 and
 *    use that every time ASN.1 routines are needed.  Application could
 *    for example allocate one SilcAsn1 and use that for all ASN.1 encoding
 *    and decoding.
 *
 *    When this context is freed with silc_asn1_free all memory will be
 *    freed, and all encoded ASN.1 buffers becomes invalid.  Also all
 *    data that is returned by silc_asn1_decode function becomes invalid.
 *
 ***/
SilcAsn1 silc_asn1_alloc(void);

/****f* silcasn1/SilcASN1API/silc_asn1_free
 *
 * SYNOPSIS
 *
 *    void silc_asn1_free(SilcAsn1 asn1);
 *
 * DESCRIPTION
 *
 *    Frees the SilcAsn1 context and all allocated memory.  All encoded
 *    buffers and all decoded buffers with this context becomes invalid
 *    after this call.
 *
 ***/
void silc_asn1_free(SilcAsn1 asn1);

/****f* silcasn1/SilcASN1API/silc_asn1_init
 *
 * SYNOPSIS
 *
 *    SilcBool silc_asn1_init(SilcAsn1 asn1);
 *
 * DESCRIPTION
 *
 *    Initializes a pre-allocated SilcAsn1 context.  This call is
 *    equivalent to silc_asn1_alloc except that this takes the pre-allocated
 *    context as argument.
 *
 * EXAMPLE
 *
 *    SilcAsn1Struct asn1;
 *    if (!silc_asn1_init(&asn1))
 *      error;
 *
 ***/
SilcBool silc_asn1_init(SilcAsn1 asn1);

/****f* silcasn1/SilcASN1API/silc_asn1_uninit
 *
 * SYNOPSIS
 *
 *    void silc_asn1_uninit(SilcAsn1 asn1);
 *
 * DESCRIPTION
 *
 *    Uninitializes a pre-allocated SilcAsn1 context.  Use this function
 *    instead of silc_asn1_free if you used silc_asn1_init.
 *
 ***/
void silc_asn1_uninit(SilcAsn1 asn1);

/****f* silcasn1/SilcASN1API/silc_asn1_encode
 *
 * SYNOPSIS
 *
 *    SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...);
 *
 * DESCRIPTION
 *
 *    Encodes ASN.1 encoded buffer into `dest', from variable argument
 *    list of ASN.1 types.  The variable argument list forms the ASN.1
 *    trees and nodes that are encoded into the `dest'.  By default, the
 *    memory for `dest' is allocated from the `asn1', and the buffer becomes
 *    invalid either by calling silc_asn1_free, silc_asn1_uninit, or when
 *    silc_asn1_encode is called for the next time.
 *
 *    If the SILC_ASN1_OPTS macro with SILC_ASN1_ALLOC option is given then
 *    the `dest' is dynamically allocated and caller must free it by itself.
 *    Alternatively if SILC_ASN1_ACCUMUL is given then memory is accumulated
 *    from `asn1' for `dest' and it is freed only when silc_asn1_free or
 *    silc_asn1_uninit is called.  Next call to silc_asn1_encode will not
 *    cancel the previous result, but will accumulate more memory for new
 *    result.
 *
 *    The variable argument list is constructed by using various
 *    macros, for example SILC_ASN1_SEQUENCE, etc.  The variable argument
 *    list must always be ended with SILC_ASN1_END type.
 *
 *    If encoding is successful this returns TRUE, FALSE on error.
 *
 * EXAMPLE
 *
 *    silc_asn1_encode(asn1, buf,
 *                     SILC_ASN1_SEQUENCE,
 *                       SILC_ASN1_BOOLEAN(bool_val),
 *                       SILC_ASN1_OCTET_STRING(string, string_len),
 *                       SILC_ASN1_SEQUENCE_T(0, 2),
 *                         SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 100, foo),
 *                       SILC_ASN1_END,
 *                       SILC_ASN1_OCTET_STRING_T(0, 1, string2, string2_len),
 *                     SILC_ASN1_END, SILC_ASN1_END);
 *
 *    Creates ASN.1 tree that looks something like:
 *
 *    buf ::= SEQUENCE {
 *      bool_val      BOOLEAN,
 *      string        OCTET-STRING,
 *               [2]  SEQUENCE {
 *                      foo   [100] EXPLICIT BOOLEAN }
 *      string2  [1]  OCTET-STRING }
 *
 ***/
SilcBool silc_asn1_encode(SilcAsn1 asn1, SilcBuffer dest, ...);

/****f* silcasn1/SilcASN1API/silc_asn1_decode
 *
 * SYNOPSIS
 *
 *    SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);
 *
 * DESCRIPTION
 *
 *    Decodes the ASN.1 encoded buffer `src' by the ASN.1 types sent
 *    as argument.  The ASN.1 types sent as argument must be found from
 *    the `src' for this function to decode successfully.
 *
 *    The memory allocated for the results are allocated from `asn1' and
 *    they become invalid if `asn1' becomes invalid.  Next (second) call
 *    to this function does NOT invalidate the previous results.  However,
 *    third call to this function does invalidate the results of the first
 *    call but not second.  On the other hand, fourth call invalidates
 *    the results of the second call but not third, fifth call invalidates
 *    the results of the third call but not fourth, and so on.  This allows
 *    efficient decoding, when silc_asn1_decode must be called multiple times
 *    to decode all data, without new memory allocations.  However, caller
 *    must be cautios and understand that the every second call invalidates
 *    the results of every second previous results.
 *
 *    If the SILC_ASN1_OPTS macro with SILC_ASN1_ALLOC option is given then
 *    all results are dynamically allocated and caller must free them by
 *    itself. Alternatively if SILC_ASN1_ACCUMUL is given then memory is
 *    accumulated from `asn1' for results and they are freed only when the
 *    silc_asn1_free or silc_asn1_uninit is called.  Next calls to the
 *    silc_asn1_decode will NOT invalidate the old results, but will
 *    accumulate more memory for new results.  If the SILC_ASN1_OPTS is not
 *    given at all then the default allocation method (decribed above)
 *    applies.
 *
 *    If caller needs to store the results even after `asn1' becomes invalid
 *    then call must either use SILC_ASN1_ALLOC option or duplicate the
 *    results by itself.
 *
 * EXAMPLE
 *
 *    SilcBool bool_val, foo;
 *    unsigned char *string, string2;
 *    SilcUInt32 string_len, string2_len;
 *
 *    silc_asn1_decode(asn1, tree,
 *                     SILC_ASN1_SEQUENCE,
 *                       SILC_ASN1_BOOLEAN(&bool_val),
 *                       SILC_ASN1_OCTET_STRING(&string, &string_len),
 *                       SILC_ASN1_SEQUENCE_T(0, 2),
 *                         SILC_ASN1_BOOLEAN_T(SILC_ASN1_EXPLICIT, 100, &foo),
 *                       SILC_ASN1_END,
 *                       SILC_ASN1_OCTET_STRING_T(0, 1, &str2, &str2_len),
 *                     SILC_ASN1_END, SILC_ASN1_END);
 *
 ***/
SilcBool silc_asn1_decode(SilcAsn1 asn1, SilcBuffer src, ...);

/****f* silcasn1/SilcASN1API/SILC_ASN1_OPTS
 *
 * SYNOPSIS
 *
 *    SILC_ASN1_OPTS(opts)
 *
 * DESCRIPTION
 *
 *    The `opts' is SilcAsn1Options.  This macro can be used to set
 *    options for silc_asn1_encode and silc_asn1_decode functions.
 *
 * NOTES
 *
 *    Only the SILC_ASN1_ALLOC and SILC_ASN1_ACCUMUL flags may be
 *    set with this macro.
 *
 *    This macro must be the first macro in the variable argument list
 *    in the function.
 *
 * EXAMPLE
 *
 *    silc_asn1_decode(asn1, tree,
 *                     SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
 *                     SILC_ASN1_SEQUENCE,
 *                       SILC_ASN1_BOOLEAN(&bool_val),
 *                       SILC_ASN1_OCTET_STRING(&string, &string_len),
 *                     SILC_ASN1_END, SILC_ASN1_END);
 *
 ***/
#define SILC_ASN1_OPTS(opts) SILC_ASN1_TAG_OPTS, (opts)

/****f* silcasn1/SilcASN1API/SILC_ASN1_ANY
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_ANY(buffer)
 *    SILC_ASN1_ANY_T(opts, tag, buffer)
 *
 *    Decoding:
 *    SILC_ASN1_ANY(&buffer)
 *    SILC_ASN1_ANY_T(opts, tag, buffer)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode another ASN.1 node.  The buffer type
 *    is SilcBuffer.  This macro can be used for example to split large
 *    tree into multiple nodes, and then decoding the nodes separately from
 *    the buffers.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * EXAMPLE
 *
 *    // Encode node of two boolean values
 *    silc_asn1_encode(asn1, node,
 *                     SILC_ASN1_BOOLEAN(val1),
 *                     SILC_ASN1_BOOLEAN(val2),
 *                     SILC_ASN1_END);
 *
 *    // Encode tree with the node
 *    silc_asn1_encode(asn1, tree,
 *                     SILC_ASN1_SEQUENCE_T(SILC_ASN1_PRIVATE, 101),
 *                       SILC_ASN1_ANY(node),
 *                       SILC_ASN1_BOOLEAN(boolval),
 *                     SILC_ASN1_END, SILC_ASN1_END);
 *
 ***/
#define SILC_ASN1_ANY(x) SILC_ASN1_U1(ANY, x)
#define SILC_ASN1_ANY_T(o, t, x) SILC_ASN1_T1(ANY, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_ANY_PRIMITIVE
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_ANY_PRIMITIVE(tag, buffer)
 *    SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, buffer)
 *
 *    Decoding:
 *    SILC_ASN1_ANY_PRIMITIVE(tag, &buffer)
 *    SILC_ASN1_ANY_PRIMITIVE_T(opts, tag, buffer)
 *
 * DESCRIPTION
 *
 *    Special macro used to encode pre-encoded primitive data blob.  The data
 *    can be any primitive type that is already encoded in correct format.
 *    The caller is responsible of making sure the data is formatted
 *    correctly.  When decoding this returns the raw data blob and the caller
 *    must know of what type and format it is.  The buffer type is SilcBuffer.
 *
 *    This macro can be used in cases when the data to be encoded is already
 *    in encoded format, and it only needs to be added to ASN.1 tree.  The
 *    SILC_ASN1_ANY cannot be used with primitives when tagging implicitly,
 *    in these cases this macro can be used.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * EXAMPLE
 *
 *    // Get MP integer in encoded format
 *    mpbuf = mp_get_octet_string(mp);
 *
 *    // Encode the MP integer data to the tree
 *    silc_asn1_encode(asn1, tree,
 *                     SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_INTEGER, mpbuf),
 *                     SILC_ASN1_END);
 *
 *    // Decode the MP integer data from the tree
 *    silc_asn1_decode(asn1, tree,
 *                     SILC_ASN1_ANY_PRIMITIVE(SILC_ASN1_TAG_INTEGER, &buffer),
 *                     SILC_ASN1_END);
 *
 ***/
#define SILC_ASN1_ANY_PRIMITIVE(t, x) SILC_ASN1_T1(ANY_PRIMITIVE, 0, t, x)
#define SILC_ASN1_ANY_PRIMITIVE_T(o, t, x) SILC_ASN1_T1(ANY_PRIMITIVE, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_SEQUENCE
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_SEQUENCE
 *    SILC_ASN1_SEQUENCE_T(opts, tag)
 *
 *    Decoding:
 *    SILC_ASN1_SEQUENCE
 *    SILC_ASN1_SEQUENCE_T(opts, tag)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode sequence.  The sequence must be
 *    terminated with SILC_ASN1_END.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * EXAMPLE
 *
 *    silc_asn1_encode(asn1, tree,
 *                     SILC_ASN1_SEQUENCE,
 *                       SILC_ASN1_ANY(node),
 *                       SILC_ASN1_BOOLEAN(boolval),
 *                     SILC_ASN1_END, SILC_ASN1_END);
 *
 ***/
#define SILC_ASN1_SEQUENCE SILC_ASN1_U0(SEQUENCE)
#define SILC_ASN1_SEQUENCE_T(o, t) SILC_ASN1_T0(SEQUENCE, o, t)

/****f* silcasn1/SilcASN1API/SILC_ASN1_SET
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_SET
 *    SILC_ASN1_SET_T(opts, tag)
 *
 *    Decoding:
 *    SILC_ASN1_SET
 *    SILC_ASN1_SET_T(opts, tag)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode set.  The set must be terminated
 *    with SILC_ASN1_END.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * EXAMPLE
 *
 *    silc_asn1_encode(asn1, tree,
 *                     SILC_ASN1_SET_T(SILC_ASN1_EXPLICIT, 0),
 *                       SILC_ASN1_BOOLEAN(boolval),
 *                     SILC_ASN1_END, SILC_ASN1_END);
 *
 ***/
#define SILC_ASN1_SET SILC_ASN1_U0(SET)
#define SILC_ASN1_SET_T(o, t) SILC_ASN1_T0(SET, o, t)

/****f* silcasn1/SilcASN1API/SILC_ASN1_SEQUENCE_OF
 *
 * SYNOPSIS
 *
 *    Decoding:
 *    SILC_ASN1_SEQUENCE_OF(bufarray, numbufs)
 *
 * DESCRIPTION
 *
 *    Macro used to decode sequence of specified type.  This returns
 *    an array of SilcBuffers and number of buffers in the array.  The
 *    SILC_ASN1_CHOICE macro may also be used with this macro.
 *
 * NOTES
 *
 *    This macro must be used either with SILC_ASN1_ALLOC or SILC_ASN1_ACCUMUL
 *    flags.  Do not use this macro without flags.
 *
 * EXAMPLE
 *
 *     SilcBuffer bufs;
 *     SilcUInt32 count;
 *
 *     // Decode sequence of sequences.  Each returned buffer in the array
 *     // is a sequence.
 *     silc_asn1_decode(asn1, exts,
 *                      SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
 *                      SILC_ASN1_SEQUENCE_OF(&bufs, &count),
 *                        SILC_ASN1_TAG_SEQUENCE,
 *                      SILC_ASN1_END, SILC_ASN1_END);
 *
 ***/
#define SILC_ASN1_SEQUENCE_OF(x, c) SILC_ASN1_U2(SEQUENCE_OF, x, c)

/****f* silcasn1/SilcASN1API/SILC_ASN1_SET_OF
 *
 * SYNOPSIS
 *
 *    Decoding:
 *    SILC_ASN1_SET_OF(bufarray, numbufs)
 *
 * DESCRIPTION
 *
 *    Macro used to decode set of specified type.  This returns
 *    an array of SilcBuffers and number of buffers in the array.  The
 *    SILC_ASN1_CHOICE macro may also be used with this macro.
 *
 * NOTES
 *
 *    This macro must be used either with SILC_ASN1_ALLOC or SILC_ASN1_ACCUMUL
 *    flags.  Do not use this macro without flags.
 *
 * EXAMPLE
 *
 *     // Decode set of sequences.  Each returned buffer in the array
 *     // is a sequence.
 *     silc_asn1_decode(asn1, exts,
 *                      SILC_ASN1_OPTS(SILC_ASN1_ALLOC),
 *                      SILC_ASN1_SET_OF(&bufs, &count),
 *                        SILC_ASN1_TAG_SEQUENCE,
 *                      SILC_ASN1_END, SILC_ASN1_END);
 *
 ***/
#define SILC_ASN1_SET_OF(x, c) SILC_ASN1_U2(SEQUENCE_OF, x, c)

/****f* silcasn1/SilcASN1API/SILC_ASN1_CHOICE
 *
 * SYNOPSIS
 *
 *    Decoding:
 *    SILC_ASN1_CHOICE
 *
 * DESCRIPTION
 *
 *    Macro used to specify choices in decoding.  The choice list must
 *    be terminated with SILC_ASN1_END.  There is no limit how many choices
 *    can be specified in the list.
 *
 * EXAMPLE
 *
 *    // Decode timeval that is either UTC or generalized time
 *    silc_asn1_decode(asn1, tree,
 *                     SILC_ASN1_SEQUENCE,
 *                       SILC_ASN1_CHOICE,
 *                         SILC_ASN1_UTC_TIME(&timeval),
 *                         SILC_ASN1_GEN_TIME(&timeval),
 *                       SILC_ASN1_END,
 *                     SILC_ASN1_END, SILC_ASN1_END);
 *
 ***/
#define SILC_ASN1_CHOICE SILC_ASN1_U0(CHOICE)

/****f* silcasn1/SilcASN1API/SILC_ASN1_BOOLEAN
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_BOOLEAN(boolval)
 *    SILC_ASN1_BOOLEAN_T(opts, tag, boolval)
 *
 *    Decoding:
 *    SILC_ASN1_BOOLEAN(&boolval)
 *    SILC_ASN1_BOOLEAN_T(opts, tag, &boolval)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode boolean value.  The boolean type
 *    is SilcBool.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_BOOLEAN(x) SILC_ASN1_U1(BOOLEAN, x)
#define SILC_ASN1_BOOLEAN_T(o, t, x) SILC_ASN1_T1(BOOLEAN, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_INT
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_INT(integer)
 *    SILC_ASN1_INT_T(opts, tag, &integer)
 *
 *    Decoding:
 *    SILC_ASN1_INT(&integer)
 *    SILC_ASN1_INT_T(opts, tag, &integer);
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode multiple precision integer.  The
 *    integer type is SilcMPInt.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_INT(x) SILC_ASN1_U1(INTEGER, x)
#define SILC_ASN1_INT_T(o, t, x) SILC_ASN1_T1(INTEGER, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_SHORT_INT
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_SHORT_INT(integer)
 *    SILC_ASN1_SHORT_INT_T(opts, tag, &integer)
 *
 *    Decoding:
 *    SILC_ASN1_SHORT_INT(&integer)
 *    SILC_ASN1_SHORT_INT_T(opts, tag, &integer);
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode short integer (32 bits).  The
 *    integer type is SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_SHORT_INT(x) SILC_ASN1_U1(SHORT_INTEGER, x)
#define SILC_ASN1_SHORT_INT_T(o, t, x) SILC_ASN1_T1(SHORT_INTEGER, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_ENUM
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_ENUM(enum)
 *    SILC_ASN1_ENUM_T(opts, tag, &enum)
 *
 *    Decoding:
 *    SILC_ASN1_ENUM(&enum)
 *    SILC_ASN1_ENUM_T(opts, tag, &enum);
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode enumeration value.  The enumeration
 *    type is SilcMPInt.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_ENUM(x) SILC_ASN1_U1(ENUM, x)
#define SILC_ASN1_ENUM_T(o, t, x) SILC_ASN1_T1(ENUM, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_BIT_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_BIT_STRING(str, str_len)
 *    SILC_ASN1_BIT_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_BIT_STRING(&str, &str_len)
 *    SILC_ASN1_BIT_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode bit string.  The string length in
 *    encoding must be in bits (bytes * 8).  The decoded length is in
 *    bits as well.  The string type is unsigned char and string length
 *    SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_BIT_STRING(x, xl) SILC_ASN1_U2(BIT_STRING, x, xl)
#define SILC_ASN1_BIT_STRING_T(o, t, x, xl) SILC_ASN1_T2(BIT_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_NULL
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_NULL
 *    SILC_ASN1_NULL_T(opts, tag)
 *
 *    Decoding:
 *    SILC_ASN1_NULL
 *    SILC_ASN1_NULL_T(opts, tag)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode null value.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_NULL SILC_ASN1_U0(NULL)
#define SILC_ASN1_NULL_T(o, t) SILC_ASN1_T0(NULL, 0, t)

/****f* silcasn1/SilcASN1API/SILC_ASN1_OID
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_OID(oid)
 *    SILC_ASN1_OID_T(opts, tag, oid)
 *
 *    Decoding:
 *    SILC_ASN1_OID(&oid)
 *    SILC_ASN1_OID_T(opts, tag, &oid)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode OID string.  The OID string type
 *    is NULL terminated char.  Its length can be determinted with strlen().
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_OID(x) SILC_ASN1_U1(OID, x)
#define SILC_ASN1_OID_T(o, t, x) SILC_ASN1_UT(OID, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_OCTET_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_OCTET_STRING(str, str_len)
 *    SILC_ASN1_OCTET_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_OCTET_STRING(&str, &str_len)
 *    SILC_ASN1_OCTET_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode octet string.  The string type is
 *    unsigned char and string length SilcUInt32.  Octet string is
 *    considered to be 8-bit unsigned binary data.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_OCTET_STRING(x, xl) SILC_ASN1_U2(OCTET_STRING, x, xl)
#define SILC_ASN1_OCTET_STRING_T(o, t, x, xl) SILC_ASN1_T2(OCTET_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_UTF8_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_UTF8_STRING(str, str_len)
 *    SILC_ASN1_UTF8_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_UTF8_STRING(&str, &str_len)
 *    SILC_ASN1_UTF8_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode UTF-8 string.  The string type is
 *    unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The data is also encoded to
 *    or decoded from UTF-8.
 *
 ***/
#define SILC_ASN1_UTF8_STRING(x, xl) SILC_ASN1_U2(UTF8_STRING, x, xl)
#define SILC_ASN1_UTF8_STRING_T(o, t, x, xl) SILC_ASN1_T2(UTF8_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_NUMERIC_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_NUMERIC_STRING(str, str_len)
 *    SILC_ASN1_NUMERIC_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_NUMERIC_STRING(&str, &str_len)
 *    SILC_ASN1_NUMERIC_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode numerical string.  The string type is
 *    unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from numerical.
 *
 ***/
#define SILC_ASN1_NUMERIC_STRING(x, xl) SILC_ASN1_U2(NUMERIC_STRING, x, xl)
#define SILC_ASN1_NUMERIC_STRING_T(o, t, x, xl) SILC_ASN1_T2(NUMERIC_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_PRINTABLE_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_PRINTABLE_STRING(str, str_len)
 *    SILC_ASN1_PRINTABLE_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_PRINTABLE_STRING(&str, &str_len)
 *    SILC_ASN1_PRINTABLE_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode printable string.  The string type is
 *    unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from printable.
 *
 ***/
#define SILC_ASN1_PRINTABLE_STRING(x, xl) SILC_ASN1_U2(PRINTABLE_STRING, x, xl)
#define SILC_ASN1_PRINTABLE_STRING_T(o, t, x, xl) SILC_ASN1_T2(PRINTABLE_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_TELETEX_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_TELETEX_STRING(str, str_len)
 *    SILC_ASN1_TELETEX_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_TELETEX_STRING(&str, &str_len)
 *    SILC_ASN1_TELETEX_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode teletex (T61) string.  The string type is
 *    unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from teletex (T61).
 *
 ***/
#define SILC_ASN1_TELETEX_STRING(x, xl) SILC_ASN1_U2(TELETEX_STRING, x, xl)
#define SILC_ASN1_TELETEX_STRING_T(o, t, x, xl) SILC_ASN1_T2(TELETEX_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_IA5_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_IA5_STRING(str, str_len)
 *    SILC_ASN1_IA5_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_IA5_STRING(&str, &str_len)
 *    SILC_ASN1_IA5_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode US ASCII (IA5) string.  The string type
 *    is unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from US ASCII (IA5).
 *
 ***/
#define SILC_ASN1_IA5_STRING(x, xl) SILC_ASN1_U2(IA5_STRING, x, xl)
#define SILC_ASN1_IA5_STRING_T(o, t, x, xl) SILC_ASN1_T2(IA5_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_VISIBLE_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_VISIBLE_STRING(str, str_len)
 *    SILC_ASN1_VISIBLE_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_VISIBLE_STRING(&str, &str_len)
 *    SILC_ASN1_VISIBLE_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode visible string.  The string type is
 *    unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from visible.
 *
 ***/
#define SILC_ASN1_VISIBLE_STRING(x, xl) SILC_ASN1_U2(VISIBLE_STRING, x, xl)
#define SILC_ASN1_VISIBLE_STRING_T(o, t, x, xl) SILC_ASN1_T2(VISIBLE_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_UNIVERSAL_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_UNIVERSAL_STRING(str, str_len)
 *    SILC_ASN1_UNIVERSAL_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_UNIVERSAL_STRING(&str, &str_len)
 *    SILC_ASN1_UNIVERSAL_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode universal (UCS-4) string.  The string
 *    type is unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from universal (UCS-4).
 *
 ***/
#define SILC_ASN1_UNIVERSAL_STRING(x, xl) SILC_ASN1_U2(UNIVERSAL_STRING, x, xl)
#define SILC_ASN1_UNIVERSAL_STRING_T(o, t, x, xl) SILC_ASN1_T2(UNIVERSAL_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_BMP_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_BMP_STRING(str, str_len)
 *    SILC_ASN1_BMP_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_BMP_STRING(&str, &str_len)
 *    SILC_ASN1_BMP_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode BMP (UCS-2) string.  The string type is
 *    unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from BMP (UCS-2)
 *
 ***/
#define SILC_ASN1_BMP_STRING(x, xl) SILC_ASN1_U2(BMP_STRING, x, xl)
#define SILC_ASN1_BMP_STRING_T(o, t, x, xl) SILC_ASN1_T2(BMP_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_UNRESTRICTED_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_UNRESTRICTED_STRING(str, str_len)
 *    SILC_ASN1_UNRESTRICTED_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_UNRESTRICTED_STRING(&str, &str_len)
 *    SILC_ASN1_UNRESTRICTED_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode unrestricted string.  The string type is
 *    unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from unrestricted.  NOTE: this implementation use 8-bit ASCII.
 *
 ***/
#define SILC_ASN1_UNRESTRICTED_STRING(x, xl) SILC_ASN1_U2(UNRESTRICTED_STRING, x, xl)
#define SILC_ASN1_UNRESTRICTED_STRING_T(o, t, x, xl) SILC_ASN1_T2(UNRESTRICTED_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_GENERAL_STRING
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_GENERAL_STRING(str, str_len)
 *    SILC_ASN1_GENERAL_STRING_T(opts, tag, str, str_len)
 *
 *    Decoding:
 *    SILC_ASN1_GENERAL_STRING(&str, &str_len)
 *    SILC_ASN1_GENERAL_STRING_T(opts, tag, &str, &str_len)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode general string.  The string type is
 *    unsigned char and string length SilcUInt32.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 * NOTES
 *
 *    The string must be in UTF-8 encoding when encoding.  The decoded
 *    string will be in UTF-8 encoding.  The actual data is encoded to
 *    or decoded from general.  NOTE: this implementation use 8-bit ASCII.
 *
 ***/
#define SILC_ASN1_GENERAL_STRING(x, xl) SILC_ASN1_U2(GENERAL_STRING, x, xl)
#define SILC_ASN1_GENERAL_STRING_T(o, t, x, xl) SILC_ASN1_T2(GENERAL_STRING, o, t, x, xl)

/****f* silcasn1/SilcASN1API/SILC_ASN1_UTC_TIME
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_UTC_TIME(timeval)
 *    SILC_ASN1_UTC_TIME_T(opts, tag, timeval)
 *
 *    Decoding:
 *    SILC_ASN1_UTC_TIME(&str, &timeval)
 *    SILC_ASN1_UTC_TIME_T(opts, tag, timeval)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode universal (UTC) time value.  The
 *    time value type is SilcTime.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_UTC_TIME(x) SILC_ASN1_U1(UTC_TIME, x)
#define SILC_ASN1_UTC_TIME_T(o, t, x) SILC_ASN1_T1(UTC_TIME, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_GEN_TIME
 *
 * SYNOPSIS
 *
 *    Encoding:
 *    SILC_ASN1_GEN_TIME(timeval)
 *    SILC_ASN1_GEN_TIME_T(opts, tag, timeval)
 *
 *    Decoding:
 *    SILC_ASN1_GEN_TIME(&str, &timeval)
 *    SILC_ASN1_GEN_TIME_T(opts, tag, timeval)
 *
 * DESCRIPTION
 *
 *    Macro used to encode or decode generalized time value.  The
 *    time value type is SilcTime.
 *
 *    The `opts' is SilcAsn1Options.  The `tag' is a tag number.
 *
 ***/
#define SILC_ASN1_GEN_TIME(x) SILC_ASN1_U1(GENERALIZED_TIME, x)
#define SILC_ASN1_GEN_TIME_T(o, t, x) SILC_ASN1_T1(GENERALIZED_TIME, o, t, x)

/****f* silcasn1/SilcASN1API/SILC_ASN1_END
 *
 * SYNOPSIS
 *
 *    SILC_ASN1_END
 *
 * DESCRIPTION
 *
 *    The SILC_ASN1_END is used to terminate the variable argument list in
 *    silc_asn1_encode and silc_asn1_decode functions.  It is also used to
 *    terminate SILC_ASN1_SEQUENCE, SILC_ASN1_SEQUENCE_T, SILC_ASN1_SET,
 *    SILC_ASN1_SET_T, SILC_ASN1_SEQUENCE_OF, SILC_ASN1_SET_OF and
 *    SILC_ASN1_CHOICE macros.
 *
 ***/
#define SILC_ASN1_END 0

#endif /* SILCASN1_H */
