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
33asn1_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
55static 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
88asn1_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
107asn1_error_code
108asn1_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
127asn1_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
159static asn1_error_code
160encode_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
178asn1_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
186asn1_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
195asn1_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
208asn1_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
215asn1_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
223asn1_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
276asn1_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
284asn1_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
302asn1_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
331static int
332get_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}
352static asn1_error_code
353encode_sequence_of(asn1buf *buf, int seqlen, const void *val,
354                   const struct atype_info *eltinfo,
355                   unsigned int *retlen);
356
357static asn1_error_code
358encode_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
368static asn1_error_code
369just_encode_sequence(asn1buf *buf, const void *val,
370                     const struct seq_info *seq,
371                     unsigned int *retlen);
372static asn1_error_code
373encode_a_field(asn1buf *buf, const void *val,
374               const struct field_info *field,
375               unsigned int *retlen);
376
377asn1_error_code
378krb5int_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
431static asn1_error_code
432encode_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
579static asn1_error_code
580encode_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
609static asn1_error_code
610just_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
642static asn1_error_code
643encode_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
672krb5_error_code
673krb5int_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;
697cleanup:
698    asn1buf_destroy(&buf);
699    return retval;
700}
701