1*ba7b222eSGlenn Barry /* -*- mode: c; indent-tabs-mode: nil -*- */
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  * src/lib/krb5/asn.1/asn1_encode.c
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 /* ASN.1 primitive encoders */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include "asn1_encode.h"
317c478bd9Sstevel@tonic-gate #include "asn1_make.h"
327c478bd9Sstevel@tonic-gate 
asn1_encode_boolean(asn1buf * buf,asn1_intmax val,unsigned int * retlen)33*ba7b222eSGlenn Barry asn1_error_code asn1_encode_boolean(asn1buf *buf, asn1_intmax val,
34*ba7b222eSGlenn Barry                                     unsigned int *retlen)
357c478bd9Sstevel@tonic-gate {
36*ba7b222eSGlenn Barry     asn1_error_code retval;
37*ba7b222eSGlenn Barry     unsigned int length = 0;
38*ba7b222eSGlenn Barry     unsigned int partlen = 1;
39*ba7b222eSGlenn Barry     asn1_octet bval;
40*ba7b222eSGlenn Barry 
41*ba7b222eSGlenn Barry     bval = val ? 0xFF : 0x00;
42*ba7b222eSGlenn Barry 
43*ba7b222eSGlenn Barry     retval = asn1buf_insert_octet(buf, bval);
44*ba7b222eSGlenn Barry     if (retval) return retval;
45*ba7b222eSGlenn Barry 
46*ba7b222eSGlenn Barry     length = partlen;
47*ba7b222eSGlenn Barry     retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_BOOLEAN, length, &partlen);
48*ba7b222eSGlenn Barry     if (retval) return retval;
49*ba7b222eSGlenn Barry     length += partlen;
50*ba7b222eSGlenn Barry 
51*ba7b222eSGlenn Barry     *retlen = length;
52*ba7b222eSGlenn Barry     return 0;
537c478bd9Sstevel@tonic-gate }
547c478bd9Sstevel@tonic-gate 
asn1_encode_integer_internal(asn1buf * buf,asn1_intmax val,unsigned int * retlen)55*ba7b222eSGlenn Barry static asn1_error_code asn1_encode_integer_internal(asn1buf *buf,
56*ba7b222eSGlenn Barry                                                     asn1_intmax val,
57*ba7b222eSGlenn Barry                                                     unsigned int *retlen)
587c478bd9Sstevel@tonic-gate {
59*ba7b222eSGlenn Barry     asn1_error_code retval;
60*ba7b222eSGlenn Barry     unsigned int length = 0;
61*ba7b222eSGlenn Barry     long valcopy;
62*ba7b222eSGlenn Barry     int digit;
63*ba7b222eSGlenn Barry 
64*ba7b222eSGlenn Barry     valcopy = val;
65*ba7b222eSGlenn Barry     do {
66*ba7b222eSGlenn Barry         digit = (int) (valcopy&0xFF);
67*ba7b222eSGlenn Barry         retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
68*ba7b222eSGlenn Barry         if (retval) return retval;
69*ba7b222eSGlenn Barry         length++;
70*ba7b222eSGlenn Barry         valcopy = valcopy >> 8;
71*ba7b222eSGlenn Barry     } while (valcopy != 0 && valcopy != ~0);
72*ba7b222eSGlenn Barry 
73*ba7b222eSGlenn Barry     if ((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */
74*ba7b222eSGlenn Barry         retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
75*ba7b222eSGlenn Barry         if (retval) return retval;
76*ba7b222eSGlenn Barry         length++;
77*ba7b222eSGlenn Barry     } else if ((val < 0) && ((digit&0x80) != 0x80)) {
78*ba7b222eSGlenn Barry         retval = asn1buf_insert_octet(buf,0xFF);
79*ba7b222eSGlenn Barry         if (retval) return retval;
80*ba7b222eSGlenn Barry         length++;
81*ba7b222eSGlenn Barry     }
82*ba7b222eSGlenn Barry 
83*ba7b222eSGlenn Barry 
84*ba7b222eSGlenn Barry     *retlen = length;
85*ba7b222eSGlenn Barry     return 0;
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
asn1_encode_integer(asn1buf * buf,asn1_intmax val,unsigned int * retlen)88*ba7b222eSGlenn Barry asn1_error_code asn1_encode_integer(asn1buf * buf, asn1_intmax val,
89*ba7b222eSGlenn Barry                                     unsigned int *retlen)
907c478bd9Sstevel@tonic-gate {
91*ba7b222eSGlenn Barry     asn1_error_code retval;
92*ba7b222eSGlenn Barry     unsigned int length = 0;
93*ba7b222eSGlenn Barry     unsigned  int partlen;
94*ba7b222eSGlenn Barry     retval = asn1_encode_integer_internal(buf, val, &partlen);
95*ba7b222eSGlenn Barry     if (retval) return retval;
96*ba7b222eSGlenn Barry 
97*ba7b222eSGlenn Barry     length = partlen;
98*ba7b222eSGlenn Barry     retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
99*ba7b222eSGlenn Barry     if (retval) return retval;
100*ba7b222eSGlenn Barry     length += partlen;
101*ba7b222eSGlenn Barry 
102*ba7b222eSGlenn Barry     *retlen = length;
103*ba7b222eSGlenn Barry     return 0;
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate 
106*ba7b222eSGlenn Barry #if 0
107*ba7b222eSGlenn Barry asn1_error_code
108*ba7b222eSGlenn Barry asn1_encode_enumerated(asn1buf * buf, long val,
109*ba7b222eSGlenn Barry                        unsigned int *retlen)
1107c478bd9Sstevel@tonic-gate {
111*ba7b222eSGlenn Barry     asn1_error_code retval;
112*ba7b222eSGlenn Barry     unsigned int length = 0;
113*ba7b222eSGlenn Barry     unsigned  int partlen;
114*ba7b222eSGlenn Barry     retval = asn1_encode_integer_internal(buf, val, &partlen);
115*ba7b222eSGlenn Barry     if (retval) return retval;
116*ba7b222eSGlenn Barry 
117*ba7b222eSGlenn Barry     length = partlen;
118*ba7b222eSGlenn Barry     retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_ENUMERATED,length, &partlen);
119*ba7b222eSGlenn Barry     if (retval) return retval;
120*ba7b222eSGlenn Barry     length += partlen;
121*ba7b222eSGlenn Barry 
122*ba7b222eSGlenn Barry     *retlen = length;
123*ba7b222eSGlenn Barry     return 0;
1247c478bd9Sstevel@tonic-gate }
125*ba7b222eSGlenn Barry #endif
1267c478bd9Sstevel@tonic-gate 
asn1_encode_unsigned_integer(asn1buf * buf,asn1_uintmax val,unsigned int * retlen)127*ba7b222eSGlenn Barry asn1_error_code asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
128*ba7b222eSGlenn Barry                                              unsigned int *retlen)
1297c478bd9Sstevel@tonic-gate {
130*ba7b222eSGlenn Barry     asn1_error_code retval;
131*ba7b222eSGlenn Barry     unsigned int length = 0;
132*ba7b222eSGlenn Barry     unsigned int partlen;
133*ba7b222eSGlenn Barry     unsigned long valcopy;
134*ba7b222eSGlenn Barry     int digit;
135*ba7b222eSGlenn Barry 
136*ba7b222eSGlenn Barry     valcopy = val;
137*ba7b222eSGlenn Barry     do {
138*ba7b222eSGlenn Barry         digit = (int) (valcopy&0xFF);
139*ba7b222eSGlenn Barry         retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
140*ba7b222eSGlenn Barry         if (retval) return retval;
141*ba7b222eSGlenn Barry         length++;
142*ba7b222eSGlenn Barry         valcopy = valcopy >> 8;
143*ba7b222eSGlenn Barry     } while (valcopy != 0);
144*ba7b222eSGlenn Barry 
145*ba7b222eSGlenn Barry     if (digit&0x80) {                     /* make sure the high bit is */
146*ba7b222eSGlenn Barry         retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
147*ba7b222eSGlenn Barry         if (retval) return retval;
148*ba7b222eSGlenn Barry         length++;
149*ba7b222eSGlenn Barry     }
150*ba7b222eSGlenn Barry 
151*ba7b222eSGlenn Barry     retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
152*ba7b222eSGlenn Barry     if (retval) return retval;
153*ba7b222eSGlenn Barry     length += partlen;
154*ba7b222eSGlenn Barry 
155*ba7b222eSGlenn Barry     *retlen = length;
156*ba7b222eSGlenn Barry     return 0;
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
159*ba7b222eSGlenn Barry static asn1_error_code
encode_bytestring_with_tag(asn1buf * buf,unsigned int len,const void * val,int tag,unsigned int * retlen)160*ba7b222eSGlenn Barry encode_bytestring_with_tag(asn1buf *buf, unsigned int len,
161*ba7b222eSGlenn Barry                            const void *val, int tag,
162*ba7b222eSGlenn Barry                            unsigned int *retlen)
1637c478bd9Sstevel@tonic-gate {
164*ba7b222eSGlenn Barry     asn1_error_code retval;
165*ba7b222eSGlenn Barry     unsigned int length;
166*ba7b222eSGlenn Barry 
167*ba7b222eSGlenn Barry     if (len > 0 && val == 0) return ASN1_MISSING_FIELD;
168*ba7b222eSGlenn Barry     retval = asn1buf_insert_octetstring(buf, len, val);
169*ba7b222eSGlenn Barry     if (retval) return retval;
170*ba7b222eSGlenn Barry     retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, tag,
171*ba7b222eSGlenn Barry                            len, &length);
172*ba7b222eSGlenn Barry     if (retval) return retval;
173*ba7b222eSGlenn Barry 
174*ba7b222eSGlenn Barry     *retlen = len + length;
175*ba7b222eSGlenn Barry     return 0;
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
asn1_encode_oid(asn1buf * buf,unsigned int len,const asn1_octet * val,unsigned int * retlen)178*ba7b222eSGlenn Barry asn1_error_code asn1_encode_oid(asn1buf *buf, unsigned int len,
179*ba7b222eSGlenn Barry                                 const asn1_octet *val,
180*ba7b222eSGlenn Barry                                 unsigned int *retlen)
1817c478bd9Sstevel@tonic-gate {
182*ba7b222eSGlenn Barry     return encode_bytestring_with_tag(buf, len, val, ASN1_OBJECTIDENTIFIER,
183*ba7b222eSGlenn Barry                                       retlen);
184*ba7b222eSGlenn Barry }
1857c478bd9Sstevel@tonic-gate 
asn1_encode_octetstring(asn1buf * buf,unsigned int len,const void * val,unsigned int * retlen)186*ba7b222eSGlenn Barry asn1_error_code asn1_encode_octetstring(asn1buf *buf, unsigned int len,
187*ba7b222eSGlenn Barry                                         const void *val,
188*ba7b222eSGlenn Barry                                         unsigned int *retlen)
189*ba7b222eSGlenn Barry {
190*ba7b222eSGlenn Barry     return encode_bytestring_with_tag(buf, len, val, ASN1_OCTETSTRING,
191*ba7b222eSGlenn Barry                                       retlen);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate 
194*ba7b222eSGlenn Barry #if 0
1957c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_null(asn1buf *buf, int *retlen)
1967c478bd9Sstevel@tonic-gate {
197*ba7b222eSGlenn Barry     asn1_error_code retval;
198*ba7b222eSGlenn Barry 
199*ba7b222eSGlenn Barry     retval = asn1buf_insert_octet(buf,0x00);
200*ba7b222eSGlenn Barry     if (retval) return retval;
201*ba7b222eSGlenn Barry     retval = asn1buf_insert_octet(buf,0x05);
202*ba7b222eSGlenn Barry     if (retval) return retval;
203*ba7b222eSGlenn Barry 
204*ba7b222eSGlenn Barry     *retlen = 2;
205*ba7b222eSGlenn Barry     return 0;
2067c478bd9Sstevel@tonic-gate }
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_printablestring(asn1buf *buf, unsigned int len,
209*ba7b222eSGlenn Barry                                             const char *val, int *retlen)
2107c478bd9Sstevel@tonic-gate {
211*ba7b222eSGlenn Barry     return encode_bytestring_with_tag(buf, len, val, ASN1_PRINTABLESTRING,
212*ba7b222eSGlenn Barry                                       retlen);
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_ia5string(asn1buf *buf, unsigned int len,
216*ba7b222eSGlenn Barry                                       const char *val, int *retlen)
2177c478bd9Sstevel@tonic-gate {
218*ba7b222eSGlenn Barry     return encode_bytestring_with_tag(buf, len, val, ASN1_IA5STRING,
219*ba7b222eSGlenn Barry                                       retlen);
2207c478bd9Sstevel@tonic-gate }
221*ba7b222eSGlenn Barry #endif
2227c478bd9Sstevel@tonic-gate 
asn1_encode_generaltime(asn1buf * buf,time_t val,unsigned int * retlen)2237c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_generaltime(asn1buf *buf, time_t val,
224*ba7b222eSGlenn Barry                                         unsigned int *retlen)
2257c478bd9Sstevel@tonic-gate {
226*ba7b222eSGlenn Barry     struct tm *gtime, gtimebuf;
227*ba7b222eSGlenn Barry     char s[16], *sp;
228*ba7b222eSGlenn Barry     time_t gmt_time = val;
229*ba7b222eSGlenn Barry 
230*ba7b222eSGlenn Barry     /*
231*ba7b222eSGlenn Barry      * Time encoding: YYYYMMDDhhmmssZ
232*ba7b222eSGlenn Barry      */
233*ba7b222eSGlenn Barry     if (gmt_time == 0) {
234*ba7b222eSGlenn Barry         sp = "19700101000000Z";
235*ba7b222eSGlenn Barry     } else {
236*ba7b222eSGlenn Barry         int len;
237*ba7b222eSGlenn Barry 
238*ba7b222eSGlenn Barry         /*
239*ba7b222eSGlenn Barry          * Sanity check this just to be paranoid, as gmtime can return NULL,
240*ba7b222eSGlenn Barry          * and some bogus implementations might overrun on the sprintf.
241*ba7b222eSGlenn Barry          */
242505d05c7Sgtb #ifdef HAVE_GMTIME_R
243159d09a2SMark Phalan # ifdef GMTIME_R_RETURNS_INT
244*ba7b222eSGlenn Barry         if (gmtime_r(&gmt_time, &gtimebuf) != 0)
245*ba7b222eSGlenn Barry             return ASN1_BAD_GMTIME;
246159d09a2SMark Phalan # else
247*ba7b222eSGlenn Barry         if (gmtime_r(&gmt_time, &gtimebuf) == NULL)
248*ba7b222eSGlenn Barry             return ASN1_BAD_GMTIME;
249159d09a2SMark Phalan # endif
250505d05c7Sgtb #else
251*ba7b222eSGlenn Barry         gtime = gmtime(&gmt_time);
252*ba7b222eSGlenn Barry         if (gtime == NULL)
253*ba7b222eSGlenn Barry             return ASN1_BAD_GMTIME;
254*ba7b222eSGlenn Barry         memcpy(&gtimebuf, gtime, sizeof(gtimebuf));
255505d05c7Sgtb #endif
256*ba7b222eSGlenn Barry         gtime = &gtimebuf;
257*ba7b222eSGlenn Barry 
258*ba7b222eSGlenn Barry         if (gtime->tm_year > 8099 || gtime->tm_mon > 11 ||
259*ba7b222eSGlenn Barry             gtime->tm_mday > 31 || gtime->tm_hour > 23 ||
260*ba7b222eSGlenn Barry             gtime->tm_min > 59 || gtime->tm_sec > 59)
261*ba7b222eSGlenn Barry             return ASN1_BAD_GMTIME;
262*ba7b222eSGlenn Barry         len = snprintf(s, sizeof(s), "%04d%02d%02d%02d%02d%02dZ",
263*ba7b222eSGlenn Barry                        1900+gtime->tm_year, gtime->tm_mon+1,
264*ba7b222eSGlenn Barry                        gtime->tm_mday, gtime->tm_hour,
265*ba7b222eSGlenn Barry                        gtime->tm_min, gtime->tm_sec);
266*ba7b222eSGlenn Barry         if (SNPRINTF_OVERFLOW(len, sizeof(s)))
267*ba7b222eSGlenn Barry             /* Shouldn't be possible given above tests.  */
268*ba7b222eSGlenn Barry             return ASN1_BAD_GMTIME;
269*ba7b222eSGlenn Barry         sp = s;
270*ba7b222eSGlenn Barry     }
271*ba7b222eSGlenn Barry 
272*ba7b222eSGlenn Barry     return encode_bytestring_with_tag(buf, 15, sp, ASN1_GENERALTIME,
273*ba7b222eSGlenn Barry                                       retlen);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
asn1_encode_generalstring(asn1buf * buf,unsigned int len,const void * val,unsigned int * retlen)2767c478bd9Sstevel@tonic-gate asn1_error_code asn1_encode_generalstring(asn1buf *buf, unsigned int len,
277*ba7b222eSGlenn Barry                                           const void *val,
278*ba7b222eSGlenn Barry                                           unsigned int *retlen)
279*ba7b222eSGlenn Barry {
280*ba7b222eSGlenn Barry     return encode_bytestring_with_tag(buf, len, val, ASN1_GENERALSTRING,
281*ba7b222eSGlenn Barry                                       retlen);
282*ba7b222eSGlenn Barry }
283*ba7b222eSGlenn Barry 
asn1_encode_bitstring(asn1buf * buf,unsigned int len,const void * val,unsigned int * retlen)284*ba7b222eSGlenn Barry asn1_error_code asn1_encode_bitstring(asn1buf *buf, unsigned int len,
285*ba7b222eSGlenn Barry                                       const void *val,
286*ba7b222eSGlenn Barry                                       unsigned int *retlen)
2877c478bd9Sstevel@tonic-gate {
288*ba7b222eSGlenn Barry     asn1_error_code retval;
289*ba7b222eSGlenn Barry     unsigned int length;
290*ba7b222eSGlenn Barry 
291*ba7b222eSGlenn Barry     retval = asn1buf_insert_octetstring(buf, len, val);
292*ba7b222eSGlenn Barry     if (retval) return retval;
293*ba7b222eSGlenn Barry     retval = asn1buf_insert_octet(buf, 0);
294*ba7b222eSGlenn Barry     if (retval) return retval;
295*ba7b222eSGlenn Barry     retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_BITSTRING,
296*ba7b222eSGlenn Barry                            len+1, &length);
297*ba7b222eSGlenn Barry     if (retval) return retval;
298*ba7b222eSGlenn Barry     *retlen = len + 1 + length;
299*ba7b222eSGlenn Barry     return 0;
300*ba7b222eSGlenn Barry }
301*ba7b222eSGlenn Barry 
asn1_encode_opaque(asn1buf * buf,unsigned int len,const void * val,unsigned int * retlen)302*ba7b222eSGlenn Barry asn1_error_code asn1_encode_opaque(asn1buf *buf, unsigned int len,
303*ba7b222eSGlenn Barry                                    const void *val, unsigned int *retlen)
304*ba7b222eSGlenn Barry {
305*ba7b222eSGlenn Barry     asn1_error_code retval;
306*ba7b222eSGlenn Barry 
307*ba7b222eSGlenn Barry     retval = asn1buf_insert_octetstring(buf, len, val);
308*ba7b222eSGlenn Barry     if (retval) return retval;
309*ba7b222eSGlenn Barry     *retlen = len;
310*ba7b222eSGlenn Barry     return 0;
311*ba7b222eSGlenn Barry }
312*ba7b222eSGlenn Barry 
313*ba7b222eSGlenn Barry /* ASN.1 constructed type encoder engine
314*ba7b222eSGlenn Barry 
315*ba7b222eSGlenn Barry    Two entry points here:
316*ba7b222eSGlenn Barry 
317*ba7b222eSGlenn Barry    krb5int_asn1_encode_a_thing: Incrementally adds the partial
318*ba7b222eSGlenn Barry    encoding of an object to an already-initialized asn1buf.
319*ba7b222eSGlenn Barry 
320*ba7b222eSGlenn Barry    krb5int_asn1_do_full_encode: Returns a completed encoding, in the
321*ba7b222eSGlenn Barry    correct byte order, in an allocated krb5_data.  */
322*ba7b222eSGlenn Barry 
323*ba7b222eSGlenn Barry #ifdef POINTERS_ARE_ALL_THE_SAME
324*ba7b222eSGlenn Barry #define LOADPTR(PTR,TYPE)       \
325*ba7b222eSGlenn Barry     (assert((TYPE)->loadptr != NULL), (TYPE)->loadptr(PTR))
326*ba7b222eSGlenn Barry #else
327*ba7b222eSGlenn Barry #define LOADPTR(PTR,TYPE)       \
328*ba7b222eSGlenn Barry     (*(const void *const *)(PTR))
329*ba7b222eSGlenn Barry #endif
330*ba7b222eSGlenn Barry 
331*ba7b222eSGlenn Barry static int
get_nullterm_sequence_len(const void * valp,const struct atype_info * seq)332*ba7b222eSGlenn Barry get_nullterm_sequence_len(const void *valp, const struct atype_info *seq)
333*ba7b222eSGlenn Barry {
334*ba7b222eSGlenn Barry     int i;
335*ba7b222eSGlenn Barry     const struct atype_info *a;
336*ba7b222eSGlenn Barry     const void *elt, *eltptr;
337*ba7b222eSGlenn Barry 
338*ba7b222eSGlenn Barry     a = seq;
339*ba7b222eSGlenn Barry     i = 0;
340*ba7b222eSGlenn Barry     assert(a->type == atype_ptr);
341*ba7b222eSGlenn Barry     assert(seq->size != 0);
342*ba7b222eSGlenn Barry 
343*ba7b222eSGlenn Barry     while (1) {
344*ba7b222eSGlenn Barry         eltptr = (const char *) valp + i * seq->size;
345*ba7b222eSGlenn Barry         elt = LOADPTR(eltptr, a);
346*ba7b222eSGlenn Barry         if (elt == NULL)
347*ba7b222eSGlenn Barry             break;
348*ba7b222eSGlenn Barry         i++;
349*ba7b222eSGlenn Barry     }
350*ba7b222eSGlenn Barry     return i;
351*ba7b222eSGlenn Barry }
352*ba7b222eSGlenn Barry static asn1_error_code
353*ba7b222eSGlenn Barry encode_sequence_of(asn1buf *buf, int seqlen, const void *val,
354*ba7b222eSGlenn Barry                    const struct atype_info *eltinfo,
355*ba7b222eSGlenn Barry                    unsigned int *retlen);
356*ba7b222eSGlenn Barry 
357*ba7b222eSGlenn Barry static asn1_error_code
encode_nullterm_sequence_of(asn1buf * buf,const void * val,const struct atype_info * type,int can_be_empty,unsigned int * retlen)358*ba7b222eSGlenn Barry encode_nullterm_sequence_of(asn1buf *buf, const void *val,
359*ba7b222eSGlenn Barry                             const struct atype_info *type,
360*ba7b222eSGlenn Barry                             int can_be_empty,
361*ba7b222eSGlenn Barry                             unsigned int *retlen)
362*ba7b222eSGlenn Barry {
363*ba7b222eSGlenn Barry     int length = get_nullterm_sequence_len(val, type);
364*ba7b222eSGlenn Barry     if (!can_be_empty && length == 0) return ASN1_MISSING_FIELD;
365*ba7b222eSGlenn Barry     return encode_sequence_of(buf, length, val, type, retlen);
366*ba7b222eSGlenn Barry }
3677c478bd9Sstevel@tonic-gate 
368*ba7b222eSGlenn Barry static asn1_error_code
369*ba7b222eSGlenn Barry just_encode_sequence(asn1buf *buf, const void *val,
370*ba7b222eSGlenn Barry                      const struct seq_info *seq,
371*ba7b222eSGlenn Barry                      unsigned int *retlen);
372*ba7b222eSGlenn Barry static asn1_error_code
373*ba7b222eSGlenn Barry encode_a_field(asn1buf *buf, const void *val,
374*ba7b222eSGlenn Barry                const struct field_info *field,
375*ba7b222eSGlenn Barry                unsigned int *retlen);
3767c478bd9Sstevel@tonic-gate 
377*ba7b222eSGlenn Barry asn1_error_code
krb5int_asn1_encode_a_thing(asn1buf * buf,const void * val,const struct atype_info * a,unsigned int * retlen)378*ba7b222eSGlenn Barry krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
379*ba7b222eSGlenn Barry                             const struct atype_info *a, unsigned int *retlen)
380*ba7b222eSGlenn Barry {
381*ba7b222eSGlenn Barry     switch (a->type) {
382*ba7b222eSGlenn Barry     case atype_fn:
383*ba7b222eSGlenn Barry         assert(a->enc != NULL);
384*ba7b222eSGlenn Barry         return a->enc(buf, val, retlen);
385*ba7b222eSGlenn Barry     case atype_sequence:
386*ba7b222eSGlenn Barry         assert(a->seq != NULL);
387*ba7b222eSGlenn Barry         return just_encode_sequence(buf, val, a->seq, retlen);
388*ba7b222eSGlenn Barry     case atype_ptr:
389*ba7b222eSGlenn Barry         assert(a->basetype != NULL);
390*ba7b222eSGlenn Barry         return krb5int_asn1_encode_a_thing(buf, LOADPTR(val, a),
391*ba7b222eSGlenn Barry                                            a->basetype, retlen);
392*ba7b222eSGlenn Barry     case atype_field:
393*ba7b222eSGlenn Barry         assert(a->field != NULL);
394*ba7b222eSGlenn Barry         return encode_a_field(buf, val, a->field, retlen);
395*ba7b222eSGlenn Barry     case atype_nullterm_sequence_of:
396*ba7b222eSGlenn Barry     case atype_nonempty_nullterm_sequence_of:
397*ba7b222eSGlenn Barry         assert(a->basetype != NULL);
398*ba7b222eSGlenn Barry         return encode_nullterm_sequence_of(buf, val, a->basetype,
399*ba7b222eSGlenn Barry                                            a->type == atype_nullterm_sequence_of,
400*ba7b222eSGlenn Barry                                            retlen);
401*ba7b222eSGlenn Barry     case atype_tagged_thing:
402*ba7b222eSGlenn Barry     {
403*ba7b222eSGlenn Barry         asn1_error_code retval;
404*ba7b222eSGlenn Barry         unsigned int length, sum = 0;
405*ba7b222eSGlenn Barry         retval = krb5int_asn1_encode_a_thing(buf, val, a->basetype, &length);
406*ba7b222eSGlenn Barry         if (retval) return retval;
407*ba7b222eSGlenn Barry         sum = length;
408*ba7b222eSGlenn Barry         retval = asn1_make_etag(buf, a->tagtype, a->tagval, sum, &length);
409*ba7b222eSGlenn Barry         if (retval) return retval;
410*ba7b222eSGlenn Barry         sum += length;
411*ba7b222eSGlenn Barry         *retlen = sum;
412*ba7b222eSGlenn Barry         return 0;
413*ba7b222eSGlenn Barry     }
414*ba7b222eSGlenn Barry     case atype_int:
415*ba7b222eSGlenn Barry         assert(a->loadint != NULL);
416*ba7b222eSGlenn Barry         return asn1_encode_integer(buf, a->loadint(val), retlen);
417*ba7b222eSGlenn Barry     case atype_uint:
418*ba7b222eSGlenn Barry         assert(a->loaduint != NULL);
419*ba7b222eSGlenn Barry         return asn1_encode_unsigned_integer(buf, a->loaduint(val), retlen);
420*ba7b222eSGlenn Barry     case atype_min:
421*ba7b222eSGlenn Barry     case atype_max:
422*ba7b222eSGlenn Barry     case atype_fn_len:
423*ba7b222eSGlenn Barry     default:
424*ba7b222eSGlenn Barry         assert(a->type > atype_min);
425*ba7b222eSGlenn Barry         assert(a->type < atype_max);
426*ba7b222eSGlenn Barry         assert(a->type != atype_fn_len);
427*ba7b222eSGlenn Barry         abort();
428*ba7b222eSGlenn Barry     }
429*ba7b222eSGlenn Barry }
430*ba7b222eSGlenn Barry 
431*ba7b222eSGlenn Barry static asn1_error_code
encode_a_field(asn1buf * buf,const void * val,const struct field_info * field,unsigned int * retlen)432*ba7b222eSGlenn Barry encode_a_field(asn1buf *buf, const void *val,
433*ba7b222eSGlenn Barry                const struct field_info *field,
434*ba7b222eSGlenn Barry                unsigned int *retlen)
435*ba7b222eSGlenn Barry {
436*ba7b222eSGlenn Barry     asn1_error_code retval;
437*ba7b222eSGlenn Barry     unsigned int sum = 0;
438*ba7b222eSGlenn Barry 
439*ba7b222eSGlenn Barry     if (val == NULL) return ASN1_MISSING_FIELD;
440*ba7b222eSGlenn Barry 
441*ba7b222eSGlenn Barry     switch (field->ftype) {
442*ba7b222eSGlenn Barry     case field_immediate:
443*ba7b222eSGlenn Barry     {
444*ba7b222eSGlenn Barry         unsigned int length;
445*ba7b222eSGlenn Barry 
446*ba7b222eSGlenn Barry         retval = asn1_encode_integer(buf, (asn1_intmax) field->dataoff,
447*ba7b222eSGlenn Barry                                      &length);
448*ba7b222eSGlenn Barry         if (retval) return retval;
449*ba7b222eSGlenn Barry         sum += length;
450*ba7b222eSGlenn Barry         break;
451*ba7b222eSGlenn Barry     }
452*ba7b222eSGlenn Barry     case field_sequenceof_len:
453*ba7b222eSGlenn Barry     {
454*ba7b222eSGlenn Barry         const void *dataptr, *lenptr;
455*ba7b222eSGlenn Barry         int slen;
456*ba7b222eSGlenn Barry         unsigned int length;
457*ba7b222eSGlenn Barry         const struct atype_info *a;
458*ba7b222eSGlenn Barry 
459*ba7b222eSGlenn Barry         /* The field holds a pointer to the array of objects.  So the
460*ba7b222eSGlenn Barry            address we compute is a pointer-to-pointer, and that's what
461*ba7b222eSGlenn Barry            field->atype must help us dereference.  */
462*ba7b222eSGlenn Barry         dataptr = (const char *)val + field->dataoff;
463*ba7b222eSGlenn Barry         lenptr = (const char *)val + field->lenoff;
464*ba7b222eSGlenn Barry         assert(field->atype->type == atype_ptr);
465*ba7b222eSGlenn Barry         dataptr = LOADPTR(dataptr, field->atype);
466*ba7b222eSGlenn Barry         a = field->atype->basetype;
467*ba7b222eSGlenn Barry         assert(field->lentype != 0);
468*ba7b222eSGlenn Barry         assert(field->lentype->type == atype_int || field->lentype->type == atype_uint);
469*ba7b222eSGlenn Barry         assert(sizeof(int) <= sizeof(asn1_intmax));
470*ba7b222eSGlenn Barry         assert(sizeof(unsigned int) <= sizeof(asn1_uintmax));
471*ba7b222eSGlenn Barry         if (field->lentype->type == atype_int) {
472*ba7b222eSGlenn Barry             asn1_intmax xlen = field->lentype->loadint(lenptr);
473*ba7b222eSGlenn Barry             if (xlen < 0)
474*ba7b222eSGlenn Barry                 return EINVAL;
475*ba7b222eSGlenn Barry             if ((unsigned int) xlen != (asn1_uintmax) xlen)
476*ba7b222eSGlenn Barry                 return EINVAL;
477*ba7b222eSGlenn Barry             if ((unsigned int) xlen > INT_MAX)
478*ba7b222eSGlenn Barry                 return EINVAL;
479*ba7b222eSGlenn Barry             slen = (int) xlen;
480*ba7b222eSGlenn Barry         } else {
481*ba7b222eSGlenn Barry             asn1_uintmax xlen = field->lentype->loaduint(lenptr);
482*ba7b222eSGlenn Barry             if ((unsigned int) xlen != xlen)
483*ba7b222eSGlenn Barry                 return EINVAL;
484*ba7b222eSGlenn Barry             if (xlen > INT_MAX)
485*ba7b222eSGlenn Barry                 return EINVAL;
486*ba7b222eSGlenn Barry             slen = (int) xlen;
487*ba7b222eSGlenn Barry         }
488*ba7b222eSGlenn Barry         if (slen != 0 && dataptr == NULL)
489*ba7b222eSGlenn Barry             return ASN1_MISSING_FIELD;
490*ba7b222eSGlenn Barry         retval = encode_sequence_of(buf, slen, dataptr, a, &length);
491*ba7b222eSGlenn Barry         if (retval) return retval;
492*ba7b222eSGlenn Barry         sum += length;
493*ba7b222eSGlenn Barry         break;
494*ba7b222eSGlenn Barry     }
495*ba7b222eSGlenn Barry     case field_normal:
496*ba7b222eSGlenn Barry     {
497*ba7b222eSGlenn Barry         const void *dataptr;
498*ba7b222eSGlenn Barry         const struct atype_info *a;
499*ba7b222eSGlenn Barry         unsigned int length;
500*ba7b222eSGlenn Barry 
501*ba7b222eSGlenn Barry         dataptr = (const char *)val + field->dataoff;
502*ba7b222eSGlenn Barry 
503*ba7b222eSGlenn Barry         a = field->atype;
504*ba7b222eSGlenn Barry         assert(a->type != atype_fn_len);
505*ba7b222eSGlenn Barry         retval = krb5int_asn1_encode_a_thing(buf, dataptr, a, &length);
506*ba7b222eSGlenn Barry         if (retval) {
507*ba7b222eSGlenn Barry             return retval;
508*ba7b222eSGlenn Barry         }
509*ba7b222eSGlenn Barry         sum += length;
510*ba7b222eSGlenn Barry         break;
511*ba7b222eSGlenn Barry     }
512*ba7b222eSGlenn Barry     case field_string:
513*ba7b222eSGlenn Barry     {
514*ba7b222eSGlenn Barry         const void *dataptr, *lenptr;
515*ba7b222eSGlenn Barry         const struct atype_info *a;
516*ba7b222eSGlenn Barry         size_t slen;
517*ba7b222eSGlenn Barry         unsigned int length;
518*ba7b222eSGlenn Barry 
519*ba7b222eSGlenn Barry         dataptr = (const char *)val + field->dataoff;
520*ba7b222eSGlenn Barry         lenptr = (const char *)val + field->lenoff;
521*ba7b222eSGlenn Barry 
522*ba7b222eSGlenn Barry         a = field->atype;
523*ba7b222eSGlenn Barry         assert(a->type == atype_fn_len);
524*ba7b222eSGlenn Barry         assert(field->lentype != 0);
525*ba7b222eSGlenn Barry         assert(field->lentype->type == atype_int || field->lentype->type == atype_uint);
526*ba7b222eSGlenn Barry         assert(sizeof(int) <= sizeof(asn1_intmax));
527*ba7b222eSGlenn Barry         assert(sizeof(unsigned int) <= sizeof(asn1_uintmax));
528*ba7b222eSGlenn Barry         if (field->lentype->type == atype_int) {
529*ba7b222eSGlenn Barry             asn1_intmax xlen = field->lentype->loadint(lenptr);
530*ba7b222eSGlenn Barry             if (xlen < 0)
531*ba7b222eSGlenn Barry                 return EINVAL;
532*ba7b222eSGlenn Barry             if ((size_t) xlen != (asn1_uintmax) xlen)
533*ba7b222eSGlenn Barry                 return EINVAL;
534*ba7b222eSGlenn Barry             slen = (size_t) xlen;
535*ba7b222eSGlenn Barry         } else {
536*ba7b222eSGlenn Barry             asn1_uintmax xlen = field->lentype->loaduint(lenptr);
537*ba7b222eSGlenn Barry             if ((size_t) xlen != xlen)
538*ba7b222eSGlenn Barry                 return EINVAL;
539*ba7b222eSGlenn Barry             slen = (size_t) xlen;
540*ba7b222eSGlenn Barry         }
541*ba7b222eSGlenn Barry 
542*ba7b222eSGlenn Barry         dataptr = LOADPTR(dataptr, a);
543*ba7b222eSGlenn Barry         if (slen == SIZE_MAX)
544*ba7b222eSGlenn Barry             /* Error - negative or out of size_t range.  */
545*ba7b222eSGlenn Barry             return EINVAL;
546*ba7b222eSGlenn Barry         if (dataptr == NULL && slen != 0)
547*ba7b222eSGlenn Barry             return ASN1_MISSING_FIELD;
548*ba7b222eSGlenn Barry         /* Currently our string encoders want "unsigned int" for
549*ba7b222eSGlenn Barry            lengths.  */
550*ba7b222eSGlenn Barry         if (slen != (unsigned int) slen)
551*ba7b222eSGlenn Barry             return EINVAL;
552*ba7b222eSGlenn Barry         assert(a->enclen != NULL);
553*ba7b222eSGlenn Barry         retval = a->enclen(buf, (unsigned int) slen, dataptr, &length);
554*ba7b222eSGlenn Barry         if (retval) {
555*ba7b222eSGlenn Barry             return retval;
556*ba7b222eSGlenn Barry         }
557*ba7b222eSGlenn Barry         sum += length;
558*ba7b222eSGlenn Barry         break;
559*ba7b222eSGlenn Barry     }
560*ba7b222eSGlenn Barry     default:
561*ba7b222eSGlenn Barry         assert(field->ftype > field_min);
562*ba7b222eSGlenn Barry         assert(field->ftype < field_max);
563*ba7b222eSGlenn Barry         assert(__LINE__ == 0);
564*ba7b222eSGlenn Barry         abort();
565*ba7b222eSGlenn Barry     }
566*ba7b222eSGlenn Barry     if (field->tag >= 0) {
567*ba7b222eSGlenn Barry         unsigned int length;
568*ba7b222eSGlenn Barry         retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, field->tag, sum,
569*ba7b222eSGlenn Barry                                 &length);
570*ba7b222eSGlenn Barry         if (retval) {
571*ba7b222eSGlenn Barry             return retval;
572*ba7b222eSGlenn Barry         }
573*ba7b222eSGlenn Barry         sum += length;
574*ba7b222eSGlenn Barry     }
575*ba7b222eSGlenn Barry     *retlen = sum;
576*ba7b222eSGlenn Barry     return 0;
577*ba7b222eSGlenn Barry }
578*ba7b222eSGlenn Barry 
579*ba7b222eSGlenn Barry static asn1_error_code
encode_fields(asn1buf * buf,const void * val,const struct field_info * fields,size_t nfields,unsigned int optional,unsigned int * retlen)580*ba7b222eSGlenn Barry encode_fields(asn1buf *buf, const void *val,
581*ba7b222eSGlenn Barry               const struct field_info *fields, size_t nfields,
582*ba7b222eSGlenn Barry               unsigned int optional,
583*ba7b222eSGlenn Barry               unsigned int *retlen)
584*ba7b222eSGlenn Barry {
585*ba7b222eSGlenn Barry     size_t i;
586*ba7b222eSGlenn Barry     unsigned int sum = 0;
587*ba7b222eSGlenn Barry     for (i = nfields; i > 0; i--) {
588*ba7b222eSGlenn Barry         const struct field_info *f = fields+i-1;
589*ba7b222eSGlenn Barry         unsigned int length;
590*ba7b222eSGlenn Barry         asn1_error_code retval;
591*ba7b222eSGlenn Barry         int present;
592*ba7b222eSGlenn Barry 
593*ba7b222eSGlenn Barry         if (f->opt == -1)
594*ba7b222eSGlenn Barry             present = 1;
595*ba7b222eSGlenn Barry         else if ((1u << f->opt) & optional)
596*ba7b222eSGlenn Barry             present = 1;
597*ba7b222eSGlenn Barry         else
598*ba7b222eSGlenn Barry             present = 0;
599*ba7b222eSGlenn Barry         if (present) {
600*ba7b222eSGlenn Barry             retval = encode_a_field(buf, val, f, &length);
601*ba7b222eSGlenn Barry             if (retval) return retval;
602*ba7b222eSGlenn Barry             sum += length;
603*ba7b222eSGlenn Barry         }
604*ba7b222eSGlenn Barry     }
605*ba7b222eSGlenn Barry     *retlen = sum;
606*ba7b222eSGlenn Barry     return 0;
607*ba7b222eSGlenn Barry }
608*ba7b222eSGlenn Barry 
609*ba7b222eSGlenn Barry static asn1_error_code
just_encode_sequence(asn1buf * buf,const void * val,const struct seq_info * seq,unsigned int * retlen)610*ba7b222eSGlenn Barry just_encode_sequence(asn1buf *buf, const void *val,
611*ba7b222eSGlenn Barry                      const struct seq_info *seq,
612*ba7b222eSGlenn Barry                      unsigned int *retlen)
613*ba7b222eSGlenn Barry {
614*ba7b222eSGlenn Barry     const struct field_info *fields = seq->fields;
615*ba7b222eSGlenn Barry     size_t nfields = seq->n_fields;
616*ba7b222eSGlenn Barry     unsigned int optional;
617*ba7b222eSGlenn Barry     asn1_error_code retval;
618*ba7b222eSGlenn Barry     unsigned int sum = 0;
619*ba7b222eSGlenn Barry 
620*ba7b222eSGlenn Barry     if (seq->optional)
621*ba7b222eSGlenn Barry         optional = seq->optional(val);
622*ba7b222eSGlenn Barry     else
623*ba7b222eSGlenn Barry         /* In this case, none of the field descriptors should indicate
624*ba7b222eSGlenn Barry            that we examine any bits of this value.  */
625*ba7b222eSGlenn Barry         optional = 0;
626*ba7b222eSGlenn Barry     {
627*ba7b222eSGlenn Barry         unsigned int length;
628*ba7b222eSGlenn Barry         retval = encode_fields(buf, val, fields, nfields, optional, &length);
629*ba7b222eSGlenn Barry         if (retval) return retval;
630*ba7b222eSGlenn Barry         sum += length;
631*ba7b222eSGlenn Barry     }
632*ba7b222eSGlenn Barry     {
633*ba7b222eSGlenn Barry         unsigned int length;
634*ba7b222eSGlenn Barry         retval = asn1_make_sequence(buf, sum, &length);
635*ba7b222eSGlenn Barry         if (retval) return retval;
636*ba7b222eSGlenn Barry         sum += length;
637*ba7b222eSGlenn Barry     }
638*ba7b222eSGlenn Barry     *retlen = sum;
639*ba7b222eSGlenn Barry     return 0;
640*ba7b222eSGlenn Barry }
641*ba7b222eSGlenn Barry 
642*ba7b222eSGlenn Barry static asn1_error_code
encode_sequence_of(asn1buf * buf,int seqlen,const void * val,const struct atype_info * eltinfo,unsigned int * retlen)643*ba7b222eSGlenn Barry encode_sequence_of(asn1buf *buf, int seqlen, const void *val,
644*ba7b222eSGlenn Barry                    const struct atype_info *eltinfo,
645*ba7b222eSGlenn Barry                    unsigned int *retlen)
646*ba7b222eSGlenn Barry {
647*ba7b222eSGlenn Barry     asn1_error_code retval;
648*ba7b222eSGlenn Barry     unsigned int sum = 0;
649*ba7b222eSGlenn Barry     int i;
650*ba7b222eSGlenn Barry 
651*ba7b222eSGlenn Barry     for (i = seqlen-1; i >= 0; i--) {
652*ba7b222eSGlenn Barry         const void *eltptr;
653*ba7b222eSGlenn Barry         unsigned int length;
654*ba7b222eSGlenn Barry         const struct atype_info *a = eltinfo;
655*ba7b222eSGlenn Barry 
656*ba7b222eSGlenn Barry         assert(eltinfo->size != 0);
657*ba7b222eSGlenn Barry         eltptr = (const char *)val + i * eltinfo->size;
658*ba7b222eSGlenn Barry         retval = krb5int_asn1_encode_a_thing(buf, eltptr, a, &length);
659*ba7b222eSGlenn Barry         if (retval) return retval;
660*ba7b222eSGlenn Barry         sum += length;
661*ba7b222eSGlenn Barry     }
662*ba7b222eSGlenn Barry     {
663*ba7b222eSGlenn Barry         unsigned int length;
664*ba7b222eSGlenn Barry         retval = asn1_make_sequence(buf, sum, &length);
665*ba7b222eSGlenn Barry         if (retval) return retval;
666*ba7b222eSGlenn Barry         sum += length;
667*ba7b222eSGlenn Barry     }
668*ba7b222eSGlenn Barry     *retlen = sum;
669*ba7b222eSGlenn Barry     return 0;
670*ba7b222eSGlenn Barry }
671*ba7b222eSGlenn Barry 
672*ba7b222eSGlenn Barry krb5_error_code
krb5int_asn1_do_full_encode(const void * rep,krb5_data ** code,const struct atype_info * a)673*ba7b222eSGlenn Barry krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
674*ba7b222eSGlenn Barry                             const struct atype_info *a)
675*ba7b222eSGlenn Barry {
676*ba7b222eSGlenn Barry     unsigned int length;
677*ba7b222eSGlenn Barry     asn1_error_code retval;
678*ba7b222eSGlenn Barry     asn1buf *buf = NULL;
679*ba7b222eSGlenn Barry     krb5_data *d;
680*ba7b222eSGlenn Barry 
681*ba7b222eSGlenn Barry     *code = NULL;
682*ba7b222eSGlenn Barry 
683*ba7b222eSGlenn Barry     if (rep == NULL)
684*ba7b222eSGlenn Barry         return ASN1_MISSING_FIELD;
685*ba7b222eSGlenn Barry 
686*ba7b222eSGlenn Barry     retval = asn1buf_create(&buf);
687*ba7b222eSGlenn Barry     if (retval)
688*ba7b222eSGlenn Barry         return retval;
689*ba7b222eSGlenn Barry 
690*ba7b222eSGlenn Barry     retval = krb5int_asn1_encode_a_thing(buf, rep, a, &length);
691*ba7b222eSGlenn Barry     if (retval)
692*ba7b222eSGlenn Barry         goto cleanup;
693*ba7b222eSGlenn Barry     retval = asn12krb5_buf(buf, &d);
694*ba7b222eSGlenn Barry     if (retval)
695*ba7b222eSGlenn Barry         goto cleanup;
696*ba7b222eSGlenn Barry     *code = d;
697*ba7b222eSGlenn Barry cleanup:
698*ba7b222eSGlenn Barry     asn1buf_destroy(&buf);
699*ba7b222eSGlenn Barry     return retval;
7007c478bd9Sstevel@tonic-gate }
701