diff options
-rw-r--r-- | src/lib/libcrypto/asn1/asn1_lib.c | 6 | ||||
-rw-r--r-- | src/lib/libcrypto/asn1/asn1_locl.h | 6 | ||||
-rw-r--r-- | src/lib/libcrypto/asn1/tasn_dec.c | 164 |
3 files changed, 113 insertions, 63 deletions
diff --git a/src/lib/libcrypto/asn1/asn1_lib.c b/src/lib/libcrypto/asn1/asn1_lib.c index 6a29c327fe..97ce6caeef 100644 --- a/src/lib/libcrypto/asn1/asn1_lib.c +++ b/src/lib/libcrypto/asn1/asn1_lib.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: asn1_lib.c,v 1.52 2022/03/26 14:47:58 jsing Exp $ */ | 1 | /* $OpenBSD: asn1_lib.c,v 1.53 2022/04/28 18:30:57 jsing Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2021 Joel Sing <jsing@openbsd.org> | 3 | * Copyright (c) 2021 Joel Sing <jsing@openbsd.org> |
4 | * | 4 | * |
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | #include "bytestring.h" | 21 | #include "bytestring.h" |
22 | 22 | ||
23 | static int | 23 | int |
24 | asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class, | 24 | asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class, |
25 | int *out_constructed, uint32_t *out_tag_number) | 25 | int *out_constructed, uint32_t *out_tag_number) |
26 | { | 26 | { |
@@ -76,7 +76,7 @@ asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class, | |||
76 | return 1; | 76 | return 1; |
77 | } | 77 | } |
78 | 78 | ||
79 | static int | 79 | int |
80 | asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite, | 80 | asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite, |
81 | uint32_t *out_length) | 81 | uint32_t *out_length) |
82 | { | 82 | { |
diff --git a/src/lib/libcrypto/asn1/asn1_locl.h b/src/lib/libcrypto/asn1/asn1_locl.h index 4d4c7a348d..86907aa8f0 100644 --- a/src/lib/libcrypto/asn1/asn1_locl.h +++ b/src/lib/libcrypto/asn1/asn1_locl.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: asn1_locl.h,v 1.27 2022/04/27 17:56:13 jsing Exp $ */ | 1 | /* $OpenBSD: asn1_locl.h,v 1.28 2022/04/28 18:30:57 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 2006. | 3 | * project 2006. |
4 | */ | 4 | */ |
@@ -193,6 +193,10 @@ int UTF8_putc(unsigned char *str, int len, unsigned long value); | |||
193 | 193 | ||
194 | int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); | 194 | int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); |
195 | 195 | ||
196 | int asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class, | ||
197 | int *out_constructed, uint32_t *out_tag_number); | ||
198 | int asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite, | ||
199 | uint32_t *out_length); | ||
196 | int asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_class, | 200 | int asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_class, |
197 | int *out_constructed, uint32_t *out_tag_number, int *out_indefinite, | 201 | int *out_constructed, uint32_t *out_tag_number, int *out_indefinite, |
198 | uint32_t *out_length); | 202 | uint32_t *out_length); |
diff --git a/src/lib/libcrypto/asn1/tasn_dec.c b/src/lib/libcrypto/asn1/tasn_dec.c index b88c5f2bc1..8b02c13e6b 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.53 2022/04/27 17:56:13 jsing Exp $ */ | 1 | /* $OpenBSD: tasn_dec.c,v 1.54 2022/04/28 18:30:57 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 | */ |
@@ -81,10 +81,6 @@ static int asn1_find_end(const unsigned char **in, long len, char inf); | |||
81 | static int asn1_collect(CBB *cbb, const unsigned char **in, long len, | 81 | static int asn1_collect(CBB *cbb, const unsigned char **in, long len, |
82 | char inf, int tag, int aclass, int depth); | 82 | char inf, int tag, int aclass, int depth); |
83 | 83 | ||
84 | static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, | ||
85 | char *inf, char *cst, const unsigned char **in, long len, int exptag, | ||
86 | int expclass, char opt); | ||
87 | |||
88 | static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, | 84 | static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, |
89 | long len, const ASN1_ITEM *it, int tag, int aclass, char opt, int depth); | 85 | long len, const ASN1_ITEM *it, int tag, int aclass, char opt, int depth); |
90 | static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, | 86 | static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, |
@@ -96,6 +92,13 @@ static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, | |||
96 | static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, | 92 | static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, |
97 | const ASN1_ITEM *it); | 93 | const ASN1_ITEM *it); |
98 | 94 | ||
95 | static int asn1_check_tag_cbs(CBS *cbs, long *out_len, int *out_tag, | ||
96 | uint8_t *out_class, char *out_indefinite, char *out_constructed, | ||
97 | int expected_tag, int expected_class, char optional); | ||
98 | static int asn1_check_tag(long *out_len, int *out_tag, uint8_t *out_class, | ||
99 | char *out_indefinite, char *out_constructed, const unsigned char **in, | ||
100 | long len, int expected_tag, int expected_class, char optional); | ||
101 | |||
99 | ASN1_VALUE * | 102 | ASN1_VALUE * |
100 | ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | 103 | ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, |
101 | const ASN1_ITEM *it) | 104 | const ASN1_ITEM *it) |
@@ -187,8 +190,8 @@ asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | |||
187 | 190 | ||
188 | p = *in; | 191 | p = *in; |
189 | /* Just read in tag and class */ | 192 | /* Just read in tag and class */ |
190 | ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, | 193 | ret = asn1_check_tag(NULL, &otag, &oclass, NULL, NULL, &p, len, |
191 | &p, len, -1, 0, 1); | 194 | -1, 0, 1); |
192 | if (!ret) { | 195 | if (!ret) { |
193 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 196 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
194 | goto err; | 197 | goto err; |
@@ -295,8 +298,8 @@ asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, | |||
295 | aclass = V_ASN1_UNIVERSAL; | 298 | aclass = V_ASN1_UNIVERSAL; |
296 | } | 299 | } |
297 | /* Get SEQUENCE length and update len, p */ | 300 | /* Get SEQUENCE length and update len, p */ |
298 | ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, | 301 | ret = asn1_check_tag(&len, NULL, NULL, &seq_eoc, &cst, &p, len, |
299 | &p, len, tag, aclass, opt); | 302 | tag, aclass, opt); |
300 | if (!ret) { | 303 | if (!ret) { |
301 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 304 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
302 | goto err; | 305 | goto err; |
@@ -478,8 +481,8 @@ asn1_template_ex_d2i(ASN1_VALUE **val, const unsigned char **in, long inlen, | |||
478 | * content and where it starts: so read in EXPLICIT header to | 481 | * content and where it starts: so read in EXPLICIT header to |
479 | * get the info. | 482 | * get the info. |
480 | */ | 483 | */ |
481 | ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst, | 484 | ret = asn1_check_tag(&len, NULL, NULL, &exp_eoc, &cst, &p, |
482 | &p, inlen, tt->tag, aclass, opt); | 485 | inlen, tt->tag, aclass, opt); |
483 | q = p; | 486 | q = p; |
484 | if (!ret) { | 487 | if (!ret) { |
485 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 488 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
@@ -555,8 +558,8 @@ asn1_template_noexp_d2i(ASN1_VALUE **val, const unsigned char **in, long len, | |||
555 | sktag = V_ASN1_SEQUENCE; | 558 | sktag = V_ASN1_SEQUENCE; |
556 | } | 559 | } |
557 | /* Get the tag */ | 560 | /* Get the tag */ |
558 | ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL, | 561 | ret = asn1_check_tag(&len, NULL, NULL, &sk_eoc, NULL, &p, len, |
559 | &p, len, sktag, skaclass, opt); | 562 | sktag, skaclass, opt); |
560 | if (!ret) { | 563 | if (!ret) { |
561 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 564 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
562 | return 0; | 565 | return 0; |
@@ -680,8 +683,8 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, | |||
680 | return 0; | 683 | return 0; |
681 | } | 684 | } |
682 | p = *in; | 685 | p = *in; |
683 | ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, | 686 | ret = asn1_check_tag(NULL, &utype, &oclass, NULL, NULL, &p, |
684 | &p, inlen, -1, 0, 0); | 687 | inlen, -1, 0, 0); |
685 | if (!ret) { | 688 | if (!ret) { |
686 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 689 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
687 | return 0; | 690 | return 0; |
@@ -695,8 +698,8 @@ asn1_d2i_ex_primitive(ASN1_VALUE **pval, const unsigned char **in, long inlen, | |||
695 | } | 698 | } |
696 | p = *in; | 699 | p = *in; |
697 | /* Check header */ | 700 | /* Check header */ |
698 | ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, | 701 | ret = asn1_check_tag(&plen, NULL, NULL, &inf, &cst, &p, inlen, tag, |
699 | &p, inlen, tag, aclass, opt); | 702 | aclass, opt); |
700 | if (!ret) { | 703 | if (!ret) { |
701 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 704 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
702 | return 0; | 705 | return 0; |
@@ -938,7 +941,7 @@ asn1_find_end(const unsigned char **in, long len, char inf) | |||
938 | } | 941 | } |
939 | q = p; | 942 | q = p; |
940 | /* Just read in a header: only care about the length */ | 943 | /* Just read in a header: only care about the length */ |
941 | if (!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len, | 944 | if (!asn1_check_tag(&plen, NULL, NULL, &inf, NULL, &p, len, |
942 | -1, 0, 0)) { | 945 | -1, 0, 0)) { |
943 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 946 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
944 | return 0; | 947 | return 0; |
@@ -1001,8 +1004,8 @@ asn1_collect(CBB *cbb, const unsigned char **in, long len, char inf, | |||
1001 | break; | 1004 | break; |
1002 | } | 1005 | } |
1003 | 1006 | ||
1004 | if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, | 1007 | if (!asn1_check_tag(&plen, NULL, NULL, &ininf, &cst, &p, len, |
1005 | len, tag, aclass, 0)) { | 1008 | tag, aclass, 0)) { |
1006 | ASN1error(ERR_R_NESTED_ASN1_ERROR); | 1009 | ASN1error(ERR_R_NESTED_ASN1_ERROR); |
1007 | return 0; | 1010 | return 0; |
1008 | } | 1011 | } |
@@ -1044,56 +1047,99 @@ asn1_check_eoc(const unsigned char **in, long len) | |||
1044 | return 0; | 1047 | return 0; |
1045 | } | 1048 | } |
1046 | 1049 | ||
1047 | /* Check an ASN1 tag and length: a bit like ASN1_get_object | ||
1048 | * but it sets the length for indefinite length constructed | ||
1049 | * form, we don't know the exact length but we can set an | ||
1050 | * upper bound to the amount of data available minus the | ||
1051 | * header length just read. | ||
1052 | */ | ||
1053 | |||
1054 | static int | 1050 | static int |
1055 | asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, | 1051 | asn1_check_tag_cbs(CBS *cbs, long *out_len, int *out_tag, uint8_t *out_class, |
1056 | char *cst, const unsigned char **in, long len, int exptag, int expclass, | 1052 | char *out_indefinite, char *out_constructed, int expected_tag, |
1057 | char opt) | 1053 | int expected_class, char optional) |
1058 | { | 1054 | { |
1059 | int i; | 1055 | uint32_t tag_number, length; |
1060 | int ptag, pclass; | 1056 | int constructed, indefinite; |
1061 | long plen; | 1057 | uint8_t tag_class; |
1062 | const unsigned char *p, *q; | 1058 | |
1063 | 1059 | if (out_len != NULL) | |
1064 | p = *in; | 1060 | *out_len = 0; |
1065 | q = p; | 1061 | if (out_tag != NULL) |
1066 | 1062 | *out_tag = 0; | |
1067 | i = ASN1_get_object(&p, &plen, &ptag, &pclass, len); | 1063 | if (out_class != NULL) |
1068 | if (i & 0x80) { | 1064 | *out_class = 0; |
1065 | if (out_indefinite != NULL) | ||
1066 | *out_indefinite = 0; | ||
1067 | if (out_constructed != NULL) | ||
1068 | *out_constructed = 0; | ||
1069 | |||
1070 | if (!asn1_get_identifier_cbs(cbs, 0, &tag_class, &constructed, | ||
1071 | &tag_number)) { | ||
1069 | ASN1error(ASN1_R_BAD_OBJECT_HEADER); | 1072 | ASN1error(ASN1_R_BAD_OBJECT_HEADER); |
1070 | return 0; | 1073 | return 0; |
1071 | } | 1074 | } |
1072 | if (exptag >= 0) { | 1075 | if (expected_tag >= 0) { |
1073 | if ((exptag != ptag) || (expclass != pclass)) { | 1076 | if (expected_tag != tag_number || |
1074 | /* If type is OPTIONAL, not an error: | 1077 | expected_class != tag_class << 6) { |
1075 | * indicate missing type. | 1078 | /* Indicate missing type if this is OPTIONAL. */ |
1076 | */ | 1079 | if (optional) |
1077 | if (opt) | ||
1078 | return -1; | 1080 | return -1; |
1081 | |||
1079 | ASN1error(ASN1_R_WRONG_TAG); | 1082 | ASN1error(ASN1_R_WRONG_TAG); |
1080 | return 0; | 1083 | return 0; |
1081 | } | 1084 | } |
1082 | } | 1085 | } |
1086 | if (!asn1_get_length_cbs(cbs, 0, &indefinite, &length)) { | ||
1087 | ASN1error(ASN1_R_BAD_OBJECT_HEADER); | ||
1088 | return 0; | ||
1089 | } | ||
1083 | 1090 | ||
1084 | if (i & 1) | 1091 | /* Indefinite length can only be used with constructed encoding. */ |
1085 | plen = len - (p - q); | 1092 | if (indefinite && !constructed) { |
1086 | if (inf) | 1093 | ASN1error(ASN1_R_BAD_OBJECT_HEADER); |
1087 | *inf = i & 1; | 1094 | return 0; |
1088 | if (cst) | 1095 | } |
1089 | *cst = i & V_ASN1_CONSTRUCTED; | 1096 | |
1090 | if (olen) | 1097 | if (!indefinite && CBS_len(cbs) < length) { |
1091 | *olen = plen; | 1098 | ASN1error(ASN1_R_TOO_LONG); |
1092 | if (oclass) | 1099 | return 0; |
1093 | *oclass = pclass; | 1100 | } |
1094 | if (otag) | 1101 | |
1095 | *otag = ptag; | 1102 | if (tag_number > INT_MAX || CBS_len(cbs) > INT_MAX) { |
1103 | ASN1error(ASN1_R_TOO_LONG); | ||
1104 | return 0; | ||
1105 | } | ||
1106 | |||
1107 | if (indefinite) | ||
1108 | length = CBS_len(cbs); | ||
1109 | |||
1110 | if (out_len != NULL) | ||
1111 | *out_len = length; | ||
1112 | if (out_tag != NULL) | ||
1113 | *out_tag = tag_number; | ||
1114 | if (out_class != NULL) | ||
1115 | *out_class = tag_class << 6; | ||
1116 | if (out_indefinite != NULL && indefinite) | ||
1117 | *out_indefinite = 1 << 0; | ||
1118 | if (out_constructed != NULL && constructed) | ||
1119 | *out_constructed = 1 << 5; | ||
1096 | 1120 | ||
1097 | *in = p; | ||
1098 | return 1; | 1121 | return 1; |
1099 | } | 1122 | } |
1123 | |||
1124 | static int | ||
1125 | asn1_check_tag(long *out_len, int *out_tag, unsigned char *out_class, | ||
1126 | char *out_indefinite, char *out_constructed, const unsigned char **in, | ||
1127 | long len, int expected_tag, int expected_class, char optional) | ||
1128 | { | ||
1129 | CBS cbs; | ||
1130 | int ret; | ||
1131 | |||
1132 | if (len < 0) | ||
1133 | return 0; | ||
1134 | |||
1135 | CBS_init(&cbs, *in, len); | ||
1136 | |||
1137 | ret = asn1_check_tag_cbs(&cbs, out_len, out_tag, out_class, | ||
1138 | out_indefinite, out_constructed, expected_tag, expected_class, | ||
1139 | optional); | ||
1140 | |||
1141 | if (ret == 1) | ||
1142 | *in = CBS_data(&cbs); | ||
1143 | |||
1144 | return ret; | ||
1145 | } | ||