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  */
287c478bd9Sstevel@tonic-gate #ifndef __ASN1_ENCODE_H__
297c478bd9Sstevel@tonic-gate #define __ASN1_ENCODE_H__
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>
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate    Overview
397c478bd9Sstevel@tonic-gate      Each of these procedures inserts the encoding of an ASN.1
407c478bd9Sstevel@tonic-gate      primitive in a coding buffer.
427c478bd9Sstevel@tonic-gate    Operations
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 */
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. */
657c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_enumerated
66*ba7b222eSGlenn Barry (asn1buf *buf, long val, unsigned int *retlen);
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. */
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
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. */
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. */
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. */
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. */
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 */
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. */
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     }
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 
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    }
619*ba7b222eSGlenn Barry #define FIELD_INT_IMM(VALUE,TAG)   \
620*ba7b222eSGlenn Barry     { field_immediate, VALUE, 0, TAG, -1, 0, }
621*ba7b222eSGlenn Barry 
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     }
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