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"
30 #include "asn1_make.h"
33 asn1_encode_boolean(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
35 asn1_octet bval = val ? 0xFF : 0x00;
38 return asn1buf_insert_octet(buf, bval);
42 asn1_encode_integer(asn1buf *buf, asn1_intmax val, unsigned int *retlen)
44 asn1_error_code retval;
45 unsigned int length = 0;
51 digit = (int) (valcopy&0xFF);
52 retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
53 if (retval) return retval;
55 valcopy = valcopy >> 8;
56 } while (valcopy != 0 && valcopy != ~0);
58 if ((val > 0) && ((digit&0x80) == 0x80)) { /* make sure the high bit is */
59 retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
60 if (retval) return retval;
62 } else if ((val < 0) && ((digit&0x80) != 0x80)) {
63 retval = asn1buf_insert_octet(buf,0xFF);
64 if (retval) return retval;
74 asn1_encode_unsigned_integer(asn1buf *buf, asn1_uintmax val,
77 asn1_error_code retval;
78 unsigned int length = 0;
79 unsigned long valcopy;
84 digit = (int) (valcopy&0xFF);
85 retval = asn1buf_insert_octet(buf,(asn1_octet) digit);
86 if (retval) return retval;
88 valcopy = valcopy >> 8;
89 } while (valcopy != 0);
91 if (digit&0x80) { /* make sure the high bit is */
92 retval = asn1buf_insert_octet(buf,0); /* of the proper signed-ness */
93 if (retval) return retval;
102 asn1_encode_bytestring(asn1buf *buf, unsigned int len, const void *val,
103 unsigned int *retlen)
105 if (len > 0 && val == NULL) return ASN1_MISSING_FIELD;
107 return asn1buf_insert_octetstring(buf, len, val);
111 asn1_encode_generaltime(asn1buf *buf, time_t val, unsigned int *retlen)
113 struct tm *gtime, gtimebuf;
115 time_t gmt_time = val;
118 * Time encoding: YYYYMMDDhhmmssZ
121 sp = "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;
159 return asn1_encode_bytestring(buf, 15, sp, retlen);
163 asn1_encode_bitstring(asn1buf *buf, unsigned int len, const void *val,
164 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');
175 * ASN.1 constructed type encoder engine
177 * Two entry points here:
179 * krb5int_asn1_encode_type: Incrementally adds the contents-only encoding of
180 * an object to an already-initialized asn1buf, and returns its tag
183 * krb5int_asn1_do_full_encode: Returns a completed encoding, in the
184 * correct byte order, in an allocated krb5_data.
187 #ifdef POINTERS_ARE_ALL_THE_SAME
188 #define LOADPTR(PTR,TYPE) \
189 (*(const void *const *)(PTR))
191 #define LOADPTR(PTR,PTRINFO) \
192 (assert((PTRINFO)->loadptr != NULL), (PTRINFO)->loadptr(PTR))
196 get_nullterm_sequence_len(const void *valp, const struct atype_info *seq)
199 const struct atype_info *a;
200 const struct ptr_info *ptr;
201 const void *elt, *eltptr;
205 assert(a->type == atype_ptr);
206 assert(seq->size != 0);
210 eltptr = (const char *) valp + i * seq->size;
211 elt = LOADPTR(eltptr, ptr);
218 static asn1_error_code
219 encode_sequence_of(asn1buf *buf, unsigned int seqlen, const void *val,
220 const struct atype_info *eltinfo,
221 unsigned int *retlen);
223 static asn1_error_code
224 encode_nullterm_sequence_of(asn1buf *buf, const void *val,
225 const struct atype_info *type,
227 unsigned int *retlen)
229 unsigned int length = get_nullterm_sequence_len(val, type);
230 if (!can_be_empty && length == 0) return ASN1_MISSING_FIELD;
231 return encode_sequence_of(buf, length, val, type, retlen);
235 load_int(const void *val, size_t size)
238 case 1: return *(signed char *)val;
239 case 2: return *(krb5_int16 *)val;
240 case 4: return *(krb5_int32 *)val;
241 case 8: return *(INT64_TYPE *)val;
247 load_uint(const void *val, size_t size)
250 case 1: return *(unsigned char *)val;
251 case 2: return *(krb5_ui_2 *)val;
252 case 4: return *(krb5_ui_4 *)val;
253 case 8: return *(UINT64_TYPE *)val;
258 static asn1_error_code
259 just_encode_sequence(asn1buf *buf, const void *val,
260 const struct seq_info *seq,
261 unsigned int *retlen);
262 static asn1_error_code
263 encode_a_field(asn1buf *buf, const void *val, const struct field_info *field,
266 /* Encode a value (contents only, no outer tag) according to a type, and return
267 * its encoded tag information. */
269 krb5int_asn1_encode_type(asn1buf *buf, const void *val,
270 const struct atype_info *a, taginfo *rettag)
272 asn1_error_code retval;
275 case atype_primitive: {
276 const struct primitive_info *prim = a->tinfo;
277 assert(prim->enc != NULL);
278 retval = prim->enc(buf, val, &rettag->length);
279 if (retval) return retval;
280 rettag->asn1class = UNIVERSAL;
281 rettag->construction = PRIMITIVE;
282 rettag->tagnum = prim->tagval;
286 const struct fn_info *fn = a->tinfo;
287 assert(fn->enc != NULL);
288 return fn->enc(buf, val, rettag);
291 assert(a->tinfo != NULL);
292 retval = just_encode_sequence(buf, val, a->tinfo, &rettag->length);
295 rettag->asn1class = UNIVERSAL;
296 rettag->construction = CONSTRUCTED;
297 rettag->tagnum = ASN1_SEQUENCE;
300 const struct ptr_info *ptr = a->tinfo;
301 assert(ptr->basetype != NULL);
302 return krb5int_asn1_encode_type(buf, LOADPTR(val, ptr), ptr->basetype,
306 assert(a->tinfo != NULL);
307 return encode_a_field(buf, val, a->tinfo, rettag);
308 case atype_nullterm_sequence_of:
309 case atype_nonempty_nullterm_sequence_of:
310 assert(a->tinfo != NULL);
311 retval = encode_nullterm_sequence_of(buf, val, a->tinfo,
313 atype_nullterm_sequence_of,
317 rettag->asn1class = UNIVERSAL;
318 rettag->construction = CONSTRUCTED;
319 rettag->tagnum = ASN1_SEQUENCE;
321 case atype_tagged_thing: {
322 const struct tagged_info *tag = a->tinfo;
323 retval = krb5int_asn1_encode_type(buf, val, tag->basetype, rettag);
326 if (!tag->implicit) {
328 retval = asn1_make_tag(buf, rettag->asn1class,
329 rettag->construction, rettag->tagnum,
330 rettag->length, &tlen);
333 rettag->length += tlen;
334 rettag->construction = tag->construction;
336 rettag->asn1class = tag->tagtype;
337 rettag->tagnum = tag->tagval;
341 retval = asn1_encode_integer(buf, load_int(val, a->size),
345 rettag->asn1class = UNIVERSAL;
346 rettag->construction = PRIMITIVE;
347 rettag->tagnum = ASN1_INTEGER;
351 retval = asn1_encode_unsigned_integer(buf, load_uint(val, a->size),
355 rettag->asn1class = UNIVERSAL;
356 rettag->construction = PRIMITIVE;
357 rettag->tagnum = ASN1_INTEGER;
362 case atype_string: /* only usable with field_string */
363 case atype_der: /* only usable with field_der */
364 case atype_choice: /* only usable with field_choice */
366 assert(a->type > atype_min);
367 assert(a->type < atype_max);
368 assert(a->type != atype_string);
369 assert(a->type != atype_der);
370 assert(a->type != atype_choice);
377 static asn1_error_code
378 encode_type_and_tag(asn1buf *buf, const void *val, const struct atype_info *a,
379 unsigned int *retlen)
382 asn1_error_code retval;
385 retval = krb5int_asn1_encode_type(buf, val, a, &t);
388 retval = asn1_make_tag(buf, t.asn1class, t.construction, t.tagnum,
392 *retlen = t.length + tlen;
396 static asn1_error_code
397 get_field_len(const void *val, const struct field_info *field,
398 unsigned int *retlen)
400 const void *lenptr = (const char *)val + field->lenoff;
402 assert(field->lentype != NULL);
403 assert(field->lentype->type == atype_int ||
404 field->lentype->type == atype_uint);
405 assert(sizeof(int) <= sizeof(asn1_intmax));
406 assert(sizeof(unsigned int) <= sizeof(asn1_uintmax));
407 if (field->lentype->type == atype_int) {
408 asn1_intmax xlen = load_int(lenptr, field->lentype->size);
411 if ((unsigned int)xlen != (asn1_uintmax)xlen)
413 if ((unsigned int)xlen > UINT_MAX)
415 *retlen = (unsigned int)xlen;
417 asn1_uintmax xlen = load_uint(lenptr, field->lentype->size);
418 if ((unsigned int)xlen != xlen)
422 *retlen = (unsigned int)xlen;
427 /* Split a DER encoding into tag and contents. Insert the contents into buf,
428 * then return the length of the contents and the tag. */
429 static asn1_error_code
430 split_der(asn1buf *buf, const unsigned char *der, unsigned int len,
434 krb5_data der_data = make_data((unsigned char *)der, len);
435 asn1_error_code retval;
437 retval = asn1buf_wrap_data(&der_buf, &der_data);
440 retval = asn1_get_tag_2(&der_buf, rettag);
443 if ((unsigned int)asn1buf_remains(&der_buf, 0) != rettag->length)
445 return asn1buf_insert_bytestring(buf, rettag->length,
446 der + len - rettag->length);
449 /* Encode part of a value (contents only, no tag) according to a field
450 * descriptor and return its encoded length and tag. */
451 static asn1_error_code
452 encode_a_field(asn1buf *buf, const void *val, const struct field_info *field,
455 asn1_error_code retval;
457 if (val == NULL) return ASN1_MISSING_FIELD;
458 assert(!(field->tag_implicit && field->tag < 0));
460 switch (field->ftype) {
461 case field_immediate: {
462 retval = asn1_encode_integer(buf, (asn1_intmax) field->dataoff,
466 rettag->asn1class = UNIVERSAL;
467 rettag->construction = PRIMITIVE;
468 rettag->tagnum = ASN1_INTEGER;
471 case field_sequenceof_len: {
472 const void *dataptr = (const char *)val + field->dataoff;
474 const struct ptr_info *ptrinfo;
477 * The field holds a pointer to the array of objects. So the
478 * address we compute is a pointer-to-pointer, and that's what
479 * field->atype must help us dereference.
481 assert(field->atype->type == atype_ptr);
482 ptrinfo = field->atype->tinfo;
483 dataptr = LOADPTR(dataptr, ptrinfo);
484 retval = get_field_len(val, field, &slen);
487 if (slen != 0 && dataptr == NULL)
488 return ASN1_MISSING_FIELD;
489 retval = encode_sequence_of(buf, slen, dataptr, ptrinfo->basetype,
493 rettag->asn1class = UNIVERSAL;
494 rettag->construction = CONSTRUCTED;
495 rettag->tagnum = ASN1_SEQUENCE;
499 const void *dataptr = (const char *)val + field->dataoff;
500 retval = krb5int_asn1_encode_type(buf, dataptr, field->atype, rettag);
506 const void *dataptr = (const char *)val + field->dataoff;
507 const struct atype_info *a;
509 const struct string_info *string;
512 assert(a->type == atype_string);
513 retval = get_field_len(val, field, &slen);
517 dataptr = LOADPTR(dataptr, string);
518 if (dataptr == NULL && slen != 0)
519 return ASN1_MISSING_FIELD;
520 assert(string->enclen != NULL);
521 retval = string->enclen(buf, slen, dataptr, &rettag->length);
524 rettag->asn1class = UNIVERSAL;
525 rettag->construction = PRIMITIVE;
526 rettag->tagnum = string->tagval;
530 const void *dataptr = (const char *)val + field->dataoff;
531 const struct atype_info *a;
533 const struct ptr_info *ptr;
536 assert(a->type == atype_der);
537 retval = get_field_len(val, field, &slen);
541 dataptr = LOADPTR(dataptr, ptr);
542 if (dataptr == NULL && slen != 0)
543 return ASN1_MISSING_FIELD;
544 retval = split_der(buf, dataptr, slen, rettag);
550 const void *dataptr = (const char *)val + field->dataoff;
552 const struct seq_info *seq;
554 assert(field->atype->type == atype_choice);
555 seq = field->atype->tinfo;
556 retval = get_field_len(val, field, &choice);
559 if (choice > seq->n_fields)
560 return ASN1_MISSING_FIELD;
561 retval = encode_a_field(buf, dataptr, &seq->fields[choice], rettag);
567 assert(field->ftype > field_min);
568 assert(field->ftype < field_max);
569 assert(__LINE__ == 0);
573 if (field->tag >= 0) {
574 if (!field->tag_implicit) {
576 retval = asn1_make_tag(buf, rettag->asn1class,
577 rettag->construction, rettag->tagnum,
578 rettag->length, &tlen);
581 rettag->length += tlen;
582 rettag->construction = CONSTRUCTED;
584 rettag->asn1class = CONTEXT_SPECIFIC;
585 rettag->tagnum = field->tag;
590 static asn1_error_code
591 encode_fields(asn1buf *buf, const void *val,
592 const struct field_info *fields, size_t nfields,
593 unsigned int optional,
594 unsigned int *retlen)
597 unsigned int sum = 0;
598 for (i = nfields; i > 0; i--) {
599 const struct field_info *f = fields+i-1;
601 asn1_error_code retval;
603 if (f->opt != -1 && !((1u << f->opt) & optional))
605 retval = encode_a_field(buf, val, f, &t);
609 retval = asn1_make_tag(buf, t.asn1class, t.construction, t.tagnum,
610 t.length, &t.length);
619 static asn1_error_code
620 just_encode_sequence(asn1buf *buf, const void *val,
621 const struct seq_info *seq,
622 unsigned int *retlen)
624 unsigned int optional;
626 /* If any fields might be optional, get a bitmask of optional fields. */
627 optional = (seq->optional == NULL) ? 0 : seq->optional(val);
628 return encode_fields(buf, val, seq->fields, seq->n_fields, optional,
632 static asn1_error_code
633 encode_sequence_of(asn1buf *buf, unsigned int seqlen, const void *val,
634 const struct atype_info *eltinfo,
635 unsigned int *retlen)
637 asn1_error_code retval;
638 unsigned int sum = 0, i;
640 for (i = seqlen; i > 0; i--) {
643 const struct atype_info *a = eltinfo;
645 assert(eltinfo->size != 0);
646 eltptr = (const char *)val + (i - 1) * eltinfo->size;
647 retval = encode_type_and_tag(buf, eltptr, a, &length);
657 krb5int_asn1_do_full_encode(const void *rep, krb5_data **code,
658 const struct atype_info *a)
661 asn1_error_code retval;
668 return ASN1_MISSING_FIELD;
670 retval = asn1buf_create(&buf);
674 retval = encode_type_and_tag(buf, rep, a, &length);
677 retval = asn12krb5_buf(buf, &d);
682 asn1buf_destroy(&buf);