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 | } | ||
