summaryrefslogtreecommitdiff
path: root/src/lib/krb5/asn.1/asn1_encode.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/krb5/asn.1/asn1_encode.h')
-rw-r--r--src/lib/krb5/asn.1/asn1_encode.h588
1 files changed, 588 insertions, 0 deletions
diff --git a/src/lib/krb5/asn.1/asn1_encode.h b/src/lib/krb5/asn.1/asn1_encode.h
new file mode 100644
index 000000000000..d95f65473c3a
--- /dev/null
+++ b/src/lib/krb5/asn.1/asn1_encode.h
@@ -0,0 +1,588 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* lib/krb5/asn.1/asn1_encode.h */
+/*
+ * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __ASN1_ENCODE_H__
+#define __ASN1_ENCODE_H__
+
+#include "k5-int.h"
+#include "krbasn1.h"
+#include "asn1buf.h"
+#include <time.h>
+
+typedef struct {
+ asn1_class asn1class;
+ asn1_construction construction;
+ asn1_tagnum tagnum;
+
+ /* When decoding, stores the leading and trailing lengths of a tag. Used
+ * by store_der(). */
+ size_t tag_len;
+ size_t tag_end_len;
+} taginfo;
+
+/* These functions are referenced by encoder structures. They handle the
+ * encoding of primitive ASN.1 types. */
+asn1_error_code k5_asn1_encode_bool(asn1buf *buf, intmax_t val,
+ size_t *len_out);
+asn1_error_code k5_asn1_encode_int(asn1buf *buf, intmax_t val,
+ size_t *len_out);
+asn1_error_code k5_asn1_encode_uint(asn1buf *buf, uintmax_t val,
+ size_t *len_out);
+asn1_error_code k5_asn1_encode_bytestring(asn1buf *buf,
+ unsigned char *const *val,
+ size_t len, size_t *len_out);
+asn1_error_code k5_asn1_encode_bitstring(asn1buf *buf,
+ unsigned char *const *val,
+ size_t len, size_t *len_out);
+asn1_error_code k5_asn1_encode_generaltime(asn1buf *buf, time_t val,
+ size_t *len_out);
+
+/* These functions are referenced by encoder structures. They handle the
+ * decoding of primitive ASN.1 types. */
+asn1_error_code k5_asn1_decode_bool(const unsigned char *asn1, size_t len,
+ intmax_t *val);
+asn1_error_code k5_asn1_decode_int(const unsigned char *asn1, size_t len,
+ intmax_t *val);
+asn1_error_code k5_asn1_decode_uint(const unsigned char *asn1, size_t len,
+ uintmax_t *val);
+asn1_error_code k5_asn1_decode_generaltime(const unsigned char *asn1,
+ size_t len, time_t *time_out);
+asn1_error_code k5_asn1_decode_bytestring(const unsigned char *asn1,
+ size_t len, unsigned char **str_out,
+ size_t *len_out);
+asn1_error_code k5_asn1_decode_bitstring(const unsigned char *asn1, size_t len,
+ unsigned char **bits_out,
+ size_t *len_out);
+
+/*
+ * An atype_info structure specifies how to map a C object to an ASN.1 value.
+ *
+ * We wind up with a lot of load-time relocations being done, which is
+ * a bit annoying. Be careful about "fixing" that at the cost of too
+ * much run-time performance. It might work to have a master "module"
+ * descriptor with pointers to various arrays (type descriptors,
+ * strings, field descriptors, functions) most of which don't need
+ * relocation themselves, and replace most of the pointers with table
+ * indices.
+ *
+ * It's a work in progress.
+ */
+
+enum atype_type {
+ /* For bounds checking only. By starting with 2, we guarantee that
+ * zero-initialized storage will be recognized as invalid. */
+ atype_min = 1,
+ /* Use a function table to handle encoding or decoding. tinfo is a struct
+ * fn_info *. */
+ atype_fn,
+ /* C object is a pointer to the object to be encoded or decoded. tinfo is
+ * a struct ptr_info *. */
+ atype_ptr,
+ /* C object to be encoded or decoded is at an offset from the original
+ * pointer. tinfo is a struct offset_info *. */
+ atype_offset,
+ /*
+ * Indicates a sequence field which may or may not be present in the C
+ * object or ASN.1 sequence. tinfo is a struct optional_info *. Must be
+ * used within a sequence, although the optional type may be nested within
+ * offset, ptr, and/or tag types.
+ */
+ atype_optional,
+ /*
+ * C object contains an integer and another C object at specified offsets,
+ * to be combined and encoded or decoded as specified by a cntype_info
+ * structure. tinfo is a struct counted_info *.
+ */
+ atype_counted,
+ /* Sequence. tinfo is a struct seq_info *. */
+ atype_sequence,
+ /*
+ * Sequence-of, with pointer to base type descriptor, represented as a
+ * null-terminated array of pointers (and thus the "base" type descriptor
+ * is actually an atype_ptr node). tinfo is a struct atype_info * giving
+ * the base type.
+ */
+ atype_nullterm_sequence_of,
+ atype_nonempty_nullterm_sequence_of,
+ /* Tagged version of another type. tinfo is a struct tagged_info *. */
+ atype_tagged_thing,
+ /* Boolean value. tinfo is NULL (size field determines C type width). */
+ atype_bool,
+ /* Signed or unsigned integer. tinfo is NULL. */
+ atype_int,
+ atype_uint,
+ /*
+ * Integer value taken from the type info, not from the object being
+ * encoded. tinfo is a struct immediate_info * giving the integer value
+ * and error code to return if a decoded object doesn't match it (or 0 if
+ * the value shouldn't be checked on decode).
+ */
+ atype_int_immediate,
+ /* Unused except for bounds checking. */
+ atype_max
+};
+
+struct atype_info {
+ enum atype_type type;
+ size_t size; /* Used for sequence-of processing */
+ const void *tinfo; /* Points to type-specific structure */
+};
+
+struct fn_info {
+ asn1_error_code (*enc)(asn1buf *, const void *, taginfo *, size_t *);
+ asn1_error_code (*dec)(const taginfo *, const unsigned char *, size_t,
+ void *);
+ int (*check_tag)(const taginfo *);
+ void (*free_func)(void *);
+};
+
+struct ptr_info {
+ void *(*loadptr)(const void *);
+ void (*storeptr)(void *, void *);
+ const struct atype_info *basetype;
+};
+
+struct offset_info {
+ unsigned int dataoff : 9;
+ const struct atype_info *basetype;
+};
+
+struct optional_info {
+ int (*is_present)(const void *);
+ void (*init)(void *);
+ const struct atype_info *basetype;
+};
+
+struct counted_info {
+ unsigned int dataoff : 9;
+ unsigned int lenoff : 9;
+ unsigned int lensigned : 1;
+ unsigned int lensize : 5;
+ const struct cntype_info *basetype;
+};
+
+struct tagged_info {
+ unsigned int tagval : 16, tagtype : 8, construction : 6, implicit : 1;
+ const struct atype_info *basetype;
+};
+
+struct immediate_info {
+ intmax_t val;
+ asn1_error_code err;
+};
+
+/* A cntype_info structure specifies how to map a C object and count (length or
+ * union distinguisher) to an ASN.1 value. */
+
+enum cntype_type {
+ cntype_min = 1,
+
+ /*
+ * Apply an encoder function (contents only) and wrap it in a universal
+ * primitive tag. The C object must be a char * or unsigned char *. tinfo
+ * is a struct string_info *.
+ */
+ cntype_string,
+
+ /*
+ * The C object is a DER encoding (with tag), to be simply inserted on
+ * encode or stored on decode. The C object must be a char * or unsigned
+ * char *. tinfo is NULL.
+ */
+ cntype_der,
+
+ /* An ASN.1 sequence-of value, represtened in C as a counted array. struct
+ * atype_info * giving the base type, which must be of type atype_ptr. */
+ cntype_seqof,
+
+ /* An ASN.1 choice, represented in C as a distinguisher and union. tinfo
+ * is a struct choice_info *. */
+ cntype_choice,
+
+ cntype_max
+};
+
+struct cntype_info {
+ enum cntype_type type;
+ const void *tinfo;
+};
+
+struct string_info {
+ asn1_error_code (*enc)(asn1buf *, unsigned char *const *, size_t,
+ size_t *);
+ asn1_error_code (*dec)(const unsigned char *, size_t, unsigned char **,
+ size_t *);
+ unsigned int tagval : 5;
+};
+
+struct choice_info {
+ const struct atype_info **options;
+ size_t n_options;
+};
+
+struct seq_info {
+ const struct atype_info **fields;
+ size_t n_fields;
+ /* Currently all sequences are assumed to be extensible. */
+};
+
+/*
+ * The various DEF*TYPE macros must:
+ *
+ * + Define a type named aux_type_##DESCNAME, for use in any types derived from
+ * the type being defined.
+ *
+ * + Define an atype_info struct named k5_atype_##DESCNAME
+ *
+ * + Define a type-specific structure, referenced by the tinfo field
+ * of the atype_info structure.
+ *
+ * + Define any extra stuff needed in the type descriptor, like
+ * pointer-load functions.
+ *
+ * + Accept a following semicolon syntactically, to keep Emacs parsing
+ * (and indentation calculating) code happy.
+ *
+ * Nothing else should directly define the atype_info structures.
+ */
+
+/* Define a type using a function table. */
+#define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN, DECFN, CHECKFN, FREEFN) \
+ typedef CTYPENAME aux_type_##DESCNAME; \
+ static const struct fn_info aux_info_##DESCNAME = { \
+ ENCFN, DECFN, CHECKFN, FREEFN \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_fn, sizeof(CTYPENAME), &aux_info_##DESCNAME \
+ }
+/* A sequence, defined by the indicated series of types, and an optional
+ * function indicating which fields are not present. */
+#define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS) \
+ typedef CTYPENAME aux_type_##DESCNAME; \
+ static const struct seq_info aux_seqinfo_##DESCNAME = { \
+ FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0]) \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_sequence, sizeof(CTYPENAME), &aux_seqinfo_##DESCNAME \
+ }
+/* A boolean type. */
+#define DEFBOOLTYPE(DESCNAME, CTYPENAME) \
+ typedef CTYPENAME aux_type_##DESCNAME; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_bool, sizeof(CTYPENAME), NULL \
+ }
+/* Integer types. */
+#define DEFINTTYPE(DESCNAME, CTYPENAME) \
+ typedef CTYPENAME aux_type_##DESCNAME; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_int, sizeof(CTYPENAME), NULL \
+ }
+#define DEFUINTTYPE(DESCNAME, CTYPENAME) \
+ typedef CTYPENAME aux_type_##DESCNAME; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_uint, sizeof(CTYPENAME), NULL \
+ }
+#define DEFINT_IMMEDIATE(DESCNAME, VAL, ERR) \
+ typedef int aux_type_##DESCNAME; \
+ static const struct immediate_info aux_info_##DESCNAME = { \
+ VAL, ERR \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_int_immediate, 0, &aux_info_##DESCNAME \
+ }
+
+/* Pointers to other types, to be encoded as those other types. */
+#ifdef POINTERS_ARE_ALL_THE_SAME
+#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \
+ typedef aux_type_##BASEDESCNAME *aux_type_##DESCNAME; \
+ static const struct ptr_info aux_info_##DESCNAME = { \
+ NULL, NULL, &k5_atype_##BASEDESCNAME \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_ptr, sizeof(aux_type_##DESCNAME), \
+ &aux_info_##DESCNAME \
+ }
+#else
+#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \
+ typedef aux_type_##BASEDESCNAME *aux_type_##DESCNAME; \
+ static void * \
+ aux_loadptr_##DESCNAME(const void *p) \
+ { \
+ return *(aux_type_##DESCNAME *)p; \
+ } \
+ static void \
+ aux_storeptr_##DESCNAME(void *ptr, void *val) \
+ { \
+ *(aux_type_##DESCNAME *)val = ptr; \
+ } \
+ static const struct ptr_info aux_info_##DESCNAME = { \
+ aux_loadptr_##DESCNAME, aux_storeptr_##DESCNAME, \
+ &k5_atype_##BASEDESCNAME \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_ptr, sizeof(aux_type_##DESCNAME), \
+ &aux_info_##DESCNAME \
+ }
+#endif
+#define DEFOFFSETTYPE(DESCNAME, STYPE, FIELDNAME, BASEDESC) \
+ typedef STYPE aux_type_##DESCNAME; \
+ static const struct offset_info aux_info_##DESCNAME = { \
+ OFFOF(STYPE, FIELDNAME, aux_type_##BASEDESC), \
+ &k5_atype_##BASEDESC \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_offset, sizeof(aux_type_##DESCNAME), \
+ &aux_info_##DESCNAME \
+ }
+#define DEFCOUNTEDTYPE_base(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, SIGNED, \
+ CDESC) \
+ typedef STYPE aux_type_##DESCNAME; \
+ const struct counted_info aux_info_##DESCNAME = { \
+ OFFOF(STYPE, DATAFIELD, aux_ptrtype_##CDESC), \
+ OFFOF(STYPE, COUNTFIELD, aux_counttype_##CDESC), \
+ SIGNED, sizeof(((STYPE*)0)->COUNTFIELD), \
+ &k5_cntype_##CDESC \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_counted, sizeof(STYPE), \
+ &aux_info_##DESCNAME \
+ }
+#define DEFCOUNTEDTYPE(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, CDESC) \
+ DEFCOUNTEDTYPE_base(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, 0, CDESC)
+#define DEFCOUNTEDTYPE_SIGNED(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, CDESC) \
+ DEFCOUNTEDTYPE_base(DESCNAME, STYPE, DATAFIELD, COUNTFIELD, 1, CDESC)
+
+/* Optional sequence fields. The basic form allows arbitrary test and
+ * initializer functions to be used. INIT may be null. */
+#define DEFOPTIONALTYPE(DESCNAME, PRESENT, INIT, BASEDESC) \
+ typedef aux_type_##BASEDESC aux_type_##DESCNAME; \
+ static const struct optional_info aux_info_##DESCNAME = { \
+ PRESENT, INIT, &k5_atype_##BASEDESC \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_optional, sizeof(aux_type_##DESCNAME), \
+ &aux_info_##DESCNAME \
+ }
+/* This form defines an is_present function for a zero-valued integer or null
+ * pointer of the base type's C type. */
+#define DEFOPTIONALZEROTYPE(DESCNAME, BASEDESC) \
+ static int \
+ aux_present_##DESCNAME(const void *p) \
+ { \
+ return *(aux_type_##BASEDESC *)p != 0; \
+ } \
+ DEFOPTIONALTYPE(DESCNAME, aux_present_##DESCNAME, NULL, BASEDESC)
+/* This form defines an is_present function for a null or empty null-terminated
+ * array of the base type's C type. */
+#define DEFOPTIONALEMPTYTYPE(DESCNAME, BASEDESC) \
+ static int \
+ aux_present_##DESCNAME(const void *p) \
+ { \
+ const aux_type_##BASEDESC *val = p; \
+ return (*val != NULL && **val != NULL); \
+ } \
+ DEFOPTIONALTYPE(DESCNAME, aux_present_##DESCNAME, NULL, BASEDESC)
+
+/*
+ * This encodes a pointer-to-pointer-to-thing where the passed-in
+ * value points to a null-terminated list of pointers to objects to be
+ * encoded, and encodes a (possibly empty) SEQUENCE OF these objects.
+ *
+ * BASEDESCNAME is a descriptor name for the pointer-to-thing
+ * type.
+ *
+ * When dealing with a structure containing a
+ * pointer-to-pointer-to-thing field, make a DEFPTRTYPE of this type,
+ * and use that type for the structure field.
+ */
+#define DEFNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \
+ typedef aux_type_##BASEDESCNAME aux_type_##DESCNAME; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_nullterm_sequence_of, sizeof(aux_type_##DESCNAME), \
+ &k5_atype_##BASEDESCNAME \
+ }
+#define DEFNONEMPTYNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \
+ typedef aux_type_##BASEDESCNAME aux_type_##DESCNAME; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_nonempty_nullterm_sequence_of, \
+ sizeof(aux_type_##DESCNAME), \
+ &k5_atype_##BASEDESCNAME \
+ }
+
+/* Objects with an explicit or implicit tag. (Implicit tags will ignore the
+ * construction field.) */
+#define DEFTAGGEDTYPE(DESCNAME, CLASS, CONSTRUCTION, TAG, IMPLICIT, BASEDESC) \
+ typedef aux_type_##BASEDESC aux_type_##DESCNAME; \
+ static const struct tagged_info aux_info_##DESCNAME = { \
+ TAG, CLASS, CONSTRUCTION, IMPLICIT, &k5_atype_##BASEDESC \
+ }; \
+ const struct atype_info k5_atype_##DESCNAME = { \
+ atype_tagged_thing, sizeof(aux_type_##DESCNAME), \
+ &aux_info_##DESCNAME \
+ }
+/* Objects with an explicit APPLICATION tag added. */
+#define DEFAPPTAGGEDTYPE(DESCNAME, TAG, BASEDESC) \
+ DEFTAGGEDTYPE(DESCNAME, APPLICATION, CONSTRUCTED, TAG, 0, BASEDESC)
+/* Object with a context-specific tag added */
+#define DEFCTAGGEDTYPE(DESCNAME, TAG, BASEDESC) \
+ DEFTAGGEDTYPE(DESCNAME, CONTEXT_SPECIFIC, CONSTRUCTED, TAG, 0, BASEDESC)
+#define DEFCTAGGEDTYPE_IMPLICIT(DESCNAME, TAG, BASEDESC) \
+ DEFTAGGEDTYPE(DESCNAME, CONTEXT_SPECIFIC, CONSTRUCTED, TAG, 1, BASEDESC)
+
+/* Define an offset type with an explicit context tag wrapper (the usual case
+ * for an RFC 4120 sequence field). */
+#define DEFFIELD(NAME, STYPE, FIELDNAME, TAG, DESC) \
+ DEFOFFSETTYPE(NAME##_untagged, STYPE, FIELDNAME, DESC); \
+ DEFCTAGGEDTYPE(NAME, TAG, NAME##_untagged)
+/* Define a counted type with an explicit context tag wrapper. */
+#define DEFCNFIELD(NAME, STYPE, DATAFIELD, LENFIELD, TAG, CDESC) \
+ DEFCOUNTEDTYPE(NAME##_untagged, STYPE, DATAFIELD, LENFIELD, CDESC); \
+ DEFCTAGGEDTYPE(NAME, TAG, NAME##_untagged)
+/* Like DEFFIELD but with an implicit context tag. */
+#define DEFFIELD_IMPLICIT(NAME, STYPE, FIELDNAME, TAG, DESC) \
+ DEFOFFSETTYPE(NAME##_untagged, STYPE, FIELDNAME, DESC); \
+ DEFCTAGGEDTYPE_IMPLICIT(NAME, TAG, NAME##_untagged)
+
+/*
+ * DEFCOUNTED*TYPE macros must:
+ *
+ * + Define types named aux_ptrtype_##DESCNAME and aux_counttype_##DESCNAME, to
+ * allow type checking when the counted type is referenced with structure
+ * field offsets in DEFCOUNTEDTYPE.
+ *
+ * + Define a cntype_info struct named k5_cntype_##DESCNAME
+ *
+ * + Define a type-specific structure, referenced by the tinfo field of the
+ * cntype_info structure.
+ *
+ * + Accept a following semicolon syntactically.
+ */
+
+#define DEFCOUNTEDSTRINGTYPE(DESCNAME, DTYPE, LTYPE, ENCFN, DECFN, TAGVAL) \
+ typedef DTYPE aux_ptrtype_##DESCNAME; \
+ typedef LTYPE aux_counttype_##DESCNAME; \
+ static const struct string_info aux_info_##DESCNAME = { \
+ ENCFN, DECFN, TAGVAL \
+ }; \
+ const struct cntype_info k5_cntype_##DESCNAME = { \
+ cntype_string, &aux_info_##DESCNAME \
+ }
+
+#define DEFCOUNTEDDERTYPE(DESCNAME, DTYPE, LTYPE) \
+ typedef DTYPE aux_ptrtype_##DESCNAME; \
+ typedef LTYPE aux_counttype_##DESCNAME; \
+ const struct cntype_info k5_cntype_##DESCNAME = { \
+ cntype_der, NULL \
+ }
+
+#define DEFCOUNTEDSEQOFTYPE(DESCNAME, LTYPE, BASEDESC) \
+ typedef aux_type_##BASEDESC aux_ptrtype_##DESCNAME; \
+ typedef LTYPE aux_counttype_##DESCNAME; \
+ const struct cntype_info k5_cntype_##DESCNAME = { \
+ cntype_seqof, &k5_atype_##BASEDESC \
+ }
+
+#define DEFCHOICETYPE(DESCNAME, UTYPE, DTYPE, FIELDS) \
+ typedef UTYPE aux_ptrtype_##DESCNAME; \
+ typedef DTYPE aux_counttype_##DESCNAME; \
+ static const struct choice_info aux_info_##DESCNAME = { \
+ FIELDS, sizeof(FIELDS) / sizeof(FIELDS[0]) \
+ }; \
+ const struct cntype_info k5_cntype_##DESCNAME = { \
+ cntype_choice, &aux_info_##DESCNAME \
+ }
+
+/*
+ * Declare an externally-defined type. This is a hack we should do
+ * away with once we move to generating code from a script. For now,
+ * this macro is unfortunately not compatible with the defining macros
+ * above, since you can't do the typedefs twice and we need the
+ * declarations to produce typedefs. (We could eliminate the typedefs
+ * from the DEF* macros, but then every DEF* macro use, even the ones
+ * for internal type nodes we only use to build other types, would
+ * need an accompanying declaration which explicitly lists the
+ * type.)
+ */
+#define IMPORT_TYPE(DESCNAME, CTYPENAME) \
+ typedef CTYPENAME aux_type_##DESCNAME; \
+ extern const struct atype_info k5_atype_##DESCNAME
+
+/* Partially encode the contents of a type and return its tag information.
+ * Used only by kdc_req_body. */
+asn1_error_code
+k5_asn1_encode_atype(asn1buf *buf, const void *val, const struct atype_info *a,
+ taginfo *tag_out, size_t *len_out);
+
+/* Decode the tag and contents of a type, storing the result in the
+ * caller-allocated C object val. Used only by kdc_req_body. */
+asn1_error_code
+k5_asn1_decode_atype(const taginfo *t, const unsigned char *asn1,
+ size_t len, const struct atype_info *a, void *val);
+
+/* Returns a completed encoding, with tag and in the correct byte order, in an
+ * allocated krb5_data. */
+extern krb5_error_code
+k5_asn1_full_encode(const void *rep, const struct atype_info *a,
+ krb5_data **code_out);
+asn1_error_code
+k5_asn1_full_decode(const krb5_data *code, const struct atype_info *a,
+ void **rep_out);
+
+#define MAKE_ENCODER(FNAME, DESC) \
+ krb5_error_code \
+ FNAME(const aux_type_##DESC *rep, krb5_data **code_out) \
+ { \
+ return k5_asn1_full_encode(rep, &k5_atype_##DESC, code_out); \
+ } \
+ extern int dummy /* gobble semicolon */
+
+#define MAKE_DECODER(FNAME, DESC) \
+ krb5_error_code \
+ FNAME(const krb5_data *code, aux_type_##DESC **rep_out) \
+ { \
+ asn1_error_code ret; \
+ void *rep; \
+ *rep_out = NULL; \
+ ret = k5_asn1_full_decode(code, &k5_atype_##DESC, &rep); \
+ if (ret) \
+ return ret; \
+ *rep_out = rep; \
+ return 0; \
+ } \
+ extern int dummy /* gobble semicolon */
+
+#include <stddef.h>
+/*
+ * Ugly hack!
+ * Like "offsetof", but with type checking.
+ */
+#define WARN_IF_TYPE_MISMATCH(LVALUE, TYPE) \
+ (sizeof(0 ? (TYPE *) 0 : &(LVALUE)))
+#define OFFOF(TYPE,FIELD,FTYPE) \
+ (offsetof(TYPE, FIELD) \
+ + 0 * WARN_IF_TYPE_MISMATCH(((TYPE*)0)->FIELD, FTYPE))
+
+#endif