1/* 2 * Copyright (c) 2009 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "der_locl.h" 37#include <com_err.h> 38 39#undef HEIMDAL_PRINTF_ATTRIBUTE 40#define HEIMDAL_PRINTF_ATTRIBUTE(x) 41#undef HEIMDAL_NORETURN_ATTRIBUTE 42#define HEIMDAL_NORETURN_ATTRIBUTE 43 44#ifdef __APPLE__ 45#pragma clang diagnostic push 46#pragma clang diagnostic ignored "-Wlanguage-extension-token" 47 48const char *__crashreporter_info__ = NULL; 49asm(".desc ___crashreporter_info__, 0x10"); 50static char crashreporter_info[100]; 51 52#pragma clang diagnostic pop 53#endif 54 55 56void 57asn1_abort(const char *fmt, ...) 58 HEIMDAL_PRINTF_ATTRIBUTE((printf, 1, 2)) 59 HEIMDAL_NORETURN_ATTRIBUTE 60{ 61#ifdef __APPLE__ 62 va_list ap; 63 va_start(ap, fmt); 64 vsnprintf(crashreporter_info, sizeof(crashreporter_info), fmt, ap); 65 va_end(ap); 66 __crashreporter_info__ = crashreporter_info; 67#endif 68 abort(); 69} 70 71 72 73struct asn1_type_func asn1_template_prim[A1T_NUM_ENTRY] = { 74#define el(name, type) { \ 75 (asn1_type_encode)der_put_##name, \ 76 (asn1_type_decode)der_get_##name, \ 77 (asn1_type_length)der_length_##name, \ 78 (asn1_type_copy)der_copy_##name, \ 79 (asn1_type_release)der_free_##name, \ 80 sizeof(type) \ 81 } 82#define elber(name, type) { \ 83 (asn1_type_encode)der_put_##name, \ 84 (asn1_type_decode)der_get_##name##_ber, \ 85 (asn1_type_length)der_length_##name, \ 86 (asn1_type_copy)der_copy_##name, \ 87 (asn1_type_release)der_free_##name, \ 88 sizeof(type) \ 89 } 90 el(integer, int), 91 el(heim_integer, heim_integer), 92 el(integer, int), 93 el(unsigned, unsigned), 94 el(general_string, heim_general_string), 95 el(octet_string, heim_octet_string), 96 elber(octet_string, heim_octet_string), 97 el(ia5_string, heim_ia5_string), 98 el(bmp_string, heim_bmp_string), 99 el(universal_string, heim_universal_string), 100 el(printable_string, heim_printable_string), 101 el(visible_string, heim_visible_string), 102 el(utf8string, heim_utf8_string), 103 el(generalized_time, time_t), 104 el(utctime, time_t), 105 el(bit_string, heim_bit_string), 106 { (asn1_type_encode)der_put_boolean, (asn1_type_decode)der_get_boolean, 107 (asn1_type_length)der_length_boolean, (asn1_type_copy)der_copy_integer, 108 (asn1_type_release)der_free_integer, sizeof(int) 109 }, 110 el(oid, heim_oid), 111 el(general_string, heim_general_string), 112#undef el 113#undef elber 114}; 115 116size_t 117_asn1_sizeofType(const struct asn1_template *t) 118{ 119 return t->offset; 120} 121 122/* 123 * Here is abstraction to not so well evil fact of bit fields in C, 124 * they are endian dependent, so when getting and setting bits in the 125 * host local structure we need to know the endianness of the host. 126 * 127 * Its not the first time in Heimdal this have bitten us, and some day 128 * we'll grow up and use #defined constant, but bit fields are still 129 * so pretty and shiny. 130 */ 131 132static void 133_asn1_bmember_get_bit(const unsigned char *p, void *data, 134 unsigned int bit, size_t size) 135{ 136 unsigned int localbit = bit % 8; 137 if ((*p >> (7 - localbit)) & 1) { 138#ifdef WORDS_BIGENDIAN 139 *(unsigned int *)data |= (1 << ((size * 8) - bit - 1)); 140#else 141 *(unsigned int *)data |= (1 << bit); 142#endif 143 } 144} 145 146int 147_asn1_bmember_isset_bit(const void *data, unsigned int bit, size_t size) 148{ 149#ifdef WORDS_BIGENDIAN 150 if ((*(unsigned int *)data) & (1 << ((size * 8) - bit - 1))) 151 return 1; 152 return 0; 153#else 154 if ((*(unsigned int *)data) & (1 << bit)) 155 return 1; 156 return 0; 157#endif 158} 159 160void 161_asn1_bmember_put_bit(unsigned char *p, const void *data, unsigned int bit, 162 size_t size, unsigned int *bitset) 163{ 164 unsigned int localbit = bit % 8; 165 166 if (_asn1_bmember_isset_bit(data, bit, size)) { 167 *p |= (1 << (7 - localbit)); 168 if (*bitset == 0) 169 *bitset = (7 - localbit) + 1; 170 } 171} 172 173int 174_asn1_decode(const struct asn1_template *t, unsigned flags, 175 const unsigned char *p, size_t len, void *data, size_t *size) 176{ 177 size_t elements = A1_HEADER_LEN(t); 178 size_t oldlen = len; 179 int ret = 0; 180 const unsigned char *startp = NULL; 181 unsigned int template_flags = t->tt; 182 183 /* skip over header */ 184 t++; 185 186 if (template_flags & A1_HF_PRESERVE) 187 startp = p; 188 189 while (elements) { 190 switch (t->tt & A1_OP_MASK) { 191 case A1_OP_TYPE: 192 case A1_OP_TYPE_EXTERN: { 193 size_t newsize, elsize; 194 void *el = DPO(data, t->offset); 195 void **pel = (void **)el; 196 197 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { 198 elsize = _asn1_sizeofType(t->ptr); 199 } else { 200 const struct asn1_type_func *f = t->ptr; 201 elsize = f->size; 202 } 203 204 if (t->tt & A1_FLAG_OPTIONAL) { 205 *pel = calloc(1, elsize); 206 if (*pel == NULL) 207 return ENOMEM; 208 el = *pel; 209 } 210 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { 211 ret = _asn1_decode(t->ptr, flags, p, len, el, &newsize); 212 } else { 213 const struct asn1_type_func *f = t->ptr; 214 ret = (f->decode)(p, len, el, &newsize); 215 } 216 if (ret) { 217 if (t->tt & A1_FLAG_OPTIONAL) { 218 free(*pel); 219 *pel = NULL; 220 break; 221 } 222 return ret; 223 } 224 p += newsize; len -= newsize; 225 226 break; 227 } 228 case A1_OP_TAG: { 229 Der_type dertype; 230 size_t newsize; 231 size_t datalen, l; 232 void *olddata = data; 233 int is_indefinite = 0; 234 int subflags = flags; 235 236 ret = der_match_tag_and_length(p, len, A1_TAG_CLASS(t->tt), 237 &dertype, A1_TAG_TAG(t->tt), 238 &datalen, &l); 239 if (ret) { 240 if (t->tt & A1_FLAG_OPTIONAL) 241 break; 242 return ret; 243 } 244 245 p += l; len -= l; 246 247 /* 248 * Only allow indefinite encoding for OCTET STRING and BER 249 * for now. Should handle BIT STRING too. 250 */ 251 252 if (dertype != A1_TAG_TYPE(t->tt) && (flags & A1_PF_ALLOW_BER)) { 253 const struct asn1_template *subtype = t->ptr; 254 subtype++; /* skip header */ 255 256 if (((subtype->tt & A1_OP_MASK) == A1_OP_PARSE) && 257 A1_PARSE_TYPE(subtype->tt) == A1T_OCTET_STRING) 258 subflags |= A1_PF_INDEFINTE; 259 } 260 261 if (datalen == ASN1_INDEFINITE) { 262 if ((flags & A1_PF_ALLOW_BER) == 0) 263 return ASN1_GOT_BER; 264 is_indefinite = 1; 265 datalen = len; 266 if (datalen < 2) 267 return ASN1_OVERRUN; 268 /* hide EndOfContent for sub-decoder, catching it below */ 269 datalen -= 2; 270 } else if (datalen > len) 271 return ASN1_OVERRUN; 272 273 data = DPO(data, t->offset); 274 275 if (t->tt & A1_FLAG_OPTIONAL) { 276 void **el = (void **)data; 277 size_t ellen = _asn1_sizeofType(t->ptr); 278 279 *el = calloc(1, ellen); 280 if (*el == NULL) 281 return ENOMEM; 282 data = *el; 283 } 284 285 ret = _asn1_decode(t->ptr, subflags, p, datalen, data, &newsize); 286 if (ret) 287 return ret; 288 289 if (is_indefinite) { 290 /* If we use indefinite encoding, the newsize is the datasize. */ 291 datalen = newsize; 292 } else if (newsize != datalen) { 293 /* Check for hidden data that might be after the real tag */ 294 return ASN1_EXTRA_DATA; 295 } 296 297 len -= datalen; 298 p += datalen; 299 300 /* 301 * Indefinite encoding needs a trailing EndOfContent, 302 * check for that. 303 */ 304 if (is_indefinite) { 305 ret = der_match_tag_and_length(p, len, ASN1_C_UNIV, 306 &dertype, UT_EndOfContent, 307 &datalen, &l); 308 if (ret) 309 return ret; 310 if (dertype != PRIM) 311 return ASN1_BAD_ID; 312 if (datalen != 0) 313 return ASN1_INDEF_EXTRA_DATA; 314 p += l; len -= l; 315 } 316 data = olddata; 317 318 break; 319 } 320 case A1_OP_PARSE: { 321 unsigned int type = A1_PARSE_TYPE(t->tt); 322 size_t newsize; 323 void *el = DPO(data, t->offset); 324 325 /* 326 * INDEFINITE primitive types are one element after the 327 * same type but non-INDEFINITE version. 328 */ 329 if (flags & A1_PF_INDEFINTE) 330 type++; 331 332 if (type >= sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { 333 ABORT_ON_ERROR("type larger then asn1_template_prim: %d", type); 334 } 335 336 ret = (asn1_template_prim[type].decode)(p, len, el, &newsize); 337 if (ret) 338 return ret; 339 p += newsize; len -= newsize; 340 341 break; 342 } 343 case A1_OP_SETOF: 344 case A1_OP_SEQOF: { 345 struct template_of *el = DPO(data, t->offset); 346 size_t newsize; 347 size_t ellen = _asn1_sizeofType(t->ptr); 348 size_t vallength = 0; 349 350 while (len > 0) { 351 void *tmp; 352 size_t newlen = vallength + ellen; 353 if (vallength > newlen) 354 return ASN1_OVERFLOW; 355 356 tmp = realloc(el->val, newlen); 357 if (tmp == NULL) 358 return ENOMEM; 359 360 memset(DPO(tmp, vallength), 0, ellen); 361 el->val = tmp; 362 el->len++; 363 364 ret = _asn1_decode(t->ptr, flags & (~A1_PF_INDEFINTE), p, len, 365 DPO(el->val, vallength), &newsize); 366 if (ret) 367 return ret; 368 vallength = newlen; 369 p += newsize; len -= newsize; 370 } 371 372 break; 373 } 374 case A1_OP_BMEMBER: { 375 const struct asn1_template *bmember = t->ptr; 376 size_t bsize = bmember->offset; 377 size_t belements = A1_HEADER_LEN(bmember); 378 size_t pos = 0; 379 380 bmember++; 381 382 memset(data, 0, bsize); 383 384 if (len < 1) 385 return ASN1_OVERRUN; 386 p++; len--; 387 388 while (belements && len) { 389 while (bmember->offset / 8 > pos / 8) { 390 if (len < 1) 391 break; 392 p++; len--; 393 pos += 8; 394 } 395 if (len) { 396 _asn1_bmember_get_bit(p, data, bmember->offset, bsize); 397 belements--; bmember++; 398 } 399 } 400 len = 0; 401 break; 402 } 403 case A1_OP_CHOICE: { 404 const struct asn1_template *choice = t->ptr; 405 int *element = DPO(data, choice->offset); 406 size_t datalen; 407 unsigned int i; 408 409 /* provide a invalid value as default (0, so same as memset) */ 410 *element = ASN1_CHOICE_INVALID; 411 412 for (i = 1; i < A1_HEADER_LEN(choice) + 1; i++) { 413 /* should match first tag instead, store it in choice.tt */ 414 ret = _asn1_decode(choice[i].ptr, 0, p, len, 415 DPO(data, choice[i].offset), &datalen); 416 if (ret == 0) { 417 *element = i; 418 p += datalen; len -= datalen; 419 break; 420 } else if (ret != ASN1_BAD_ID && ret != ASN1_MISPLACED_FIELD && ret != ASN1_MISSING_FIELD) { 421 _asn1_free_top(choice[i].ptr, DPO(data, choice[i].offset)); 422 return ret; 423 } 424 _asn1_free_top(choice[i].ptr, DPO(data, choice[i].offset)); 425 } 426 if (i >= A1_HEADER_LEN(choice) + 1) { 427 if (choice->tt == 0) 428 return ASN1_BAD_ID; 429 430 *element = ASN1_CHOICE_ELLIPSIS; 431 ret = der_get_octet_string(p, len, 432 DPO(data, choice->tt), &datalen); 433 if (ret) 434 return ret; 435 p += datalen; len -= datalen; 436 } 437 438 break; 439 } 440 default: 441 ABORT_ON_ERROR("unknown opcode: %d", (t->tt & A1_OP_MASK)); 442 } 443 t++; 444 elements--; 445 } 446 /* if we are using padding, eat up read of context */ 447 if (template_flags & A1_HF_ELLIPSIS) 448 len = 0; 449 450 oldlen -= len; 451 452 if (size) 453 *size = oldlen; 454 455 /* 456 * saved the raw bits if asked for it, useful for signature 457 * verification. 458 */ 459 if (startp) { 460 heim_octet_string *save = data; 461 462 save->data = malloc(oldlen); 463 if (save->data == NULL) 464 return ENOMEM; 465 else { 466 save->length = oldlen; 467 memcpy(save->data, startp, oldlen); 468 } 469 } 470 return 0; 471} 472 473int 474_asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const void *data, size_t *size) 475{ 476 size_t elements = A1_HEADER_LEN(t); 477 int ret = 0; 478 size_t oldlen = len; 479 480 t += A1_HEADER_LEN(t); 481 482 while (elements) { 483 switch (t->tt & A1_OP_MASK) { 484 case A1_OP_TYPE: 485 case A1_OP_TYPE_EXTERN: { 486 size_t newsize; 487 const void *el = DPOC(data, t->offset); 488 489 if (t->tt & A1_FLAG_OPTIONAL) { 490 void **pel = (void **)el; 491 if (*pel == NULL) 492 break; 493 el = *pel; 494 } 495 496 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { 497 ret = _asn1_encode(t->ptr, p, len, el, &newsize); 498 } else { 499 const struct asn1_type_func *f = t->ptr; 500 ret = (f->encode)(p, len, el, &newsize); 501 } 502 503 if (ret) 504 return ret; 505 p -= newsize; len -= newsize; 506 507 break; 508 } 509 case A1_OP_TAG: { 510 const void *olddata = data; 511 size_t l, datalen; 512 513 data = DPOC(data, t->offset); 514 515 if (t->tt & A1_FLAG_OPTIONAL) { 516 void **el = (void **)data; 517 if (*el == NULL) { 518 data = olddata; 519 break; 520 } 521 data = *el; 522 } 523 524 ret = _asn1_encode(t->ptr, p, len, data, &datalen); 525 if (ret) 526 return ret; 527 528 len -= datalen; p -= datalen; 529 530 ret = der_put_length_and_tag(p, len, datalen, 531 A1_TAG_CLASS(t->tt), 532 A1_TAG_TYPE(t->tt), 533 A1_TAG_TAG(t->tt), &l); 534 if (ret) 535 return ret; 536 537 p -= l; len -= l; 538 539 data = olddata; 540 541 break; 542 } 543 case A1_OP_PARSE: { 544 unsigned int type = A1_PARSE_TYPE(t->tt); 545 size_t newsize; 546 const void *el = DPOC(data, t->offset); 547 548 if (type > sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { 549 ABORT_ON_ERROR("type larger then asn1_template_prim: %d", type); 550 } 551 552 ret = (asn1_template_prim[type].encode)(p, len, el, &newsize); 553 if (ret) 554 return ret; 555 p -= newsize; len -= newsize; 556 557 break; 558 } 559 case A1_OP_SETOF: { 560 const struct template_of *el = DPOC(data, t->offset); 561 size_t ellen = _asn1_sizeofType(t->ptr); 562 heim_octet_string *val; 563 unsigned char *elptr = el->val; 564 size_t i, totallen; 565 566 if (el->len == 0) 567 break; 568 569 if (el->len > UINT_MAX/sizeof(val[0])) 570 return ERANGE; 571 572 val = calloc(el->len, sizeof(val[0])); 573 if (val == NULL) 574 return ENOMEM; 575 576 for(totallen = 0, i = 0; i < el->len; i++) { 577 unsigned char *next; 578 size_t l; 579 580 val[i].length = _asn1_length(t->ptr, elptr); 581 if (val[i].length) { 582 val[i].data = malloc(val[i].length); 583 if (val[i].data == NULL) { 584 ret = ENOMEM; 585 break; 586 } 587 } 588 589 ret = _asn1_encode(t->ptr, DPO(val[i].data, val[i].length - 1), 590 val[i].length, elptr, &l); 591 if (ret) 592 break; 593 594 next = elptr + ellen; 595 if (next < elptr) { 596 ret = ASN1_OVERFLOW; 597 break; 598 } 599 elptr = next; 600 totallen += val[i].length; 601 } 602 if (ret == 0 && totallen > len) 603 ret = ASN1_OVERFLOW; 604 if (ret) { 605 for (i = 0; i < el->len; i++) 606 free(val[i].data); 607 free(val); 608 return ret; 609 } 610 611 len -= totallen; 612 613 qsort(val, el->len, sizeof(val[0]), _heim_der_set_sort); 614 615 i = el->len - 1; 616 do { 617 p -= val[i].length; 618 memcpy(p + 1, val[i].data, val[i].length); 619 free(val[i].data); 620 } while(i-- > 0); 621 free(val); 622 623 break; 624 625 } 626 case A1_OP_SEQOF: { 627 struct template_of *el = DPO(data, t->offset); 628 size_t ellen = _asn1_sizeofType(t->ptr); 629 size_t newsize; 630 unsigned int i; 631 unsigned char *elptr = el->val; 632 633 if (el->len == 0) 634 break; 635 636 elptr += ellen * (el->len - 1); 637 638 for (i = 0; i < el->len; i++) { 639 ret = _asn1_encode(t->ptr, p, len, 640 elptr, 641 &newsize); 642 if (ret) 643 return ret; 644 p -= newsize; len -= newsize; 645 elptr -= ellen; 646 } 647 648 break; 649 } 650 case A1_OP_BMEMBER: { 651 const struct asn1_template *bmember = t->ptr; 652 size_t bsize = bmember->offset; 653 size_t belements = A1_HEADER_LEN(bmember); 654 size_t pos; 655 unsigned char c = 0; 656 unsigned int bitset = 0; 657 int rfc1510 = (bmember->tt & A1_HBF_RFC1510); 658 659 bmember += belements; 660 661 if (rfc1510) 662 pos = 31; 663 else 664 pos = bmember->offset; 665 666 while (belements && len) { 667 while (bmember->offset / 8 < pos / 8) { 668 if (rfc1510 || bitset || c) { 669 if (len < 1) 670 return ASN1_OVERFLOW; 671 *p-- = c; len--; 672 } 673 c = 0; 674 pos -= 8; 675 } 676 _asn1_bmember_put_bit(&c, data, bmember->offset, bsize, &bitset); 677 belements--; bmember--; 678 } 679 if (rfc1510 || bitset) { 680 if (len < 1) 681 return ASN1_OVERFLOW; 682 *p-- = c; len--; 683 } 684 685 if (len < 1) 686 return ASN1_OVERFLOW; 687 if (rfc1510 || bitset == 0) 688 *p-- = 0; 689 else 690 *p-- = bitset - 1; 691 692 len--; 693 694 break; 695 } 696 case A1_OP_CHOICE: { 697 const struct asn1_template *choice = t->ptr; 698 const int *element = DPOC(data, choice->offset); 699 size_t datalen; 700 const void *el; 701 702 if (*element == ASN1_CHOICE_INVALID || *element > (int)A1_HEADER_LEN(choice)) { 703 ABORT_ON_ERROR("invalid choice: %d", *element); 704 } 705 706 if (*element == ASN1_CHOICE_ELLIPSIS) { 707 ret += der_put_octet_string(p, len, 708 DPOC(data, choice->tt), &datalen); 709 } else { 710 choice += *element; 711 el = DPOC(data, choice->offset); 712 ret = _asn1_encode(choice->ptr, p, len, el, &datalen); 713 if (ret) 714 return ret; 715 } 716 len -= datalen; p -= datalen; 717 718 break; 719 } 720 default: 721 ABORT_ON_ERROR("unknown opcode: %d", (t->tt & A1_OP_MASK)); 722 } 723 t--; 724 elements--; 725 } 726 if (size) 727 *size = oldlen - len; 728 729 return 0; 730} 731 732size_t 733_asn1_length(const struct asn1_template *t, const void *data) 734{ 735 size_t elements = A1_HEADER_LEN(t); 736 size_t ret = 0; 737 738 t += A1_HEADER_LEN(t); 739 740 while (elements) { 741 switch (t->tt & A1_OP_MASK) { 742 case A1_OP_TYPE: 743 case A1_OP_TYPE_EXTERN: { 744 const void *el = DPOC(data, t->offset); 745 746 if (t->tt & A1_FLAG_OPTIONAL) { 747 void **pel = (void **)el; 748 if (*pel == NULL) 749 break; 750 el = *pel; 751 } 752 753 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { 754 ret += _asn1_length(t->ptr, el); 755 } else { 756 const struct asn1_type_func *f = t->ptr; 757 ret += (f->length)(el); 758 } 759 break; 760 } 761 case A1_OP_TAG: { 762 size_t datalen; 763 const void *olddata = data; 764 765 data = DPO(data, t->offset); 766 767 if (t->tt & A1_FLAG_OPTIONAL) { 768 void **el = (void **)data; 769 if (*el == NULL) { 770 data = olddata; 771 break; 772 } 773 data = *el; 774 } 775 datalen = _asn1_length(t->ptr, data); 776 ret += der_length_tag(A1_TAG_TAG(t->tt)) + der_length_len(datalen); 777 ret += datalen; 778 data = olddata; 779 break; 780 } 781 case A1_OP_PARSE: { 782 unsigned int type = A1_PARSE_TYPE(t->tt); 783 const void *el = DPOC(data, t->offset); 784 785 if (type > sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { 786 ABORT_ON_ERROR("type larger then asn1_template_prim: %d", type); 787 } 788 ret += (asn1_template_prim[type].length)(el); 789 break; 790 } 791 case A1_OP_SETOF: 792 case A1_OP_SEQOF: { 793 const struct template_of *el = DPOC(data, t->offset); 794 size_t ellen = _asn1_sizeofType(t->ptr); 795 const unsigned char *element = el->val; 796 unsigned int i; 797 798 for (i = 0; i < el->len; i++) { 799 ret += _asn1_length(t->ptr, element); 800 element += ellen; 801 } 802 803 break; 804 } 805 case A1_OP_BMEMBER: { 806 const struct asn1_template *bmember = t->ptr; 807 size_t size = bmember->offset; 808 size_t belements = A1_HEADER_LEN(bmember); 809 int rfc1510 = (bmember->tt & A1_HBF_RFC1510); 810 811 if (rfc1510) { 812 ret += 5; 813 } else { 814 815 ret += 1; 816 817 bmember += belements; 818 819 while (belements) { 820 if (_asn1_bmember_isset_bit(data, bmember->offset, size)) { 821 ret += (bmember->offset / 8) + 1; 822 break; 823 } 824 belements--; bmember--; 825 } 826 } 827 break; 828 } 829 case A1_OP_CHOICE: { 830 const struct asn1_template *choice = t->ptr; 831 const int *element = DPOC(data, choice->offset); 832 833 if (*element == ASN1_CHOICE_INVALID || *element > (int)A1_HEADER_LEN(choice)) { 834 ABORT_ON_ERROR("invalid choice: %d", *element); 835 } 836 837 if (*element == ASN1_CHOICE_ELLIPSIS) { 838 ret += der_length_octet_string(DPOC(data, choice->tt)); 839 } else { 840 choice += *element; 841 ret += _asn1_length(choice->ptr, DPOC(data, choice->offset)); 842 } 843 break; 844 } 845 default: 846 ABORT_ON_ERROR("unknown opcode: %d", (t->tt & A1_OP_MASK)); 847 } 848 elements--; 849 t--; 850 } 851 return ret; 852} 853 854void 855_asn1_free(const struct asn1_template *t, void *data) 856{ 857 size_t elements = A1_HEADER_LEN(t); 858 859 if (t->tt & A1_HF_PRESERVE) 860 der_free_octet_string(data); 861 862 t++; 863 864 while (elements) { 865 switch (t->tt & A1_OP_MASK) { 866 case A1_OP_TYPE: 867 case A1_OP_TYPE_EXTERN: { 868 void *el = DPO(data, t->offset); 869 870 if (t->tt & A1_FLAG_OPTIONAL) { 871 void **pel = (void **)el; 872 if (*pel == NULL) 873 break; 874 el = *pel; 875 } 876 877 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { 878 _asn1_free(t->ptr, el); 879 } else { 880 const struct asn1_type_func *f = t->ptr; 881 (f->release)(el); 882 } 883 if (t->tt & A1_FLAG_OPTIONAL) 884 free(el); 885 886 break; 887 } 888 case A1_OP_PARSE: { 889 unsigned int type = A1_PARSE_TYPE(t->tt); 890 void *el = DPO(data, t->offset); 891 892 if (type > sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { 893 ABORT_ON_ERROR("type larger then asn1_template_prim: %d", type); 894 } 895 (asn1_template_prim[type].release)(el); 896 break; 897 } 898 case A1_OP_TAG: { 899 void *el = DPO(data, t->offset); 900 901 if (t->tt & A1_FLAG_OPTIONAL) { 902 void **pel = (void **)el; 903 if (*pel == NULL) 904 break; 905 el = *pel; 906 } 907 908 _asn1_free(t->ptr, el); 909 910 if (t->tt & A1_FLAG_OPTIONAL) 911 free(el); 912 913 break; 914 } 915 case A1_OP_SETOF: 916 case A1_OP_SEQOF: { 917 struct template_of *el = DPO(data, t->offset); 918 size_t ellen = _asn1_sizeofType(t->ptr); 919 unsigned char *element = el->val; 920 unsigned int i; 921 922 for (i = 0; i < el->len; i++) { 923 _asn1_free(t->ptr, element); 924 element += ellen; 925 } 926 free(el->val); 927 el->val = NULL; 928 el->len = 0; 929 930 break; 931 } 932 case A1_OP_BMEMBER: 933 break; 934 case A1_OP_CHOICE: { 935 const struct asn1_template *choice = t->ptr; 936 const int *element = DPOC(data, choice->offset); 937 938 if (*element == ASN1_CHOICE_INVALID) 939 break; 940 941 if (*element > (int)A1_HEADER_LEN(choice)) { 942 ABORT_ON_ERROR("invalid choice: %d", *element); 943 } 944 945 if (*element == ASN1_CHOICE_ELLIPSIS) { 946 der_free_octet_string(DPO(data, choice->tt)); 947 } else { 948 choice += *element; 949 _asn1_free(choice->ptr, DPO(data, choice->offset)); 950 } 951 break; 952 } 953 default: 954 ABORT_ON_ERROR("unknown opcode: %d", (t->tt & A1_OP_MASK)); 955 } 956 t++; 957 elements--; 958 } 959} 960 961int 962_asn1_copy(const struct asn1_template *t, const void *from, void *to) 963{ 964 size_t elements = A1_HEADER_LEN(t); 965 int ret = 0; 966 int preserve = (t->tt & A1_HF_PRESERVE); 967 968 t++; 969 970 if (preserve) { 971 ret = der_copy_octet_string(from, to); 972 if (ret) 973 return ret; 974 } 975 976 while (elements) { 977 switch (t->tt & A1_OP_MASK) { 978 case A1_OP_TYPE: 979 case A1_OP_TYPE_EXTERN: { 980 const void *fel = DPOC(from, t->offset); 981 void *tel = DPO(to, t->offset); 982 void **ptel = (void **)tel; 983 size_t size; 984 985 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { 986 size = _asn1_sizeofType(t->ptr); 987 } else { 988 const struct asn1_type_func *f = t->ptr; 989 size = f->size; 990 } 991 992 if (t->tt & A1_FLAG_OPTIONAL) { 993 void **pfel = (void **)fel; 994 if (*pfel == NULL) 995 break; 996 fel = *pfel; 997 998 tel = *ptel = calloc(1, size); 999 if (tel == NULL) 1000 return ENOMEM; 1001 } 1002 1003 if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) { 1004 ret = _asn1_copy(t->ptr, fel, tel); 1005 } else { 1006 const struct asn1_type_func *f = t->ptr; 1007 ret = (f->copy)(fel, tel); 1008 } 1009 1010 if (ret) { 1011 if (t->tt & A1_FLAG_OPTIONAL) { 1012 free(*ptel); 1013 *ptel = NULL; 1014 } 1015 return ret; 1016 } 1017 break; 1018 } 1019 case A1_OP_PARSE: { 1020 unsigned int type = A1_PARSE_TYPE(t->tt); 1021 const void *fel = DPOC(from, t->offset); 1022 void *tel = DPO(to, t->offset); 1023 1024 if (type > sizeof(asn1_template_prim)/sizeof(asn1_template_prim[0])) { 1025 ABORT_ON_ERROR("type larger then asn1_template_prim: %d", type); 1026 } 1027 ret = (asn1_template_prim[type].copy)(fel, tel); 1028 if (ret) 1029 return ret; 1030 break; 1031 } 1032 case A1_OP_TAG: { 1033 const void *oldfrom = from; 1034 void *oldto = to; 1035 void **tel = NULL; 1036 1037 from = DPOC(from, t->offset); 1038 to = DPO(to, t->offset); 1039 1040 if (t->tt & A1_FLAG_OPTIONAL) { 1041 void **fel = (void **)from; 1042 tel = (void **)to; 1043 if (*fel == NULL) { 1044 from = oldfrom; 1045 to = oldto; 1046 break; 1047 } 1048 from = *fel; 1049 1050 to = *tel = calloc(1, _asn1_sizeofType(t->ptr)); 1051 if (to == NULL) 1052 return ENOMEM; 1053 } 1054 1055 ret = _asn1_copy(t->ptr, from, to); 1056 if (ret) { 1057 if (tel) { 1058 free(*tel); 1059 *tel = NULL; 1060 } 1061 return ret; 1062 } 1063 1064 from = oldfrom; 1065 to = oldto; 1066 1067 break; 1068 } 1069 case A1_OP_SETOF: 1070 case A1_OP_SEQOF: { 1071 const struct template_of *fel = DPOC(from, t->offset); 1072 struct template_of *tel = DPO(to, t->offset); 1073 size_t ellen = _asn1_sizeofType(t->ptr); 1074 unsigned int i; 1075 1076 tel->val = calloc(fel->len, ellen); 1077 if (tel->val == NULL) 1078 return ENOMEM; 1079 1080 tel->len = fel->len; 1081 1082 for (i = 0; i < fel->len; i++) { 1083 ret = _asn1_copy(t->ptr, 1084 DPOC(fel->val, (i * ellen)), 1085 DPO(tel->val, (i *ellen))); 1086 if (ret) 1087 return ret; 1088 } 1089 break; 1090 } 1091 case A1_OP_BMEMBER: { 1092 const struct asn1_template *bmember = t->ptr; 1093 size_t size = bmember->offset; 1094 memcpy(to, from, size); 1095 break; 1096 } 1097 case A1_OP_CHOICE: { 1098 const struct asn1_template *choice = t->ptr; 1099 const int *felement = DPOC(from, choice->offset); 1100 int *telement = DPO(to, choice->offset); 1101 1102 if (*felement == ASN1_CHOICE_INVALID || *felement > (int)A1_HEADER_LEN(choice)) 1103 return ASN1_INVALID_CHOICE; 1104 1105 *telement = *felement; 1106 1107 if (*felement == ASN1_CHOICE_ELLIPSIS) { 1108 ret = der_copy_octet_string(DPOC(from, choice->tt), DPO(to, choice->tt)); 1109 } else { 1110 choice += *felement; 1111 ret = _asn1_copy(choice->ptr, 1112 DPOC(from, choice->offset), 1113 DPO(to, choice->offset)); 1114 } 1115 if (ret) 1116 return ret; 1117 break; 1118 } 1119 default: 1120 ABORT_ON_ERROR("unknown opcode: %d", (t->tt & A1_OP_MASK)); 1121 } 1122 t++; 1123 elements--; 1124 } 1125 return 0; 1126} 1127 1128int 1129_asn1_decode_top(const struct asn1_template *t, unsigned flags, const unsigned char *p, size_t len, void *data, size_t *size) 1130{ 1131 int ret; 1132 memset(data, 0, t->offset); 1133 ret = _asn1_decode(t, flags, p, len, data, size); 1134 if (ret) 1135 _asn1_free_top(t, data); 1136 1137 return ret; 1138} 1139 1140int 1141_asn1_copy_top(const struct asn1_template *t, const void *from, void *to) 1142{ 1143 int ret; 1144 memset(to, 0, t->offset); 1145 ret = _asn1_copy(t, from, to); 1146 if (ret) 1147 _asn1_free_top(t, to); 1148 1149 return ret; 1150} 1151 1152void 1153_asn1_free_top(const struct asn1_template *t, void *data) 1154{ 1155 _asn1_free(t, data); 1156 memset(data, 0, t->offset); 1157} 1158 1159#ifdef ASN1_CAPTURE_DATA 1160 1161void 1162_asn1_capture_data(const char *type, const unsigned char *p, size_t len) 1163{ 1164 static unsigned long count = 0; 1165 char *filename = NULL; 1166 int fd; 1167 1168 asprintf(&filename, "/tmp/asn1/heimdal-%s-%s-%d-%lu", getprogname(), type, getpid(), count++); 1169 if (filename == NULL) 1170 return; 1171 1172 fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644); 1173 free(filename); 1174 if (fd < 0) 1175 return; 1176 write(fd, type, strlen(type) + 1); 1177 write(fd, p, len); 1178 close(fd); 1179} 1180 1181#endif 1182