2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * src/lib/krb5/asn.1/asn1_encode.h
2N/A *
2N/A * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
2N/A * All Rights Reserved.
2N/A *
2N/A * Export of this software from the United States of America may
2N/A * require a specific license from the United States Government.
2N/A * It is the responsibility of any person or organization contemplating
2N/A * export to obtain such a license before exporting.
2N/A *
2N/A * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2N/A * distribute this software and its documentation for any purpose and
2N/A * without fee is hereby granted, provided that the above copyright
2N/A * notice appear in all copies and that both that copyright notice and
2N/A * this permission notice appear in supporting documentation, and that
2N/A * the name of M.I.T. not be used in advertising or publicity pertaining
2N/A * to distribution of the software without specific, written prior
2N/A * permission. Furthermore if you modify this software you must label
2N/A * your software as modified software and not distribute it in such a
2N/A * fashion that it might be confused with the original M.I.T. software.
2N/A * M.I.T. makes no representations about the suitability of
2N/A * this software for any purpose. It is provided "as is" without express
2N/A * or implied warranty.
2N/A */
2N/A
2N/A#ifndef __ASN1_ENCODE_H__
2N/A#define __ASN1_ENCODE_H__
2N/A
2N/A#include "k5-int.h"
2N/A#include "krbasn1.h"
2N/A#include "asn1buf.h"
2N/A#include <time.h>
2N/A
2N/A/*
2N/A * Overview
2N/A *
2N/A * Each of these procedures inserts the encoding of an ASN.1
2N/A * primitive in a coding buffer.
2N/A *
2N/A * Operations
2N/A *
2N/A * asn1_encode_boolean
2N/A * asn1_encode_integer
2N/A * asn1_encode_unsigned_integer
2N/A * asn1_encode_octetstring
2N/A * asn1_encode_generaltime
2N/A * asn1_encode_generalstring
2N/A * asn1_encode_bitstring
2N/A * asn1_encode_oid
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_boolean(asn1buf *buf, asn1_intmax val,
2N/A unsigned int *retlen);
2N/Aasn1_error_code asn1_encode_integer(asn1buf *buf, asn1_intmax val,
2N/A unsigned int *retlen);
2N/A/*
2N/A * requires *buf is allocated
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_enumerated(asn1buf *buf, long val,
2N/A unsigned int *retlen);
2N/A
2N/Aasn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
2N/A unsigned int *retlen);
2N/A/*
2N/A * requires *buf is allocated
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len,
2N/A const void *val, unsigned int *retlen);
2N/A/*
2N/A * requires *buf is allocated
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A#define asn1_encode_charstring asn1_encode_octetstring
2N/A
2N/Aasn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len,
2N/A const asn1_octet *val, unsigned int *retlen);
2N/A/*
2N/A * requires *buf is allocated
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_null(asn1buf *buf, int *retlen);
2N/A/*
2N/A * requires *buf is allocated
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of NULL into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len,
2N/A const char *val, int *retlen);
2N/A/*
2N/A * requires *buf is allocated
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len,
2N/A const char *val, int *retlen);
2N/A/*
2N/A * requires *buf is allocated
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val,
2N/A unsigned int *retlen);
2N/A/*
2N/A * requires *buf is allocated
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A * Note: The encoding of GeneralizedTime is YYYYMMDDhhmmZ
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_generalstring(asn1buf *buf,
2N/A unsigned int len, const void *val,
2N/A unsigned int *retlen);
2N/A/*
2N/A * requires *buf is allocated, val has a length of len characters
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_bitstring(asn1buf *buf, unsigned int len,
2N/A const void *val,
2N/A unsigned int *retlen);
2N/A/*
2N/A * requires *buf is allocated, val has a length of len characters
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/Aasn1_error_code asn1_encode_opaque(asn1buf *buf, unsigned int len,
2N/A const void *val,
2N/A unsigned int *retlen);
2N/A/*
2N/A * requires *buf is allocated, val has a length of len characters
2N/A * modifies *buf, *retlen
2N/A * effects Inserts the encoding of val into *buf and returns
2N/A * the length of the encoding in *retlen.
2N/A * Returns ENOMEM to signal an unsuccesful attempt
2N/A * to expand the buffer.
2N/A */
2N/A
2N/A/*
2N/A * Type descriptor info.
2N/A *
2N/A * In this context, a "type" is a combination of a C data type
2N/A * and an ASN.1 encoding scheme for it. So we would have to define
2N/A * different "types" for:
2N/A *
2N/A * * unsigned char* encoded as octet string
2N/A * * char* encoded as octet string
2N/A * * char* encoded as generalstring
2N/A * * krb5_data encoded as octet string
2N/A * * krb5_data encoded as generalstring
2N/A * * int32_t encoded as integer
2N/A * * unsigned char encoded as integer
2N/A *
2N/A * Perhaps someday some kind of flags could be defined so that minor
2N/A * variations on the C types could be handled via common routines.
2N/A *
2N/A * The handling of strings is pretty messy. Currently, we have a
2N/A * separate kind of encoder function that takes an extra length
2N/A * parameter. Perhaps we should just give up on that, always deal
2N/A * with just a single location, and handle strings by via encoder
2N/A * functions for krb5_data, keyblock, etc.
2N/A *
2N/A * We wind up with a lot of load-time relocations being done, which is
2N/A * a bit annoying. Be careful about "fixing" that at the cost of too
2N/A * much run-time performance. It might work to have a master "module"
2N/A * descriptor with pointers to various arrays (type descriptors,
2N/A * strings, field descriptors, functions) most of which don't need
2N/A * relocation themselves, and replace most of the pointers with table
2N/A * indices.
2N/A *
2N/A * It's a work in progress.
2N/A */
2N/A
2N/Aenum atype_type {
2N/A /*
2N/A * For bounds checking only. By starting with values above 1, we
2N/A * guarantee that zero-initialized storage will be recognized as
2N/A * invalid.
2N/A */
2N/A atype_min = 1,
2N/A /* Encoder function to be called with address of <thing>. */
2N/A atype_fn,
2N/A /*
2N/A * Encoder function to be called with address of <thing> and a
2N/A * length (unsigned int).
2N/A */
2N/A atype_fn_len,
2N/A /*
2N/A * Pointer to actual thing to be encoded.
2N/A *
2N/A * Most of the fields are related only to the C type -- size, how
2N/A * to fetch a pointer in a type-safe fashion -- but since the base
2N/A * type descriptor encapsulates the encoding as well, different
2N/A * encodings for the same C type may require different pointer-to
2N/A * types as well.
2N/A *
2N/A * Must not refer to atype_fn_len.
2N/A */
2N/A atype_ptr,
2N/A /* Sequence, with pointer to sequence descriptor header. */
2N/A atype_sequence,
2N/A /*
2N/A * Sequence-of, with pointer to base type descriptor, represented
2N/A * as a null-terminated array of pointers (and thus the "base"
2N/A * type descriptor is actually an atype_ptr node).
2N/A */
2N/A atype_nullterm_sequence_of,
2N/A atype_nonempty_nullterm_sequence_of,
2N/A /*
2N/A * Encode this object using a single field descriptor. This may
2N/A * mean the atype/field breakdown needs revision....
2N/A *
2N/A * Main expected uses: Encode realm component of principal as a
2N/A * GENERALSTRING. Pluck data and length fields out of a structure
2N/A * and encode a counted SEQUENCE OF.
2N/A */
2N/A atype_field,
2N/A /* Tagged version of another type. */
2N/A atype_tagged_thing,
2N/A /* Integer types. */
2N/A atype_int,
2N/A atype_uint,
2N/A /* Unused except for bounds checking. */
2N/A atype_max
2N/A};
2N/A
2N/A/*
2N/A * Initialized structures could be a lot smaller if we could use C99
2N/A * designated initializers, and a union for all the type-specific
2N/A * stuff. Maybe use the hack we use for krb5int_access, where we use
2N/A * a run-time initialize if the compiler doesn't support designated
2N/A * initializers? That's a lot of work here, though, with so many
2N/A * little structures. Maybe if/when these get auto-generated.
2N/A */
2N/Astruct atype_info {
2N/A enum atype_type type;
2N/A /* used for sequence-of processing */
2N/A unsigned int size;
2N/A /* atype_fn */
2N/A asn1_error_code (*enc)(asn1buf *, const void *, unsigned int *);
2N/A /* atype_fn_len */
2N/A asn1_error_code (*enclen)(asn1buf *, unsigned int, const void *,
2N/A unsigned int *);
2N/A /* atype_ptr, atype_fn_len */
2N/A const void *(*loadptr)(const void *);
2N/A /* atype_ptr, atype_nullterm_sequence_of */
2N/A const struct atype_info *basetype;
2N/A /* atype_sequence */
2N/A const struct seq_info *seq;
2N/A /* atype_field */
2N/A const struct field_info *field;
2N/A /* atype_tagged_thing */
2N/A unsigned int tagval : 8, tagtype : 8;
2N/A /* atype_[u]int */
2N/A asn1_intmax (*loadint)(const void *);
2N/A asn1_uintmax (*loaduint)(const void *);
2N/A};
2N/A
2N/A/*
2N/A * The various DEF*TYPE macros must:
2N/A *
2N/A * + Define a type named aux_typedefname_##DESCNAME, for use in any
2N/A * types derived from the type being defined.
2N/A *
2N/A * + Define an atype_info struct named krb5int_asn1type_##DESCNAME.
2N/A *
2N/A * + Define any extra stuff needed in the type descriptor, like
2N/A * pointer-load functions.
2N/A *
2N/A * + Accept a following semicolon syntactically, to keep Emacs parsing
2N/A * (and indentation calculating) code happy.
2N/A *
2N/A * Nothing else should directly define the atype_info structures.
2N/A */
2N/A
2N/A/*
2N/A * Define a type for which we must use an explicit encoder function.
2N/A * The DEFFNTYPE variant uses a function taking a void*, the
2N/A * DEFFNXTYPE form wants a function taking a pointer to the actual C
2N/A * type to be encoded; you should use the latter unless you've already
2N/A * got the void* function supplied elsewhere.
2N/A *
2N/A * Of course, we need a single, consistent type for the descriptor
2N/A * structure field, so we use the function pointer type that uses
2N/A * void*, and create a wrapper function in DEFFNXTYPE. However, in
2N/A * all our cases so far, the supplied function is static and not used
2N/A * otherwise, so the compiler can merge it with the wrapper function
2N/A * if the optimizer is good enough.
2N/A */
2N/A#define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_fn, sizeof(CTYPENAME), ENCFN, \
2N/A }
2N/A#define DEFFNXTYPE(DESCNAME, CTYPENAME, ENCFN) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A static asn1_error_code \
2N/A aux_encfn_##DESCNAME(asn1buf *buf, const void *val, \
2N/A unsigned int *retlen) \
2N/A { \
2N/A return ENCFN(buf, \
2N/A (const aux_typedefname_##DESCNAME *)val, \
2N/A retlen); \
2N/A } \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_fn, sizeof(CTYPENAME), aux_encfn_##DESCNAME, \
2N/A }
2N/A/*
2N/A * XXX The handling of data+length fields really needs reworking.
2N/A * A type descriptor probably isn't the right way.
2N/A *
2N/A * Also, the C type is likely to be one of char*, unsigned char*,
2N/A * or (maybe) void*. An enumerator or reference to an external
2N/A * function would be more compact.
2N/A *
2N/A * The supplied encoder function takes as an argument the data pointer
2N/A * loaded from the indicated location, not the address of the field.
2N/A * This isn't consistent with DEFFN[X]TYPE above, but all of the uses
2N/A * of DEFFNLENTYPE are for string encodings, and that's how our
2N/A * string-encoding primitives work. So be it.
2N/A */
2N/A#ifdef POINTERS_ARE_ALL_THE_SAME
2N/A#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_fn_len, 0, 0, ENCFN, \
2N/A }
2N/A#else
2N/A#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A static const void *loadptr_for_##DESCNAME(const void *pv) \
2N/A { \
2N/A const aux_typedefname_##DESCNAME *p = pv; \
2N/A return *p; \
2N/A } \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_fn_len, 0, 0, ENCFN, \
2N/A loadptr_for_##DESCNAME \
2N/A }
2N/A#endif
2N/A/*
2N/A * A sequence, defined by the indicated series of fields, and an
2N/A * optional function indicating which fields are present.
2N/A */
2N/A#define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS, OPT) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A static const struct seq_info aux_seqinfo_##DESCNAME = { \
2N/A OPT, FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0]) \
2N/A }; \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_sequence, sizeof(CTYPENAME), 0,0,0,0, \
2N/A &aux_seqinfo_##DESCNAME, \
2N/A }
2N/A/* Integer types. */
2N/A#define DEFINTTYPE(DESCNAME, CTYPENAME) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A static asn1_intmax loadint_##DESCNAME(const void *p) \
2N/A { \
2N/A assert(sizeof(CTYPENAME) <= sizeof(asn1_intmax)); \
2N/A return *(const aux_typedefname_##DESCNAME *)p; \
2N/A } \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_int, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \
2N/A loadint_##DESCNAME, 0, \
2N/A }
2N/A#define DEFUINTTYPE(DESCNAME, CTYPENAME) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A static asn1_uintmax loaduint_##DESCNAME(const void *p) \
2N/A { \
2N/A assert(sizeof(CTYPENAME) <= sizeof(asn1_uintmax)); \
2N/A return *(const aux_typedefname_##DESCNAME *)p; \
2N/A } \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_uint, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \
2N/A 0, loaduint_##DESCNAME, \
2N/A }
2N/A/* Pointers to other types, to be encoded as those other types. */
2N/A#ifdef POINTERS_ARE_ALL_THE_SAME
2N/A#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \
2N/A typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, 0, \
2N/A &krb5int_asn1type_##BASEDESCNAME, 0 \
2N/A }
2N/A#else
2N/A#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \
2N/A typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \
2N/A static const void * \
2N/A loadptr_for_##BASEDESCNAME##_from_##DESCNAME(const void *p) \
2N/A { \
2N/A const aux_typedefname_##DESCNAME *inptr = p; \
2N/A const aux_typedefname_##BASEDESCNAME *retptr; \
2N/A retptr = *inptr; \
2N/A return retptr; \
2N/A } \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, \
2N/A loadptr_for_##BASEDESCNAME##_from_##DESCNAME, \
2N/A &krb5int_asn1type_##BASEDESCNAME, 0 \
2N/A }
2N/A#endif
2N/A/*
2N/A * This encodes a pointer-to-pointer-to-thing where the passed-in
2N/A * value points to a null-terminated list of pointers to objects to be
2N/A * encoded, and encodes a (possibly empty) SEQUENCE OF these objects.
2N/A *
2N/A * BASEDESCNAME is a descriptor name for the pointer-to-thing
2N/A * type.
2N/A *
2N/A * When dealing with a structure containing a
2N/A * pointer-to-pointer-to-thing field, make a DEFPTRTYPE of this type,
2N/A * and use that type for the structure field.
2N/A */
2N/A#define DEFNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \
2N/A typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME; \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_nullterm_sequence_of, sizeof(aux_typedefname_##DESCNAME), \
2N/A 0, 0, \
2N/A 0 /* loadptr */, \
2N/A &krb5int_asn1type_##BASEDESCNAME, 0 \
2N/A }
2N/A#define DEFNONEMPTYNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \
2N/A typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME; \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_nonempty_nullterm_sequence_of, \
2N/A sizeof(aux_typedefname_##DESCNAME), \
2N/A 0, 0, \
2N/A 0 /* loadptr */, \
2N/A &krb5int_asn1type_##BASEDESCNAME, 0 \
2N/A }
2N/A/*
2N/A * Encode a thing (probably sub-fields within the structure) as a
2N/A * single object.
2N/A */
2N/A#define DEFFIELDTYPE(DESCNAME, CTYPENAME, FIELDINFO) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A static const struct field_info aux_fieldinfo_##DESCNAME = FIELDINFO; \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_field, sizeof(CTYPENAME), 0, 0, 0, 0, 0, \
2N/A &aux_fieldinfo_##DESCNAME \
2N/A }
2N/A/* Objects with an APPLICATION tag added. */
2N/A#define DEFAPPTAGGEDTYPE(DESCNAME, TAG, BASEDESC) \
2N/A typedef aux_typedefname_##BASEDESC aux_typedefname_##DESCNAME; \
2N/A const struct atype_info krb5int_asn1type_##DESCNAME = { \
2N/A atype_tagged_thing, sizeof(aux_typedefname_##DESCNAME), \
2N/A 0, 0, 0, &krb5int_asn1type_##BASEDESC, 0, 0, TAG, APPLICATION \
2N/A }
2N/A
2N/A/*
2N/A * Declare an externally-defined type. This is a hack we should do
2N/A * away with once we move to generating code from a script. For now,
2N/A * this macro is unfortunately not compatible with the defining macros
2N/A * above, since you can't do the typedefs twice and we need the
2N/A * declarations to produce typedefs. (We could eliminate the typedefs
2N/A * from the DEF* macros, but then every DEF* macro use, even the ones
2N/A * for internal type nodes we only use to build other types, would
2N/A * need an accompanying declaration which explicitly lists the
2N/A * type.)
2N/A */
2N/A#define IMPORT_TYPE(DESCNAME, CTYPENAME) \
2N/A typedef CTYPENAME aux_typedefname_##DESCNAME; \
2N/A extern const struct atype_info krb5int_asn1type_##DESCNAME
2N/A
2N/A/*
2N/A * Create a partial-encoding function by the indicated name, for the
2N/A * indicated type. Should only be needed until we've converted all of
2N/A * the encoders, then everything should use descriptor tables.
2N/A */
2N/Aextern asn1_error_code
2N/Akrb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
2N/A const struct atype_info *a, unsigned int *retlen);
2N/A#define MAKE_ENCFN(FNAME,DESC) \
2N/A static asn1_error_code FNAME(asn1buf *buf, \
2N/A const aux_typedefname_##DESC *val, \
2N/A unsigned int *retlen) \
2N/A { \
2N/A return krb5int_asn1_encode_a_thing(buf, val, \
2N/A &krb5int_asn1type_##DESC, \
2N/A retlen); \
2N/A } \
2N/A extern int dummy /* gobble semicolon */
2N/A
2N/A/*
2N/A * Sequence field descriptor.
2N/A *
2N/A * Currently we assume everything is a single object with a type
2N/A * descriptor, and then we bolt on some ugliness on the side for
2N/A * handling strings with length fields.
2N/A *
2N/A * Anything with "interesting" encoding handling, like a sequence-of
2N/A * or a pointer to the actual value to encode, is handled via opaque
2N/A * types with their own encoder functions. Most of that should
2N/A * eventually change.
2N/A */
2N/A
2N/Aenum field_type {
2N/A /* Unused except for range checking. */
2N/A field_min = 1,
2N/A /* Field ATYPE describes processing of field at DATAOFF. */
2N/A field_normal,
2N/A /*
2N/A * Encode an "immediate" integer value stored in DATAOFF, with no
2N/A * reference to the data structure.
2N/A */
2N/A field_immediate,
2N/A /*
2N/A * Encode some kind of string field encoded with pointer and
2N/A * length. (A GENERALSTRING represented as a null-terminated C
2N/A * string would be handled as field_normal.)
2N/A */
2N/A field_string,
2N/A /*
2N/A * LENOFF indicates a value describing the length of the array at
2N/A * DATAOFF, encoded as a sequence-of with the element type
2N/A * described by ATYPE.
2N/A */
2N/A field_sequenceof_len,
2N/A /* Unused except for range checking. */
2N/A field_max
2N/A};
2N/A/* To do: Consider using bitfields. */
2N/Astruct field_info {
2N/A /* Type of the field. */
2N/A unsigned int /* enum field_type */ ftype : 3;
2N/A
2N/A /*
2N/A * Use of DATAOFF and LENOFF are described by the value in FTYPE.
2N/A * Generally DATAOFF will be the offset from the supplied pointer
2N/A * at which we find the object to be encoded.
2N/A */
2N/A unsigned int dataoff : 9, lenoff : 9;
2N/A
2N/A /*
2N/A * If TAG is non-negative, a context tag with that value is added
2N/A * to the encoding of the thing. (XXX This would encode more
2N/A * compactly as an unsigned bitfield value tagnum+1, with 0=no
2N/A * tag.) The tag is omitted for optional fields that are not
2N/A * present.
2N/A *
2N/A * It's a bit illogical to combine the tag and other field info,
2N/A * since really a sequence field could have zero or several
2N/A * context tags, and of course a tag could be used elsewhere. But
2N/A * the normal mode in the Kerberos ASN.1 description is to use one
2N/A * context tag on each sequence field, so for now let's address
2N/A * that case primarily and work around the other cases (thus tag<0
2N/A * means skip tagging).
2N/A */
2N/A signed int tag : 5;
2N/A
2N/A /*
2N/A * If OPT is non-negative and the sequence header structure has a
2N/A * function pointer describing which fields are present, OPT is
2N/A * the bit position indicating whether the currently-described
2N/A * element is present. (XXX Similar encoding issue.)
2N/A *
2N/A * Note: Most of the time, I'm using the same number here as for
2N/A * the context tag. This is just because it's easier for me to
2N/A * keep track while working on the code by hand. The *only*
2N/A * meaningful correlation is of this value and the bits set by the
2N/A * "optional" function when examining the data structure.
2N/A */
2N/A signed int opt : 5;
2N/A
2N/A /*
2N/A * For some values of FTYPE, this describes the type of the
2N/A * object(s) to be encoded.
2N/A */
2N/A const struct atype_info *atype;
2N/A
2N/A /*
2N/A * We use different types for "length" fields in different places.
2N/A * So we need a good way to retrieve the various kinds of lengths
2N/A * in a compatible way. This may be a string length, or the
2N/A * length of an array of objects to encode in a SEQUENCE OF.
2N/A *
2N/A * In case the field is signed and negative, or larger than
2N/A * size_t, return SIZE_MAX as an error indication. We'll assume
2N/A * for now that we'll never have 4G-1 (or 2**64-1, or on tiny
2N/A * systems, 65535) sized values. On most if not all systems we
2N/A * care about, SIZE_MAX is equivalent to "all of addressable
2N/A * memory" minus one byte. That wouldn't leave enough extra room
2N/A * for the structure we're encoding, so it's pretty safe to assume
2N/A * SIZE_MAX won't legitimately come up on those systems.
2N/A *
2N/A * If this code gets ported to a segmented architecture or other
2N/A * system where it might be possible... figure it out then.
2N/A */
2N/A const struct atype_info *lentype;
2N/A};
2N/A
2N/A/*
2N/A * Normal or optional sequence fields at a particular offset, encoded
2N/A * as indicated by the listed DESCRiptor.
2N/A */
2N/A#define FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,OPT) \
2N/A { \
2N/A field_normal, OFFOF(TYPE, FIELDNAME, aux_typedefname_##DESCR), \
2N/A 0, TAG, OPT, &krb5int_asn1type_##DESCR \
2N/A }
2N/A#define FIELDOF_NORM(TYPE,DESCR,FIELDNAME,TAG) \
2N/A FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,-1)
2N/A/*
2N/A * If encoding a subset of the fields of the current structure (for
2N/A * example, a flat structure describing data that gets encoded as a
2N/A * sequence containing one or more sequences), use ENCODEAS, no struct
2N/A * field name(s), and the indicated type descriptor must support the
2N/A * current struct type.
2N/A */
2N/A#define FIELDOF_ENCODEAS(TYPE,DESCR,TAG) \
2N/A FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,-1)
2N/A#define FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,OPT) \
2N/A { \
2N/A field_normal, \
2N/A 0 * sizeof(0 ? (TYPE *)0 : (aux_typedefname_##DESCR *) 0), \
2N/A 0, TAG, OPT, &krb5int_asn1type_##DESCR \
2N/A }
2N/A
2N/A/*
2N/A * Reinterpret some subset of the structure itself as something
2N/A * else.
2N/A */
2N/A#define FIELD_SELF(DESCR, TAG) \
2N/A { field_normal, 0, 0, TAG, -1, &krb5int_asn1type_##DESCR }
2N/A
2N/A#define FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,OPT) \
2N/A { \
2N/A field_string, \
2N/A OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \
2N/A OFFOF(STYPE, LENFIELD, aux_typedefname_##LENDESC), \
2N/A TAG, OPT, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENDESC \
2N/A }
2N/A#define FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,OPT) \
2N/A FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,uint,LENFIELD,TAG,OPT)
2N/A#define FIELDOF_STRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG) \
2N/A FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,-1)
2N/A#define FIELDOF_STRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \
2N/A FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,-1)
2N/A#define FIELD_INT_IMM(VALUE,TAG) \
2N/A { field_immediate, VALUE, 0, TAG, -1, 0, }
2N/A
2N/A#define FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG) \
2N/A { \
2N/A field_sequenceof_len, \
2N/A OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \
2N/A OFFOF(STYPE, LENFIELD, aux_typedefname_##LENTYPE), \
2N/A TAG, -1, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENTYPE \
2N/A }
2N/A#define FIELDOF_SEQOF_INT32(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \
2N/A FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,int32,TAG)
2N/A
2N/Astruct seq_info {
2N/A /*
2N/A * If present, returns a bitmask indicating which fields are
2N/A * present. See the "opt" field in struct field_info.
2N/A */
2N/A unsigned int (*optional)(const void *);
2N/A /* Indicates an array of sequence field descriptors. */
2N/A const struct field_info *fields;
2N/A size_t n_fields;
2N/A /* Missing: Extensibility handling. (New field type?) */
2N/A};
2N/A
2N/Aextern krb5_error_code
2N/Akrb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
2N/A const struct atype_info *a);
2N/A
2N/A#define MAKE_FULL_ENCODER(FNAME, DESC) \
2N/A krb5_error_code FNAME(const aux_typedefname_##DESC *rep, \
2N/A krb5_data **code) \
2N/A { \
2N/A return krb5int_asn1_do_full_encode(rep, code, \
2N/A &krb5int_asn1type_##DESC); \
2N/A } \
2N/A extern int dummy /* gobble semicolon */
2N/A
2N/A#include <stddef.h>
2N/A/*
2N/A * Ugly hack!
2N/A * Like "offsetof", but with type checking.
2N/A */
2N/A#define WARN_IF_TYPE_MISMATCH(LVALUE, TYPE) \
2N/A (sizeof(0 ? (TYPE *) 0 : &(LVALUE)))
2N/A#define OFFOF(TYPE,FIELD,FTYPE) \
2N/A (offsetof(TYPE, FIELD) \
2N/A + 0 * WARN_IF_TYPE_MISMATCH(((TYPE*)0)->FIELD, FTYPE))
2N/A
2N/A#endif