/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
* src/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>
/*
* Overview
*
* Each of these procedures inserts the encoding of an ASN.1
* primitive in a coding buffer.
*
* Operations
*
* asn1_encode_boolean
* asn1_encode_integer
* asn1_encode_unsigned_integer
* asn1_encode_octetstring
* asn1_encode_generaltime
* asn1_encode_generalstring
* asn1_encode_bitstring
* asn1_encode_oid
*/
asn1_error_code asn1_encode_boolean(asn1buf *buf, asn1_intmax val,
unsigned int *retlen);
asn1_error_code asn1_encode_integer(asn1buf *buf, asn1_intmax val,
unsigned int *retlen);
/*
* requires *buf is allocated
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
asn1_error_code asn1_encode_enumerated(asn1buf *buf, long val,
unsigned int *retlen);
asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
unsigned int *retlen);
/*
* requires *buf is allocated
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len,
const void *val, unsigned int *retlen);
/*
* requires *buf is allocated
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
#define asn1_encode_charstring asn1_encode_octetstring
asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len,
const asn1_octet *val, unsigned int *retlen);
/*
* requires *buf is allocated
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen);
/*
* requires *buf is allocated
* modifies *buf, *retlen
* effects Inserts the encoding of NULL into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len,
const char *val, int *retlen);
/*
* requires *buf is allocated
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
asn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len,
const char *val, int *retlen);
/*
* requires *buf is allocated
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val,
unsigned int *retlen);
/*
* requires *buf is allocated
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
* Note: The encoding of GeneralizedTime is YYYYMMDDhhmmZ
*/
asn1_error_code asn1_encode_generalstring(asn1buf *buf,
unsigned int len, const void *val,
unsigned int *retlen);
/*
* requires *buf is allocated, val has a length of len characters
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
asn1_error_code asn1_encode_bitstring(asn1buf *buf, unsigned int len,
const void *val,
unsigned int *retlen);
/*
* requires *buf is allocated, val has a length of len characters
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
asn1_error_code asn1_encode_opaque(asn1buf *buf, unsigned int len,
const void *val,
unsigned int *retlen);
/*
* requires *buf is allocated, val has a length of len characters
* modifies *buf, *retlen
* effects Inserts the encoding of val into *buf and returns
* the length of the encoding in *retlen.
* Returns ENOMEM to signal an unsuccesful attempt
* to expand the buffer.
*/
/*
* Type descriptor info.
*
* In this context, a "type" is a combination of a C data type
* and an ASN.1 encoding scheme for it. So we would have to define
* different "types" for:
*
* * unsigned char* encoded as octet string
* * char* encoded as octet string
* * char* encoded as generalstring
* * krb5_data encoded as octet string
* * krb5_data encoded as generalstring
* * int32_t encoded as integer
* * unsigned char encoded as integer
*
* Perhaps someday some kind of flags could be defined so that minor
* variations on the C types could be handled via common routines.
*
* The handling of strings is pretty messy. Currently, we have a
* separate kind of encoder function that takes an extra length
* parameter. Perhaps we should just give up on that, always deal
* with just a single location, and handle strings by via encoder
* functions for krb5_data, keyblock, etc.
*
* 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 values above 1, we
* guarantee that zero-initialized storage will be recognized as
* invalid.
*/
atype_min = 1,
/* Encoder function to be called with address of <thing>. */
atype_fn,
/*
* Encoder function to be called with address of <thing> and a
* length (unsigned int).
*/
atype_fn_len,
/*
* Pointer to actual thing to be encoded.
*
* Most of the fields are related only to the C type -- size, how
* to fetch a pointer in a type-safe fashion -- but since the base
* type descriptor encapsulates the encoding as well, different
* encodings for the same C type may require different pointer-to
* types as well.
*
* Must not refer to atype_fn_len.
*/
atype_ptr,
/* Sequence, with pointer to sequence descriptor header. */
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).
*/
atype_nullterm_sequence_of,
atype_nonempty_nullterm_sequence_of,
/*
* Encode this object using a single field descriptor. This may
* mean the atype/field breakdown needs revision....
*
* Main expected uses: Encode realm component of principal as a
* GENERALSTRING. Pluck data and length fields out of a structure
* and encode a counted SEQUENCE OF.
*/
atype_field,
/* Tagged version of another type. */
atype_tagged_thing,
/* Integer types. */
atype_int,
atype_uint,
/* Unused except for bounds checking. */
atype_max
};
/*
* Initialized structures could be a lot smaller if we could use C99
* designated initializers, and a union for all the type-specific
* stuff. Maybe use the hack we use for krb5int_access, where we use
* a run-time initialize if the compiler doesn't support designated
* initializers? That's a lot of work here, though, with so many
* little structures. Maybe if/when these get auto-generated.
*/
struct atype_info {
enum atype_type type;
/* used for sequence-of processing */
unsigned int size;
/* atype_fn */
asn1_error_code (*enc)(asn1buf *, const void *, unsigned int *);
/* atype_fn_len */
asn1_error_code (*enclen)(asn1buf *, unsigned int, const void *,
unsigned int *);
/* atype_ptr, atype_fn_len */
const void *(*loadptr)(const void *);
/* atype_ptr, atype_nullterm_sequence_of */
const struct atype_info *basetype;
/* atype_sequence */
const struct seq_info *seq;
/* atype_field */
const struct field_info *field;
/* atype_tagged_thing */
unsigned int tagval : 8, tagtype : 8;
/* atype_[u]int */
asn1_intmax (*loadint)(const void *);
asn1_uintmax (*loaduint)(const void *);
};
/*
* The various DEF*TYPE macros must:
*
* + Define a type named aux_typedefname_##DESCNAME, for use in any
* types derived from the type being defined.
*
* + Define an atype_info struct named krb5int_asn1type_##DESCNAME.
*
* + 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 for which we must use an explicit encoder function.
* The DEFFNTYPE variant uses a function taking a void*, the
* DEFFNXTYPE form wants a function taking a pointer to the actual C
* type to be encoded; you should use the latter unless you've already
* got the void* function supplied elsewhere.
*
* Of course, we need a single, consistent type for the descriptor
* structure field, so we use the function pointer type that uses
* void*, and create a wrapper function in DEFFNXTYPE. However, in
* all our cases so far, the supplied function is static and not used
* otherwise, so the compiler can merge it with the wrapper function
* if the optimizer is good enough.
*/
#define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN) \
typedef CTYPENAME aux_typedefname_##DESCNAME; \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_fn, sizeof(CTYPENAME), ENCFN, \
}
#define DEFFNXTYPE(DESCNAME, CTYPENAME, ENCFN) \
typedef CTYPENAME aux_typedefname_##DESCNAME; \
static asn1_error_code \
aux_encfn_##DESCNAME(asn1buf *buf, const void *val, \
unsigned int *retlen) \
{ \
return ENCFN(buf, \
(const aux_typedefname_##DESCNAME *)val, \
retlen); \
} \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_fn, sizeof(CTYPENAME), aux_encfn_##DESCNAME, \
}
/*
* XXX The handling of data+length fields really needs reworking.
* A type descriptor probably isn't the right way.
*
* Also, the C type is likely to be one of char*, unsigned char*,
* or (maybe) void*. An enumerator or reference to an external
* function would be more compact.
*
* The supplied encoder function takes as an argument the data pointer
* loaded from the indicated location, not the address of the field.
* This isn't consistent with DEFFN[X]TYPE above, but all of the uses
* of DEFFNLENTYPE are for string encodings, and that's how our
* string-encoding primitives work. So be it.
*/
#ifdef POINTERS_ARE_ALL_THE_SAME
#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN) \
typedef CTYPENAME aux_typedefname_##DESCNAME; \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_fn_len, 0, 0, ENCFN, \
}
#else
#define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN) \
typedef CTYPENAME aux_typedefname_##DESCNAME; \
static const void *loadptr_for_##DESCNAME(const void *pv) \
{ \
const aux_typedefname_##DESCNAME *p = pv; \
return *p; \
} \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_fn_len, 0, 0, ENCFN, \
loadptr_for_##DESCNAME \
}
#endif
/*
* A sequence, defined by the indicated series of fields, and an
* optional function indicating which fields are present.
*/
#define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS, OPT) \
typedef CTYPENAME aux_typedefname_##DESCNAME; \
static const struct seq_info aux_seqinfo_##DESCNAME = { \
OPT, FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0]) \
}; \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_sequence, sizeof(CTYPENAME), 0,0,0,0, \
&aux_seqinfo_##DESCNAME, \
}
/* Integer types. */
#define DEFINTTYPE(DESCNAME, CTYPENAME) \
typedef CTYPENAME aux_typedefname_##DESCNAME; \
static asn1_intmax loadint_##DESCNAME(const void *p) \
{ \
assert(sizeof(CTYPENAME) <= sizeof(asn1_intmax)); \
return *(const aux_typedefname_##DESCNAME *)p; \
} \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_int, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \
loadint_##DESCNAME, 0, \
}
#define DEFUINTTYPE(DESCNAME, CTYPENAME) \
typedef CTYPENAME aux_typedefname_##DESCNAME; \
static asn1_uintmax loaduint_##DESCNAME(const void *p) \
{ \
assert(sizeof(CTYPENAME) <= sizeof(asn1_uintmax)); \
return *(const aux_typedefname_##DESCNAME *)p; \
} \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_uint, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \
0, loaduint_##DESCNAME, \
}
/* Pointers to other types, to be encoded as those other types. */
#ifdef POINTERS_ARE_ALL_THE_SAME
#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \
typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, 0, \
&krb5int_asn1type_##BASEDESCNAME, 0 \
}
#else
#define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \
typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \
static const void * \
loadptr_for_##BASEDESCNAME##_from_##DESCNAME(const void *p) \
{ \
const aux_typedefname_##DESCNAME *inptr = p; \
const aux_typedefname_##BASEDESCNAME *retptr; \
retptr = *inptr; \
return retptr; \
} \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, \
loadptr_for_##BASEDESCNAME##_from_##DESCNAME, \
&krb5int_asn1type_##BASEDESCNAME, 0 \
}
#endif
/*
* 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_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME; \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_nullterm_sequence_of, sizeof(aux_typedefname_##DESCNAME), \
0, 0, \
0 /* loadptr */, \
&krb5int_asn1type_##BASEDESCNAME, 0 \
}
#define DEFNONEMPTYNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \
typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME; \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_nonempty_nullterm_sequence_of, \
sizeof(aux_typedefname_##DESCNAME), \
0, 0, \
0 /* loadptr */, \
&krb5int_asn1type_##BASEDESCNAME, 0 \
}
/*
* Encode a thing (probably sub-fields within the structure) as a
* single object.
*/
#define DEFFIELDTYPE(DESCNAME, CTYPENAME, FIELDINFO) \
typedef CTYPENAME aux_typedefname_##DESCNAME; \
static const struct field_info aux_fieldinfo_##DESCNAME = FIELDINFO; \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_field, sizeof(CTYPENAME), 0, 0, 0, 0, 0, \
&aux_fieldinfo_##DESCNAME \
}
/* Objects with an APPLICATION tag added. */
#define DEFAPPTAGGEDTYPE(DESCNAME, TAG, BASEDESC) \
typedef aux_typedefname_##BASEDESC aux_typedefname_##DESCNAME; \
const struct atype_info krb5int_asn1type_##DESCNAME = { \
atype_tagged_thing, sizeof(aux_typedefname_##DESCNAME), \
0, 0, 0, &krb5int_asn1type_##BASEDESC, 0, 0, TAG, APPLICATION \
}
/*
* 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_typedefname_##DESCNAME; \
extern const struct atype_info krb5int_asn1type_##DESCNAME
/*
* Create a partial-encoding function by the indicated name, for the
* indicated type. Should only be needed until we've converted all of
* the encoders, then everything should use descriptor tables.
*/
extern asn1_error_code
krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
const struct atype_info *a, unsigned int *retlen);
#define MAKE_ENCFN(FNAME,DESC) \
static asn1_error_code FNAME(asn1buf *buf, \
const aux_typedefname_##DESC *val, \
unsigned int *retlen) \
{ \
return krb5int_asn1_encode_a_thing(buf, val, \
&krb5int_asn1type_##DESC, \
retlen); \
} \
extern int dummy /* gobble semicolon */
/*
* Sequence field descriptor.
*
* Currently we assume everything is a single object with a type
* descriptor, and then we bolt on some ugliness on the side for
* handling strings with length fields.
*
* Anything with "interesting" encoding handling, like a sequence-of
* or a pointer to the actual value to encode, is handled via opaque
* types with their own encoder functions. Most of that should
* eventually change.
*/
enum field_type {
/* Unused except for range checking. */
field_min = 1,
/* Field ATYPE describes processing of field at DATAOFF. */
field_normal,
/*
* Encode an "immediate" integer value stored in DATAOFF, with no
* reference to the data structure.
*/
field_immediate,
/*
* Encode some kind of string field encoded with pointer and
* length. (A GENERALSTRING represented as a null-terminated C
* string would be handled as field_normal.)
*/
field_string,
/*
* LENOFF indicates a value describing the length of the array at
* DATAOFF, encoded as a sequence-of with the element type
* described by ATYPE.
*/
field_sequenceof_len,
/* Unused except for range checking. */
field_max
};
/* To do: Consider using bitfields. */
struct field_info {
/* Type of the field. */
unsigned int /* enum field_type */ ftype : 3;
/*
* Use of DATAOFF and LENOFF are described by the value in FTYPE.
* Generally DATAOFF will be the offset from the supplied pointer
* at which we find the object to be encoded.
*/
unsigned int dataoff : 9, lenoff : 9;
/*
* If TAG is non-negative, a context tag with that value is added
* to the encoding of the thing. (XXX This would encode more
* compactly as an unsigned bitfield value tagnum+1, with 0=no
* tag.) The tag is omitted for optional fields that are not
* present.
*
* It's a bit illogical to combine the tag and other field info,
* since really a sequence field could have zero or several
* context tags, and of course a tag could be used elsewhere. But
* the normal mode in the Kerberos ASN.1 description is to use one
* context tag on each sequence field, so for now let's address
* that case primarily and work around the other cases (thus tag<0
* means skip tagging).
*/
signed int tag : 5;
/*
* If OPT is non-negative and the sequence header structure has a
* function pointer describing which fields are present, OPT is
* the bit position indicating whether the currently-described
* element is present. (XXX Similar encoding issue.)
*
* Note: Most of the time, I'm using the same number here as for
* the context tag. This is just because it's easier for me to
* keep track while working on the code by hand. The *only*
* meaningful correlation is of this value and the bits set by the
* "optional" function when examining the data structure.
*/
signed int opt : 5;
/*
* For some values of FTYPE, this describes the type of the
* object(s) to be encoded.
*/
const struct atype_info *atype;
/*
* We use different types for "length" fields in different places.
* So we need a good way to retrieve the various kinds of lengths
* in a compatible way. This may be a string length, or the
* length of an array of objects to encode in a SEQUENCE OF.
*
* In case the field is signed and negative, or larger than
* size_t, return SIZE_MAX as an error indication. We'll assume
* for now that we'll never have 4G-1 (or 2**64-1, or on tiny
* systems, 65535) sized values. On most if not all systems we
* care about, SIZE_MAX is equivalent to "all of addressable
* memory" minus one byte. That wouldn't leave enough extra room
* for the structure we're encoding, so it's pretty safe to assume
* SIZE_MAX won't legitimately come up on those systems.
*
* If this code gets ported to a segmented architecture or other
* system where it might be possible... figure it out then.
*/
const struct atype_info *lentype;
};
/*
* Normal or optional sequence fields at a particular offset, encoded
* as indicated by the listed DESCRiptor.
*/
#define FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,OPT) \
{ \
field_normal, OFFOF(TYPE, FIELDNAME, aux_typedefname_##DESCR), \
0, TAG, OPT, &krb5int_asn1type_##DESCR \
}
#define FIELDOF_NORM(TYPE,DESCR,FIELDNAME,TAG) \
FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,-1)
/*
* If encoding a subset of the fields of the current structure (for
* example, a flat structure describing data that gets encoded as a
* sequence containing one or more sequences), use ENCODEAS, no struct
* field name(s), and the indicated type descriptor must support the
* current struct type.
*/
#define FIELDOF_ENCODEAS(TYPE,DESCR,TAG) \
FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,-1)
#define FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,OPT) \
{ \
field_normal, \
0 * sizeof(0 ? (TYPE *)0 : (aux_typedefname_##DESCR *) 0), \
0, TAG, OPT, &krb5int_asn1type_##DESCR \
}
/*
* Reinterpret some subset of the structure itself as something
* else.
*/
#define FIELD_SELF(DESCR, TAG) \
{ field_normal, 0, 0, TAG, -1, &krb5int_asn1type_##DESCR }
#define FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,OPT) \
{ \
field_string, \
OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \
OFFOF(STYPE, LENFIELD, aux_typedefname_##LENDESC), \
TAG, OPT, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENDESC \
}
#define FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,OPT) \
FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,uint,LENFIELD,TAG,OPT)
#define FIELDOF_STRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG) \
FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,-1)
#define FIELDOF_STRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \
FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,-1)
#define FIELD_INT_IMM(VALUE,TAG) \
{ field_immediate, VALUE, 0, TAG, -1, 0, }
#define FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG) \
{ \
field_sequenceof_len, \
OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \
OFFOF(STYPE, LENFIELD, aux_typedefname_##LENTYPE), \
TAG, -1, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENTYPE \
}
#define FIELDOF_SEQOF_INT32(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \
FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,int32,TAG)
struct seq_info {
/*
* If present, returns a bitmask indicating which fields are
* present. See the "opt" field in struct field_info.
*/
unsigned int (*optional)(const void *);
/* Indicates an array of sequence field descriptors. */
const struct field_info *fields;
size_t n_fields;
/* Missing: Extensibility handling. (New field type?) */
};
extern krb5_error_code
krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
const struct atype_info *a);
#define MAKE_FULL_ENCODER(FNAME, DESC) \
krb5_error_code FNAME(const aux_typedefname_##DESC *rep, \
krb5_data **code) \
{ \
return krb5int_asn1_do_full_encode(rep, code, \
&krb5int_asn1type_##DESC); \
} \
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