diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 158 |
1 files changed, 86 insertions, 72 deletions
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index f04ec66bc7..3cc2146e45 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.59 2022/05/07 10:03:49 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.60 2022/05/07 10:13:56 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 | */ |
| @@ -645,86 +645,89 @@ asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, | |||
| 645 | } | 645 | } |
| 646 | 646 | ||
| 647 | static int | 647 | static int |
| 648 | asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, | 648 | asn1_d2i_ex_primitive_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, |
| 649 | const ASN1_ITEM *it, int tag, int aclass, char opt) | 649 | int tag_number, int tag_class, char optional) |
| 650 | { | 650 | { |
| 651 | int ret = 0, utype; | 651 | CBS cbs_any, cbs_content, cbs_object, cbs_initial; |
| 652 | long plen; | 652 | char constructed, indefinite; |
| 653 | char cst, inf; | ||
| 654 | const unsigned char *p; | ||
| 655 | const unsigned char *content = NULL; | ||
| 656 | uint8_t *data = NULL; | 653 | uint8_t *data = NULL; |
| 657 | size_t data_len = 0; | 654 | size_t data_len = 0; |
| 658 | CBS cbs; | 655 | int utype = it->utype; |
| 656 | unsigned char oclass; | ||
| 657 | size_t length; | ||
| 659 | CBB cbb; | 658 | CBB cbb; |
| 660 | long len; | 659 | int tag_ret; |
| 660 | int ret = 0; | ||
| 661 | 661 | ||
| 662 | memset(&cbb, 0, sizeof(cbb)); | 662 | memset(&cbb, 0, sizeof(cbb)); |
| 663 | 663 | ||
| 664 | if (!pval) { | 664 | CBS_dup(cbs, &cbs_initial); |
| 665 | CBS_init(&cbs_content, NULL, 0); | ||
| 666 | CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs)); | ||
| 667 | |||
| 668 | if (pval == NULL) { | ||
| 665 | ASN1error(ASN1_R_ILLEGAL_NULL); | 669 | ASN1error(ASN1_R_ILLEGAL_NULL); |
| 666 | return 0; /* Should never happen */ | 670 | goto err; |
| 667 | } | 671 | } |
| 668 | 672 | ||
| 669 | if (it->itype == ASN1_ITYPE_MSTRING) { | 673 | if (it->itype == ASN1_ITYPE_MSTRING) { |
| 670 | utype = tag; | 674 | utype = tag_number; |
| 671 | tag = -1; | 675 | tag_number = -1; |
| 672 | } else | 676 | } |
| 673 | utype = it->utype; | ||
| 674 | 677 | ||
| 675 | if (utype == V_ASN1_ANY) { | 678 | if (utype == V_ASN1_ANY) { |
| 676 | /* If type is ANY need to figure out type from tag */ | 679 | /* Determine type from ASN.1 tag. */ |
| 677 | unsigned char oclass; | 680 | if (tag_number >= 0) { |
| 678 | if (tag >= 0) { | ||
| 679 | ASN1error(ASN1_R_ILLEGAL_TAGGED_ANY); | 681 | ASN1error(ASN1_R_ILLEGAL_TAGGED_ANY); |
| 680 | return 0; | 682 | goto err; |
| 681 | } | 683 | } |
| 682 | if (opt) { | 684 | if (optional) { |
| 683 | ASN1error(ASN1_R_ILLEGAL_OPTIONAL_ANY); | 685 | ASN1error(ASN1_R_ILLEGAL_OPTIONAL_ANY); |
| 684 | return 0; | 686 | goto err; |
| 685 | } | 687 | } |
| 686 | p = *in; | 688 | /* XXX - avoid reading the header twice for ANY. */ |
| 687 | ret = asn1_check_tag(NULL, &utype, &oclass, NULL, NULL, &p, | 689 | CBS_dup(&cbs_object, &cbs_any); |
| 688 | inlen, -1, 0, 0); | 690 | tag_ret = asn1_check_tag_cbs(&cbs_any, NULL, &utype, &oclass, |
| 689 | if (!ret) { | 691 | NULL, NULL, -1, 0, 0); |
| 692 | if (tag_ret != 1) { | ||
| 690 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 693 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 691 | return 0; | 694 | goto err; |
| 692 | } | 695 | } |
| 693 | if (oclass != V_ASN1_UNIVERSAL) | 696 | if (oclass != V_ASN1_UNIVERSAL) |
| 694 | utype = V_ASN1_OTHER; | 697 | utype = V_ASN1_OTHER; |
| 695 | } | 698 | } |
| 696 | if (tag == -1) { | 699 | |
| 697 | tag = utype; | 700 | if (tag_number == -1) { |
| 698 | aclass = V_ASN1_UNIVERSAL; | 701 | tag_number = utype; |
| 702 | tag_class = V_ASN1_UNIVERSAL; | ||
| 699 | } | 703 | } |
| 700 | p = *in; | 704 | |
| 701 | /* Check header */ | 705 | tag_ret = asn1_check_tag_cbs(&cbs_object, &length, NULL, NULL, &indefinite, |
| 702 | ret = asn1_check_tag(&plen, NULL, NULL, &inf, &cst, &p, inlen, tag, | 706 | &constructed, tag_number, tag_class, optional); |
| 703 | aclass, opt); | 707 | if (tag_ret == -1) { |
| 704 | if (!ret) { | 708 | ret = -1; |
| 709 | goto err; | ||
| 710 | } | ||
| 711 | if (tag_ret != 1) { | ||
| 705 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 712 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 706 | return 0; | 713 | goto err; |
| 707 | } else if (ret == -1) | 714 | } |
| 708 | return -1; | 715 | |
| 709 | ret = 0; | 716 | /* SEQUENCE and SET must be constructed. */ |
| 710 | /* SEQUENCE, SET and "OTHER" are left in encoded form */ | 717 | if ((utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET) && !constructed) { |
| 711 | if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || | 718 | ASN1error(ASN1_R_TYPE_NOT_CONSTRUCTED); |
| 712 | (utype == V_ASN1_OTHER)) { | 719 | goto err; |
| 713 | if (utype != V_ASN1_OTHER && !cst) { | 720 | } |
| 714 | /* SEQUENCE and SET must be constructed */ | ||
| 715 | ASN1error(ASN1_R_TYPE_NOT_CONSTRUCTED); | ||
| 716 | return 0; | ||
| 717 | } | ||
| 718 | 721 | ||
| 719 | content = *in; | 722 | /* SEQUENCE, SET and "OTHER" are left in encoded form. */ |
| 720 | if (plen < 0) | 723 | if (utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET || |
| 724 | utype == V_ASN1_OTHER) { | ||
| 725 | if (!asn1_find_end(&cbs_object, length, indefinite)) | ||
| 721 | goto err; | 726 | goto err; |
| 722 | CBS_init(&cbs, p, plen); | 727 | if (!CBS_get_bytes(&cbs_initial, &cbs_content, |
| 723 | if (!asn1_find_end(&cbs, plen, inf)) | 728 | CBS_offset(&cbs_object))) |
| 724 | goto err; | 729 | goto err; |
| 725 | p = CBS_data(&cbs); | 730 | } else if (constructed) { |
| 726 | len = p - content; | ||
| 727 | } else if (cst) { | ||
| 728 | /* | 731 | /* |
| 729 | * Should really check the internal tags are correct but | 732 | * Should really check the internal tags are correct but |
| 730 | * some things may get this wrong. The relevant specs | 733 | * some things may get this wrong. The relevant specs |
| @@ -734,34 +737,24 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, | |||
| 734 | */ | 737 | */ |
| 735 | if (!CBB_init(&cbb, 0)) | 738 | if (!CBB_init(&cbb, 0)) |
| 736 | goto err; | 739 | goto err; |
| 737 | if (plen < 0) | 740 | if (!asn1_collect(&cbb, &cbs_object, indefinite, -1, |
| 741 | V_ASN1_UNIVERSAL, 0)) | ||
| 738 | goto err; | 742 | goto err; |
| 739 | CBS_init(&cbs, p, plen); | ||
| 740 | if (!asn1_collect(&cbb, &cbs, inf, -1, V_ASN1_UNIVERSAL, 0)) | ||
| 741 | goto err; | ||
| 742 | p = CBS_data(&cbs); | ||
| 743 | if (!CBB_finish(&cbb, &data, &data_len)) | 743 | if (!CBB_finish(&cbb, &data, &data_len)) |
| 744 | goto err; | 744 | goto err; |
| 745 | 745 | ||
| 746 | if (data_len > LONG_MAX) | 746 | CBS_init(&cbs_content, data, data_len); |
| 747 | goto err; | ||
| 748 | |||
| 749 | content = data; | ||
| 750 | len = data_len; | ||
| 751 | } else { | 747 | } else { |
| 752 | content = p; | 748 | if (!CBS_get_bytes(&cbs_object, &cbs_content, length)) |
| 753 | len = plen; | 749 | goto err; |
| 754 | p += plen; | ||
| 755 | } | 750 | } |
| 756 | 751 | ||
| 757 | /* We now have content length and type: translate into a structure */ | 752 | if (!asn1_ex_c2i(pval, &cbs_content, utype, it)) |
| 758 | if (len < 0) | ||
| 759 | goto err; | 753 | goto err; |
| 760 | CBS_init(&cbs, content, len); | 754 | |
| 761 | if (!asn1_ex_c2i(pval, &cbs, utype, it)) | 755 | if (!CBS_skip(cbs, CBS_offset(&cbs_object))) |
| 762 | goto err; | 756 | goto err; |
| 763 | 757 | ||
| 764 | *in = p; | ||
| 765 | ret = 1; | 758 | ret = 1; |
| 766 | 759 | ||
| 767 | err: | 760 | err: |
| @@ -772,6 +765,27 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, | |||
| 772 | } | 765 | } |
| 773 | 766 | ||
| 774 | static int | 767 | static int |
| 768 | asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, | ||
| 769 | const ASN1_ITEM *it, int tag_number, int tag_class, char optional) | ||
| 770 | { | ||
| 771 | CBS cbs; | ||
| 772 | int ret; | ||
| 773 | |||
| 774 | if (inlen < 0) | ||
| 775 | return 0; | ||
| 776 | |||
| 777 | CBS_init(&cbs, *in, inlen); | ||
| 778 | |||
| 779 | ret = asn1_d2i_ex_primitive_cbs(pval, &cbs, it, tag_number, tag_class, | ||
| 780 | optional); | ||
| 781 | |||
| 782 | if (ret == 1) | ||
| 783 | *in = CBS_data(&cbs); | ||
| 784 | |||
| 785 | return ret; | ||
| 786 | } | ||
| 787 | |||
| 788 | static int | ||
| 775 | asn1_ex_c2i_primitive(ASN1_VALUE **pval, CBS *content, int utype, const ASN1_ITEM *it) | 789 | asn1_ex_c2i_primitive(ASN1_VALUE **pval, CBS *content, int utype, const ASN1_ITEM *it) |
| 776 | { | 790 | { |
| 777 | ASN1_STRING *stmp; | 791 | ASN1_STRING *stmp; |
