diff options
Diffstat (limited to 'src/lib/libcrypto/asn1/tasn_dec.c')
| -rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 386 |
1 files changed, 168 insertions, 218 deletions
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index 234484d6b2..79cbd4c75b 100644 --- a/src/lib/libcrypto/asn1/tasn_dec.c +++ b/src/lib/libcrypto/asn1/tasn_dec.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: tasn_dec.c,v 1.70 2022/05/17 19:09:16 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.71 2022/05/19 19:31:39 jsing Exp $ */ |
| 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
| 3 | * project 2000. | 3 | * project 2000. |
| 4 | */ | 4 | */ |
| @@ -75,22 +75,16 @@ | |||
| 75 | */ | 75 | */ |
| 76 | #define ASN1_MAX_CONSTRUCTED_NEST 30 | 76 | #define ASN1_MAX_CONSTRUCTED_NEST 30 |
| 77 | 77 | ||
| 78 | static int asn1_check_eoc(const unsigned char **in, long len); | 78 | static int asn1_check_eoc(CBS *cbs); |
| 79 | static int asn1_check_eoc_cbs(CBS *cbs); | ||
| 80 | static int asn1_find_end(CBS *cbs, size_t length, char indefinite); | 79 | static int asn1_find_end(CBS *cbs, size_t length, char indefinite); |
| 81 | 80 | ||
| 82 | static int asn1_collect(CBB *cbb, CBS *cbs, char indefinite, int expected_tag, | 81 | static int asn1_collect(CBB *cbb, CBS *cbs, char indefinite, int expected_tag, |
| 83 | int expected_class, int depth); | 82 | int expected_class, int depth); |
| 84 | 83 | ||
| 85 | static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, | 84 | static int asn1_template_ex_d2i(ASN1_VALUE **pval, CBS *cbs, |
| 86 | long len, const ASN1_ITEM *it, int tag_number, int tag_class, char optional, | 85 | const ASN1_TEMPLATE *tt, char optional, int depth); |
| 87 | int depth); | 86 | static int asn1_template_noexp_d2i(ASN1_VALUE **pval, CBS *cbs, |
| 88 | static int asn1_template_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, | ||
| 89 | const ASN1_TEMPLATE *tt, char optional, int depth); | 87 | const ASN1_TEMPLATE *tt, char optional, int depth); |
| 90 | static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, | ||
| 91 | long len, const ASN1_TEMPLATE *tt, char opt, int depth); | ||
| 92 | static int asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, | ||
| 93 | long len, const ASN1_TEMPLATE *tt, char opt, int depth); | ||
| 94 | static int asn1_d2i_ex_mstring(ASN1_VALUE **pval, CBS *CBS, | 88 | static int asn1_d2i_ex_mstring(ASN1_VALUE **pval, CBS *CBS, |
| 95 | const ASN1_ITEM *it, int tag_number, int tag_class, char optional); | 89 | const ASN1_ITEM *it, int tag_number, int tag_class, char optional); |
| 96 | static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, | 90 | static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, |
| @@ -98,22 +92,19 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, | |||
| 98 | static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, | 92 | static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, |
| 99 | const ASN1_ITEM *it); | 93 | const ASN1_ITEM *it); |
| 100 | 94 | ||
| 101 | static int asn1_check_tag_cbs(CBS *cbs, size_t *out_len, int *out_tag, | 95 | static int asn1_check_tag(CBS *cbs, size_t *out_len, int *out_tag, |
| 102 | uint8_t *out_class, char *out_indefinite, char *out_constructed, | 96 | uint8_t *out_class, char *out_indefinite, char *out_constructed, |
| 103 | int expected_tag, int expected_class, char optional); | 97 | int expected_tag, int expected_class, char optional); |
| 104 | static int asn1_check_tag(long *out_len, int *out_tag, uint8_t *out_class, | ||
| 105 | char *out_indefinite, char *out_constructed, const unsigned char **in, | ||
| 106 | long len, int expected_tag, int expected_class, char optional); | ||
| 107 | 98 | ||
| 108 | ASN1_VALUE * | 99 | ASN1_VALUE * |
| 109 | ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | 100 | ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long inlen, |
| 110 | const ASN1_ITEM *it) | 101 | const ASN1_ITEM *it) |
| 111 | { | 102 | { |
| 112 | ASN1_VALUE *ptmpval = NULL; | 103 | ASN1_VALUE *ptmpval = NULL; |
| 113 | 104 | ||
| 114 | if (pval == NULL) | 105 | if (pval == NULL) |
| 115 | pval = &ptmpval; | 106 | pval = &ptmpval; |
| 116 | if (asn1_item_ex_d2i(pval, in, len, it, -1, 0, 0, 0) <= 0) | 107 | if (ASN1_item_ex_d2i(pval, in, inlen, it, -1, 0, 0, 0) <= 0) |
| 117 | return NULL; | 108 | return NULL; |
| 118 | 109 | ||
| 119 | return *pval; | 110 | return *pval; |
| @@ -123,7 +114,17 @@ int | |||
| 123 | ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | 114 | ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, |
| 124 | const ASN1_TEMPLATE *tt) | 115 | const ASN1_TEMPLATE *tt) |
| 125 | { | 116 | { |
| 126 | return asn1_template_ex_d2i(pval, in, len, tt, 0, 0); | 117 | CBS cbs; |
| 118 | int ret; | ||
| 119 | |||
| 120 | if (len < 0) | ||
| 121 | return 0; | ||
| 122 | |||
| 123 | CBS_init(&cbs, *in, len); | ||
| 124 | if ((ret = asn1_template_ex_d2i(pval, &cbs, tt, 0, 0)) == 1) | ||
| 125 | *in = CBS_data(&cbs); | ||
| 126 | |||
| 127 | return ret; | ||
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | static int | 130 | static int |
| @@ -172,7 +173,7 @@ asn1_item_ex_d2i_choice(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 172 | pchptr = asn1_get_field_ptr(&achoice, tt); | 173 | pchptr = asn1_get_field_ptr(&achoice, tt); |
| 173 | 174 | ||
| 174 | /* Mark field as OPTIONAL so its absence can be identified. */ | 175 | /* Mark field as OPTIONAL so its absence can be identified. */ |
| 175 | ret = asn1_template_ex_d2i_cbs(pchptr, cbs, tt, 1, depth); | 176 | ret = asn1_template_ex_d2i(pchptr, cbs, tt, 1, depth); |
| 176 | if (ret == -1) | 177 | if (ret == -1) |
| 177 | continue; | 178 | continue; |
| 178 | if (ret != 1) { | 179 | if (ret != 1) { |
| @@ -255,7 +256,7 @@ asn1_item_ex_d2i_sequence(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 255 | } | 256 | } |
| 256 | 257 | ||
| 257 | /* Read ASN.1 SEQUENCE header. */ | 258 | /* Read ASN.1 SEQUENCE header. */ |
| 258 | ret = asn1_check_tag_cbs(&cbs_seq, &length, NULL, NULL, &indefinite, | 259 | ret = asn1_check_tag(&cbs_seq, &length, NULL, NULL, &indefinite, |
| 259 | &constructed, tag_number, tag_class, optional); | 260 | &constructed, tag_number, tag_class, optional); |
| 260 | if (ret == -1) | 261 | if (ret == -1) |
| 261 | return -1; | 262 | return -1; |
| @@ -289,7 +290,7 @@ asn1_item_ex_d2i_sequence(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 289 | } | 290 | } |
| 290 | 291 | ||
| 291 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { | 292 | for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) { |
| 292 | if (asn1_check_eoc_cbs(&cbs_seq_content)) { | 293 | if (asn1_check_eoc(&cbs_seq_content)) { |
| 293 | if (!indefinite) { | 294 | if (!indefinite) { |
| 294 | ASN1error(ASN1_R_UNEXPECTED_EOC); | 295 | ASN1error(ASN1_R_UNEXPECTED_EOC); |
| 295 | goto err; | 296 | goto err; |
| @@ -315,7 +316,7 @@ asn1_item_ex_d2i_sequence(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 315 | if (i == it->tcount - 1) | 316 | if (i == it->tcount - 1) |
| 316 | optional_field = 0; | 317 | optional_field = 0; |
| 317 | 318 | ||
| 318 | ret = asn1_template_ex_d2i_cbs(pseqval, &cbs_seq_content, | 319 | ret = asn1_template_ex_d2i(pseqval, &cbs_seq_content, |
| 319 | seqtt, optional_field, depth); | 320 | seqtt, optional_field, depth); |
| 320 | if (ret == -1) { | 321 | if (ret == -1) { |
| 321 | /* Absent OPTIONAL component. */ | 322 | /* Absent OPTIONAL component. */ |
| @@ -328,7 +329,7 @@ asn1_item_ex_d2i_sequence(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 328 | } | 329 | } |
| 329 | } | 330 | } |
| 330 | 331 | ||
| 331 | if (eoc_needed && !asn1_check_eoc_cbs(&cbs_seq_content)) { | 332 | if (eoc_needed && !asn1_check_eoc(&cbs_seq_content)) { |
| 332 | ASN1error(ASN1_R_MISSING_EOC); | 333 | ASN1error(ASN1_R_MISSING_EOC); |
| 333 | goto err; | 334 | goto err; |
| 334 | } | 335 | } |
| @@ -395,7 +396,7 @@ asn1_item_ex_d2i_sequence(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 395 | * If 'opt' set and tag mismatch return -1 to handle OPTIONAL | 396 | * If 'opt' set and tag mismatch return -1 to handle OPTIONAL |
| 396 | */ | 397 | */ |
| 397 | static int | 398 | static int |
| 398 | asn1_item_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | 399 | asn1_item_ex_d2i(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, |
| 399 | int tag_number, int tag_class, char optional, int depth) | 400 | int tag_number, int tag_class, char optional, int depth) |
| 400 | { | 401 | { |
| 401 | const ASN1_EXTERN_FUNCS *ef = it->funcs; | 402 | const ASN1_EXTERN_FUNCS *ef = it->funcs; |
| @@ -425,7 +426,7 @@ asn1_item_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 425 | ASN1error(ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); | 426 | ASN1error(ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); |
| 426 | goto err; | 427 | goto err; |
| 427 | } | 428 | } |
| 428 | return asn1_template_ex_d2i_cbs(pval, cbs, | 429 | return asn1_template_ex_d2i(pval, cbs, |
| 429 | it->templates, optional, depth); | 430 | it->templates, optional, depth); |
| 430 | } | 431 | } |
| 431 | return asn1_d2i_ex_primitive(pval, cbs, it, tag_number, | 432 | return asn1_d2i_ex_primitive(pval, cbs, it, tag_number, |
| @@ -467,10 +468,10 @@ asn1_item_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 467 | return 0; | 468 | return 0; |
| 468 | } | 469 | } |
| 469 | 470 | ||
| 470 | static int | 471 | int |
| 471 | asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long inlen, | 472 | ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long inlen, |
| 472 | const ASN1_ITEM *it, int tag_number, int tag_class, char optional, | 473 | const ASN1_ITEM *it, int tag_number, int tag_class, char optional, |
| 473 | int depth) | 474 | ASN1_TLC *ctx) |
| 474 | { | 475 | { |
| 475 | CBS cbs; | 476 | CBS cbs; |
| 476 | int ret; | 477 | int ret; |
| @@ -480,219 +481,210 @@ asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long inlen, | |||
| 480 | 481 | ||
| 481 | CBS_init(&cbs, *in, inlen); | 482 | CBS_init(&cbs, *in, inlen); |
| 482 | 483 | ||
| 483 | ret = asn1_item_ex_d2i_cbs(pval, &cbs, it, tag_number, tag_class, | 484 | if ((ret = asn1_item_ex_d2i(pval, &cbs, it, tag_number, tag_class, |
| 484 | optional, depth); | 485 | optional, 0)) == 1) |
| 485 | |||
| 486 | if (ret == 1) | ||
| 487 | *in = CBS_data(&cbs); | 486 | *in = CBS_data(&cbs); |
| 488 | 487 | ||
| 489 | return ret; | 488 | return ret; |
| 490 | } | 489 | } |
| 491 | 490 | ||
| 492 | int | ||
| 493 | ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | ||
| 494 | const ASN1_ITEM *it, int tag, int aclass, char opt, ASN1_TLC *ctx) | ||
| 495 | { | ||
| 496 | return asn1_item_ex_d2i(pval, in, len, it, tag, aclass, opt, 0); | ||
| 497 | } | ||
| 498 | |||
| 499 | static int | 491 | static int |
| 500 | asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, | 492 | asn1_template_ex_d2i(ASN1_VALUE **pval, CBS *cbs, const ASN1_TEMPLATE *tt, |
| 501 | const ASN1_TEMPLATE *tt, char opt, int depth) | 493 | char optional, int depth) |
| 502 | { | 494 | { |
| 503 | int flags, aclass; | 495 | CBS cbs_exp, cbs_exp_content; |
| 496 | char constructed, indefinite; | ||
| 497 | size_t length; | ||
| 504 | int ret; | 498 | int ret; |
| 505 | long len; | ||
| 506 | const unsigned char *p, *q; | ||
| 507 | char exp_eoc; | ||
| 508 | char cst; | ||
| 509 | 499 | ||
| 510 | if (!val) | 500 | if (pval == NULL) |
| 511 | return 0; | 501 | return 0; |
| 512 | flags = tt->flags; | ||
| 513 | aclass = flags & ASN1_TFLG_TAG_CLASS; | ||
| 514 | 502 | ||
| 515 | p = *in; | 503 | /* Check if EXPLICIT tag is expected. */ |
| 504 | if ((tt->flags & ASN1_TFLG_EXPTAG) == 0) | ||
| 505 | return asn1_template_noexp_d2i(pval, cbs, tt, optional, depth); | ||
| 516 | 506 | ||
| 517 | /* Check if EXPLICIT tag expected */ | 507 | CBS_init(&cbs_exp, CBS_data(cbs), CBS_len(cbs)); |
| 518 | if ((flags & ASN1_TFLG_EXPTAG) == 0) | ||
| 519 | return asn1_template_noexp_d2i(val, in, inlen, tt, opt, depth); | ||
| 520 | 508 | ||
| 521 | /* Need to work out amount of data available to the inner | 509 | /* Read ASN.1 header for EXPLICIT tagged object. */ |
| 522 | * content and where it starts: so read in EXPLICIT header to | 510 | ret = asn1_check_tag(&cbs_exp, &length, NULL, NULL, &indefinite, |
| 523 | * get the info. | 511 | &constructed, tt->tag, tt->flags & ASN1_TFLG_TAG_CLASS, optional); |
| 524 | */ | 512 | if (ret == -1) |
| 525 | ret = asn1_check_tag(&len, NULL, NULL, &exp_eoc, &cst, &p, | 513 | return -1; |
| 526 | inlen, tt->tag, aclass, opt); | 514 | if (ret != 1) { |
| 527 | q = p; | ||
| 528 | if (!ret) { | ||
| 529 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 515 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 530 | return 0; | 516 | return 0; |
| 531 | } else if (ret == -1) | 517 | } |
| 532 | return -1; | 518 | |
| 533 | if (!cst) { | 519 | if (!constructed) { |
| 534 | ASN1error(ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); | 520 | ASN1error(ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); |
| 535 | return 0; | 521 | return 0; |
| 536 | } | 522 | } |
| 537 | /* We've found the field so it can't be OPTIONAL now */ | 523 | |
| 538 | ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, depth); | 524 | if (indefinite) { |
| 539 | if (!ret) { | 525 | CBS_init(&cbs_exp_content, CBS_data(&cbs_exp), CBS_len(&cbs_exp)); |
| 526 | } else { | ||
| 527 | if (!CBS_get_bytes(&cbs_exp, &cbs_exp_content, length)) | ||
| 528 | goto err; | ||
| 529 | } | ||
| 530 | |||
| 531 | if ((ret = asn1_template_noexp_d2i(pval, &cbs_exp_content, tt, 0, | ||
| 532 | depth)) != 1) { | ||
| 540 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 533 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 541 | return 0; | 534 | return 0; |
| 542 | } | 535 | } |
| 543 | /* We read the field in OK so update length */ | 536 | |
| 544 | len -= p - q; | 537 | if (indefinite) { |
| 545 | if (exp_eoc) { | 538 | if (!asn1_check_eoc(&cbs_exp_content)) { |
| 546 | /* If NDEF we must have an EOC here */ | ||
| 547 | if (!asn1_check_eoc(&p, len)) { | ||
| 548 | ASN1error(ASN1_R_MISSING_EOC); | 539 | ASN1error(ASN1_R_MISSING_EOC); |
| 549 | goto err; | 540 | goto err; |
| 550 | } | 541 | } |
| 551 | } else { | 542 | if (!CBS_skip(&cbs_exp, CBS_offset(&cbs_exp_content))) |
| 552 | /* Otherwise we must hit the EXPLICIT tag end or its | ||
| 553 | * an error */ | ||
| 554 | if (len) { | ||
| 555 | ASN1error(ASN1_R_EXPLICIT_LENGTH_MISMATCH); | ||
| 556 | goto err; | 543 | goto err; |
| 557 | } | 544 | } else if (CBS_len(&cbs_exp_content) != 0) { |
| 545 | ASN1error(ASN1_R_SEQUENCE_LENGTH_MISMATCH); | ||
| 546 | goto err; | ||
| 558 | } | 547 | } |
| 559 | 548 | ||
| 560 | *in = p; | 549 | if (!CBS_skip(cbs, CBS_offset(&cbs_exp))) |
| 550 | goto err; | ||
| 551 | |||
| 561 | return 1; | 552 | return 1; |
| 562 | 553 | ||
| 563 | err: | 554 | err: |
| 564 | ASN1_template_free(val, tt); | 555 | ASN1_template_free(pval, tt); |
| 565 | return 0; | 556 | return 0; |
| 566 | } | 557 | } |
| 567 | 558 | ||
| 568 | static int | 559 | static void |
| 569 | asn1_template_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_TEMPLATE *tt, | 560 | asn1_template_stack_of_free(STACK_OF(ASN1_VALUE) *avals, const ASN1_TEMPLATE *tt) { |
| 570 | char optional, int depth) | 561 | ASN1_VALUE *aval; |
| 571 | { | ||
| 572 | const unsigned char *p; | ||
| 573 | int ret; | ||
| 574 | 562 | ||
| 575 | if (CBS_len(cbs) > LONG_MAX) | 563 | if (avals == NULL) |
| 576 | return 0; | 564 | return; |
| 577 | 565 | ||
| 578 | p = CBS_data(cbs); | 566 | while (sk_ASN1_VALUE_num(avals) > 0) { |
| 579 | ret = asn1_template_ex_d2i(pval, &p, (long)CBS_len(cbs), tt, | 567 | aval = sk_ASN1_VALUE_pop(avals); |
| 580 | optional, depth); | 568 | ASN1_item_ex_free(&aval, tt->item); |
| 581 | if (ret == 1) { | ||
| 582 | if (!CBS_skip(cbs, p - CBS_data(cbs))) | ||
| 583 | return 0; | ||
| 584 | } | 569 | } |
| 585 | return ret; | 570 | sk_ASN1_VALUE_free(avals); |
| 586 | } | 571 | } |
| 587 | 572 | ||
| 588 | static int | 573 | static int |
| 589 | asn1_template_stack_of_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, | 574 | asn1_template_stack_of_d2i(ASN1_VALUE **pval, CBS *cbs, const ASN1_TEMPLATE *tt, |
| 590 | const ASN1_TEMPLATE *tt, char opt, int depth) | 575 | char optional, int depth) |
| 591 | { | 576 | { |
| 592 | const unsigned char *p, *q; | 577 | CBS cbs_object, cbs_object_content; |
| 593 | int sktag, skaclass; | 578 | STACK_OF(ASN1_VALUE) *avals = NULL; |
| 594 | char sk_eoc; | 579 | ASN1_VALUE *aval = NULL; |
| 595 | long len; | 580 | int tag_number, tag_class; |
| 581 | int eoc_needed; | ||
| 582 | char indefinite; | ||
| 583 | size_t length; | ||
| 596 | int ret; | 584 | int ret; |
| 597 | 585 | ||
| 598 | /* SET OF, SEQUENCE OF */ | 586 | CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs)); |
| 599 | 587 | ||
| 600 | p = *in; | 588 | if (pval == NULL) |
| 601 | q = p; | 589 | return 0; |
| 602 | 590 | ||
| 603 | /* First work out expected inner tag value */ | 591 | asn1_template_stack_of_free((STACK_OF(ASN1_VALUE) *)*pval, tt); |
| 604 | if (tt->flags & ASN1_TFLG_IMPTAG) { | 592 | *pval = NULL; |
| 605 | sktag = tt->tag; | 593 | |
| 606 | skaclass = tt->flags & ASN1_TFLG_TAG_CLASS; | 594 | tag_number = tt->tag; |
| 607 | } else { | 595 | tag_class = tt->flags & ASN1_TFLG_TAG_CLASS; |
| 608 | skaclass = V_ASN1_UNIVERSAL; | 596 | |
| 609 | if (tt->flags & ASN1_TFLG_SET_OF) | 597 | /* Determine the inner tag value for SET OF or SEQUENCE OF. */ |
| 610 | sktag = V_ASN1_SET; | 598 | if ((tt->flags & ASN1_TFLG_IMPTAG) == 0) { |
| 611 | else | 599 | tag_number = V_ASN1_SEQUENCE; |
| 612 | sktag = V_ASN1_SEQUENCE; | 600 | tag_class = V_ASN1_UNIVERSAL; |
| 613 | } | 601 | if ((tt->flags & ASN1_TFLG_SET_OF) != 0) |
| 614 | /* Get the tag */ | 602 | tag_number = V_ASN1_SET; |
| 615 | ret = asn1_check_tag(&len, NULL, NULL, &sk_eoc, NULL, &p, inlen, | 603 | } |
| 616 | sktag, skaclass, opt); | 604 | |
| 617 | if (!ret) { | 605 | ret = asn1_check_tag(&cbs_object, &length, NULL, NULL, &indefinite, |
| 606 | NULL, tag_number, tag_class, optional); | ||
| 607 | if (ret == -1) | ||
| 608 | return -1; | ||
| 609 | if (ret != 1) { | ||
| 618 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 610 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 619 | return 0; | 611 | return 0; |
| 620 | } else if (ret == -1) | ||
| 621 | return -1; | ||
| 622 | if (!*val) | ||
| 623 | *val = (ASN1_VALUE *)sk_new_null(); | ||
| 624 | else { | ||
| 625 | /* We've got a valid STACK: free up any items present */ | ||
| 626 | STACK_OF(ASN1_VALUE) *sktmp = | ||
| 627 | (STACK_OF(ASN1_VALUE) *)*val; | ||
| 628 | ASN1_VALUE *vtmp; | ||
| 629 | while (sk_ASN1_VALUE_num(sktmp) > 0) { | ||
| 630 | vtmp = sk_ASN1_VALUE_pop(sktmp); | ||
| 631 | ASN1_item_ex_free(&vtmp, | ||
| 632 | tt->item); | ||
| 633 | } | ||
| 634 | } | 612 | } |
| 635 | 613 | ||
| 636 | if (!*val) { | 614 | if (indefinite) { |
| 615 | eoc_needed = 1; | ||
| 616 | CBS_init(&cbs_object_content, CBS_data(&cbs_object), | ||
| 617 | CBS_len(&cbs_object)); | ||
| 618 | } else { | ||
| 619 | eoc_needed = 0; | ||
| 620 | if (!CBS_get_bytes(&cbs_object, &cbs_object_content, | ||
| 621 | length)) | ||
| 622 | goto err; | ||
| 623 | } | ||
| 624 | |||
| 625 | if ((avals = sk_ASN1_VALUE_new_null()) == NULL) { | ||
| 637 | ASN1error(ERR_R_MALLOC_FAILURE); | 626 | ASN1error(ERR_R_MALLOC_FAILURE); |
| 638 | goto err; | 627 | goto err; |
| 639 | } | 628 | } |
| 640 | 629 | ||
| 641 | /* Read as many items as we can */ | 630 | /* Read as many items as possible. */ |
| 642 | while (len > 0) { | 631 | while (CBS_len(&cbs_object_content) > 0) { |
| 643 | ASN1_VALUE *skfield; | 632 | if (asn1_check_eoc(&cbs_object_content)) { |
| 644 | q = p; | 633 | if (!eoc_needed) { |
| 645 | /* See if EOC found */ | ||
| 646 | if (asn1_check_eoc(&p, len)) { | ||
| 647 | if (!sk_eoc) { | ||
| 648 | ASN1error(ASN1_R_UNEXPECTED_EOC); | 634 | ASN1error(ASN1_R_UNEXPECTED_EOC); |
| 649 | goto err; | 635 | goto err; |
| 650 | } | 636 | } |
| 651 | len -= p - q; | 637 | eoc_needed = 0; |
| 652 | sk_eoc = 0; | ||
| 653 | break; | 638 | break; |
| 654 | } | 639 | } |
| 655 | skfield = NULL; | 640 | if (!asn1_item_ex_d2i(&aval, &cbs_object_content, tt->item, |
| 656 | if (!asn1_item_ex_d2i(&skfield, &p, len, | 641 | -1, 0, 0, depth)) { |
| 657 | tt->item, -1, 0, 0, depth)) { | ||
| 658 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 642 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 659 | goto err; | 643 | goto err; |
| 660 | } | 644 | } |
| 661 | len -= p - q; | 645 | if (!sk_ASN1_VALUE_push(avals, aval)) { |
| 662 | if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, | ||
| 663 | skfield)) { | ||
| 664 | ASN1error(ERR_R_MALLOC_FAILURE); | 646 | ASN1error(ERR_R_MALLOC_FAILURE); |
| 665 | goto err; | 647 | goto err; |
| 666 | } | 648 | } |
| 649 | aval = NULL; | ||
| 667 | } | 650 | } |
| 668 | if (sk_eoc) { | 651 | if (eoc_needed) { |
| 669 | ASN1error(ASN1_R_MISSING_EOC); | 652 | ASN1error(ASN1_R_MISSING_EOC); |
| 670 | goto err; | 653 | goto err; |
| 671 | } | 654 | } |
| 672 | 655 | ||
| 673 | *in = p; | 656 | if (indefinite) { |
| 657 | if (!CBS_skip(&cbs_object, CBS_offset(&cbs_object_content))) | ||
| 658 | goto err; | ||
| 659 | } | ||
| 660 | |||
| 661 | if (!CBS_skip(cbs, CBS_offset(&cbs_object))) | ||
| 662 | goto err; | ||
| 663 | |||
| 664 | *pval = (ASN1_VALUE *)avals; | ||
| 665 | avals = NULL; | ||
| 666 | |||
| 674 | return 1; | 667 | return 1; |
| 675 | 668 | ||
| 676 | err: | 669 | err: |
| 677 | ASN1_template_free(val, tt); | 670 | asn1_template_stack_of_free(avals, tt); |
| 671 | ASN1_item_ex_free(&aval, tt->item); | ||
| 672 | |||
| 678 | return 0; | 673 | return 0; |
| 679 | } | 674 | } |
| 680 | 675 | ||
| 681 | static int | 676 | static int |
| 682 | asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, | 677 | asn1_template_noexp_d2i(ASN1_VALUE **pval, CBS *cbs, const ASN1_TEMPLATE *tt, |
| 683 | const ASN1_TEMPLATE *tt, char opt, int depth) | 678 | char optional, int depth) |
| 684 | { | 679 | { |
| 685 | const unsigned char *p; | ||
| 686 | int tag_number, tag_class; | 680 | int tag_number, tag_class; |
| 687 | int ret; | 681 | int ret; |
| 688 | 682 | ||
| 689 | if (!val) | 683 | if (pval == NULL) |
| 690 | return 0; | 684 | return 0; |
| 691 | 685 | ||
| 692 | p = *in; | ||
| 693 | |||
| 694 | if ((tt->flags & ASN1_TFLG_SK_MASK) != 0) | 686 | if ((tt->flags & ASN1_TFLG_SK_MASK) != 0) |
| 695 | return asn1_template_stack_of_d2i(val, in, len, tt, opt, depth); | 687 | return asn1_template_stack_of_d2i(pval, cbs, tt, optional, depth); |
| 696 | 688 | ||
| 697 | tag_number = -1; | 689 | tag_number = -1; |
| 698 | tag_class = V_ASN1_UNIVERSAL; | 690 | tag_class = V_ASN1_UNIVERSAL; |
| @@ -703,18 +695,20 @@ asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, | |||
| 703 | tag_class = tt->flags & ASN1_TFLG_TAG_CLASS; | 695 | tag_class = tt->flags & ASN1_TFLG_TAG_CLASS; |
| 704 | } | 696 | } |
| 705 | 697 | ||
| 706 | ret = asn1_item_ex_d2i(val, &p, len, tt->item, tag_number, tag_class, opt, depth); | 698 | ret = asn1_item_ex_d2i(pval, cbs, tt->item, tag_number, tag_class, |
| 707 | if (!ret) { | 699 | optional, depth); |
| 700 | if (ret == -1) | ||
| 701 | return -1; | ||
| 702 | if (ret != 1) { | ||
| 708 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 703 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 709 | goto err; | 704 | goto err; |
| 710 | } else if (ret == -1) | 705 | } |
| 711 | return -1; | ||
| 712 | 706 | ||
| 713 | *in = p; | ||
| 714 | return 1; | 707 | return 1; |
| 715 | 708 | ||
| 716 | err: | 709 | err: |
| 717 | ASN1_template_free(val, tt); | 710 | /* XXX - The called function should have freed already. */ |
| 711 | ASN1_template_free(pval, tt); | ||
| 718 | return 0; | 712 | return 0; |
| 719 | } | 713 | } |
| 720 | 714 | ||
| @@ -824,7 +818,7 @@ asn1_d2i_ex_any(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 824 | } | 818 | } |
| 825 | 819 | ||
| 826 | /* Determine type from ASN.1 tag. */ | 820 | /* Determine type from ASN.1 tag. */ |
| 827 | if (asn1_check_tag_cbs(&cbs_object, &length, &object_type, &object_class, | 821 | if (asn1_check_tag(&cbs_object, &length, &object_type, &object_class, |
| 828 | &indefinite, &constructed, -1, 0, 0) != 1) { | 822 | &indefinite, &constructed, -1, 0, 0) != 1) { |
| 829 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 823 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 830 | return 0; | 824 | return 0; |
| @@ -857,7 +851,7 @@ asn1_d2i_ex_mstring(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 857 | return 0; | 851 | return 0; |
| 858 | } | 852 | } |
| 859 | 853 | ||
| 860 | if (asn1_check_tag_cbs(&cbs_object, &length, &object_tag, &object_class, | 854 | if (asn1_check_tag(&cbs_object, &length, &object_tag, &object_class, |
| 861 | &indefinite, &constructed, -1, 0, 1) != 1) { | 855 | &indefinite, &constructed, -1, 0, 1) != 1) { |
| 862 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 856 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 863 | return 0; | 857 | return 0; |
| @@ -905,7 +899,7 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 905 | tag_class = V_ASN1_UNIVERSAL; | 899 | tag_class = V_ASN1_UNIVERSAL; |
| 906 | } | 900 | } |
| 907 | 901 | ||
| 908 | ret = asn1_check_tag_cbs(&cbs_object, &length, NULL, NULL, &indefinite, | 902 | ret = asn1_check_tag(&cbs_object, &length, NULL, NULL, &indefinite, |
| 909 | &constructed, tag_number, tag_class, optional); | 903 | &constructed, tag_number, tag_class, optional); |
| 910 | if (ret == -1) | 904 | if (ret == -1) |
| 911 | return -1; | 905 | return -1; |
| @@ -1094,12 +1088,12 @@ asn1_find_end(CBS *cbs, size_t length, char indefinite) | |||
| 1094 | eoc_count = 1; | 1088 | eoc_count = 1; |
| 1095 | 1089 | ||
| 1096 | while (CBS_len(cbs) > 0) { | 1090 | while (CBS_len(cbs) > 0) { |
| 1097 | if (asn1_check_eoc_cbs(cbs)) { | 1091 | if (asn1_check_eoc(cbs)) { |
| 1098 | if (--eoc_count == 0) | 1092 | if (--eoc_count == 0) |
| 1099 | break; | 1093 | break; |
| 1100 | continue; | 1094 | continue; |
| 1101 | } | 1095 | } |
| 1102 | if (!asn1_check_tag_cbs(cbs, &length, NULL, NULL, | 1096 | if (!asn1_check_tag(cbs, &length, NULL, NULL, |
| 1103 | &indefinite, NULL, -1, 0, 0)) { | 1097 | &indefinite, NULL, -1, 0, 0)) { |
| 1104 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 1098 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 1105 | return 0; | 1099 | return 0; |
| @@ -1147,14 +1141,14 @@ asn1_collect(CBB *cbb, CBS *cbs, char indefinite, int expected_tag, | |||
| 1147 | need_eoc = indefinite; | 1141 | need_eoc = indefinite; |
| 1148 | 1142 | ||
| 1149 | while (CBS_len(cbs) > 0) { | 1143 | while (CBS_len(cbs) > 0) { |
| 1150 | if (asn1_check_eoc_cbs(cbs)) { | 1144 | if (asn1_check_eoc(cbs)) { |
| 1151 | if (!need_eoc) { | 1145 | if (!need_eoc) { |
| 1152 | ASN1error(ASN1_R_UNEXPECTED_EOC); | 1146 | ASN1error(ASN1_R_UNEXPECTED_EOC); |
| 1153 | return 0; | 1147 | return 0; |
| 1154 | } | 1148 | } |
| 1155 | return 1; | 1149 | return 1; |
| 1156 | } | 1150 | } |
| 1157 | if (!asn1_check_tag_cbs(cbs, &length, NULL, NULL, &indefinite, | 1151 | if (!asn1_check_tag(cbs, &length, NULL, NULL, &indefinite, |
| 1158 | &constructed, expected_tag, expected_class, 0)) { | 1152 | &constructed, expected_tag, expected_class, 0)) { |
| 1159 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 1153 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 1160 | return 0; | 1154 | return 0; |
| @@ -1184,7 +1178,7 @@ asn1_collect(CBB *cbb, CBS *cbs, char indefinite, int expected_tag, | |||
| 1184 | } | 1178 | } |
| 1185 | 1179 | ||
| 1186 | static int | 1180 | static int |
| 1187 | asn1_check_eoc_cbs(CBS *cbs) | 1181 | asn1_check_eoc(CBS *cbs) |
| 1188 | { | 1182 | { |
| 1189 | uint16_t eoc; | 1183 | uint16_t eoc; |
| 1190 | 1184 | ||
| @@ -1197,22 +1191,7 @@ asn1_check_eoc_cbs(CBS *cbs) | |||
| 1197 | } | 1191 | } |
| 1198 | 1192 | ||
| 1199 | static int | 1193 | static int |
| 1200 | asn1_check_eoc(const unsigned char **in, long len) | 1194 | asn1_check_tag(CBS *cbs, size_t *out_len, int *out_tag, uint8_t *out_class, |
| 1201 | { | ||
| 1202 | const unsigned char *p; | ||
| 1203 | |||
| 1204 | if (len < 2) | ||
| 1205 | return 0; | ||
| 1206 | p = *in; | ||
| 1207 | if (!p[0] && !p[1]) { | ||
| 1208 | *in += 2; | ||
| 1209 | return 1; | ||
| 1210 | } | ||
| 1211 | return 0; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | static int | ||
| 1215 | asn1_check_tag_cbs(CBS *cbs, size_t *out_len, int *out_tag, uint8_t *out_class, | ||
| 1216 | char *out_indefinite, char *out_constructed, int expected_tag, | 1195 | char *out_indefinite, char *out_constructed, int expected_tag, |
| 1217 | int expected_class, char optional) | 1196 | int expected_class, char optional) |
| 1218 | { | 1197 | { |
| @@ -1285,32 +1264,3 @@ asn1_check_tag_cbs(CBS *cbs, size_t *out_len, int *out_tag, uint8_t *out_class, | |||
| 1285 | 1264 | ||
| 1286 | return 1; | 1265 | return 1; |
| 1287 | } | 1266 | } |
| 1288 | |||
| 1289 | static int | ||
| 1290 | asn1_check_tag(long *out_len, int *out_tag, unsigned char *out_class, | ||
| 1291 | char *out_indefinite, char *out_constructed, const unsigned char **in, | ||
| 1292 | long len, int expected_tag, int expected_class, char optional) | ||
| 1293 | { | ||
| 1294 | size_t length; | ||
| 1295 | CBS cbs; | ||
| 1296 | int ret; | ||
| 1297 | |||
| 1298 | if (len < 0) | ||
| 1299 | return 0; | ||
| 1300 | |||
| 1301 | CBS_init(&cbs, *in, len); | ||
| 1302 | |||
| 1303 | ret = asn1_check_tag_cbs(&cbs, &length, out_tag, out_class, | ||
| 1304 | out_indefinite, out_constructed, expected_tag, expected_class, | ||
| 1305 | optional); | ||
| 1306 | |||
| 1307 | if (length > LONG_MAX) | ||
| 1308 | return 0; | ||
| 1309 | if (out_len != NULL) | ||
| 1310 | *out_len = (long)length; | ||
| 1311 | |||
| 1312 | if (ret == 1) | ||
| 1313 | *in = CBS_data(&cbs); | ||
| 1314 | |||
| 1315 | return ret; | ||
| 1316 | } | ||
