diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 157 |
1 files changed, 80 insertions, 77 deletions
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index 7e416719e0..0131e3c27c 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.56 2022/05/04 10:53:26 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.57 2022/05/04 10:57:48 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 | */ |
| @@ -76,10 +76,11 @@ | |||
| 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(const unsigned char **in, long len); |
| 79 | static int asn1_find_end(const unsigned char **in, long len, char inf); | 79 | static int asn1_check_eoc_cbs(CBS *cbs); |
| 80 | static int asn1_find_end(CBS *cbs, size_t length, char indefinite); | ||
| 80 | 81 | ||
| 81 | static int asn1_collect(CBB *cbb, const unsigned char **in, long len, | 82 | static int asn1_collect(CBB *cbb, CBS *cbs, char indefinite, int expected_tag, |
| 82 | char inf, int tag, int aclass, int depth); | 83 | int expected_class, int depth); |
| 83 | 84 | ||
| 84 | static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, | 85 | static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, |
| 85 | long len, const ASN1_ITEM *it, int tag, int aclass, char opt, int depth); | 86 | long len, const ASN1_ITEM *it, int tag, int aclass, char opt, int depth); |
| @@ -716,8 +717,12 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, | |||
| 716 | } | 717 | } |
| 717 | 718 | ||
| 718 | content = *in; | 719 | content = *in; |
| 719 | if (!asn1_find_end(&p, plen, inf)) | 720 | if (plen < 0) |
| 720 | goto err; | 721 | goto err; |
| 722 | CBS_init(&cbs, p, plen); | ||
| 723 | if (!asn1_find_end(&cbs, plen, inf)) | ||
| 724 | goto err; | ||
| 725 | p = CBS_data(&cbs); | ||
| 721 | len = p - content; | 726 | len = p - content; |
| 722 | } else if (cst) { | 727 | } else if (cst) { |
| 723 | /* | 728 | /* |
| @@ -729,8 +734,12 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, | |||
| 729 | */ | 734 | */ |
| 730 | if (!CBB_init(&cbb, 0)) | 735 | if (!CBB_init(&cbb, 0)) |
| 731 | goto err; | 736 | goto err; |
| 732 | if (!asn1_collect(&cbb, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) | 737 | if (plen < 0) |
| 738 | goto err; | ||
| 739 | CBS_init(&cbs, p, plen); | ||
| 740 | if (!asn1_collect(&cbb, &cbs, inf, -1, V_ASN1_UNIVERSAL, 0)) | ||
| 733 | goto err; | 741 | goto err; |
| 742 | p = CBS_data(&cbs); | ||
| 734 | if (!CBB_finish(&cbb, &data, &data_len)) | 743 | if (!CBB_finish(&cbb, &data, &data_len)) |
| 735 | goto err; | 744 | goto err; |
| 736 | 745 | ||
| @@ -901,63 +910,48 @@ asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, const ASN1_ITEM *it) | |||
| 901 | return ret; | 910 | return ret; |
| 902 | } | 911 | } |
| 903 | 912 | ||
| 904 | /* This function finds the end of an ASN1 structure when passed its maximum | 913 | /* Find the end of an ASN.1 object. */ |
| 905 | * length, whether it is indefinite length and a pointer to the content. | ||
| 906 | * This is more efficient than calling asn1_collect because it does not | ||
| 907 | * recurse on each indefinite length header. | ||
| 908 | */ | ||
| 909 | |||
| 910 | static int | 914 | static int |
| 911 | asn1_find_end(const unsigned char **in, long len, char inf) | 915 | asn1_find_end(CBS *cbs, size_t length, char indefinite) |
| 912 | { | 916 | { |
| 913 | int expected_eoc; | 917 | size_t eoc_count; |
| 914 | long plen; | ||
| 915 | const unsigned char *p = *in, *q; | ||
| 916 | 918 | ||
| 917 | /* If not indefinite length constructed just add length */ | 919 | if (!indefinite) { |
| 918 | if (inf == 0) { | 920 | if (!CBS_skip(cbs, length)) { |
| 919 | *in += len; | 921 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 922 | return 0; | ||
| 923 | } | ||
| 920 | return 1; | 924 | return 1; |
| 921 | } | 925 | } |
| 922 | expected_eoc = 1; | 926 | |
| 923 | /* Indefinite length constructed form. Find the end when enough EOCs | 927 | eoc_count = 1; |
| 924 | * are found. If more indefinite length constructed headers | 928 | |
| 925 | * are encountered increment the expected eoc count otherwise just | 929 | while (CBS_len(cbs) > 0) { |
| 926 | * skip to the end of the data. | 930 | if (asn1_check_eoc_cbs(cbs)) { |
| 927 | */ | 931 | if (--eoc_count == 0) |
| 928 | while (len > 0) { | ||
| 929 | if (asn1_check_eoc(&p, len)) { | ||
| 930 | expected_eoc--; | ||
| 931 | if (expected_eoc == 0) | ||
| 932 | break; | 932 | break; |
| 933 | len -= 2; | ||
| 934 | continue; | 933 | continue; |
| 935 | } | 934 | } |
| 936 | q = p; | 935 | if (!asn1_check_tag_cbs(cbs, &length, NULL, NULL, |
| 937 | /* Just read in a header: only care about the length */ | 936 | &indefinite, NULL, -1, 0, 0)) { |
| 938 | if (!asn1_check_tag(&plen, NULL, NULL, &inf, NULL, &p, len, | ||
| 939 | -1, 0, 0)) { | ||
| 940 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 937 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 941 | return 0; | 938 | return 0; |
| 942 | } | 939 | } |
| 943 | if (inf) | 940 | if (indefinite) { |
| 944 | expected_eoc++; | 941 | eoc_count++; |
| 945 | else | 942 | continue; |
| 946 | p += plen; | 943 | } |
| 947 | len -= p - q; | 944 | if (!CBS_skip(cbs, length)) |
| 945 | return 0; | ||
| 948 | } | 946 | } |
| 949 | if (expected_eoc) { | 947 | |
| 948 | if (eoc_count > 0) { | ||
| 950 | ASN1error(ASN1_R_MISSING_EOC); | 949 | ASN1error(ASN1_R_MISSING_EOC); |
| 951 | return 0; | 950 | return 0; |
| 952 | } | 951 | } |
| 953 | *in = p; | 952 | |
| 954 | return 1; | 953 | return 1; |
| 955 | } | 954 | } |
| 956 | /* This function collects the asn1 data from a constructred string | ||
| 957 | * type into a buffer. The values of 'in' and 'len' should refer | ||
| 958 | * to the contents of the constructed type and 'inf' should be set | ||
| 959 | * if it is indefinite length. | ||
| 960 | */ | ||
| 961 | 955 | ||
| 962 | #ifndef ASN1_MAX_STRING_NEST | 956 | #ifndef ASN1_MAX_STRING_NEST |
| 963 | /* This determines how many levels of recursion are permitted in ASN1 | 957 | /* This determines how many levels of recursion are permitted in ASN1 |
| @@ -968,63 +962,72 @@ asn1_find_end(const unsigned char **in, long len, char inf) | |||
| 968 | #define ASN1_MAX_STRING_NEST 5 | 962 | #define ASN1_MAX_STRING_NEST 5 |
| 969 | #endif | 963 | #endif |
| 970 | 964 | ||
| 965 | /* Collect the contents from a constructed ASN.1 object. */ | ||
| 971 | static int | 966 | static int |
| 972 | asn1_collect(CBB *cbb, const unsigned char **in, long len, char inf, | 967 | asn1_collect(CBB *cbb, CBS *cbs, char indefinite, int expected_tag, |
| 973 | int tag, int aclass, int depth) | 968 | int expected_class, int depth) |
| 974 | { | 969 | { |
| 975 | const unsigned char *p, *q; | 970 | char constructed; |
| 976 | long plen; | 971 | size_t length; |
| 977 | char cst, ininf; | 972 | CBS content; |
| 973 | int need_eoc; | ||
| 978 | 974 | ||
| 979 | if (depth > ASN1_MAX_STRING_NEST) { | 975 | if (depth > ASN1_MAX_STRING_NEST) { |
| 980 | ASN1error(ASN1_R_NESTED_ASN1_STRING); | 976 | ASN1error(ASN1_R_NESTED_ASN1_STRING); |
| 981 | return 0; | 977 | return 0; |
| 982 | } | 978 | } |
| 983 | 979 | ||
| 984 | p = *in; | 980 | need_eoc = indefinite; |
| 985 | inf &= 1; | ||
| 986 | 981 | ||
| 987 | while (len > 0) { | 982 | while (CBS_len(cbs) > 0) { |
| 988 | q = p; | 983 | if (asn1_check_eoc_cbs(cbs)) { |
| 989 | /* Check for EOC */ | 984 | if (!need_eoc) { |
| 990 | if (asn1_check_eoc(&p, len)) { | ||
| 991 | /* EOC is illegal outside indefinite length | ||
| 992 | * constructed form */ | ||
| 993 | if (!inf) { | ||
| 994 | ASN1error(ASN1_R_UNEXPECTED_EOC); | 985 | ASN1error(ASN1_R_UNEXPECTED_EOC); |
| 995 | return 0; | 986 | return 0; |
| 996 | } | 987 | } |
| 997 | inf = 0; | 988 | return 1; |
| 998 | break; | ||
| 999 | } | 989 | } |
| 1000 | 990 | if (!asn1_check_tag_cbs(cbs, &length, NULL, NULL, &indefinite, | |
| 1001 | if (!asn1_check_tag(&plen, NULL, NULL, &ininf, &cst, &p, len, | 991 | &constructed, expected_tag, expected_class, 0)) { |
| 1002 | tag, aclass, 0)) { | ||
| 1003 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 992 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
| 1004 | return 0; | 993 | return 0; |
| 1005 | } | 994 | } |
| 1006 | 995 | ||
| 1007 | /* If indefinite length constructed update max length */ | 996 | if (constructed) { |
| 1008 | if (cst) { | 997 | if (!asn1_collect(cbb, cbs, indefinite, expected_tag, |
| 1009 | if (!asn1_collect(cbb, &p, plen, ininf, tag, aclass, | 998 | expected_class, depth + 1)) |
| 1010 | depth + 1)) | ||
| 1011 | return 0; | ||
| 1012 | } else if (plen > 0) { | ||
| 1013 | if (!CBB_add_bytes(cbb, p, plen)) | ||
| 1014 | return 0; | 999 | return 0; |
| 1015 | p += plen; | 1000 | continue; |
| 1016 | } | 1001 | } |
| 1017 | len -= p - q; | 1002 | |
| 1003 | if (!CBS_get_bytes(cbs, &content, length)) { | ||
| 1004 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | ||
| 1005 | return 0; | ||
| 1006 | } | ||
| 1007 | if (!CBB_add_bytes(cbb, CBS_data(&content), CBS_len(&content))) | ||
| 1008 | return 0; | ||
| 1018 | } | 1009 | } |
| 1019 | if (inf) { | 1010 | |
| 1011 | if (need_eoc) { | ||
| 1020 | ASN1error(ASN1_R_MISSING_EOC); | 1012 | ASN1error(ASN1_R_MISSING_EOC); |
| 1021 | return 0; | 1013 | return 0; |
| 1022 | } | 1014 | } |
| 1023 | *in = p; | 1015 | |
| 1024 | return 1; | 1016 | return 1; |
| 1025 | } | 1017 | } |
| 1026 | 1018 | ||
| 1027 | /* Check for ASN1 EOC and swallow it if found */ | 1019 | static int |
| 1020 | asn1_check_eoc_cbs(CBS *cbs) | ||
| 1021 | { | ||
| 1022 | uint16_t eoc; | ||
| 1023 | |||
| 1024 | if (!CBS_peek_u16(cbs, &eoc)) | ||
| 1025 | return 0; | ||
| 1026 | if (eoc != 0) | ||
| 1027 | return 0; | ||
| 1028 | |||
| 1029 | return CBS_skip(cbs, 2); | ||
| 1030 | } | ||
| 1028 | 1031 | ||
| 1029 | static int | 1032 | static int |
| 1030 | asn1_check_eoc(const unsigned char **in, long len) | 1033 | asn1_check_eoc(const unsigned char **in, long len) |
