summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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}