/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
*
* 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
*/
unsigned int *retlen);
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.
*/
unsigned int *retlen);
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.
*/
/*
* 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.
*/
/*
* 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.
*/
/*
* 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.
*/
/*
* 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.
*/
/*
* 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.
*/
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
*/
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.
*/
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.
*/
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.
*/
/* Encoder function to be called with address of <thing>. */
/*
* Encoder function to be called with address of <thing> and a
* length (unsigned int).
*/
/*
* 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.
*/
/* Sequence, with pointer to sequence descriptor header. */
/*
* 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).
*/
/*
* Encode this object using a single field descriptor. This may
*
* 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.
*/
/* Tagged version of another type. */
/* Integer types. */
/* Unused except for bounds checking. */
};
/*
* 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
*/
struct atype_info {
/* used for sequence-of processing */
unsigned int size;
/* atype_fn */
/* atype_fn_len */
unsigned int *);
/* atype_ptr, atype_fn_len */
const void *(*loadptr)(const void *);
/* atype_ptr, atype_nullterm_sequence_of */
/* atype_sequence */
/* atype_field */
/* atype_tagged_thing */
/* atype_[u]int */
};
/*
* 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.
*/
}
static asn1_error_code \
unsigned int *retlen) \
{ \
retlen); \
} \
}
/*
* 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
atype_fn_len, 0, 0, ENCFN, \
}
#else
{ \
return *p; \
} \
atype_fn_len, 0, 0, ENCFN, \
}
#endif
/*
* A sequence, defined by the indicated series of fields, and an
* optional function indicating which fields are present.
*/
}; \
atype_sequence, sizeof(CTYPENAME), 0,0,0,0, \
&aux_seqinfo_##DESCNAME, \
}
/* Integer types. */
{ \
return *(const aux_typedefname_##DESCNAME *)p; \
} \
}
{ \
return *(const aux_typedefname_##DESCNAME *)p; \
} \
atype_uint, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \
}
/* Pointers to other types, to be encoded as those other types. */
#ifdef POINTERS_ARE_ALL_THE_SAME
&krb5int_asn1type_##BASEDESCNAME, 0 \
}
#else
static const void * \
{ \
return retptr; \
} \
&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.
*/
0, 0, \
0 /* loadptr */, \
&krb5int_asn1type_##BASEDESCNAME, 0 \
}
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.
*/
atype_field, sizeof(CTYPENAME), 0, 0, 0, 0, 0, \
}
/* Objects with an APPLICATION tag added. */
}
/*
* 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.)
*/
/*
* 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
const struct atype_info *a, unsigned int *retlen);
unsigned int *retlen) \
{ \
&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 ATYPE describes processing of field at DATAOFF. */
/*
* Encode an "immediate" integer value stored in DATAOFF, with no
* reference to the data structure.
*/
/*
* 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.)
*/
/*
* LENOFF indicates a value describing the length of the array at
* DATAOFF, encoded as a sequence-of with the element type
* described by ATYPE.
*/
/* Unused except for range checking. */
};
/* To do: Consider using bitfields. */
struct field_info {
/* Type of the field. */
/*
* 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.
*/
/*
* 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).
*/
/*
* 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.
*/
/*
* For some values of FTYPE, this describes the type of the
* object(s) to be encoded.
*/
/*
* 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.
*/
};
/*
* Normal or optional sequence fields at a particular offset, encoded
* as indicated by the listed DESCRiptor.
*/
{ \
}
/*
* 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.
*/
{ \
field_normal, \
}
/*
* Reinterpret some subset of the structure itself as something
* else.
*/
{ \
field_string, \
}
{ \
}
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. */
/* Missing: Extensibility handling. (New field type?) */
};
extern krb5_error_code
const struct atype_info *a);
{ \
&krb5int_asn1type_##DESC); \
} \
extern int dummy /* gobble semicolon */
#include <stddef.h>
/*
* Ugly hack!
* Like "offsetof", but with type checking.
*/
#endif