Imported Upstream version 1.10.2
[platform/upstream/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 #include "asn1_make.h"
31
32 asn1_error_code
33 asn1_encode_boolean(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
34 {
35     asn1_error_code retval;
36     unsigned int length = 0;
37     unsigned int partlen = 1;
38     asn1_octet bval;
39
40     bval = val ? 0xFF : 0x00;
41
42     retval = asn1buf_insert_octet(buf, bval);
43     if (retval) return retval;
44
45     length = partlen;
46     retval = asn1_make_tag(buf, UNIVERSAL, PRIMITIVE, ASN1_BOOLEAN, length, &partlen);
47     if (retval) return retval;
48     length += partlen;
49
50     *retlen = length;
51     return 0;
52 }
53
54 static asn1_error_code
55 asn1_encode_integer_internal(asn1buf *buf, asn1_intmax val,
56                              unsigned int *retlen)
57 {
58     asn1_error_code retval;
59     unsigned int length = 0;
60     long valcopy;
61     int digit;
62
63     valcopy = val;
64     do {
65         digit = (int) (valcopy&0xFF);
66         retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
67         if (retval) return retval;
68         length++;
69         valcopy = valcopy >> 8;
70     } while (valcopy != 0 && valcopy != ~0);
71
72     if ((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */
73         retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
74         if (retval) return retval;
75         length++;
76     } else if ((val < 0) && ((digit&0x80) != 0x80)) {
77         retval = asn1buf_insert_octet(buf,0xFF);
78         if (retval) return retval;
79         length++;
80     }
81
82
83     *retlen = length;
84     return 0;
85 }
86
87 asn1_error_code
88 asn1_encode_integer(asn1buf * buf, asn1_intmax val, unsigned int *retlen)
89 {
90     asn1_error_code retval;
91     unsigned int length = 0;
92     unsigned  int partlen;
93     retval = asn1_encode_integer_internal(buf, val, &partlen);
94     if (retval) return retval;
95
96     length = partlen;
97     retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_INTEGER,length, &partlen);
98     if (retval) return retval;
99     length += partlen;
100
101     *retlen = length;
102     return 0;
103 }
104
105 #if 0
106 asn1_error_code
107 asn1_encode_enumerated(asn1buf * buf, long val,
108                        unsigned int *retlen)
109 {
110     asn1_error_code retval;
111     unsigned int length = 0;
112     unsigned  int partlen;
113     retval = asn1_encode_integer_internal(buf, val, &partlen);
114     if (retval) return retval;
115
116     length = partlen;
117     retval = asn1_make_tag(buf,UNIVERSAL,PRIMITIVE,ASN1_ENUMERATED,length, &partlen);
118     if (retval) return retval;
119     length += partlen;
120
121     *retlen = length;
122     return 0;
123 }
124 #endif
125
126 asn1_error_code
127 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
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
178 asn1_error_code
179 asn1_encode_oid(asn1buf *buf, unsigned int len, const void *val,
180                 unsigned int *retlen)
181 {
182     return encode_bytestring_with_tag(buf, len, val, ASN1_OBJECTIDENTIFIER,
183                                       retlen);
184 }
185
186 asn1_error_code
187 asn1_encode_octetstring(asn1buf *buf, unsigned int len, 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
223 asn1_error_code
224 asn1_encode_generaltime(asn1buf *buf, time_t val, 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
276 asn1_error_code
277 asn1_encode_generalstring(asn1buf *buf, unsigned int len, const void *val,
278                           unsigned int *retlen)
279 {
280     return encode_bytestring_with_tag(buf, len, val, ASN1_GENERALSTRING,
281                                       retlen);
282 }
283
284 asn1_error_code
285 asn1_encode_bitstring(asn1buf *buf, unsigned int len, 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
302 asn1_error_code
303 asn1_encode_opaque(asn1buf *buf, unsigned int len, const void *val,
304                    unsigned int *retlen)
305 {
306     asn1_error_code retval;
307
308     retval = asn1buf_insert_octetstring(buf, len, val);
309     if (retval) return retval;
310     *retlen = len;
311     return 0;
312 }
313
314 /*
315  * ASN.1 constructed type encoder engine
316  *
317  * Two entry points here:
318  *
319  * krb5int_asn1_encode_a_thing: Incrementally adds the partial
320  * encoding of an object to an already-initialized asn1buf.
321  *
322  * krb5int_asn1_do_full_encode: Returns a completed encoding, in the
323  * correct byte order, in an allocated krb5_data.
324  */
325
326 #ifdef POINTERS_ARE_ALL_THE_SAME
327 #define LOADPTR(PTR,TYPE)                       \
328     (*(const void *const *)(PTR))
329 #else
330 #define LOADPTR(PTR,TYPE)                                       \
331     (assert((TYPE)->loadptr != NULL), (TYPE)->loadptr(PTR))
332 #endif
333
334 static int
335 get_nullterm_sequence_len(const void *valp, const struct atype_info *seq)
336 {
337     int i;
338     const struct atype_info *a;
339     const void *elt, *eltptr;
340
341     a = seq;
342     i = 0;
343     assert(a->type == atype_ptr);
344     assert(seq->size != 0);
345
346     while (1) {
347         eltptr = (const char *) valp + i * seq->size;
348         elt = LOADPTR(eltptr, a);
349         if (elt == NULL)
350             break;
351         i++;
352     }
353     return i;
354 }
355 static asn1_error_code
356 encode_sequence_of(asn1buf *buf, int seqlen, const void *val,
357                    const struct atype_info *eltinfo,
358                    unsigned int *retlen);
359
360 static asn1_error_code
361 encode_nullterm_sequence_of(asn1buf *buf, const void *val,
362                             const struct atype_info *type,
363                             int can_be_empty,
364                             unsigned int *retlen)
365 {
366     int length = get_nullterm_sequence_len(val, type);
367     if (!can_be_empty && length == 0) return ASN1_MISSING_FIELD;
368     return encode_sequence_of(buf, length, val, type, retlen);
369 }
370
371 static asn1_error_code
372 just_encode_sequence(asn1buf *buf, const void *val,
373                      const struct seq_info *seq,
374                      unsigned int *retlen);
375 static asn1_error_code
376 encode_a_field(asn1buf *buf, const void *val,
377                const struct field_info *field,
378                unsigned int *retlen);
379
380 asn1_error_code
381 krb5int_asn1_encode_a_thing(asn1buf *buf, const void *val,
382                             const struct atype_info *a, unsigned int *retlen)
383 {
384     switch (a->type) {
385     case atype_fn:
386         assert(a->enc != NULL);
387         return a->enc(buf, val, retlen);
388     case atype_sequence:
389         assert(a->seq != NULL);
390         return just_encode_sequence(buf, val, a->seq, retlen);
391     case atype_ptr:
392         assert(a->basetype != NULL);
393         return krb5int_asn1_encode_a_thing(buf, LOADPTR(val, a),
394                                            a->basetype, retlen);
395     case atype_field:
396         assert(a->field != NULL);
397         return encode_a_field(buf, val, a->field, retlen);
398     case atype_nullterm_sequence_of:
399     case atype_nonempty_nullterm_sequence_of:
400         assert(a->basetype != NULL);
401         return encode_nullterm_sequence_of(buf, val, a->basetype,
402                                            a->type == atype_nullterm_sequence_of,
403                                            retlen);
404     case atype_tagged_thing:
405     {
406         asn1_error_code retval;
407         unsigned int length, sum = 0;
408         retval = krb5int_asn1_encode_a_thing(buf, val, a->basetype, &length);
409         if (retval) return retval;
410         sum = length;
411         retval = asn1_make_tag(buf, a->tagtype, a->construction, a->tagval, sum, &length);
412         if (retval) return retval;
413         sum += length;
414         *retlen = sum;
415         return 0;
416     }
417     case atype_int:
418         assert(a->loadint != NULL);
419         return asn1_encode_integer(buf, a->loadint(val), retlen);
420     case atype_uint:
421         assert(a->loaduint != NULL);
422         return asn1_encode_unsigned_integer(buf, a->loaduint(val), retlen);
423     case atype_min:
424     case atype_max:
425     case atype_fn_len:
426     default:
427         assert(a->type > atype_min);
428         assert(a->type < atype_max);
429         assert(a->type != atype_fn_len);
430         abort();
431     }
432 }
433
434 static asn1_error_code
435 encode_a_field(asn1buf *buf, const void *val,
436                const struct field_info *field,
437                unsigned int *retlen)
438 {
439     asn1_error_code retval;
440     unsigned int sum = 0;
441
442     if (val == NULL) return ASN1_MISSING_FIELD;
443
444     switch (field->ftype) {
445     case field_immediate:
446     {
447         unsigned int length;
448
449         retval = asn1_encode_integer(buf, (asn1_intmax) field->dataoff,
450                                      &length);
451         if (retval) return retval;
452         sum += length;
453         break;
454     }
455     case field_sequenceof_len:
456     {
457         const void *dataptr, *lenptr;
458         int slen;
459         unsigned int length;
460         const struct atype_info *a;
461
462         /*
463          * The field holds a pointer to the array of objects.  So the
464          * address we compute is a pointer-to-pointer, and that's what
465          * field->atype must help us dereference.
466          */
467         dataptr = (const char *)val + field->dataoff;
468         lenptr = (const char *)val + field->lenoff;
469         assert(field->atype->type == atype_ptr);
470         dataptr = LOADPTR(dataptr, field->atype);
471         a = field->atype->basetype;
472         assert(field->lentype != 0);
473         assert(field->lentype->type == atype_int || field->lentype->type == atype_uint);
474         assert(sizeof(int) <= sizeof(asn1_intmax));
475         assert(sizeof(unsigned int) <= sizeof(asn1_uintmax));
476         if (field->lentype->type == atype_int) {
477             asn1_intmax xlen = field->lentype->loadint(lenptr);
478             if (xlen < 0)
479                 return EINVAL;
480             if ((unsigned int) xlen != (asn1_uintmax) xlen)
481                 return EINVAL;
482             if ((unsigned int) xlen > INT_MAX)
483                 return EINVAL;
484             slen = (int) xlen;
485         } else {
486             asn1_uintmax xlen = field->lentype->loaduint(lenptr);
487             if ((unsigned int) xlen != xlen)
488                 return EINVAL;
489             if (xlen > INT_MAX)
490                 return EINVAL;
491             slen = (int) xlen;
492         }
493         if (slen != 0 && dataptr == NULL)
494             return ASN1_MISSING_FIELD;
495         retval = encode_sequence_of(buf, slen, dataptr, a, &length);
496         if (retval) return retval;
497         sum += length;
498         break;
499     }
500     case field_normal:
501     {
502         const void *dataptr;
503         const struct atype_info *a;
504         unsigned int length;
505
506         dataptr = (const char *)val + field->dataoff;
507
508         a = field->atype;
509         assert(a->type != atype_fn_len);
510         retval = krb5int_asn1_encode_a_thing(buf, dataptr, a, &length);
511         if (retval) {
512             return retval;
513         }
514         sum += length;
515         break;
516     }
517     case field_string:
518     {
519         const void *dataptr, *lenptr;
520         const struct atype_info *a;
521         size_t slen;
522         unsigned int length;
523
524         dataptr = (const char *)val + field->dataoff;
525         lenptr = (const char *)val + field->lenoff;
526
527         a = field->atype;
528         assert(a->type == atype_fn_len);
529         assert(field->lentype != 0);
530         assert(field->lentype->type == atype_int || field->lentype->type == atype_uint);
531         assert(sizeof(int) <= sizeof(asn1_intmax));
532         assert(sizeof(unsigned int) <= sizeof(asn1_uintmax));
533         if (field->lentype->type == atype_int) {
534             asn1_intmax xlen = field->lentype->loadint(lenptr);
535             if (xlen < 0)
536                 return EINVAL;
537             if ((size_t) xlen != (asn1_uintmax) xlen)
538                 return EINVAL;
539             slen = (size_t) xlen;
540         } else {
541             asn1_uintmax xlen = field->lentype->loaduint(lenptr);
542             if ((size_t) xlen != xlen)
543                 return EINVAL;
544             slen = (size_t) xlen;
545         }
546
547         dataptr = LOADPTR(dataptr, a);
548         if (slen == SIZE_MAX)
549             /* Error - negative or out of size_t range.  */
550             return EINVAL;
551         if (dataptr == NULL && slen != 0)
552             return ASN1_MISSING_FIELD;
553         /*
554          * Currently our string encoders want "unsigned int" for
555          * lengths.
556          */
557         if (slen != (unsigned int) slen)
558             return EINVAL;
559         assert(a->enclen != NULL);
560         retval = a->enclen(buf, (unsigned int) slen, dataptr, &length);
561         if (retval) {
562             return retval;
563         }
564         sum += length;
565         break;
566     }
567     default:
568         assert(field->ftype > field_min);
569         assert(field->ftype < field_max);
570         assert(__LINE__ == 0);
571         abort();
572     }
573     if (field->tag >= 0) {
574         unsigned int length;
575         retval = asn1_make_etag(buf, CONTEXT_SPECIFIC, field->tag, sum,
576                                 &length);
577         if (retval) {
578             return retval;
579         }
580         sum += length;
581     }
582     *retlen = sum;
583     return 0;
584 }
585
586 static asn1_error_code
587 encode_fields(asn1buf *buf, const void *val,
588               const struct field_info *fields, size_t nfields,
589               unsigned int optional,
590               unsigned int *retlen)
591 {
592     size_t i;
593     unsigned int sum = 0;
594     for (i = nfields; i > 0; i--) {
595         const struct field_info *f = fields+i-1;
596         unsigned int length;
597         asn1_error_code retval;
598         int present;
599
600         if (f->opt == -1)
601             present = 1;
602         else if ((1u << f->opt) & optional)
603             present = 1;
604         else
605             present = 0;
606         if (present) {
607             retval = encode_a_field(buf, val, f, &length);
608             if (retval) return retval;
609             sum += length;
610         }
611     }
612     *retlen = sum;
613     return 0;
614 }
615
616 static asn1_error_code
617 just_encode_sequence(asn1buf *buf, const void *val,
618                      const struct seq_info *seq,
619                      unsigned int *retlen)
620 {
621     const struct field_info *fields = seq->fields;
622     size_t nfields = seq->n_fields;
623     unsigned int optional;
624     asn1_error_code retval;
625     unsigned int sum = 0;
626
627     if (seq->optional)
628         optional = seq->optional(val);
629     else
630         /*
631          * In this case, none of the field descriptors should indicate
632          * that we examine any bits of this value.
633          */
634         optional = 0;
635     {
636         unsigned int length;
637         retval = encode_fields(buf, val, fields, nfields, optional, &length);
638         if (retval) return retval;
639         sum += length;
640     }
641     {
642         unsigned int length;
643         retval = asn1_make_sequence(buf, sum, &length);
644         if (retval) return retval;
645         sum += length;
646     }
647     *retlen = sum;
648     return 0;
649 }
650
651 static asn1_error_code
652 encode_sequence_of(asn1buf *buf, int seqlen, const void *val,
653                    const struct atype_info *eltinfo,
654                    unsigned int *retlen)
655 {
656     asn1_error_code retval;
657     unsigned int sum = 0;
658     int i;
659
660     for (i = seqlen-1; i >= 0; i--) {
661         const void *eltptr;
662         unsigned int length;
663         const struct atype_info *a = eltinfo;
664
665         assert(eltinfo->size != 0);
666         eltptr = (const char *)val + i * eltinfo->size;
667         retval = krb5int_asn1_encode_a_thing(buf, eltptr, a, &length);
668         if (retval) return retval;
669         sum += length;
670     }
671     {
672         unsigned int length;
673         retval = asn1_make_sequence(buf, sum, &length);
674         if (retval) return retval;
675         sum += length;
676     }
677     *retlen = sum;
678     return 0;
679 }
680
681 krb5_error_code
682 krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
683                             const struct atype_info *a)
684 {
685     unsigned int length;
686     asn1_error_code retval;
687     asn1buf *buf = NULL;
688     krb5_data *d;
689
690     *code = NULL;
691
692     if (rep == NULL)
693         return ASN1_MISSING_FIELD;
694
695     retval = asn1buf_create(&buf);
696     if (retval)
697         return retval;
698
699     retval = krb5int_asn1_encode_a_thing(buf, rep, a, &length);
700     if (retval)
701         goto cleanup;
702     retval = asn12krb5_buf(buf, &d);
703     if (retval)
704         goto cleanup;
705     *code = d;
706 cleanup:
707     asn1buf_destroy(&buf);
708     return retval;
709 }