Eliminate some unused ASN.1 encoding primitives
[krb5.git] / src / lib / krb5 / asn.1 / asn1_encode.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/asn.1/asn1_encode.c */
3 /*
4  * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26
27 /* ASN.1 primitive encoders */
28
29 #include "asn1_encode.h"
30
31 asn1_error_code
32 asn1_encode_boolean(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
33 {
34     asn1_octet bval = val ? 0xFF : 0x00;
35
36     *retlen = 1;
37     return asn1buf_insert_octet(buf, bval);
38 }
39
40 asn1_error_code
41 asn1_encode_integer(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
42 {
43     asn1_error_code retval;
44     unsigned int length = 0;
45     long valcopy;
46     int digit;
47
48     valcopy = val;
49     do {
50         digit = (int) (valcopy&0xFF);
51         retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
52         if (retval) return retval;
53         length++;
54         valcopy = valcopy >> 8;
55     } while (valcopy != 0 && valcopy != ~0);
56
57     if ((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */
58         retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
59         if (retval) return retval;
60         length++;
61     } else if ((val < 0) && ((digit&0x80) != 0x80)) {
62         retval = asn1buf_insert_octet(buf,0xFF);
63         if (retval) return retval;
64         length++;
65     }
66
67
68     *retlen = length;
69     return 0;
70 }
71
72 asn1_error_code
73 asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
74                              unsigned int *retlen)
75 {
76     asn1_error_code retval;
77     unsigned int length = 0;
78     unsigned long valcopy;
79     int digit;
80
81     valcopy = val;
82     do {
83         digit = (int) (valcopy&0xFF);
84         retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
85         if (retval) return retval;
86         length++;
87         valcopy = valcopy >> 8;
88     } while (valcopy != 0);
89
90     if (digit&0x80) {                     /* make sure the high bit is */
91         retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
92         if (retval) return retval;
93         length++;
94     }
95
96     *retlen = length;
97     return 0;
98 }
99
100 asn1_error_code
101 asn1_encode_bytestring(asn1buf *buf, unsigned char *const *val,
102                        unsigned int len, unsigned int *retlen)
103 {
104     if (len > 0 && val == NULL) return ASN1_MISSING_FIELD;
105     *retlen = len;
106     return asn1buf_insert_octetstring(buf, len, *val);
107 }
108
109 asn1_error_code
110 asn1_encode_generaltime(asn1buf *buf, time_t val, unsigned int *retlen)
111 {
112     struct tm *gtime, gtimebuf;
113     char s[16];
114     unsigned char *sp;
115     time_t gmt_time = val;
116
117     /*
118      * Time encoding: YYYYMMDDhhmmssZ
119      */
120     if (gmt_time == 0) {
121         sp = (unsigned char *)"19700101000000Z";
122     } else {
123         int len;
124
125         /*
126          * Sanity check this just to be paranoid, as gmtime can return NULL,
127          * and some bogus implementations might overrun on the sprintf.
128          */
129 #ifdef HAVE_GMTIME_R
130 # ifdef GMTIME_R_RETURNS_INT
131         if (gmtime_r(&gmt_time, &gtimebuf) != 0)
132             return ASN1_BAD_GMTIME;
133 # else
134         if (gmtime_r(&gmt_time, &gtimebuf) == NULL)
135             return ASN1_BAD_GMTIME;
136 # endif
137 #else
138         gtime = gmtime(&gmt_time);
139         if (gtime == NULL)
140             return ASN1_BAD_GMTIME;
141         memcpy(&gtimebuf, gtime, sizeof(gtimebuf));
142 #endif
143         gtime = &gtimebuf;
144
145         if (gtime->tm_year > 8099 || gtime->tm_mon > 11 ||
146             gtime->tm_mday > 31 || gtime->tm_hour > 23 ||
147             gtime->tm_min > 59 || gtime->tm_sec > 59)
148             return ASN1_BAD_GMTIME;
149         len = snprintf(s, sizeof(s), "%04d%02d%02d%02d%02d%02dZ",
150                        1900+gtime->tm_year, gtime->tm_mon+1,
151                        gtime->tm_mday, gtime->tm_hour,
152                        gtime->tm_min, gtime->tm_sec);
153         if (SNPRINTF_OVERFLOW(len, sizeof(s)))
154             /* Shouldn't be possible given above tests.  */
155             return ASN1_BAD_GMTIME;
156         sp = (unsigned char *)s;
157     }
158
159     return asn1_encode_bytestring(buf, &sp, 15, retlen);
160 }
161
162 asn1_error_code
163 asn1_encode_bitstring(asn1buf *buf, unsigned char *const *val,
164                       unsigned int len, unsigned int *retlen)
165 {
166     asn1_error_code retval;
167
168     retval = asn1buf_insert_octetstring(buf, len, *val);
169     if (retval) return retval;
170     *retlen = len + 1;
171     return asn1buf_insert_octet(buf, '\0');
172 }
173
174 static asn1_error_code
175 make_tag(asn1buf *buf, const taginfo *t, unsigned int *retlen)
176 {
177     asn1_error_code ret;
178     asn1_tagnum tag_copy;
179     unsigned int sum = 0, length, len_copy;
180
181     if (t->tagnum > ASN1_TAGNUM_MAX)
182         return ASN1_OVERFLOW;
183
184     /* Encode the length of the content within the tag. */
185     if (t->length < 128) {
186         ret = asn1buf_insert_octet(buf, t->length & 0x7F);
187         if (ret)
188             return ret;
189         length = 1;
190     } else {
191         length = 0;
192         for (len_copy = t->length; len_copy != 0; len_copy >>= 8) {
193             ret = asn1buf_insert_octet(buf, len_copy & 0xFF);
194             if (ret)
195                 return ret;
196             length++;
197         }
198         ret = asn1buf_insert_octet(buf, 0x80 | (length & 0x7F));
199         if (ret)
200             return ret;
201         length++;
202     }
203     sum += length;
204
205     /* Encode the tag and construction bit. */
206     if (t->tagnum < 31) {
207         ret = asn1buf_insert_octet(buf,
208                                    t->asn1class | t->construction | t->tagnum);
209         if (ret)
210             return ret;
211         length = 1;
212     } else {
213         tag_copy = t->tagnum;
214         length = 0;
215         ret = asn1buf_insert_octet(buf, tag_copy & 0x7F);
216         if (ret)
217             return ret;
218         tag_copy >>= 7;
219         length++;
220
221         for (; tag_copy != 0; tag_copy >>= 7) {
222             ret = asn1buf_insert_octet(buf, 0x80 | (tag_copy & 0x7F));
223             if (ret)
224                 return ret;
225             length++;
226         }
227
228         ret = asn1buf_insert_octet(buf, t->asn1class | t->construction | 0x1F);
229         if (ret)
230             return ret;
231         length++;
232     }
233     sum += length;
234
235     *retlen = sum;
236     return 0;
237 }
238
239 /*
240  * ASN.1 constructed type encoder engine
241  *
242  * Two entry points here:
243  *
244  * krb5int_asn1_encode_type: Incrementally adds the contents-only encoding of
245  * an object to an already-initialized asn1buf, and returns its tag
246  * information.
247  *
248  * krb5int_asn1_do_full_encode: Returns a completed encoding, in the
249  * correct byte order, in an allocated krb5_data.
250  */
251
252 #ifdef POINTERS_ARE_ALL_THE_SAME
253 #define LOADPTR(PTR,TYPE)                       \
254     (*(const void *const *)(PTR))
255 #else
256 #define LOADPTR(PTR,PTRINFO)                                            \
257     (assert((PTRINFO)->loadptr != NULL), (PTRINFO)->loadptr(PTR))
258 #endif
259
260 static unsigned int
261 get_nullterm_sequence_len(const void *valp, const struct atype_info *seq)
262 {
263     unsigned int i;
264     const struct atype_info *a;
265     const struct ptr_info *ptr;
266     const void *elt, *eltptr;
267
268     a = seq;
269     i = 0;
270     assert(a->type == atype_ptr);
271     assert(seq->size != 0);
272     ptr = a->tinfo;
273
274     while (1) {
275         eltptr = (const char *) valp + i * seq->size;
276         elt = LOADPTR(eltptr, ptr);
277         if (elt == NULL)
278             break;
279         i++;
280     }
281     return i;
282 }
283 static asn1_error_code
284 encode_sequence_of(asn1buf *buf, unsigned int seqlen, const void *val,
285                    const struct atype_info *eltinfo,
286                    unsigned int *retlen);
287
288 static asn1_error_code
289 encode_nullterm_sequence_of(asn1buf *buf, const void *val,
290                             const struct atype_info *type,
291                             int can_be_empty,
292                             unsigned int *retlen)
293 {
294     unsigned int length = get_nullterm_sequence_len(val, type);
295     if (!can_be_empty && length == 0) return ASN1_MISSING_FIELD;
296     return encode_sequence_of(buf, length, val, type, retlen);
297 }
298
299 static asn1_intmax
300 load_int(const void *val, size_t size)
301 {
302     switch (size) {
303     case 1: return *(signed char *)val;
304     case 2: return *(krb5_int16 *)val;
305     case 4: return *(krb5_int32 *)val;
306     case 8: return *(INT64_TYPE *)val;
307     default: abort();
308     }
309 }
310
311 static asn1_uintmax
312 load_uint(const void *val, size_t size)
313 {
314     switch (size) {
315     case 1: return *(unsigned char *)val;
316     case 2: return *(krb5_ui_2 *)val;
317     case 4: return *(krb5_ui_4 *)val;
318     case 8: return *(UINT64_TYPE *)val;
319     default: abort();
320     }
321 }
322
323 static asn1_error_code
324 load_count(const void *val, const struct counted_info *counted,
325            unsigned int *retcount)
326 {
327     const void *lenptr = (const char *)val + counted->lenoff;
328
329     assert(sizeof(int) <= sizeof(asn1_intmax));
330     assert(sizeof(unsigned int) <= sizeof(asn1_uintmax));
331     if (counted->lensigned) {
332         asn1_intmax xlen = load_int(lenptr, counted->lensize);
333         if (xlen < 0)
334             return EINVAL;
335         if ((unsigned int)xlen != (asn1_uintmax)xlen)
336             return EINVAL;
337         if ((unsigned int)xlen > UINT_MAX)
338             return EINVAL;
339         *retcount = (unsigned int)xlen;
340     } else {
341         asn1_uintmax xlen = load_uint(lenptr, counted->lensize);
342         if ((unsigned int)xlen != xlen)
343             return EINVAL;
344         if (xlen > UINT_MAX)
345             return EINVAL;
346         *retcount = (unsigned int)xlen;
347     }
348     return 0;
349 }
350
351 /* Split a DER encoding into tag and contents.  Insert the contents into buf,
352  * then return the length of the contents and the tag. */
353 static asn1_error_code
354 split_der(asn1buf *buf, unsigned char *const *der, unsigned int len,
355           taginfo *rettag)
356 {
357     asn1buf der_buf;
358     krb5_data der_data = make_data(*der, len);
359     asn1_error_code retval;
360
361     retval = asn1buf_wrap_data(&der_buf, &der_data);
362     if (retval)
363         return retval;
364     retval = asn1_get_tag_2(&der_buf, rettag);
365     if (retval)
366         return retval;
367     if ((unsigned int)asn1buf_remains(&der_buf, 0) != rettag->length)
368         return EINVAL;
369     return asn1buf_insert_bytestring(buf, rettag->length,
370                                      *der + len - rettag->length);
371 }
372
373 static asn1_error_code
374 encode_sequence(asn1buf *buf, const void *val, const struct seq_info *seq,
375                 unsigned int *retlen);
376 static asn1_error_code
377 encode_cntype(asn1buf *buf, const void *val, unsigned int len,
378               const struct cntype_info *c, taginfo *rettag);
379
380 /* Encode a value (contents only, no outer tag) according to a type, and return
381  * its encoded tag information. */
382 asn1_error_code
383 krb5int_asn1_encode_type(asn1buf *buf, const void *val,
384                          const struct atype_info *a, taginfo *rettag)
385 {
386     asn1_error_code retval;
387
388     if (val == NULL)
389         return ASN1_MISSING_FIELD;
390
391     switch (a->type) {
392     case atype_fn: {
393         const struct fn_info *fn = a->tinfo;
394         assert(fn->enc != NULL);
395         return fn->enc(buf, val, rettag);
396     }
397     case atype_sequence:
398         assert(a->tinfo != NULL);
399         retval = encode_sequence(buf, val, a->tinfo, &rettag->length);
400         if (retval)
401             return retval;
402         rettag->asn1class = UNIVERSAL;
403         rettag->construction = CONSTRUCTED;
404         rettag->tagnum = ASN1_SEQUENCE;
405         break;
406     case atype_ptr: {
407         const struct ptr_info *ptr = a->tinfo;
408         assert(ptr->basetype != NULL);
409         return krb5int_asn1_encode_type(buf, LOADPTR(val, ptr), ptr->basetype,
410                                         rettag);
411     }
412     case atype_offset: {
413         const struct offset_info *off = a->tinfo;
414         assert(off->basetype != NULL);
415         return krb5int_asn1_encode_type(buf, (const char *)val + off->dataoff,
416                                         off->basetype, rettag);
417     }
418     case atype_counted: {
419         const struct counted_info *counted = a->tinfo;
420         const void *dataptr = (const char *)val + counted->dataoff;
421         unsigned int len;
422         assert(counted->basetype != NULL);
423         retval = load_count(val, counted, &len);
424         if (retval)
425             return retval;
426         return encode_cntype(buf, dataptr, len, counted->basetype, rettag);
427     }
428     case atype_nullterm_sequence_of:
429     case atype_nonempty_nullterm_sequence_of:
430         assert(a->tinfo != NULL);
431         retval = encode_nullterm_sequence_of(buf, val, a->tinfo,
432                                              a->type ==
433                                              atype_nullterm_sequence_of,
434                                              &rettag->length);
435         if (retval)
436             return retval;
437         rettag->asn1class = UNIVERSAL;
438         rettag->construction = CONSTRUCTED;
439         rettag->tagnum = ASN1_SEQUENCE;
440         break;
441     case atype_tagged_thing: {
442         const struct tagged_info *tag = a->tinfo;
443         retval = krb5int_asn1_encode_type(buf, val, tag->basetype, rettag);
444         if (retval)
445             return retval;
446         if (!tag->implicit) {
447             unsigned int tlen;
448             retval = make_tag(buf, rettag, &tlen);
449             if (retval)
450                 return retval;
451             rettag->length += tlen;
452             rettag->construction = tag->construction;
453         }
454         rettag->asn1class = tag->tagtype;
455         rettag->tagnum = tag->tagval;
456         break;
457     }
458     case atype_int:
459         retval = asn1_encode_integer(buf, load_int(val, a->size),
460                                      &rettag->length);
461         if (retval)
462             return retval;
463         rettag->asn1class = UNIVERSAL;
464         rettag->construction = PRIMITIVE;
465         rettag->tagnum = ASN1_INTEGER;
466         break;
467     case atype_uint:
468         retval = asn1_encode_unsigned_integer(buf, load_uint(val, a->size),
469                                               &rettag->length);
470         if (retval)
471             return retval;
472         rettag->asn1class = UNIVERSAL;
473         rettag->construction = PRIMITIVE;
474         rettag->tagnum = ASN1_INTEGER;
475         break;
476     case atype_int_immediate: {
477         const int *iptr = a->tinfo;
478         retval = asn1_encode_integer(buf, *iptr, &rettag->length);
479         if (retval)
480             return retval;
481         rettag->asn1class = UNIVERSAL;
482         rettag->construction = PRIMITIVE;
483         rettag->tagnum = ASN1_INTEGER;
484         break;
485     }
486     default:
487         assert(a->type > atype_min);
488         assert(a->type < atype_max);
489         abort();
490     }
491
492     return 0;
493 }
494
495 static asn1_error_code
496 encode_type_and_tag(asn1buf *buf, const void *val, const struct atype_info *a,
497                     unsigned int *retlen)
498 {
499     taginfo t;
500     asn1_error_code retval;
501     unsigned int tlen;
502
503     retval = krb5int_asn1_encode_type(buf, val, a, &t);
504     if (retval)
505         return retval;
506     retval = make_tag(buf, &t, &tlen);
507     if (retval)
508         return retval;
509     *retlen = t.length + tlen;
510     return 0;
511 }
512
513 /*
514  * Encode an object and count according to a cntype_info structure.  val is a
515  * pointer to the object being encoded, which in most cases is itself a
516  * pointer (but is a union in the cntype_choice case).
517  */
518 static asn1_error_code
519 encode_cntype(asn1buf *buf, const void *val, unsigned int count,
520               const struct cntype_info *c, taginfo *rettag)
521 {
522     asn1_error_code retval;
523
524     switch (c->type) {
525     case cntype_string: {
526         const struct string_info *string = c->tinfo;
527         assert(string->enc != NULL);
528         retval = string->enc(buf, val, count, &rettag->length);
529         if (retval)
530             return retval;
531         rettag->asn1class = UNIVERSAL;
532         rettag->construction = PRIMITIVE;
533         rettag->tagnum = string->tagval;
534         break;
535     }
536     case cntype_der:
537         return split_der(buf, val, count, rettag);
538     case cntype_seqof: {
539         const struct atype_info *a = c->tinfo;
540         const struct ptr_info *ptr = a->tinfo;
541         assert(a->type == atype_ptr);
542         val = LOADPTR(val, ptr);
543         retval = encode_sequence_of(buf, count, val, ptr->basetype,
544                                     &rettag->length);
545         if (retval)
546             return retval;
547         rettag->asn1class = UNIVERSAL;
548         rettag->construction = CONSTRUCTED;
549         rettag->tagnum = ASN1_SEQUENCE;
550         break;
551     }
552     case cntype_choice: {
553         const struct choice_info *choice = c->tinfo;
554         if (count >= choice->n_options)
555             return ASN1_MISSING_FIELD;
556         return krb5int_asn1_encode_type(buf, val, choice->options[count],
557                                         rettag);
558     }
559
560     default:
561         assert(c->type > cntype_min);
562         assert(c->type < cntype_max);
563         abort();
564     }
565
566     return 0;
567 }
568
569 static asn1_error_code
570 encode_sequence(asn1buf *buf, const void *val, const struct seq_info *seq,
571                 unsigned int *retlen)
572 {
573     asn1_error_code retval;
574     unsigned int not_present, length, sum = 0;
575     size_t i;
576     const struct atype_info *a;
577
578     /* If any fields might be optional, get a bitmask of fields not present. */
579     not_present = (seq->optional == NULL) ? 0 : seq->optional(val);
580     for (i = seq->n_fields; i > 0; i--) {
581         a = seq->fields[i - 1];
582         if ((1u << (i - 1)) & not_present)
583             continue;
584         retval = encode_type_and_tag(buf, val, a, &length);
585         if (retval)
586             return retval;
587         sum += length;
588     }
589     *retlen = sum;
590     return 0;
591 }
592
593 static asn1_error_code
594 encode_sequence_of(asn1buf *buf, unsigned int seqlen, const void *val,
595                    const struct atype_info *eltinfo,
596                    unsigned int *retlen)
597 {
598     asn1_error_code retval;
599     unsigned int sum = 0, i;
600
601     for (i = seqlen; i > 0; i--) {
602         const void *eltptr;
603         unsigned int length;
604         const struct atype_info *a = eltinfo;
605
606         assert(eltinfo->size != 0);
607         eltptr = (const char *)val + (i - 1) * eltinfo->size;
608         retval = encode_type_and_tag(buf, eltptr, a, &length);
609         if (retval)
610             return retval;
611         sum += length;
612     }
613     *retlen = sum;
614     return 0;
615 }
616
617 krb5_error_code
618 krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
619                             const struct atype_info *a)
620 {
621     unsigned int length;
622     asn1_error_code retval;
623     asn1buf *buf = NULL;
624     krb5_data *d;
625
626     *code = NULL;
627
628     if (rep == NULL)
629         return ASN1_MISSING_FIELD;
630
631     retval = asn1buf_create(&buf);
632     if (retval)
633         return retval;
634
635     retval = encode_type_and_tag(buf, rep, a, &length);
636     if (retval)
637         goto cleanup;
638     retval = asn12krb5_buf(buf, &d);
639     if (retval)
640         goto cleanup;
641     *code = d;
642 cleanup:
643     asn1buf_destroy(&buf);
644     return retval;
645 }