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