summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2021-12-25 07:04:03 +0000
committerjsing <>2021-12-25 07:04:03 +0000
commit45bffde06d55be8341ae2ab97fd9f6d173eea785 (patch)
treedfd17445518096186f837cbf0acabb25662aebab /src
parent6142c0431dc485679ae167b6cb887a9afafb3427 (diff)
downloadopenbsd-45bffde06d55be8341ae2ab97fd9f6d173eea785.tar.gz
openbsd-45bffde06d55be8341ae2ab97fd9f6d173eea785.tar.bz2
openbsd-45bffde06d55be8341ae2ab97fd9f6d173eea785.zip
Rewrite ASN.1 identifier/length parsing in CBS.
Provide internal asn1_get_identifier_cbs() and asn1_get_length_cbs() functions that are called from asn1_get_object_cbs(). Convert the existing ASN1_get_object() function so that it calls asn1_get_object_cbs(), before mapping the result into the API that it implements. ok tb@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libcrypto/Makefile4
-rw-r--r--src/lib/libcrypto/asn1/asn1_lib.c171
-rw-r--r--src/lib/libcrypto/asn1/asn1_locl.h8
-rw-r--r--src/lib/libcrypto/asn1/asn1_old_lib.c129
4 files changed, 220 insertions, 92 deletions
diff --git a/src/lib/libcrypto/Makefile b/src/lib/libcrypto/Makefile
index 7279d5a181..cc53d8e6fe 100644
--- a/src/lib/libcrypto/Makefile
+++ b/src/lib/libcrypto/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.59 2021/12/17 11:28:05 tb Exp $ 1# $OpenBSD: Makefile,v 1.60 2021/12/25 07:04:03 jsing Exp $
2 2
3LIB= crypto 3LIB= crypto
4LIBREBUILD=y 4LIBREBUILD=y
@@ -65,7 +65,7 @@ SRCS+= n_pkey.c
65SRCS+= x_pkey.c x_exten.c bio_asn1.c bio_ndef.c asn_mime.c 65SRCS+= x_pkey.c x_exten.c bio_asn1.c bio_ndef.c asn_mime.c
66SRCS+= asn1_gen.c asn1_par.c asn1_old_lib.c asn1_err.c a_strnid.c 66SRCS+= asn1_gen.c asn1_par.c asn1_old_lib.c asn1_err.c a_strnid.c
67SRCS+= evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p8_pkey.c asn_moid.c 67SRCS+= evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p8_pkey.c asn_moid.c
68SRCS+= a_time_tm.c asn1_types.c 68SRCS+= a_time_tm.c asn1_types.c asn1_lib.c
69 69
70# bf/ 70# bf/
71SRCS+= bf_skey.c bf_ecb.c bf_cfb64.c bf_ofb64.c 71SRCS+= bf_skey.c bf_ecb.c bf_cfb64.c bf_ofb64.c
diff --git a/src/lib/libcrypto/asn1/asn1_lib.c b/src/lib/libcrypto/asn1/asn1_lib.c
new file mode 100644
index 0000000000..542a72f6f1
--- /dev/null
+++ b/src/lib/libcrypto/asn1/asn1_lib.c
@@ -0,0 +1,171 @@
1/* $OpenBSD: asn1_lib.c,v 1.51 2021/12/25 07:04:03 jsing Exp $ */
2/*
3 * Copyright (c) 2021 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <limits.h>
19
20#include "bytestring.h"
21
22static int
23asn1_get_identifier_cbs(CBS *cbs, int der_mode, uint8_t *out_class,
24 int *out_constructed, uint32_t *out_tag_number)
25{
26 uint8_t tag_class, tag_val;
27 int tag_constructed;
28 uint32_t tag_number;
29
30 /*
31 * Decode ASN.1 identifier octets - see ITU-T X.690 section 8.1.2.
32 */
33
34 *out_class = 0;
35 *out_constructed = 0;
36 *out_tag_number = 0;
37
38 if (!CBS_get_u8(cbs, &tag_val))
39 return 0;
40
41 /*
42 * ASN.1 tag class, encoding (primitive or constructed) and tag number
43 * are encoded in one or more identifier octets - the first octet
44 * contains the 2 bit tag class, the 1 bit encoding type and 5 bits
45 * of tag number.
46 *
47 * For tag numbers larger than 30 (0x1e) the 5 bit tag number in the
48 * first octet is set to all ones (0x1f) - the tag number is then
49 * encoded in subsequent octets - each of which have a one bit
50 * continuation flag and 7 bits of tag number in big-endian form.
51 * The encoding should not contain leading zeros but can for BER.
52 */
53 tag_class = (tag_val >> 6) & 0x3;
54 tag_constructed = (tag_val >> 5) & 0x1;
55 tag_number = tag_val & 0x1f;
56
57 /* Long form. */
58 if (tag_number == 0x1f) {
59 tag_number = 0;
60 do {
61 if (!CBS_get_u8(cbs, &tag_val))
62 return 0;
63 if (der_mode && tag_number == 0 && tag_val == 0x80)
64 return 0;
65 if (tag_number > (UINT32_MAX >> 7))
66 return 0;
67 tag_number = tag_number << 7 | (tag_val & 0x7f);
68 } while ((tag_val & 0x80) != 0);
69 }
70
71 *out_class = tag_class;
72 *out_constructed = tag_constructed;
73 *out_tag_number = tag_number;
74
75 return 1;
76}
77
78static int
79asn1_get_length_cbs(CBS *cbs, int der_mode, int *out_indefinite,
80 uint32_t *out_length)
81{
82 uint8_t len_bytes;
83 uint32_t length;
84 uint8_t val;
85
86 /*
87 * Decode ASN.1 length octets - see ITU-T X.690 section 8.1.3.
88 */
89
90 *out_length = 0;
91 *out_indefinite = 0;
92
93 if (!CBS_get_u8(cbs, &val))
94 return 0;
95
96 /*
97 * Short form - length is encoded in the lower 7 bits of a single byte.
98 */
99 if (val < 0x80) {
100 *out_length = val;
101 return 1;
102 }
103
104 /*
105 * Indefinite length - content continues until an End of Content (EOC)
106 * marker is reached. Must be used with constructed encoding.
107 */
108 if (val == 0x80) {
109 *out_indefinite = 1;
110 return 1;
111 }
112
113 /*
114 * Long form - the lower 7 bits of the first byte specifies the number
115 * of bytes used to encode the length, the following bytes specify the
116 * length in big-endian form. The encoding should not contain leading
117 * zeros but can for BER. A length value of 0x7f is invalid.
118 */
119 if ((len_bytes = val & 0x7f) == 0x7f)
120 return 0;
121
122 length = 0;
123
124 while (len_bytes-- > 0) {
125 if (!CBS_get_u8(cbs, &val))
126 return 0;
127 if (der_mode && length == 0 && val == 0)
128 return 0;
129 if (length > (UINT32_MAX >> 8))
130 return 0;
131 length = (length << 8) | val;
132 }
133
134 *out_length = length;
135
136 return 1;
137}
138
139int
140asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_tag_class,
141 int *out_constructed, uint32_t *out_tag_number, int *out_indefinite,
142 uint32_t *out_length)
143{
144 int constructed, indefinite;
145 uint32_t tag_number, length;
146 uint8_t tag_class;
147
148 *out_tag_class = 0;
149 *out_constructed = 0;
150 *out_tag_number = 0;
151 *out_indefinite = 0;
152 *out_length = 0;
153
154 if (!asn1_get_identifier_cbs(cbs, der_mode, &tag_class, &constructed,
155 &tag_number))
156 return 0;
157 if (!asn1_get_length_cbs(cbs, der_mode, &indefinite, &length))
158 return 0;
159
160 /* Indefinite length can only be used with constructed encoding. */
161 if (indefinite && !constructed)
162 return 0;
163
164 *out_tag_class = tag_class;
165 *out_constructed = constructed;
166 *out_tag_number = tag_number;
167 *out_indefinite = indefinite;
168 *out_length = length;
169
170 return 1;
171}
diff --git a/src/lib/libcrypto/asn1/asn1_locl.h b/src/lib/libcrypto/asn1/asn1_locl.h
index f7731ec5dd..851c6e3400 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.13 2021/12/14 17:35:21 jsing Exp $ */ 1/* $OpenBSD: asn1_locl.h,v 1.14 2021/12/25 07:04:03 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 */
@@ -56,6 +56,8 @@
56 * 56 *
57 */ 57 */
58 58
59#include "bytestring.h"
60
59__BEGIN_HIDDEN_DECLS 61__BEGIN_HIDDEN_DECLS
60 62
61/* Internal ASN1 structures and functions: not for application use */ 63/* Internal ASN1 structures and functions: not for application use */
@@ -155,6 +157,10 @@ struct x509_crl_method_st {
155int UTF8_getc(const unsigned char *str, int len, unsigned long *val); 157int UTF8_getc(const unsigned char *str, int len, unsigned long *val);
156int UTF8_putc(unsigned char *str, int len, unsigned long value); 158int UTF8_putc(unsigned char *str, int len, unsigned long value);
157 159
160int asn1_get_object_cbs(CBS *cbs, int der_mode, uint8_t *out_class,
161 int *out_constructed, uint32_t *out_tag_number, int *out_indefinite,
162 uint32_t *out_length);
163
158int asn1_tag2charwidth(int tag); 164int asn1_tag2charwidth(int tag);
159 165
160__END_HIDDEN_DECLS 166__END_HIDDEN_DECLS
diff --git a/src/lib/libcrypto/asn1/asn1_old_lib.c b/src/lib/libcrypto/asn1/asn1_old_lib.c
index cc9a48f74c..958c15b30c 100644
--- a/src/lib/libcrypto/asn1/asn1_old_lib.c
+++ b/src/lib/libcrypto/asn1/asn1_old_lib.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: asn1_old_lib.c,v 1.1 2021/12/15 18:12:10 jsing Exp $ */ 1/* $OpenBSD: asn1_old_lib.c,v 1.2 2021/12/25 07:04:03 jsing Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -63,7 +63,8 @@
63#include <openssl/asn1.h> 63#include <openssl/asn1.h>
64#include <openssl/err.h> 64#include <openssl/err.h>
65 65
66static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, int max); 66#include "asn1_locl.h"
67
67static void asn1_put_length(unsigned char **pp, int length); 68static void asn1_put_length(unsigned char **pp, int length);
68 69
69static int 70static int
@@ -96,101 +97,51 @@ int
96ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, 97ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
97 int *pclass, long omax) 98 int *pclass, long omax)
98{ 99{
99 int i, ret; 100 int constructed, indefinite;
100 long l; 101 uint32_t tag_number, length;
101 const unsigned char *p = *pp; 102 uint8_t tag_class;
102 int tag, xclass, inf; 103 CBS cbs;
103 long max = omax; 104 int ret = 0;
104 105
105 if (!max) 106 *pclass = 0;
106 goto err; 107 *ptag = 0;
107 ret = (*p & V_ASN1_CONSTRUCTED); 108 *plength = 0;
108 xclass = (*p & V_ASN1_PRIVATE); 109
109 i = *p & V_ASN1_PRIMITIVE_TAG; 110 CBS_init(&cbs, *pp, omax);
110 if (i == V_ASN1_PRIMITIVE_TAG) { /* high-tag */ 111
111 p++; 112 if (!asn1_get_object_cbs(&cbs, 0, &tag_class, &constructed, &tag_number,
112 if (--max == 0) 113 &indefinite, &length)) {
113 goto err; 114 ASN1error(ASN1_R_HEADER_TOO_LONG);
114 l = 0; 115 return 0x80;
115 while (*p & 0x80) {
116 l <<= 7L;
117 l |= *(p++) & 0x7f;
118 if (--max == 0)
119 goto err;
120 if (l > (INT_MAX >> 7L))
121 goto err;
122 }
123 l <<= 7L;
124 l |= *(p++) & 0x7f;
125 tag = (int)l;
126 if (--max == 0)
127 goto err;
128 } else {
129 tag = i;
130 p++;
131 if (--max == 0)
132 goto err;
133 } 116 }
134 *ptag = tag;
135 *pclass = xclass;
136 if (!asn1_get_length(&p, &inf, plength, (int)max))
137 goto err;
138 117
139 if (inf && !(ret & V_ASN1_CONSTRUCTED)) 118 if (tag_number > INT_MAX) {
140 goto err; 119 ASN1error(ASN1_R_HEADER_TOO_LONG);
120 return 0x80;
121 }
141 122
142 if (*plength > (omax - (p - *pp))) { 123 /*
124 * API insanity ahead... in this case we add an error to the stack and
125 * signal an error by setting the 8th bit in the return value... but we
126 * still provide all of the decoded data.
127 */
128 if (length > CBS_len(&cbs)) {
143 ASN1error(ASN1_R_TOO_LONG); 129 ASN1error(ASN1_R_TOO_LONG);
144 /* Set this so that even if things are not long enough 130 ret = 0x80;
145 * the values are set correctly */
146 ret |= 0x80;
147 } 131 }
148 *pp = p;
149 return (ret | inf);
150 132
151err: 133 *pclass = tag_class << 6;
152 ASN1error(ASN1_R_HEADER_TOO_LONG); 134 *ptag = tag_number;
153 return (0x80); 135 *plength = length;
154}
155 136
156static int 137 *pp = CBS_data(&cbs);
157asn1_get_length(const unsigned char **pp, int *inf, long *rl, int max)
158{
159 const unsigned char *p = *pp;
160 unsigned long ret = 0;
161 unsigned int i;
162 138
163 if (max-- < 1) 139 if (constructed)
164 return (0); 140 ret |= 1 << 5;
165 if (*p == 0x80) { 141 if (indefinite)
166 *inf = 1; 142 ret |= 1;
167 ret = 0; 143
168 p++; 144 return ret;
169 } else {
170 *inf = 0;
171 i = *p & 0x7f;
172 if (*(p++) & 0x80) {
173 if (max < (int)i)
174 return (0);
175 /* skip leading zeroes */
176 while (i && *p == 0) {
177 p++;
178 i--;
179 }
180 if (i > sizeof(long))
181 return 0;
182 while (i-- > 0) {
183 ret <<= 8L;
184 ret |= *(p++);
185 }
186 } else
187 ret = i;
188 }
189 if (ret > LONG_MAX)
190 return 0;
191 *pp = p;
192 *rl = (long)ret;
193 return (1);
194} 145}
195 146
196/* class 0 is constructed 147/* class 0 is constructed