summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsing <>2022-04-28 18:30:57 +0000
committerjsing <>2022-04-28 18:30:57 +0000
commit308c1defb0063d1aa0ab378d1a88c5ce12e650d9 (patch)
tree897dde441b9fb1700461ec4356623e41d0139e0a
parent7e4a5a70be4f9de72ee5cafeda9f8966ced355f5 (diff)
downloadopenbsd-308c1defb0063d1aa0ab378d1a88c5ce12e650d9.tar.gz
openbsd-308c1defb0063d1aa0ab378d1a88c5ce12e650d9.tar.bz2
openbsd-308c1defb0063d1aa0ab378d1a88c5ce12e650d9.zip
Rewrite asn1_check_tlen() using CBS.
Rather than calling asn1_get_object_cbs(), call asn1_get_identifier_cbs(), then immediately proceed with the tag number and tag class check. Only if that succeeds (or it is not required) do we call asn1_get_length_cbs(). This avoids incurring the overhead of decoding the length in the case where the tag number and tag class do not match. While here rename asn1_check_tlen() to asn1_check_tag() - while we decode the length, what we are normally checking is the tag number and tag class. Also rename the arguments for readability. For now the argument types and encoding remain unchanged. ok inoguchi@ tb@
-rw-r--r--src/lib/libcrypto/asn1/asn1_lib.c6
-rw-r--r--src/lib/libcrypto/asn1/asn1_locl.h6
-rw-r--r--src/lib/libcrypto/asn1/tasn_dec.c164
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
23static int 23int
24asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class, 24asn1_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
79static int 79int
80asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite, 80asn1_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
194int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); 194int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb);
195 195
196int asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class,
197 int *out_constructed, uint32_t *out_tag_number);
198int asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite,
199 uint32_t *out_length);
196int asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_class, 200int 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);
81static int asn1_collect(CBB *cbb, const unsigned char **in, long len, 81static 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
84static 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
88static int asn1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, 84static 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);
90static int asn1_template_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, 86static 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,
96static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype, 92static int asn1_ex_c2i(ASN1_VALUE **pval, CBS *content, int utype,
97 const ASN1_ITEM *it); 93 const ASN1_ITEM *it);
98 94
95static 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);
98static 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
99ASN1_VALUE * 102ASN1_VALUE *
100ASN1_item_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, 103ASN1_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
1054static int 1050static int
1055asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, char *inf, 1051asn1_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
1124static int
1125asn1_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}