/* -*- 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 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 */ #define MAKE_CODEC(TYPENAME, DESC) \ MAKE_ENCODER(encode_##TYPENAME, DESC); \ MAKE_DECODER(decode_##TYPENAME, DESC) #include /* * 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