diff options
author | jsing <> | 2022-05-19 19:31:39 +0000 |
---|---|---|
committer | jsing <> | 2022-05-19 19:31:39 +0000 |
commit | 94f8e2dd8817ff74b89e103a09ba4b9b884f75ec (patch) | |
tree | d5a8d51f4e6231a9fa37f965f0c30ea726552ffa /src | |
parent | 7872788c306d2030b56275c8d2970b04967c6f3b (diff) | |
download | openbsd-94f8e2dd8817ff74b89e103a09ba4b9b884f75ec.tar.gz openbsd-94f8e2dd8817ff74b89e103a09ba4b9b884f75ec.tar.bz2 openbsd-94f8e2dd8817ff74b89e103a09ba4b9b884f75ec.zip |
Rewrite the asn1_template_*() functions with CBS.
Rewrite the asn1_template_*() functions with CBS, readable variable names
and free then alloc.
This was the last caller of asn1_check_eoc() and asn1_check_tag(), hence
remove them and rename the _cbs suffixed versions in their place.
ok tb@
Diffstat (limited to 'src')
-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 | } | ||