1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/asn.1/asn1_encode.c */
4 * Copyright 1994, 2008 by the Massachusetts Institute of Technology.
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.
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.
27 /* ASN.1 primitive encoders */
29 #include "asn1_encode.h"
32 asn1_encode_boolean(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
34 asn1_octet bval = val ? 0xFF : 0x00;
37 return asn1buf_insert_octet(buf, bval);
41 asn1_encode_integer(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
43 asn1_error_code retval;
44 unsigned int length = 0;
50 digit = (int) (valcopy&0xFF);
51 retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
52 if (retval) return retval;
54 valcopy = valcopy >> 8;
55 } while (valcopy != 0 && valcopy != ~0);
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;
61 } else if ((val < 0) && ((digit&0x80) != 0x80)) {
62 retval = asn1buf_insert_octet(buf,0xFF);
63 if (retval) return retval;
73 asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
76 asn1_error_code retval;
77 unsigned int length = 0;
78 unsigned long valcopy;
83 digit = (int) (valcopy&0xFF);
84 retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
85 if (retval) return retval;
87 valcopy = valcopy >> 8;
88 } while (valcopy != 0);
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;
101 asn1_encode_bytestring(asn1buf *buf, unsigned char *const *val,
102 unsigned int len, unsigned int *retlen)
104 if (len > 0 && val == NULL) return ASN1_MISSING_FIELD;
106 return asn1buf_insert_octetstring(buf, len, *val);
110 asn1_encode_generaltime(asn1buf *buf, time_t val, unsigned int *retlen)
112 struct tm *gtime, gtimebuf;
115 time_t gmt_time = val;
118 * Time encoding: YYYYMMDDhhmmssZ
121 sp = (unsigned char *)"19700101000000Z";
126 * Sanity check this just to be paranoid, as gmtime can return NULL,
127 * and some bogus implementations might overrun on the sprintf.
130 # ifdef GMTIME_R_RETURNS_INT
131 if (gmtime_r(&gmt_time, >imebuf) != 0)
132 return ASN1_BAD_GMTIME;
134 if (gmtime_r(&gmt_time, >imebuf) == NULL)
135 return ASN1_BAD_GMTIME;
138 gtime = gmtime(&gmt_time);
140 return ASN1_BAD_GMTIME;
141 memcpy(>imebuf, gtime, sizeof(gtimebuf));
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;
159 return asn1_encode_bytestring(buf, &sp, 15, retlen);
163 asn1_encode_bitstring(asn1buf *buf, unsigned char *const *val,
164 unsigned int len, unsigned int *retlen)
166 asn1_error_code retval;
168 retval = asn1buf_insert_octetstring(buf, len, *val);
169 if (retval) return retval;
171 return asn1buf_insert_octet(buf, '\0');
174 static asn1_error_code
175 make_tag(asn1buf *buf, const taginfo *t, unsigned int *retlen)
178 asn1_tagnum tag_copy;
179 unsigned int sum = 0, length, len_copy;
181 if (t->tagnum > ASN1_TAGNUM_MAX)
182 return ASN1_OVERFLOW;
184 /* Encode the length of the content within the tag. */
185 if (t->length < 128) {
186 ret = asn1buf_insert_octet(buf, t->length & 0x7F);
192 for (len_copy = t->length; len_copy != 0; len_copy >>= 8) {
193 ret = asn1buf_insert_octet(buf, len_copy & 0xFF);
198 ret = asn1buf_insert_octet(buf, 0x80 | (length & 0x7F));
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);
213 tag_copy = t->tagnum;
215 ret = asn1buf_insert_octet(buf, tag_copy & 0x7F);
221 for (; tag_copy != 0; tag_copy >>= 7) {
222 ret = asn1buf_insert_octet(buf, 0x80 | (tag_copy & 0x7F));
228 ret = asn1buf_insert_octet(buf, t->asn1class | t->construction | 0x1F);
240 * ASN.1 constructed type encoder engine
242 * Two entry points here:
244 * krb5int_asn1_encode_type: Incrementally adds the contents-only encoding of
245 * an object to an already-initialized asn1buf, and returns its tag
248 * krb5int_asn1_do_full_encode: Returns a completed encoding, in the
249 * correct byte order, in an allocated krb5_data.
252 #ifdef POINTERS_ARE_ALL_THE_SAME
253 #define LOADPTR(PTR,TYPE) \
254 (*(const void *const *)(PTR))
256 #define LOADPTR(PTR,PTRINFO) \
257 (assert((PTRINFO)->loadptr != NULL), (PTRINFO)->loadptr(PTR))
261 get_nullterm_sequence_len(const void *valp, const struct atype_info *seq)
264 const struct atype_info *a;
265 const struct ptr_info *ptr;
266 const void *elt, *eltptr;
270 assert(a->type == atype_ptr);
271 assert(seq->size != 0);
275 eltptr = (const char *) valp + i * seq->size;
276 elt = LOADPTR(eltptr, ptr);
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);
288 static asn1_error_code
289 encode_nullterm_sequence_of(asn1buf *buf, const void *val,
290 const struct atype_info *type,
292 unsigned int *retlen)
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);
300 load_int(const void *val, size_t 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;
312 load_uint(const void *val, size_t 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;
323 static asn1_error_code
324 load_count(const void *val, const struct counted_info *counted,
325 unsigned int *retcount)
327 const void *lenptr = (const char *)val + counted->lenoff;
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);
335 if ((unsigned int)xlen != (asn1_uintmax)xlen)
337 if ((unsigned int)xlen > UINT_MAX)
339 *retcount = (unsigned int)xlen;
341 asn1_uintmax xlen = load_uint(lenptr, counted->lensize);
342 if ((unsigned int)xlen != xlen)
346 *retcount = (unsigned int)xlen;
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,
358 krb5_data der_data = make_data(*der, len);
359 asn1_error_code retval;
361 retval = asn1buf_wrap_data(&der_buf, &der_data);
364 retval = asn1_get_tag_2(&der_buf, rettag);
367 if ((unsigned int)asn1buf_remains(&der_buf, 0) != rettag->length)
369 return asn1buf_insert_bytestring(buf, rettag->length,
370 *der + len - rettag->length);
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);
380 /* Encode a value (contents only, no outer tag) according to a type, and return
381 * its encoded tag information. */
383 krb5int_asn1_encode_type(asn1buf *buf, const void *val,
384 const struct atype_info *a, taginfo *rettag)
386 asn1_error_code retval;
389 return ASN1_MISSING_FIELD;
393 const struct fn_info *fn = a->tinfo;
394 assert(fn->enc != NULL);
395 return fn->enc(buf, val, rettag);
398 assert(a->tinfo != NULL);
399 retval = encode_sequence(buf, val, a->tinfo, &rettag->length);
402 rettag->asn1class = UNIVERSAL;
403 rettag->construction = CONSTRUCTED;
404 rettag->tagnum = ASN1_SEQUENCE;
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,
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);
418 case atype_counted: {
419 const struct counted_info *counted = a->tinfo;
420 const void *dataptr = (const char *)val + counted->dataoff;
422 assert(counted->basetype != NULL);
423 retval = load_count(val, counted, &len);
426 return encode_cntype(buf, dataptr, len, counted->basetype, rettag);
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,
433 atype_nullterm_sequence_of,
437 rettag->asn1class = UNIVERSAL;
438 rettag->construction = CONSTRUCTED;
439 rettag->tagnum = ASN1_SEQUENCE;
441 case atype_tagged_thing: {
442 const struct tagged_info *tag = a->tinfo;
443 retval = krb5int_asn1_encode_type(buf, val, tag->basetype, rettag);
446 if (!tag->implicit) {
448 retval = make_tag(buf, rettag, &tlen);
451 rettag->length += tlen;
452 rettag->construction = tag->construction;
454 rettag->asn1class = tag->tagtype;
455 rettag->tagnum = tag->tagval;
459 retval = asn1_encode_integer(buf, load_int(val, a->size),
463 rettag->asn1class = UNIVERSAL;
464 rettag->construction = PRIMITIVE;
465 rettag->tagnum = ASN1_INTEGER;
468 retval = asn1_encode_unsigned_integer(buf, load_uint(val, a->size),
472 rettag->asn1class = UNIVERSAL;
473 rettag->construction = PRIMITIVE;
474 rettag->tagnum = ASN1_INTEGER;
476 case atype_int_immediate: {
477 const int *iptr = a->tinfo;
478 retval = asn1_encode_integer(buf, *iptr, &rettag->length);
481 rettag->asn1class = UNIVERSAL;
482 rettag->construction = PRIMITIVE;
483 rettag->tagnum = ASN1_INTEGER;
487 assert(a->type > atype_min);
488 assert(a->type < atype_max);
495 static asn1_error_code
496 encode_type_and_tag(asn1buf *buf, const void *val, const struct atype_info *a,
497 unsigned int *retlen)
500 asn1_error_code retval;
503 retval = krb5int_asn1_encode_type(buf, val, a, &t);
506 retval = make_tag(buf, &t, &tlen);
509 *retlen = t.length + tlen;
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).
518 static asn1_error_code
519 encode_cntype(asn1buf *buf, const void *val, unsigned int count,
520 const struct cntype_info *c, taginfo *rettag)
522 asn1_error_code retval;
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);
531 rettag->asn1class = UNIVERSAL;
532 rettag->construction = PRIMITIVE;
533 rettag->tagnum = string->tagval;
537 return split_der(buf, val, count, rettag);
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,
547 rettag->asn1class = UNIVERSAL;
548 rettag->construction = CONSTRUCTED;
549 rettag->tagnum = ASN1_SEQUENCE;
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],
561 assert(c->type > cntype_min);
562 assert(c->type < cntype_max);
569 static asn1_error_code
570 encode_sequence(asn1buf *buf, const void *val, const struct seq_info *seq,
571 unsigned int *retlen)
573 asn1_error_code retval;
574 unsigned int not_present, length, sum = 0;
576 const struct atype_info *a;
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)
584 retval = encode_type_and_tag(buf, val, a, &length);
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)
598 asn1_error_code retval;
599 unsigned int sum = 0, i;
601 for (i = seqlen; i > 0; i--) {
604 const struct atype_info *a = eltinfo;
606 assert(eltinfo->size != 0);
607 eltptr = (const char *)val + (i - 1) * eltinfo->size;
608 retval = encode_type_and_tag(buf, eltptr, a, &length);
618 krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
619 const struct atype_info *a)
622 asn1_error_code retval;
629 return ASN1_MISSING_FIELD;
631 retval = asn1buf_create(&buf);
635 retval = encode_type_and_tag(buf, rep, a, &length);
638 retval = asn12krb5_buf(buf, &d);
643 asn1buf_destroy(&buf);