1*ba7b222eSGlenn Barry /* -*- mode: c; indent-tabs-mode: nil -*- */ 27c478bd9Sstevel@tonic-gate /* 37c478bd9Sstevel@tonic-gate * src/lib/krb5/asn.1/asn1_encode.h 4*ba7b222eSGlenn Barry * 5*ba7b222eSGlenn Barry * Copyright 1994, 2008 by the Massachusetts Institute of Technology. 67c478bd9Sstevel@tonic-gate * All Rights Reserved. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 97c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 107c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 117c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 12*ba7b222eSGlenn Barry * 137c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 147c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 157c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 167c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 177c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 187c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 197c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 207c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 217c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 227c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 237c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 247c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 257c478bd9Sstevel@tonic-gate * or implied warranty. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #ifndef __ASN1_ENCODE_H__ 297c478bd9Sstevel@tonic-gate #define __ASN1_ENCODE_H__ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include "k5-int.h" 327c478bd9Sstevel@tonic-gate #include "krbasn1.h" 337c478bd9Sstevel@tonic-gate #include "asn1buf.h" 347c478bd9Sstevel@tonic-gate #include <time.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate /* 377c478bd9Sstevel@tonic-gate Overview 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate Each of these procedures inserts the encoding of an ASN.1 407c478bd9Sstevel@tonic-gate primitive in a coding buffer. 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate Operations 437c478bd9Sstevel@tonic-gate 44*ba7b222eSGlenn Barry asn1_encode_boolean 457c478bd9Sstevel@tonic-gate asn1_encode_integer 46*ba7b222eSGlenn Barry asn1_encode_unsigned_integer 477c478bd9Sstevel@tonic-gate asn1_encode_octetstring 487c478bd9Sstevel@tonic-gate asn1_encode_generaltime 497c478bd9Sstevel@tonic-gate asn1_encode_generalstring 50*ba7b222eSGlenn Barry asn1_encode_bitstring 51*ba7b222eSGlenn Barry asn1_encode_oid 527c478bd9Sstevel@tonic-gate */ 537c478bd9Sstevel@tonic-gate 54*ba7b222eSGlenn Barry asn1_error_code asn1_encode_boolean 55*ba7b222eSGlenn Barry (asn1buf *buf, asn1_intmax val, unsigned int *retlen); 567c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_integer 57*ba7b222eSGlenn Barry (asn1buf *buf, asn1_intmax val, unsigned int *retlen); 587c478bd9Sstevel@tonic-gate /* requires *buf is allocated 597c478bd9Sstevel@tonic-gate modifies *buf, *retlen 60*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 617c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 627c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 637c478bd9Sstevel@tonic-gate to expand the buffer. */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_enumerated 66*ba7b222eSGlenn Barry (asn1buf *buf, long val, unsigned int *retlen); 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_unsigned_integer 69*ba7b222eSGlenn Barry (asn1buf *buf, asn1_uintmax val, 70*ba7b222eSGlenn Barry unsigned int *retlen); 717c478bd9Sstevel@tonic-gate /* requires *buf is allocated 727c478bd9Sstevel@tonic-gate modifies *buf, *retlen 73*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 747c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 757c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 767c478bd9Sstevel@tonic-gate to expand the buffer. */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_octetstring 79*ba7b222eSGlenn Barry (asn1buf *buf, 80*ba7b222eSGlenn Barry unsigned int len, const void *val, 81*ba7b222eSGlenn Barry unsigned int *retlen); 827c478bd9Sstevel@tonic-gate /* requires *buf is allocated 837c478bd9Sstevel@tonic-gate modifies *buf, *retlen 84*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 857c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 867c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 877c478bd9Sstevel@tonic-gate to expand the buffer. */ 88*ba7b222eSGlenn Barry #define asn1_encode_charstring asn1_encode_octetstring 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_oid 91*ba7b222eSGlenn Barry (asn1buf *buf, 92*ba7b222eSGlenn Barry unsigned int len, const asn1_octet *val, 93*ba7b222eSGlenn Barry unsigned int *retlen); 947c478bd9Sstevel@tonic-gate /* requires *buf is allocated 957c478bd9Sstevel@tonic-gate modifies *buf, *retlen 96*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 977c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 987c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 997c478bd9Sstevel@tonic-gate to expand the buffer. */ 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_null 102*ba7b222eSGlenn Barry (asn1buf *buf, int *retlen); 1037c478bd9Sstevel@tonic-gate /* requires *buf is allocated 1047c478bd9Sstevel@tonic-gate modifies *buf, *retlen 105*ba7b222eSGlenn Barry effects Inserts the encoding of NULL into *buf and returns 1067c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 1077c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 1087c478bd9Sstevel@tonic-gate to expand the buffer. */ 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_printablestring 111*ba7b222eSGlenn Barry (asn1buf *buf, 112*ba7b222eSGlenn Barry unsigned int len, const char *val, 113*ba7b222eSGlenn Barry int *retlen); 1147c478bd9Sstevel@tonic-gate /* requires *buf is allocated 1157c478bd9Sstevel@tonic-gate modifies *buf, *retlen 116*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 1177c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 1187c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 1197c478bd9Sstevel@tonic-gate to expand the buffer. */ 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_ia5string 122*ba7b222eSGlenn Barry (asn1buf *buf, 123*ba7b222eSGlenn Barry unsigned int len, const char *val, 124*ba7b222eSGlenn Barry int *retlen); 1257c478bd9Sstevel@tonic-gate /* requires *buf is allocated 1267c478bd9Sstevel@tonic-gate modifies *buf, *retlen 127*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 1287c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 1297c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 1307c478bd9Sstevel@tonic-gate to expand the buffer. */ 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_generaltime 133*ba7b222eSGlenn Barry (asn1buf *buf, time_t val, unsigned int *retlen); 1347c478bd9Sstevel@tonic-gate /* requires *buf is allocated 1357c478bd9Sstevel@tonic-gate modifies *buf, *retlen 1367c478bd9Sstevel@tonic-gate effects Inserts the encoding of val into *buf and returns 1377c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 1387c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 1397c478bd9Sstevel@tonic-gate to expand the buffer. 1407c478bd9Sstevel@tonic-gate Note: The encoding of GeneralizedTime is YYYYMMDDhhmmZ */ 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_generalstring 143*ba7b222eSGlenn Barry (asn1buf *buf, 144*ba7b222eSGlenn Barry unsigned int len, const void *val, 145*ba7b222eSGlenn Barry unsigned int *retlen); 146*ba7b222eSGlenn Barry /* requires *buf is allocated, val has a length of len characters 147*ba7b222eSGlenn Barry modifies *buf, *retlen 148*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 149*ba7b222eSGlenn Barry the length of the encoding in *retlen. 150*ba7b222eSGlenn Barry Returns ENOMEM to signal an unsuccesful attempt 151*ba7b222eSGlenn Barry to expand the buffer. */ 152*ba7b222eSGlenn Barry 153*ba7b222eSGlenn Barry asn1_error_code asn1_encode_bitstring(asn1buf *buf, unsigned int len, 154*ba7b222eSGlenn Barry const void *val, 155*ba7b222eSGlenn Barry unsigned int *retlen); 156*ba7b222eSGlenn Barry /* requires *buf is allocated, val has a length of len characters 157*ba7b222eSGlenn Barry modifies *buf, *retlen 158*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 159*ba7b222eSGlenn Barry the length of the encoding in *retlen. 160*ba7b222eSGlenn Barry Returns ENOMEM to signal an unsuccesful attempt 161*ba7b222eSGlenn Barry to expand the buffer. */ 162*ba7b222eSGlenn Barry 163*ba7b222eSGlenn Barry asn1_error_code asn1_encode_opaque(asn1buf *buf, unsigned int len, 164*ba7b222eSGlenn Barry const void *val, 165*ba7b222eSGlenn Barry unsigned int *retlen); 1667c478bd9Sstevel@tonic-gate /* requires *buf is allocated, val has a length of len characters 1677c478bd9Sstevel@tonic-gate modifies *buf, *retlen 168*ba7b222eSGlenn Barry effects Inserts the encoding of val into *buf and returns 1697c478bd9Sstevel@tonic-gate the length of the encoding in *retlen. 1707c478bd9Sstevel@tonic-gate Returns ENOMEM to signal an unsuccesful attempt 1717c478bd9Sstevel@tonic-gate to expand the buffer. */ 1727c478bd9Sstevel@tonic-gate 173*ba7b222eSGlenn Barry /* Type descriptor info. 174*ba7b222eSGlenn Barry 175*ba7b222eSGlenn Barry In this context, a "type" is a combination of a C data type 176*ba7b222eSGlenn Barry and an ASN.1 encoding scheme for it. So we would have to define 177*ba7b222eSGlenn Barry different "types" for: 178*ba7b222eSGlenn Barry 179*ba7b222eSGlenn Barry * unsigned char* encoded as octet string 180*ba7b222eSGlenn Barry * char* encoded as octet string 181*ba7b222eSGlenn Barry * char* encoded as generalstring 182*ba7b222eSGlenn Barry * krb5_data encoded as octet string 183*ba7b222eSGlenn Barry * krb5_data encoded as generalstring 184*ba7b222eSGlenn Barry * int32_t encoded as integer 185*ba7b222eSGlenn Barry * unsigned char encoded as integer 186*ba7b222eSGlenn Barry 187*ba7b222eSGlenn Barry Perhaps someday some kind of flags could be defined so that minor 188*ba7b222eSGlenn Barry variations on the C types could be handled via common routines. 189*ba7b222eSGlenn Barry 190*ba7b222eSGlenn Barry The handling of strings is pretty messy. Currently, we have a 191*ba7b222eSGlenn Barry separate kind of encoder function that takes an extra length 192*ba7b222eSGlenn Barry parameter. Perhaps we should just give up on that, always deal 193*ba7b222eSGlenn Barry with just a single location, and handle strings by via encoder 194*ba7b222eSGlenn Barry functions for krb5_data, keyblock, etc. 195*ba7b222eSGlenn Barry 196*ba7b222eSGlenn Barry We wind up with a lot of load-time relocations being done, which is 197*ba7b222eSGlenn Barry a bit annoying. Be careful about "fixing" that at the cost of too 198*ba7b222eSGlenn Barry much run-time performance. It might work to have a master "module" 199*ba7b222eSGlenn Barry descriptor with pointers to various arrays (type descriptors, 200*ba7b222eSGlenn Barry strings, field descriptors, functions) most of which don't need 201*ba7b222eSGlenn Barry relocation themselves, and replace most of the pointers with table 202*ba7b222eSGlenn Barry indices. 203*ba7b222eSGlenn Barry 204*ba7b222eSGlenn Barry It's a work in progress. */ 205*ba7b222eSGlenn Barry 206*ba7b222eSGlenn Barry enum atype_type { 207*ba7b222eSGlenn Barry /* For bounds checking only. By starting with values above 1, we 208*ba7b222eSGlenn Barry guarantee that zero-initialized storage will be recognized as 209*ba7b222eSGlenn Barry invalid. */ 210*ba7b222eSGlenn Barry atype_min = 1, 211*ba7b222eSGlenn Barry /* Encoder function to be called with address of <thing>. */ 212*ba7b222eSGlenn Barry atype_fn, 213*ba7b222eSGlenn Barry /* Encoder function to be called with address of <thing> and a 214*ba7b222eSGlenn Barry length (unsigned int). */ 215*ba7b222eSGlenn Barry atype_fn_len, 216*ba7b222eSGlenn Barry /* Pointer to actual thing to be encoded. 217*ba7b222eSGlenn Barry 218*ba7b222eSGlenn Barry Most of the fields are related only to the C type -- size, how 219*ba7b222eSGlenn Barry to fetch a pointer in a type-safe fashion -- but since the base 220*ba7b222eSGlenn Barry type descriptor encapsulates the encoding as well, different 221*ba7b222eSGlenn Barry encodings for the same C type may require different pointer-to 222*ba7b222eSGlenn Barry types as well. 223*ba7b222eSGlenn Barry 224*ba7b222eSGlenn Barry Must not refer to atype_fn_len. */ 225*ba7b222eSGlenn Barry atype_ptr, 226*ba7b222eSGlenn Barry /* Sequence, with pointer to sequence descriptor header. */ 227*ba7b222eSGlenn Barry atype_sequence, 228*ba7b222eSGlenn Barry /* Sequence-of, with pointer to base type descriptor, represented 229*ba7b222eSGlenn Barry as a null-terminated array of pointers (and thus the "base" 230*ba7b222eSGlenn Barry type descriptor is actually an atype_ptr node). */ 231*ba7b222eSGlenn Barry atype_nullterm_sequence_of, 232*ba7b222eSGlenn Barry atype_nonempty_nullterm_sequence_of, 233*ba7b222eSGlenn Barry /* Encode this object using a single field descriptor. This may 234*ba7b222eSGlenn Barry mean the atype/field breakdown needs revision.... 235*ba7b222eSGlenn Barry 236*ba7b222eSGlenn Barry Main expected uses: Encode realm component of principal as a 237*ba7b222eSGlenn Barry GENERALSTRING. Pluck data and length fields out of a structure 238*ba7b222eSGlenn Barry and encode a counted SEQUENCE OF. */ 239*ba7b222eSGlenn Barry atype_field, 240*ba7b222eSGlenn Barry /* Tagged version of another type. */ 241*ba7b222eSGlenn Barry atype_tagged_thing, 242*ba7b222eSGlenn Barry /* Integer types. */ 243*ba7b222eSGlenn Barry atype_int, 244*ba7b222eSGlenn Barry atype_uint, 245*ba7b222eSGlenn Barry /* Unused except for bounds checking. */ 246*ba7b222eSGlenn Barry atype_max 247*ba7b222eSGlenn Barry }; 248*ba7b222eSGlenn Barry 249*ba7b222eSGlenn Barry /* Initialized structures could be a lot smaller if we could use C99 250*ba7b222eSGlenn Barry designated initializers, and a union for all the type-specific 251*ba7b222eSGlenn Barry stuff. Maybe use the hack we use for krb5int_access, where we use 252*ba7b222eSGlenn Barry a run-time initialize if the compiler doesn't support designated 253*ba7b222eSGlenn Barry initializers? That's a lot of work here, though, with so many 254*ba7b222eSGlenn Barry little structures. Maybe if/when these get auto-generated. */ 255*ba7b222eSGlenn Barry struct atype_info { 256*ba7b222eSGlenn Barry enum atype_type type; 257*ba7b222eSGlenn Barry /* used for sequence-of processing */ 258*ba7b222eSGlenn Barry unsigned int size; 259*ba7b222eSGlenn Barry /* atype_fn */ 260*ba7b222eSGlenn Barry asn1_error_code (*enc)(asn1buf *, const void *, unsigned int *); 261*ba7b222eSGlenn Barry /* atype_fn_len */ 262*ba7b222eSGlenn Barry asn1_error_code (*enclen)(asn1buf *, unsigned int, const void *, 263*ba7b222eSGlenn Barry unsigned int *); 264*ba7b222eSGlenn Barry /* atype_ptr, atype_fn_len */ 265*ba7b222eSGlenn Barry const void *(*loadptr)(const void *); 266*ba7b222eSGlenn Barry /* atype_ptr, atype_nullterm_sequence_of */ 267*ba7b222eSGlenn Barry const struct atype_info *basetype; 268*ba7b222eSGlenn Barry /* atype_sequence */ 269*ba7b222eSGlenn Barry const struct seq_info *seq; 270*ba7b222eSGlenn Barry /* atype_field */ 271*ba7b222eSGlenn Barry const struct field_info *field; 272*ba7b222eSGlenn Barry /* atype_tagged_thing */ 273*ba7b222eSGlenn Barry unsigned int tagval : 8, tagtype : 8; 274*ba7b222eSGlenn Barry /* atype_[u]int */ 275*ba7b222eSGlenn Barry asn1_intmax (*loadint)(const void *); 276*ba7b222eSGlenn Barry asn1_uintmax (*loaduint)(const void *); 277*ba7b222eSGlenn Barry }; 278*ba7b222eSGlenn Barry 279*ba7b222eSGlenn Barry /* The various DEF*TYPE macros must: 280*ba7b222eSGlenn Barry 281*ba7b222eSGlenn Barry + Define a type named aux_typedefname_##DESCNAME, for use in any 282*ba7b222eSGlenn Barry types derived from the type being defined. 283*ba7b222eSGlenn Barry 284*ba7b222eSGlenn Barry + Define an atype_info struct named krb5int_asn1type_##DESCNAME. 285*ba7b222eSGlenn Barry 286*ba7b222eSGlenn Barry + Define any extra stuff needed in the type descriptor, like 287*ba7b222eSGlenn Barry pointer-load functions. 288*ba7b222eSGlenn Barry 289*ba7b222eSGlenn Barry + Accept a following semicolon syntactically, to keep Emacs parsing 290*ba7b222eSGlenn Barry (and indentation calculating) code happy. 291*ba7b222eSGlenn Barry 292*ba7b222eSGlenn Barry Nothing else should directly define the atype_info structures. */ 293*ba7b222eSGlenn Barry 294*ba7b222eSGlenn Barry /* Define a type for which we must use an explicit encoder function. 295*ba7b222eSGlenn Barry The DEFFNTYPE variant uses a function taking a void*, the 296*ba7b222eSGlenn Barry DEFFNXTYPE form wants a function taking a pointer to the actual C 297*ba7b222eSGlenn Barry type to be encoded; you should use the latter unless you've already 298*ba7b222eSGlenn Barry got the void* function supplied elsewhere. 299*ba7b222eSGlenn Barry 300*ba7b222eSGlenn Barry Of course, we need a single, consistent type for the descriptor 301*ba7b222eSGlenn Barry structure field, so we use the function pointer type that uses 302*ba7b222eSGlenn Barry void*, and create a wrapper function in DEFFNXTYPE. However, in 303*ba7b222eSGlenn Barry all our cases so far, the supplied function is static and not used 304*ba7b222eSGlenn Barry otherwise, so the compiler can merge it with the wrapper function 305*ba7b222eSGlenn Barry if the optimizer is good enough. */ 306*ba7b222eSGlenn Barry #define DEFFNTYPE(DESCNAME, CTYPENAME, ENCFN) \ 307*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 308*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 309*ba7b222eSGlenn Barry atype_fn, sizeof(CTYPENAME), ENCFN, \ 310*ba7b222eSGlenn Barry } 311*ba7b222eSGlenn Barry #define DEFFNXTYPE(DESCNAME, CTYPENAME, ENCFN) \ 312*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 313*ba7b222eSGlenn Barry static asn1_error_code \ 314*ba7b222eSGlenn Barry aux_encfn_##DESCNAME(asn1buf *buf, const void *val, \ 315*ba7b222eSGlenn Barry unsigned int *retlen) \ 316*ba7b222eSGlenn Barry { \ 317*ba7b222eSGlenn Barry return ENCFN(buf, \ 318*ba7b222eSGlenn Barry (const aux_typedefname_##DESCNAME *)val, \ 319*ba7b222eSGlenn Barry retlen); \ 320*ba7b222eSGlenn Barry } \ 321*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 322*ba7b222eSGlenn Barry atype_fn, sizeof(CTYPENAME), aux_encfn_##DESCNAME, \ 323*ba7b222eSGlenn Barry } 324*ba7b222eSGlenn Barry /* XXX The handling of data+length fields really needs reworking. 325*ba7b222eSGlenn Barry A type descriptor probably isn't the right way. 326*ba7b222eSGlenn Barry 327*ba7b222eSGlenn Barry Also, the C type is likely to be one of char*, unsigned char*, 328*ba7b222eSGlenn Barry or (maybe) void*. An enumerator or reference to an external 329*ba7b222eSGlenn Barry function would be more compact. 330*ba7b222eSGlenn Barry 331*ba7b222eSGlenn Barry The supplied encoder function takes as an argument the data pointer 332*ba7b222eSGlenn Barry loaded from the indicated location, not the address of the field. 333*ba7b222eSGlenn Barry This isn't consistent with DEFFN[X]TYPE above, but all of the uses 334*ba7b222eSGlenn Barry of DEFFNLENTYPE are for string encodings, and that's how our 335*ba7b222eSGlenn Barry string-encoding primitives work. So be it. */ 336*ba7b222eSGlenn Barry #ifdef POINTERS_ARE_ALL_THE_SAME 337*ba7b222eSGlenn Barry #define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN) \ 338*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 339*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 340*ba7b222eSGlenn Barry atype_fn_len, 0, 0, ENCFN, \ 341*ba7b222eSGlenn Barry } 342*ba7b222eSGlenn Barry #else 343*ba7b222eSGlenn Barry #define DEFFNLENTYPE(DESCNAME, CTYPENAME, ENCFN) \ 344*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 345*ba7b222eSGlenn Barry static const void *loadptr_for_##DESCNAME(const void *pv) \ 346*ba7b222eSGlenn Barry { \ 347*ba7b222eSGlenn Barry const aux_typedefname_##DESCNAME *p = pv; \ 348*ba7b222eSGlenn Barry return *p; \ 349*ba7b222eSGlenn Barry } \ 350*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 351*ba7b222eSGlenn Barry atype_fn_len, 0, 0, ENCFN, \ 352*ba7b222eSGlenn Barry loadptr_for_##DESCNAME \ 353*ba7b222eSGlenn Barry } 354*ba7b222eSGlenn Barry #endif 355*ba7b222eSGlenn Barry /* A sequence, defined by the indicated series of fields, and an 356*ba7b222eSGlenn Barry optional function indicating which fields are present. */ 357*ba7b222eSGlenn Barry #define DEFSEQTYPE(DESCNAME, CTYPENAME, FIELDS, OPT) \ 358*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 359*ba7b222eSGlenn Barry static const struct seq_info aux_seqinfo_##DESCNAME = { \ 360*ba7b222eSGlenn Barry OPT, FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0]) \ 361*ba7b222eSGlenn Barry }; \ 362*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 363*ba7b222eSGlenn Barry atype_sequence, sizeof(CTYPENAME), 0,0,0,0, \ 364*ba7b222eSGlenn Barry &aux_seqinfo_##DESCNAME, \ 365*ba7b222eSGlenn Barry } 366*ba7b222eSGlenn Barry /* Integer types. */ 367*ba7b222eSGlenn Barry #define DEFINTTYPE(DESCNAME, CTYPENAME) \ 368*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 369*ba7b222eSGlenn Barry static asn1_intmax loadint_##DESCNAME(const void *p) \ 370*ba7b222eSGlenn Barry { \ 371*ba7b222eSGlenn Barry assert(sizeof(CTYPENAME) <= sizeof(asn1_intmax)); \ 372*ba7b222eSGlenn Barry return *(const aux_typedefname_##DESCNAME *)p; \ 373*ba7b222eSGlenn Barry } \ 374*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 375*ba7b222eSGlenn Barry atype_int, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \ 376*ba7b222eSGlenn Barry loadint_##DESCNAME, 0, \ 377*ba7b222eSGlenn Barry } 378*ba7b222eSGlenn Barry #define DEFUINTTYPE(DESCNAME, CTYPENAME) \ 379*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 380*ba7b222eSGlenn Barry static asn1_uintmax loaduint_##DESCNAME(const void *p) \ 381*ba7b222eSGlenn Barry { \ 382*ba7b222eSGlenn Barry assert(sizeof(CTYPENAME) <= sizeof(asn1_uintmax)); \ 383*ba7b222eSGlenn Barry return *(const aux_typedefname_##DESCNAME *)p; \ 384*ba7b222eSGlenn Barry } \ 385*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 386*ba7b222eSGlenn Barry atype_uint, sizeof(CTYPENAME), 0, 0, 0, 0, 0, 0, 0, 0, \ 387*ba7b222eSGlenn Barry 0, loaduint_##DESCNAME, \ 388*ba7b222eSGlenn Barry } 389*ba7b222eSGlenn Barry /* Pointers to other types, to be encoded as those other types. */ 390*ba7b222eSGlenn Barry #ifdef POINTERS_ARE_ALL_THE_SAME 391*ba7b222eSGlenn Barry #define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \ 392*ba7b222eSGlenn Barry typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \ 393*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 394*ba7b222eSGlenn Barry atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, 0, \ 395*ba7b222eSGlenn Barry &krb5int_asn1type_##BASEDESCNAME, 0 \ 396*ba7b222eSGlenn Barry } 397*ba7b222eSGlenn Barry #else 398*ba7b222eSGlenn Barry #define DEFPTRTYPE(DESCNAME,BASEDESCNAME) \ 399*ba7b222eSGlenn Barry typedef aux_typedefname_##BASEDESCNAME * aux_typedefname_##DESCNAME; \ 400*ba7b222eSGlenn Barry static const void * \ 401*ba7b222eSGlenn Barry loadptr_for_##BASEDESCNAME##_from_##DESCNAME(const void *p) \ 402*ba7b222eSGlenn Barry { \ 403*ba7b222eSGlenn Barry const aux_typedefname_##DESCNAME *inptr = p; \ 404*ba7b222eSGlenn Barry const aux_typedefname_##BASEDESCNAME *retptr; \ 405*ba7b222eSGlenn Barry retptr = *inptr; \ 406*ba7b222eSGlenn Barry return retptr; \ 407*ba7b222eSGlenn Barry } \ 408*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 409*ba7b222eSGlenn Barry atype_ptr, sizeof(aux_typedefname_##DESCNAME), 0, 0, \ 410*ba7b222eSGlenn Barry loadptr_for_##BASEDESCNAME##_from_##DESCNAME, \ 411*ba7b222eSGlenn Barry &krb5int_asn1type_##BASEDESCNAME, 0 \ 412*ba7b222eSGlenn Barry } 413*ba7b222eSGlenn Barry #endif 414*ba7b222eSGlenn Barry /* This encodes a pointer-to-pointer-to-thing where the passed-in 415*ba7b222eSGlenn Barry value points to a null-terminated list of pointers to objects to be 416*ba7b222eSGlenn Barry encoded, and encodes a (possibly empty) SEQUENCE OF these objects. 417*ba7b222eSGlenn Barry 418*ba7b222eSGlenn Barry BASEDESCNAME is a descriptor name for the pointer-to-thing 419*ba7b222eSGlenn Barry type. 420*ba7b222eSGlenn Barry 421*ba7b222eSGlenn Barry When dealing with a structure containing a 422*ba7b222eSGlenn Barry pointer-to-pointer-to-thing field, make a DEFPTRTYPE of this type, 423*ba7b222eSGlenn Barry and use that type for the structure field. */ 424*ba7b222eSGlenn Barry #define DEFNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \ 425*ba7b222eSGlenn Barry typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME; \ 426*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 427*ba7b222eSGlenn Barry atype_nullterm_sequence_of, sizeof(aux_typedefname_##DESCNAME), \ 428*ba7b222eSGlenn Barry 0, 0, \ 429*ba7b222eSGlenn Barry 0 /* loadptr */, \ 430*ba7b222eSGlenn Barry &krb5int_asn1type_##BASEDESCNAME, 0 \ 431*ba7b222eSGlenn Barry } 432*ba7b222eSGlenn Barry #define DEFNONEMPTYNULLTERMSEQOFTYPE(DESCNAME,BASEDESCNAME) \ 433*ba7b222eSGlenn Barry typedef aux_typedefname_##BASEDESCNAME aux_typedefname_##DESCNAME; \ 434*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 435*ba7b222eSGlenn Barry atype_nonempty_nullterm_sequence_of, \ 436*ba7b222eSGlenn Barry sizeof(aux_typedefname_##DESCNAME), \ 437*ba7b222eSGlenn Barry 0, 0, \ 438*ba7b222eSGlenn Barry 0 /* loadptr */, \ 439*ba7b222eSGlenn Barry &krb5int_asn1type_##BASEDESCNAME, 0 \ 440*ba7b222eSGlenn Barry } 441*ba7b222eSGlenn Barry /* Encode a thing (probably sub-fields within the structure) as a 442*ba7b222eSGlenn Barry single object. */ 443*ba7b222eSGlenn Barry #define DEFFIELDTYPE(DESCNAME, CTYPENAME, FIELDINFO) \ 444*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 445*ba7b222eSGlenn Barry static const struct field_info aux_fieldinfo_##DESCNAME = FIELDINFO; \ 446*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 447*ba7b222eSGlenn Barry atype_field, sizeof(CTYPENAME), 0, 0, 0, 0, 0, \ 448*ba7b222eSGlenn Barry &aux_fieldinfo_##DESCNAME \ 449*ba7b222eSGlenn Barry } 450*ba7b222eSGlenn Barry /* Objects with an APPLICATION tag added. */ 451*ba7b222eSGlenn Barry #define DEFAPPTAGGEDTYPE(DESCNAME, TAG, BASEDESC) \ 452*ba7b222eSGlenn Barry typedef aux_typedefname_##BASEDESC aux_typedefname_##DESCNAME; \ 453*ba7b222eSGlenn Barry const struct atype_info krb5int_asn1type_##DESCNAME = { \ 454*ba7b222eSGlenn Barry atype_tagged_thing, sizeof(aux_typedefname_##DESCNAME), \ 455*ba7b222eSGlenn Barry 0, 0, 0, &krb5int_asn1type_##BASEDESC, 0, 0, TAG, APPLICATION \ 456*ba7b222eSGlenn Barry } 457*ba7b222eSGlenn Barry 458*ba7b222eSGlenn Barry /* Declare an externally-defined type. This is a hack we should do 459*ba7b222eSGlenn Barry away with once we move to generating code from a script. For now, 460*ba7b222eSGlenn Barry this macro is unfortunately not compatible with the defining macros 461*ba7b222eSGlenn Barry above, since you can't do the typedefs twice and we need the 462*ba7b222eSGlenn Barry declarations to produce typedefs. (We could eliminate the typedefs 463*ba7b222eSGlenn Barry from the DEF* macros, but then every DEF* macro use, even the ones 464*ba7b222eSGlenn Barry for internal type nodes we only use to build other types, would 465*ba7b222eSGlenn Barry need an accompanying declaration which explicitly lists the 466*ba7b222eSGlenn Barry type.) */ 467*ba7b222eSGlenn Barry #define IMPORT_TYPE(DESCNAME, CTYPENAME) \ 468*ba7b222eSGlenn Barry typedef CTYPENAME aux_typedefname_##DESCNAME; \ 469*ba7b222eSGlenn Barry extern const struct atype_info krb5int_asn1type_##DESCNAME 470*ba7b222eSGlenn Barry 471*ba7b222eSGlenn Barry /* Create a partial-encoding function by the indicated name, for the 472*ba7b222eSGlenn Barry indicated type. Should only be needed until we've converted all of 473*ba7b222eSGlenn Barry the encoders, then everything should use descriptor tables. */ 474*ba7b222eSGlenn Barry extern asn1_error_code 475*ba7b222eSGlenn Barry krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val, 476*ba7b222eSGlenn Barry const struct atype_info *a, unsigned int *retlen); 477*ba7b222eSGlenn Barry #define MAKE_ENCFN(FNAME,DESC) \ 478*ba7b222eSGlenn Barry static asn1_error_code FNAME (asn1buf *buf, \ 479*ba7b222eSGlenn Barry const aux_typedefname_##DESC *val, \ 480*ba7b222eSGlenn Barry unsigned int *retlen) \ 481*ba7b222eSGlenn Barry { \ 482*ba7b222eSGlenn Barry return krb5int_asn1_encode_a_thing(buf, val, \ 483*ba7b222eSGlenn Barry &krb5int_asn1type_##DESC, \ 484*ba7b222eSGlenn Barry retlen); \ 485*ba7b222eSGlenn Barry } \ 486*ba7b222eSGlenn Barry extern int dummy /* gobble semicolon */ 487*ba7b222eSGlenn Barry 488*ba7b222eSGlenn Barry /* Sequence field descriptor. 489*ba7b222eSGlenn Barry 490*ba7b222eSGlenn Barry Currently we assume everything is a single object with a type 491*ba7b222eSGlenn Barry descriptor, and then we bolt on some ugliness on the side for 492*ba7b222eSGlenn Barry handling strings with length fields. 493*ba7b222eSGlenn Barry 494*ba7b222eSGlenn Barry Anything with "interesting" encoding handling, like a sequence-of 495*ba7b222eSGlenn Barry or a pointer to the actual value to encode, is handled via opaque 496*ba7b222eSGlenn Barry types with their own encoder functions. Most of that should 497*ba7b222eSGlenn Barry eventually change. */ 498*ba7b222eSGlenn Barry 499*ba7b222eSGlenn Barry enum field_type { 500*ba7b222eSGlenn Barry /* Unused except for range checking. */ 501*ba7b222eSGlenn Barry field_min = 1, 502*ba7b222eSGlenn Barry /* Field ATYPE describes processing of field at DATAOFF. */ 503*ba7b222eSGlenn Barry field_normal, 504*ba7b222eSGlenn Barry /* Encode an "immediate" integer value stored in DATAOFF, with no 505*ba7b222eSGlenn Barry reference to the data structure. */ 506*ba7b222eSGlenn Barry field_immediate, 507*ba7b222eSGlenn Barry /* Encode some kind of string field encoded with pointer and 508*ba7b222eSGlenn Barry length. (A GENERALSTRING represented as a null-terminated C 509*ba7b222eSGlenn Barry string would be handled as field_normal.) */ 510*ba7b222eSGlenn Barry field_string, 511*ba7b222eSGlenn Barry /* LENOFF indicates a value describing the length of the array at 512*ba7b222eSGlenn Barry DATAOFF, encoded as a sequence-of with the element type 513*ba7b222eSGlenn Barry described by ATYPE. */ 514*ba7b222eSGlenn Barry field_sequenceof_len, 515*ba7b222eSGlenn Barry /* Unused except for range checking. */ 516*ba7b222eSGlenn Barry field_max 517*ba7b222eSGlenn Barry }; 518*ba7b222eSGlenn Barry /* To do: Consider using bitfields. */ 519*ba7b222eSGlenn Barry struct field_info { 520*ba7b222eSGlenn Barry /* Type of the field. */ 521*ba7b222eSGlenn Barry unsigned int /* enum field_type */ ftype : 3; 522*ba7b222eSGlenn Barry 523*ba7b222eSGlenn Barry /* Use of DATAOFF and LENOFF are described by the value in FTYPE. 524*ba7b222eSGlenn Barry Generally DATAOFF will be the offset from the supplied pointer 525*ba7b222eSGlenn Barry at which we find the object to be encoded. */ 526*ba7b222eSGlenn Barry unsigned int dataoff : 9, lenoff : 9; 527*ba7b222eSGlenn Barry 528*ba7b222eSGlenn Barry /* If TAG is non-negative, a context tag with that value is added 529*ba7b222eSGlenn Barry to the encoding of the thing. (XXX This would encode more 530*ba7b222eSGlenn Barry compactly as an unsigned bitfield value tagnum+1, with 0=no 531*ba7b222eSGlenn Barry tag.) The tag is omitted for optional fields that are not 532*ba7b222eSGlenn Barry present. 533*ba7b222eSGlenn Barry 534*ba7b222eSGlenn Barry It's a bit illogical to combine the tag and other field info, 535*ba7b222eSGlenn Barry since really a sequence field could have zero or several 536*ba7b222eSGlenn Barry context tags, and of course a tag could be used elsewhere. But 537*ba7b222eSGlenn Barry the normal mode in the Kerberos ASN.1 description is to use one 538*ba7b222eSGlenn Barry context tag on each sequence field, so for now let's address 539*ba7b222eSGlenn Barry that case primarily and work around the other cases (thus tag<0 540*ba7b222eSGlenn Barry means skip tagging). */ 541*ba7b222eSGlenn Barry signed int tag : 5; 542*ba7b222eSGlenn Barry 543*ba7b222eSGlenn Barry /* If OPT is non-negative and the sequence header structure has a 544*ba7b222eSGlenn Barry function pointer describing which fields are present, OPT is 545*ba7b222eSGlenn Barry the bit position indicating whether the currently-described 546*ba7b222eSGlenn Barry element is present. (XXX Similar encoding issue.) 547*ba7b222eSGlenn Barry 548*ba7b222eSGlenn Barry Note: Most of the time, I'm using the same number here as for 549*ba7b222eSGlenn Barry the context tag. This is just because it's easier for me to 550*ba7b222eSGlenn Barry keep track while working on the code by hand. The *only* 551*ba7b222eSGlenn Barry meaningful correlation is of this value and the bits set by the 552*ba7b222eSGlenn Barry "optional" function when examining the data structure. */ 553*ba7b222eSGlenn Barry signed int opt : 5; 554*ba7b222eSGlenn Barry 555*ba7b222eSGlenn Barry /* For some values of FTYPE, this describes the type of the 556*ba7b222eSGlenn Barry object(s) to be encoded. */ 557*ba7b222eSGlenn Barry const struct atype_info *atype; 558*ba7b222eSGlenn Barry 559*ba7b222eSGlenn Barry /* We use different types for "length" fields in different places. 560*ba7b222eSGlenn Barry So we need a good way to retrieve the various kinds of lengths 561*ba7b222eSGlenn Barry in a compatible way. This may be a string length, or the 562*ba7b222eSGlenn Barry length of an array of objects to encode in a SEQUENCE OF. 563*ba7b222eSGlenn Barry 564*ba7b222eSGlenn Barry In case the field is signed and negative, or larger than 565*ba7b222eSGlenn Barry size_t, return SIZE_MAX as an error indication. We'll assume 566*ba7b222eSGlenn Barry for now that we'll never have 4G-1 (or 2**64-1, or on tiny 567*ba7b222eSGlenn Barry systems, 65535) sized values. On most if not all systems we 568*ba7b222eSGlenn Barry care about, SIZE_MAX is equivalent to "all of addressable 569*ba7b222eSGlenn Barry memory" minus one byte. That wouldn't leave enough extra room 570*ba7b222eSGlenn Barry for the structure we're encoding, so it's pretty safe to assume 571*ba7b222eSGlenn Barry SIZE_MAX won't legitimately come up on those systems. 572*ba7b222eSGlenn Barry 573*ba7b222eSGlenn Barry If this code gets ported to a segmented architecture or other 574*ba7b222eSGlenn Barry system where it might be possible... figure it out then. */ 575*ba7b222eSGlenn Barry const struct atype_info *lentype; 576*ba7b222eSGlenn Barry }; 577*ba7b222eSGlenn Barry 578*ba7b222eSGlenn Barry /* Normal or optional sequence fields at a particular offset, encoded 579*ba7b222eSGlenn Barry as indicated by the listed DESCRiptor. */ 580*ba7b222eSGlenn Barry #define FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,OPT) \ 581*ba7b222eSGlenn Barry { \ 582*ba7b222eSGlenn Barry field_normal, OFFOF(TYPE, FIELDNAME, aux_typedefname_##DESCR), \ 583*ba7b222eSGlenn Barry 0, TAG, OPT, &krb5int_asn1type_##DESCR \ 584*ba7b222eSGlenn Barry } 585*ba7b222eSGlenn Barry #define FIELDOF_NORM(TYPE,DESCR,FIELDNAME,TAG) \ 586*ba7b222eSGlenn Barry FIELDOF_OPT(TYPE,DESCR,FIELDNAME,TAG,-1) 587*ba7b222eSGlenn Barry /* If encoding a subset of the fields of the current structure (for 588*ba7b222eSGlenn Barry example, a flat structure describing data that gets encoded as a 589*ba7b222eSGlenn Barry sequence containing one or more sequences), use ENCODEAS, no struct 590*ba7b222eSGlenn Barry field name(s), and the indicated type descriptor must support the 591*ba7b222eSGlenn Barry current struct type. */ 592*ba7b222eSGlenn Barry #define FIELDOF_ENCODEAS(TYPE,DESCR,TAG) \ 593*ba7b222eSGlenn Barry FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,-1) 594*ba7b222eSGlenn Barry #define FIELDOF_ENCODEAS_OPT(TYPE,DESCR,TAG,OPT) \ 595*ba7b222eSGlenn Barry { \ 596*ba7b222eSGlenn Barry field_normal, \ 597*ba7b222eSGlenn Barry 0 * sizeof(0 ? (TYPE *)0 : (aux_typedefname_##DESCR *) 0), \ 598*ba7b222eSGlenn Barry 0, TAG, OPT, &krb5int_asn1type_##DESCR \ 599*ba7b222eSGlenn Barry } 600*ba7b222eSGlenn Barry 601*ba7b222eSGlenn Barry /* Reinterpret some subset of the structure itself as something 602*ba7b222eSGlenn Barry else. */ 603*ba7b222eSGlenn Barry #define FIELD_SELF(DESCR, TAG) \ 604*ba7b222eSGlenn Barry { field_normal, 0, 0, TAG, -1, &krb5int_asn1type_##DESCR } 605*ba7b222eSGlenn Barry 606*ba7b222eSGlenn Barry #define FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,OPT) \ 607*ba7b222eSGlenn Barry { \ 608*ba7b222eSGlenn Barry field_string, \ 609*ba7b222eSGlenn Barry OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \ 610*ba7b222eSGlenn Barry OFFOF(STYPE, LENFIELD, aux_typedefname_##LENDESC), \ 611*ba7b222eSGlenn Barry TAG, OPT, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENDESC \ 612*ba7b222eSGlenn Barry } 613*ba7b222eSGlenn Barry #define FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,OPT) \ 614*ba7b222eSGlenn Barry FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,uint,LENFIELD,TAG,OPT) 615*ba7b222eSGlenn Barry #define FIELDOF_STRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG) \ 616*ba7b222eSGlenn Barry FIELDOF_OPTSTRINGL(STYPE,DESC,PTRFIELD,LENDESC,LENFIELD,TAG,-1) 617*ba7b222eSGlenn Barry #define FIELDOF_STRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \ 618*ba7b222eSGlenn Barry FIELDOF_OPTSTRING(STYPE,DESC,PTRFIELD,LENFIELD,TAG,-1) 619*ba7b222eSGlenn Barry #define FIELD_INT_IMM(VALUE,TAG) \ 620*ba7b222eSGlenn Barry { field_immediate, VALUE, 0, TAG, -1, 0, } 621*ba7b222eSGlenn Barry 622*ba7b222eSGlenn Barry #define FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,LENTYPE,TAG) \ 623*ba7b222eSGlenn Barry { \ 624*ba7b222eSGlenn Barry field_sequenceof_len, \ 625*ba7b222eSGlenn Barry OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC), \ 626*ba7b222eSGlenn Barry OFFOF(STYPE, LENFIELD, aux_typedefname_##LENTYPE), \ 627*ba7b222eSGlenn Barry TAG, -1, &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENTYPE \ 628*ba7b222eSGlenn Barry } 629*ba7b222eSGlenn Barry #define FIELDOF_SEQOF_INT32(STYPE,DESC,PTRFIELD,LENFIELD,TAG) \ 630*ba7b222eSGlenn Barry FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,int32,TAG) 631*ba7b222eSGlenn Barry 632*ba7b222eSGlenn Barry struct seq_info { 633*ba7b222eSGlenn Barry /* If present, returns a bitmask indicating which fields are 634*ba7b222eSGlenn Barry present. See the "opt" field in struct field_info. */ 635*ba7b222eSGlenn Barry unsigned int (*optional)(const void *); 636*ba7b222eSGlenn Barry /* Indicates an array of sequence field descriptors. */ 637*ba7b222eSGlenn Barry const struct field_info *fields; 638*ba7b222eSGlenn Barry size_t n_fields; 639*ba7b222eSGlenn Barry /* Missing: Extensibility handling. (New field type?) */ 640*ba7b222eSGlenn Barry }; 641*ba7b222eSGlenn Barry 642*ba7b222eSGlenn Barry extern krb5_error_code 643*ba7b222eSGlenn Barry krb5int_asn1_do_full_encode(const void *rep, krb5_data **code, 644*ba7b222eSGlenn Barry const struct atype_info *a); 645*ba7b222eSGlenn Barry 646*ba7b222eSGlenn Barry #define MAKE_FULL_ENCODER(FNAME, DESC) \ 647*ba7b222eSGlenn Barry krb5_error_code FNAME(const aux_typedefname_##DESC *rep, \ 648*ba7b222eSGlenn Barry krb5_data **code) \ 649*ba7b222eSGlenn Barry { \ 650*ba7b222eSGlenn Barry return krb5int_asn1_do_full_encode(rep, code, \ 651*ba7b222eSGlenn Barry &krb5int_asn1type_##DESC); \ 652*ba7b222eSGlenn Barry } \ 653*ba7b222eSGlenn Barry extern int dummy /* gobble semicolon */ 654*ba7b222eSGlenn Barry 655*ba7b222eSGlenn Barry #include <stddef.h> 656*ba7b222eSGlenn Barry /* Ugly hack! 657*ba7b222eSGlenn Barry Like "offsetof", but with type checking. */ 658*ba7b222eSGlenn Barry #define WARN_IF_TYPE_MISMATCH(LVALUE, TYPE) \ 659*ba7b222eSGlenn Barry (sizeof(0 ? (TYPE *) 0 : &(LVALUE))) 660*ba7b222eSGlenn Barry #define OFFOF(TYPE,FIELD,FTYPE) \ 661*ba7b222eSGlenn Barry (offsetof(TYPE, FIELD) \ 662*ba7b222eSGlenn Barry + 0 * WARN_IF_TYPE_MISMATCH(((TYPE*)0)->FIELD, FTYPE)) 663*ba7b222eSGlenn Barry 6647c478bd9Sstevel@tonic-gate #endif 665