diff options
author | jsing <> | 2022-05-17 12:23:52 +0000 |
---|---|---|
committer | jsing <> | 2022-05-17 12:23:52 +0000 |
commit | 440516cf733a3d776a7133a827812490af8d75e1 (patch) | |
tree | a9bc9123c236536286916e542b234437fde5b6ef /src | |
parent | 8b50bcf55793c7830584351b3cadc861113b9b41 (diff) | |
download | openbsd-440516cf733a3d776a7133a827812490af8d75e1.tar.gz openbsd-440516cf733a3d776a7133a827812490af8d75e1.tar.bz2 openbsd-440516cf733a3d776a7133a827812490af8d75e1.zip |
Refactor ASN.1 template functions before rewriting.
Change asn1_template_ex_d2i() so that we short circuit in the no explicit
tagging case.
Split out the SET OF/SEQUENCE OF handling from asn1_template_noexp_d2i()
into a asn1_template_stack_of_d2i() function and simplify the remaining
code.
ok tb@
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 278 |
1 files changed, 145 insertions, 133 deletions
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index 744dde23c0..88b61a997d 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.68 2022/05/16 20:06:15 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.69 2022/05/17 12:23:52 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 | */ |
@@ -528,10 +528,6 @@ ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | |||
528 | return asn1_item_ex_d2i(pval, in, len, it, tag, aclass, opt, 0); | 528 | return asn1_item_ex_d2i(pval, in, len, it, tag, aclass, opt, 0); |
529 | } | 529 | } |
530 | 530 | ||
531 | /* Templates are handled with two separate functions. | ||
532 | * One handles any EXPLICIT tag and the other handles the rest. | ||
533 | */ | ||
534 | |||
535 | static int | 531 | static int |
536 | asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, | 532 | asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, |
537 | const ASN1_TEMPLATE *tt, char opt, int depth) | 533 | const ASN1_TEMPLATE *tt, char opt, int depth) |
@@ -541,6 +537,7 @@ asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, | |||
541 | long len; | 537 | long len; |
542 | const unsigned char *p, *q; | 538 | const unsigned char *p, *q; |
543 | char exp_eoc; | 539 | char exp_eoc; |
540 | char cst; | ||
544 | 541 | ||
545 | if (!val) | 542 | if (!val) |
546 | return 0; | 543 | return 0; |
@@ -550,48 +547,47 @@ asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, | |||
550 | p = *in; | 547 | p = *in; |
551 | 548 | ||
552 | /* Check if EXPLICIT tag expected */ | 549 | /* Check if EXPLICIT tag expected */ |
553 | if (flags & ASN1_TFLG_EXPTAG) { | 550 | if ((flags & ASN1_TFLG_EXPTAG) == 0) |
554 | char cst; | 551 | return asn1_template_noexp_d2i(val, in, inlen, tt, opt, depth); |
555 | /* Need to work out amount of data available to the inner | 552 | |
556 | * content and where it starts: so read in EXPLICIT header to | 553 | /* Need to work out amount of data available to the inner |
557 | * get the info. | 554 | * content and where it starts: so read in EXPLICIT header to |
558 | */ | 555 | * get the info. |
559 | ret = asn1_check_tag(&len, NULL, NULL, &exp_eoc, &cst, &p, | 556 | */ |
560 | inlen, tt->tag, aclass, opt); | 557 | ret = asn1_check_tag(&len, NULL, NULL, &exp_eoc, &cst, &p, |
561 | q = p; | 558 | inlen, tt->tag, aclass, opt); |
562 | if (!ret) { | 559 | q = p; |
563 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 560 | if (!ret) { |
564 | return 0; | 561 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
565 | } else if (ret == -1) | 562 | return 0; |
566 | return -1; | 563 | } else if (ret == -1) |
567 | if (!cst) { | 564 | return -1; |
568 | ASN1error(ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); | 565 | if (!cst) { |
569 | return 0; | 566 | ASN1error(ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); |
570 | } | 567 | return 0; |
571 | /* We've found the field so it can't be OPTIONAL now */ | 568 | } |
572 | ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, depth); | 569 | /* We've found the field so it can't be OPTIONAL now */ |
573 | if (!ret) { | 570 | ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, depth); |
574 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 571 | if (!ret) { |
575 | return 0; | 572 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
573 | return 0; | ||
574 | } | ||
575 | /* We read the field in OK so update length */ | ||
576 | len -= p - q; | ||
577 | if (exp_eoc) { | ||
578 | /* If NDEF we must have an EOC here */ | ||
579 | if (!asn1_check_eoc(&p, len)) { | ||
580 | ASN1error(ASN1_R_MISSING_EOC); | ||
581 | goto err; | ||
576 | } | 582 | } |
577 | /* We read the field in OK so update length */ | 583 | } else { |
578 | len -= p - q; | 584 | /* Otherwise we must hit the EXPLICIT tag end or its |
579 | if (exp_eoc) { | 585 | * an error */ |
580 | /* If NDEF we must have an EOC here */ | 586 | if (len) { |
581 | if (!asn1_check_eoc(&p, len)) { | 587 | ASN1error(ASN1_R_EXPLICIT_LENGTH_MISMATCH); |
582 | ASN1error(ASN1_R_MISSING_EOC); | 588 | goto err; |
583 | goto err; | ||
584 | } | ||
585 | } else { | ||
586 | /* Otherwise we must hit the EXPLICIT tag end or its | ||
587 | * an error */ | ||
588 | if (len) { | ||
589 | ASN1error(ASN1_R_EXPLICIT_LENGTH_MISMATCH); | ||
590 | goto err; | ||
591 | } | ||
592 | } | 589 | } |
593 | } else | 590 | } |
594 | return asn1_template_noexp_d2i(val, in, inlen, tt, opt, depth); | ||
595 | 591 | ||
596 | *in = p; | 592 | *in = p; |
597 | return 1; | 593 | return 1; |
@@ -622,112 +618,88 @@ asn1_template_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_TEMPLATE *tt, | |||
622 | } | 618 | } |
623 | 619 | ||
624 | static int | 620 | static int |
625 | asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, | 621 | asn1_template_stack_of_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, |
626 | const ASN1_TEMPLATE *tt, char opt, int depth) | 622 | const ASN1_TEMPLATE *tt, char opt, int depth) |
627 | { | 623 | { |
628 | int flags, aclass; | ||
629 | int ret; | ||
630 | const unsigned char *p, *q; | 624 | const unsigned char *p, *q; |
625 | int sktag, skaclass; | ||
626 | char sk_eoc; | ||
627 | long len; | ||
628 | int ret; | ||
631 | 629 | ||
632 | if (!val) | 630 | /* SET OF, SEQUENCE OF */ |
633 | return 0; | ||
634 | flags = tt->flags; | ||
635 | aclass = flags & ASN1_TFLG_TAG_CLASS; | ||
636 | 631 | ||
637 | p = *in; | 632 | p = *in; |
638 | q = p; | 633 | q = p; |
639 | 634 | ||
640 | if (flags & ASN1_TFLG_SK_MASK) { | 635 | /* First work out expected inner tag value */ |
641 | /* SET OF, SEQUENCE OF */ | 636 | if (tt->flags & ASN1_TFLG_IMPTAG) { |
642 | int sktag, skaclass; | 637 | sktag = tt->tag; |
643 | char sk_eoc; | 638 | skaclass = tt->flags & ASN1_TFLG_TAG_CLASS; |
644 | /* First work out expected inner tag value */ | 639 | } else { |
645 | if (flags & ASN1_TFLG_IMPTAG) { | 640 | skaclass = V_ASN1_UNIVERSAL; |
646 | sktag = tt->tag; | 641 | if (tt->flags & ASN1_TFLG_SET_OF) |
647 | skaclass = aclass; | 642 | sktag = V_ASN1_SET; |
648 | } else { | 643 | else |
649 | skaclass = V_ASN1_UNIVERSAL; | 644 | sktag = V_ASN1_SEQUENCE; |
650 | if (flags & ASN1_TFLG_SET_OF) | 645 | } |
651 | sktag = V_ASN1_SET; | 646 | /* Get the tag */ |
652 | else | 647 | ret = asn1_check_tag(&len, NULL, NULL, &sk_eoc, NULL, &p, inlen, |
653 | sktag = V_ASN1_SEQUENCE; | 648 | sktag, skaclass, opt); |
654 | } | 649 | if (!ret) { |
655 | /* Get the tag */ | 650 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
656 | ret = asn1_check_tag(&len, NULL, NULL, &sk_eoc, NULL, &p, len, | 651 | return 0; |
657 | sktag, skaclass, opt); | 652 | } else if (ret == -1) |
658 | if (!ret) { | 653 | return -1; |
659 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 654 | if (!*val) |
660 | return 0; | 655 | *val = (ASN1_VALUE *)sk_new_null(); |
661 | } else if (ret == -1) | 656 | else { |
662 | return -1; | 657 | /* We've got a valid STACK: free up any items present */ |
663 | if (!*val) | 658 | STACK_OF(ASN1_VALUE) *sktmp = |
664 | *val = (ASN1_VALUE *)sk_new_null(); | 659 | (STACK_OF(ASN1_VALUE) *)*val; |
665 | else { | 660 | ASN1_VALUE *vtmp; |
666 | /* We've got a valid STACK: free up any items present */ | 661 | while (sk_ASN1_VALUE_num(sktmp) > 0) { |
667 | STACK_OF(ASN1_VALUE) *sktmp = | 662 | vtmp = sk_ASN1_VALUE_pop(sktmp); |
668 | (STACK_OF(ASN1_VALUE) *)*val; | 663 | ASN1_item_ex_free(&vtmp, |
669 | ASN1_VALUE *vtmp; | 664 | tt->item); |
670 | while (sk_ASN1_VALUE_num(sktmp) > 0) { | ||
671 | vtmp = sk_ASN1_VALUE_pop(sktmp); | ||
672 | ASN1_item_ex_free(&vtmp, | ||
673 | tt->item); | ||
674 | } | ||
675 | } | 665 | } |
666 | } | ||
676 | 667 | ||
677 | if (!*val) { | 668 | if (!*val) { |
678 | ASN1error(ERR_R_MALLOC_FAILURE); | 669 | ASN1error(ERR_R_MALLOC_FAILURE); |
679 | goto err; | 670 | goto err; |
680 | } | 671 | } |
681 | 672 | ||
682 | /* Read as many items as we can */ | 673 | /* Read as many items as we can */ |
683 | while (len > 0) { | 674 | while (len > 0) { |
684 | ASN1_VALUE *skfield; | 675 | ASN1_VALUE *skfield; |
685 | q = p; | 676 | q = p; |
686 | /* See if EOC found */ | 677 | /* See if EOC found */ |
687 | if (asn1_check_eoc(&p, len)) { | 678 | if (asn1_check_eoc(&p, len)) { |
688 | if (!sk_eoc) { | 679 | if (!sk_eoc) { |
689 | ASN1error(ASN1_R_UNEXPECTED_EOC); | 680 | ASN1error(ASN1_R_UNEXPECTED_EOC); |
690 | goto err; | ||
691 | } | ||
692 | len -= p - q; | ||
693 | sk_eoc = 0; | ||
694 | break; | ||
695 | } | ||
696 | skfield = NULL; | ||
697 | if (!asn1_item_ex_d2i(&skfield, &p, len, | ||
698 | tt->item, -1, 0, 0, depth)) { | ||
699 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
700 | goto err; | 681 | goto err; |
701 | } | 682 | } |
702 | len -= p - q; | 683 | len -= p - q; |
703 | if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, | 684 | sk_eoc = 0; |
704 | skfield)) { | 685 | break; |
705 | ASN1error(ERR_R_MALLOC_FAILURE); | ||
706 | goto err; | ||
707 | } | ||
708 | } | ||
709 | if (sk_eoc) { | ||
710 | ASN1error(ASN1_R_MISSING_EOC); | ||
711 | goto err; | ||
712 | } | 686 | } |
713 | } else if (flags & ASN1_TFLG_IMPTAG) { | 687 | skfield = NULL; |
714 | /* IMPLICIT tagging */ | 688 | if (!asn1_item_ex_d2i(&skfield, &p, len, |
715 | ret = asn1_item_ex_d2i(val, &p, len, | 689 | tt->item, -1, 0, 0, depth)) { |
716 | tt->item, tt->tag, aclass, opt, depth); | ||
717 | if (!ret) { | ||
718 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 690 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
719 | goto err; | 691 | goto err; |
720 | } else if (ret == -1) | 692 | } |
721 | return -1; | 693 | len -= p - q; |
722 | } else { | 694 | if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, |
723 | /* Nothing special */ | 695 | skfield)) { |
724 | ret = asn1_item_ex_d2i(val, &p, len, tt->item, -1, 0, | 696 | ASN1error(ERR_R_MALLOC_FAILURE); |
725 | opt, depth); | ||
726 | if (!ret) { | ||
727 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
728 | goto err; | 697 | goto err; |
729 | } else if (ret == -1) | 698 | } |
730 | return -1; | 699 | } |
700 | if (sk_eoc) { | ||
701 | ASN1error(ASN1_R_MISSING_EOC); | ||
702 | goto err; | ||
731 | } | 703 | } |
732 | 704 | ||
733 | *in = p; | 705 | *in = p; |
@@ -739,6 +711,46 @@ asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, | |||
739 | } | 711 | } |
740 | 712 | ||
741 | static int | 713 | static int |
714 | asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, | ||
715 | const ASN1_TEMPLATE *tt, char opt, int depth) | ||
716 | { | ||
717 | const unsigned char *p; | ||
718 | int tag_number, tag_class; | ||
719 | int ret; | ||
720 | |||
721 | if (!val) | ||
722 | return 0; | ||
723 | |||
724 | p = *in; | ||
725 | |||
726 | if ((tt->flags & ASN1_TFLG_SK_MASK) != 0) | ||
727 | return asn1_template_stack_of_d2i(val, in, len, tt, opt, depth); | ||
728 | |||
729 | tag_number = -1; | ||
730 | tag_class = V_ASN1_UNIVERSAL; | ||
731 | |||
732 | /* See if we need to use IMPLICIT tagging. */ | ||
733 | if ((tt->flags & ASN1_TFLG_IMPTAG) != 0) { | ||
734 | tag_number = tt->tag; | ||
735 | tag_class = tt->flags & ASN1_TFLG_TAG_CLASS; | ||
736 | } | ||
737 | |||
738 | ret = asn1_item_ex_d2i(val, &p, len, tt->item, tag_number, tag_class, opt, depth); | ||
739 | if (!ret) { | ||
740 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
741 | goto err; | ||
742 | } else if (ret == -1) | ||
743 | return -1; | ||
744 | |||
745 | *in = p; | ||
746 | return 1; | ||
747 | |||
748 | err: | ||
749 | ASN1_template_free(val, tt); | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int | ||
742 | asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | 754 | asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, |
743 | int tag_number, int tag_class, char optional) | 755 | int tag_number, int tag_class, char optional) |
744 | { | 756 | { |