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 33 asn1_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 55 static 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 88 asn1_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 107 asn1_error_code 108 asn1_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 127 asn1_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 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 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 186 asn1_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 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 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, >imebuf) != 0) 245 return ASN1_BAD_GMTIME; 246 # else 247 if (gmtime_r(&gmt_time, >imebuf) == 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(>imebuf, gtime, sizeof(gtimebuf)); 255 #endif 256 gtime = >imebuf; 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 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 284 asn1_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 302 asn1_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 331 static int 332 get_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 } 352 static asn1_error_code 353 encode_sequence_of(asn1buf *buf, int seqlen, const void *val, 354 const struct atype_info *eltinfo, 355 unsigned int *retlen); 356 357 static asn1_error_code 358 encode_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 368 static asn1_error_code 369 just_encode_sequence(asn1buf *buf, const void *val, 370 const struct seq_info *seq, 371 unsigned int *retlen); 372 static asn1_error_code 373 encode_a_field(asn1buf *buf, const void *val, 374 const struct field_info *field, 375 unsigned int *retlen); 376 377 asn1_error_code 378 krb5int_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 431 static asn1_error_code 432 encode_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 579 static asn1_error_code 580 encode_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 609 static asn1_error_code 610 just_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 642 static asn1_error_code 643 encode_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 672 krb5_error_code 673 krb5int_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; 697 cleanup: 698 asn1buf_destroy(&buf); 699 return retval; 700 } 701