xref: /titanic_44/usr/src/lib/gss_mechs/mech_krb5/krb5/asn.1/asn1_encode.c (revision ba7b222e36bac28710a7f43739283302b617e7f5)
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