summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/asn1/tasn_dec.c157
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
78static int asn1_check_eoc(const unsigned char **in, long len); 78static int asn1_check_eoc(const unsigned char **in, long len);
79static int asn1_find_end(const unsigned char **in, long len, char inf); 79static int asn1_check_eoc_cbs(CBS *cbs);
80static int asn1_find_end(CBS *cbs, size_t length, char indefinite);
80 81
81static int asn1_collect(CBB *cbb, const unsigned char **in, long len, 82static 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
84static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, 85static 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
910static int 914static int
911asn1_find_end(const unsigned char **in, long len, char inf) 915asn1_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. */
971static int 966static int
972asn1_collect(CBB *cbb, const unsigned char **in, long len, char inf, 967asn1_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 */ 1019static int
1020asn1_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
1029static int 1032static int
1030asn1_check_eoc(const unsigned char **in, long len) 1033asn1_check_eoc(const unsigned char **in, long len)