diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 244 |
1 files changed, 146 insertions, 98 deletions
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index 88b61a997d..234484d6b2 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.69 2022/05/17 12:23:52 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.70 2022/05/17 19:09:16 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 | */ |
| @@ -91,6 +91,8 @@ static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, | |||
| 91 | long len, const ASN1_TEMPLATE *tt, char opt, int depth); | 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, | 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); | 93 | long len, const ASN1_TEMPLATE *tt, char opt, int depth); |
| 94 | static int asn1_d2i_ex_mstring(ASN1_VALUE **pval, CBS *CBS, | ||
| 95 | const ASN1_ITEM *it, int tag_number, int tag_class, char optional); | ||
| 94 | static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, | 96 | static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, |
| 95 | const ASN1_ITEM *it, int tag_number, int tag_class, char optional); | 97 | const ASN1_ITEM *it, int tag_number, int tag_class, char optional); |
| 96 | static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, | 98 | static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, |
| @@ -399,9 +401,6 @@ asn1_item_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 399 | const ASN1_EXTERN_FUNCS *ef = it->funcs; | 401 | const ASN1_EXTERN_FUNCS *ef = it->funcs; |
| 400 | const unsigned char *p = NULL; | 402 | const unsigned char *p = NULL; |
| 401 | ASN1_TLC ctx = { 0 }; | 403 | ASN1_TLC ctx = { 0 }; |
| 402 | CBS cbs_mstring; | ||
| 403 | unsigned char oclass; | ||
| 404 | int otag; | ||
| 405 | int ret = 0; | 404 | int ret = 0; |
| 406 | 405 | ||
| 407 | if (pval == NULL) | 406 | if (pval == NULL) |
| @@ -433,39 +432,8 @@ asn1_item_ex_d2i_cbs(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 433 | tag_class, optional); | 432 | tag_class, optional); |
| 434 | 433 | ||
| 435 | case ASN1_ITYPE_MSTRING: | 434 | case ASN1_ITYPE_MSTRING: |
| 436 | /* | 435 | return asn1_d2i_ex_mstring(pval, cbs, it, tag_number, tag_class, |
| 437 | * It never makes sense for multi-strings to have implicit | 436 | optional); |
| 438 | * tagging, so if tag != -1, then this looks like an error in | ||
| 439 | * the template. | ||
| 440 | */ | ||
| 441 | if (tag_number != -1) { | ||
| 442 | ASN1error(ASN1_R_BAD_TEMPLATE); | ||
| 443 | goto err; | ||
| 444 | } | ||
| 445 | |||
| 446 | /* XXX - avoid reading the header twice for MSTRING. */ | ||
| 447 | CBS_dup(cbs, &cbs_mstring); | ||
| 448 | if (asn1_check_tag_cbs(&cbs_mstring, NULL, &otag, &oclass, | ||
| 449 | NULL, NULL, -1, 0, 1) != 1) { | ||
| 450 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 451 | goto err; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* Must be UNIVERSAL class */ | ||
| 455 | if (oclass != V_ASN1_UNIVERSAL) { | ||
| 456 | if (optional) | ||
| 457 | return -1; | ||
| 458 | ASN1error(ASN1_R_MSTRING_NOT_UNIVERSAL); | ||
| 459 | goto err; | ||
| 460 | } | ||
| 461 | /* Check tag matches bit map */ | ||
| 462 | if (!(ASN1_tag2bit(otag) & it->utype)) { | ||
| 463 | if (optional) | ||
| 464 | return -1; | ||
| 465 | ASN1error(ASN1_R_MSTRING_WRONG_TAG); | ||
| 466 | goto err; | ||
| 467 | } | ||
| 468 | return asn1_d2i_ex_primitive(pval, cbs, it, otag, 0, 0); | ||
| 469 | 437 | ||
| 470 | case ASN1_ITYPE_EXTERN: | 438 | case ASN1_ITYPE_EXTERN: |
| 471 | if (CBS_len(cbs) > LONG_MAX) | 439 | if (CBS_len(cbs) > LONG_MAX) |
| @@ -750,74 +718,35 @@ asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, | |||
| 750 | return 0; | 718 | return 0; |
| 751 | } | 719 | } |
| 752 | 720 | ||
| 721 | /* | ||
| 722 | * Decode ASN.1 content into a primitive type. There are three possible forms - | ||
| 723 | * a SEQUENCE/SET/OTHER that is stored verbatim (including the ASN.1 tag and | ||
| 724 | * length octets), constructed objects and non-constructed objects. In the | ||
| 725 | * first two cases indefinite length is permitted, which we may need to handle. | ||
| 726 | * When this function is called the *cbs should reference the start of the | ||
| 727 | * ASN.1 object (i.e. the tag/length header), while *cbs_object should | ||
| 728 | * reference the start of the object contents (i.e. after the tag/length | ||
| 729 | * header. Additionally, the *cbs_object offset should be relative to the | ||
| 730 | * ASN.1 object being parsed. On success the *cbs will point at the octet | ||
| 731 | * after the object. | ||
| 732 | */ | ||
| 753 | static int | 733 | static int |
| 754 | asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | 734 | asn1_d2i_ex_primitive_content(ASN1_VALUE **pval, CBS *cbs, CBS *cbs_object, |
| 755 | int tag_number, int tag_class, char optional) | 735 | int utype, char constructed, char indefinite, size_t length, |
| 736 | const ASN1_ITEM *it) | ||
| 756 | { | 737 | { |
| 757 | CBS cbs_any, cbs_content, cbs_object, cbs_initial; | 738 | CBS cbs_content, cbs_initial; |
| 758 | char constructed, indefinite; | ||
| 759 | uint8_t *data = NULL; | 739 | uint8_t *data = NULL; |
| 760 | size_t data_len = 0; | 740 | size_t data_len = 0; |
| 761 | int utype = it->utype; | ||
| 762 | unsigned char oclass; | ||
| 763 | size_t length; | ||
| 764 | CBB cbb; | 741 | CBB cbb; |
| 765 | int tag_ret; | ||
| 766 | int ret = 0; | 742 | int ret = 0; |
| 767 | 743 | ||
| 768 | memset(&cbb, 0, sizeof(cbb)); | 744 | memset(&cbb, 0, sizeof(cbb)); |
| 769 | 745 | ||
| 770 | CBS_dup(cbs, &cbs_initial); | 746 | CBS_dup(cbs, &cbs_initial); |
| 771 | CBS_init(&cbs_content, NULL, 0); | 747 | CBS_init(&cbs_content, NULL, 0); |
| 772 | CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs)); | ||
| 773 | |||
| 774 | if (pval == NULL) { | ||
| 775 | ASN1error(ASN1_R_ILLEGAL_NULL); | ||
| 776 | goto err; | ||
| 777 | } | ||
| 778 | |||
| 779 | if (it->itype == ASN1_ITYPE_MSTRING) { | ||
| 780 | utype = tag_number; | ||
| 781 | tag_number = -1; | ||
| 782 | } | ||
| 783 | |||
| 784 | if (utype == V_ASN1_ANY) { | ||
| 785 | /* Determine type from ASN.1 tag. */ | ||
| 786 | if (tag_number >= 0) { | ||
| 787 | ASN1error(ASN1_R_ILLEGAL_TAGGED_ANY); | ||
| 788 | goto err; | ||
| 789 | } | ||
| 790 | if (optional) { | ||
| 791 | ASN1error(ASN1_R_ILLEGAL_OPTIONAL_ANY); | ||
| 792 | goto err; | ||
| 793 | } | ||
| 794 | /* XXX - avoid reading the header twice for ANY. */ | ||
| 795 | CBS_dup(&cbs_object, &cbs_any); | ||
| 796 | tag_ret = asn1_check_tag_cbs(&cbs_any, NULL, &utype, &oclass, | ||
| 797 | NULL, NULL, -1, 0, 0); | ||
| 798 | if (tag_ret != 1) { | ||
| 799 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 800 | goto err; | ||
| 801 | } | ||
| 802 | if (oclass != V_ASN1_UNIVERSAL) | ||
| 803 | utype = V_ASN1_OTHER; | ||
| 804 | } | ||
| 805 | 748 | ||
| 806 | if (tag_number == -1) { | 749 | /* XXX - check primitive vs constructed based on utype. */ |
| 807 | tag_number = utype; | ||
| 808 | tag_class = V_ASN1_UNIVERSAL; | ||
| 809 | } | ||
| 810 | |||
| 811 | tag_ret = asn1_check_tag_cbs(&cbs_object, &length, NULL, NULL, &indefinite, | ||
| 812 | &constructed, tag_number, tag_class, optional); | ||
| 813 | if (tag_ret == -1) { | ||
| 814 | ret = -1; | ||
| 815 | goto err; | ||
| 816 | } | ||
| 817 | if (tag_ret != 1) { | ||
| 818 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 819 | goto err; | ||
| 820 | } | ||
| 821 | 750 | ||
| 822 | /* SEQUENCE and SET must be constructed. */ | 751 | /* SEQUENCE and SET must be constructed. */ |
| 823 | if ((utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET) && !constructed) { | 752 | if ((utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET) && !constructed) { |
| @@ -828,10 +757,10 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 828 | /* SEQUENCE, SET and "OTHER" are left in encoded form. */ | 757 | /* SEQUENCE, SET and "OTHER" are left in encoded form. */ |
| 829 | if (utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET || | 758 | if (utype == V_ASN1_SEQUENCE || utype == V_ASN1_SET || |
| 830 | utype == V_ASN1_OTHER) { | 759 | utype == V_ASN1_OTHER) { |
| 831 | if (!asn1_find_end(&cbs_object, length, indefinite)) | 760 | if (!asn1_find_end(cbs_object, length, indefinite)) |
| 832 | goto err; | 761 | goto err; |
| 833 | if (!CBS_get_bytes(&cbs_initial, &cbs_content, | 762 | if (!CBS_get_bytes(&cbs_initial, &cbs_content, |
| 834 | CBS_offset(&cbs_object))) | 763 | CBS_offset(cbs_object))) |
| 835 | goto err; | 764 | goto err; |
| 836 | } else if (constructed) { | 765 | } else if (constructed) { |
| 837 | /* | 766 | /* |
| @@ -843,7 +772,7 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 843 | */ | 772 | */ |
| 844 | if (!CBB_init(&cbb, 0)) | 773 | if (!CBB_init(&cbb, 0)) |
| 845 | goto err; | 774 | goto err; |
| 846 | if (!asn1_collect(&cbb, &cbs_object, indefinite, -1, | 775 | if (!asn1_collect(&cbb, cbs_object, indefinite, -1, |
| 847 | V_ASN1_UNIVERSAL, 0)) | 776 | V_ASN1_UNIVERSAL, 0)) |
| 848 | goto err; | 777 | goto err; |
| 849 | if (!CBB_finish(&cbb, &data, &data_len)) | 778 | if (!CBB_finish(&cbb, &data, &data_len)) |
| @@ -851,14 +780,14 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 851 | 780 | ||
| 852 | CBS_init(&cbs_content, data, data_len); | 781 | CBS_init(&cbs_content, data, data_len); |
| 853 | } else { | 782 | } else { |
| 854 | if (!CBS_get_bytes(&cbs_object, &cbs_content, length)) | 783 | if (!CBS_get_bytes(cbs_object, &cbs_content, length)) |
| 855 | goto err; | 784 | goto err; |
| 856 | } | 785 | } |
| 857 | 786 | ||
| 858 | if (!asn1_ex_c2i(pval, &cbs_content, utype, it)) | 787 | if (!asn1_ex_c2i(pval, &cbs_content, utype, it)) |
| 859 | goto err; | 788 | goto err; |
| 860 | 789 | ||
| 861 | if (!CBS_skip(cbs, CBS_offset(&cbs_object))) | 790 | if (!CBS_skip(cbs, CBS_offset(cbs_object))) |
| 862 | goto err; | 791 | goto err; |
| 863 | 792 | ||
| 864 | ret = 1; | 793 | ret = 1; |
| @@ -871,6 +800,125 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | |||
| 871 | } | 800 | } |
| 872 | 801 | ||
| 873 | static int | 802 | static int |
| 803 | asn1_d2i_ex_any(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | ||
| 804 | int tag_number, int tag_class, char optional) | ||
| 805 | { | ||
| 806 | char constructed, indefinite; | ||
| 807 | unsigned char object_class; | ||
| 808 | int object_type; | ||
| 809 | CBS cbs_object; | ||
| 810 | size_t length; | ||
| 811 | |||
| 812 | CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs)); | ||
| 813 | |||
| 814 | if (it->utype != V_ASN1_ANY) | ||
| 815 | return 0; | ||
| 816 | |||
| 817 | if (tag_number >= 0) { | ||
| 818 | ASN1error(ASN1_R_ILLEGAL_TAGGED_ANY); | ||
| 819 | return 0; | ||
| 820 | } | ||
| 821 | if (optional) { | ||
| 822 | ASN1error(ASN1_R_ILLEGAL_OPTIONAL_ANY); | ||
| 823 | return 0; | ||
| 824 | } | ||
| 825 | |||
| 826 | /* Determine type from ASN.1 tag. */ | ||
| 827 | if (asn1_check_tag_cbs(&cbs_object, &length, &object_type, &object_class, | ||
| 828 | &indefinite, &constructed, -1, 0, 0) != 1) { | ||
| 829 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 830 | return 0; | ||
| 831 | } | ||
| 832 | if (object_class != V_ASN1_UNIVERSAL) | ||
| 833 | object_type = V_ASN1_OTHER; | ||
| 834 | |||
| 835 | return asn1_d2i_ex_primitive_content(pval, cbs, &cbs_object, object_type, | ||
| 836 | constructed, indefinite, length, it); | ||
| 837 | } | ||
| 838 | |||
| 839 | static int | ||
| 840 | asn1_d2i_ex_mstring(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | ||
| 841 | int tag_number, int tag_class, char optional) | ||
| 842 | { | ||
| 843 | char constructed, indefinite; | ||
| 844 | unsigned char object_class; | ||
| 845 | int object_tag; | ||
| 846 | CBS cbs_object; | ||
| 847 | size_t length; | ||
| 848 | |||
| 849 | CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs)); | ||
| 850 | |||
| 851 | /* | ||
| 852 | * It never makes sense for multi-strings to have implicit tagging, so | ||
| 853 | * if tag_number != -1, then this looks like an error in the template. | ||
| 854 | */ | ||
| 855 | if (tag_number != -1) { | ||
| 856 | ASN1error(ASN1_R_BAD_TEMPLATE); | ||
| 857 | return 0; | ||
| 858 | } | ||
| 859 | |||
| 860 | if (asn1_check_tag_cbs(&cbs_object, &length, &object_tag, &object_class, | ||
| 861 | &indefinite, &constructed, -1, 0, 1) != 1) { | ||
| 862 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 863 | return 0; | ||
| 864 | } | ||
| 865 | |||
| 866 | /* Class must be UNIVERSAL. */ | ||
| 867 | if (object_class != V_ASN1_UNIVERSAL) { | ||
| 868 | if (optional) | ||
| 869 | return -1; | ||
| 870 | ASN1error(ASN1_R_MSTRING_NOT_UNIVERSAL); | ||
| 871 | return 0; | ||
| 872 | } | ||
| 873 | /* Check tag matches bit map. */ | ||
| 874 | if ((ASN1_tag2bit(object_tag) & it->utype) == 0) { | ||
| 875 | if (optional) | ||
| 876 | return -1; | ||
| 877 | ASN1error(ASN1_R_MSTRING_WRONG_TAG); | ||
| 878 | return 0; | ||
| 879 | } | ||
| 880 | |||
| 881 | return asn1_d2i_ex_primitive_content(pval, cbs, &cbs_object, | ||
| 882 | object_tag, constructed, indefinite, length, it); | ||
| 883 | } | ||
| 884 | |||
| 885 | static int | ||
| 886 | asn1_d2i_ex_primitive(ASN1_VALUE **pval, CBS *cbs, const ASN1_ITEM *it, | ||
| 887 | int tag_number, int tag_class, char optional) | ||
| 888 | { | ||
| 889 | CBS cbs_object; | ||
| 890 | char constructed, indefinite; | ||
| 891 | int utype = it->utype; | ||
| 892 | size_t length; | ||
| 893 | int ret; | ||
| 894 | |||
| 895 | CBS_init(&cbs_object, CBS_data(cbs), CBS_len(cbs)); | ||
| 896 | |||
| 897 | if (it->itype == ASN1_ITYPE_MSTRING) | ||
| 898 | return 0; | ||
| 899 | |||
| 900 | if (it->utype == V_ASN1_ANY) | ||
| 901 | return asn1_d2i_ex_any(pval, cbs, it, tag_number, tag_class, optional); | ||
| 902 | |||
| 903 | if (tag_number == -1) { | ||
| 904 | tag_number = it->utype; | ||
| 905 | tag_class = V_ASN1_UNIVERSAL; | ||
| 906 | } | ||
| 907 | |||
| 908 | ret = asn1_check_tag_cbs(&cbs_object, &length, NULL, NULL, &indefinite, | ||
| 909 | &constructed, tag_number, tag_class, optional); | ||
| 910 | if (ret == -1) | ||
| 911 | return -1; | ||
| 912 | if (ret != 1) { | ||
| 913 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 914 | return 0; | ||
| 915 | } | ||
| 916 | |||
| 917 | return asn1_d2i_ex_primitive_content(pval, cbs, &cbs_object, utype, | ||
| 918 | constructed, indefinite, length, it); | ||
| 919 | } | ||
| 920 | |||
| 921 | static int | ||
| 874 | asn1_ex_c2i_primitive(ASN1_VALUE **pval, CBS *content, int utype, const ASN1_ITEM *it) | 922 | asn1_ex_c2i_primitive(ASN1_VALUE **pval, CBS *content, int utype, const ASN1_ITEM *it) |
| 875 | { | 923 | { |
| 876 | ASN1_STRING *stmp; | 924 | ASN1_STRING *stmp; |
