diff options
author | jsing <> | 2022-06-25 15:39:12 +0000 |
---|---|---|
committer | jsing <> | 2022-06-25 15:39:12 +0000 |
commit | 3ab5d00cdb582673304e9a788e751bb52462af01 (patch) | |
tree | 4c32a379c7481081397694e536925a512b9fe440 /src/lib/libcrypto/asn1/a_int.c | |
parent | 07a0e24fbcc811580c51bdba7ac4be5b3a8129de (diff) | |
download | openbsd-3ab5d00cdb582673304e9a788e751bb52462af01.tar.gz openbsd-3ab5d00cdb582673304e9a788e751bb52462af01.tar.bz2 openbsd-3ab5d00cdb582673304e9a788e751bb52462af01.zip |
Rewrite ASN1_INTEGER_{get,set}() using CBS/CBB
In the process, prepare to provide ASN1_INTEGER_{get,set}_{u,}int64().
ok beck@ tb@
Diffstat (limited to 'src/lib/libcrypto/asn1/a_int.c')
-rw-r--r-- | src/lib/libcrypto/asn1/a_int.c | 237 |
1 files changed, 177 insertions, 60 deletions
diff --git a/src/lib/libcrypto/asn1/a_int.c b/src/lib/libcrypto/asn1/a_int.c index 6ad0df3d1e..546713ae46 100644 --- a/src/lib/libcrypto/asn1/a_int.c +++ b/src/lib/libcrypto/asn1/a_int.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: a_int.c,v 1.40 2022/06/25 14:22:54 jsing Exp $ */ | 1 | /* $OpenBSD: a_int.c,v 1.41 2022/06/25 15:39:12 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 | * |
@@ -80,6 +80,16 @@ ASN1_INTEGER_new(void) | |||
80 | return (ASN1_INTEGER *)ASN1_item_new(&ASN1_INTEGER_it); | 80 | return (ASN1_INTEGER *)ASN1_item_new(&ASN1_INTEGER_it); |
81 | } | 81 | } |
82 | 82 | ||
83 | static void | ||
84 | asn1_aint_clear(ASN1_INTEGER *aint) | ||
85 | { | ||
86 | freezero(aint->data, aint->length); | ||
87 | |||
88 | memset(aint, 0, sizeof(*aint)); | ||
89 | |||
90 | aint->type = V_ASN1_INTEGER; | ||
91 | } | ||
92 | |||
83 | void | 93 | void |
84 | ASN1_INTEGER_free(ASN1_INTEGER *a) | 94 | ASN1_INTEGER_free(ASN1_INTEGER *a) |
85 | { | 95 | { |
@@ -117,83 +127,190 @@ ASN1_INTEGER_cmp(const ASN1_INTEGER *a, const ASN1_INTEGER *b) | |||
117 | } | 127 | } |
118 | 128 | ||
119 | int | 129 | int |
120 | ASN1_INTEGER_set(ASN1_INTEGER *a, long v) | 130 | asn1_aint_get_uint64(CBS *cbs, uint64_t *out_val) |
121 | { | 131 | { |
122 | int j, k; | 132 | uint64_t val = 0; |
123 | unsigned int i; | 133 | uint8_t u8; |
124 | unsigned char buf[sizeof(long) + 1]; | 134 | |
125 | long d; | 135 | *out_val = 0; |
126 | 136 | ||
127 | a->type = V_ASN1_INTEGER; | 137 | while (CBS_len(cbs) > 0) { |
128 | /* XXX ssl/ssl_asn1.c:i2d_SSL_SESSION() depends upon this bound vae */ | 138 | if (!CBS_get_u8(cbs, &u8)) |
129 | if (a->length < (int)(sizeof(long) + 1)) { | 139 | return 0; |
130 | free(a->data); | 140 | if (val > (UINT64_MAX >> 8)) { |
131 | a->data = calloc(1, sizeof(long) + 1); | 141 | ASN1error(ASN1_R_TOO_LARGE); |
132 | } | 142 | return 0; |
133 | if (a->data == NULL) { | 143 | } |
134 | ASN1error(ERR_R_MALLOC_FAILURE); | 144 | val = val << 8 | u8; |
135 | return (0); | ||
136 | } | 145 | } |
137 | d = v; | 146 | |
138 | if (d < 0) { | 147 | *out_val = val; |
139 | d = -d; | 148 | |
140 | a->type = V_ASN1_NEG_INTEGER; | 149 | return 1; |
150 | } | ||
151 | |||
152 | int | ||
153 | asn1_aint_set_uint64(uint64_t val, uint8_t **out_data, int *out_len) | ||
154 | { | ||
155 | uint8_t *data = NULL; | ||
156 | size_t data_len = 0; | ||
157 | int started = 0; | ||
158 | uint8_t u8; | ||
159 | CBB cbb; | ||
160 | int i; | ||
161 | int ret = 0; | ||
162 | |||
163 | if (!CBB_init(&cbb, sizeof(long))) | ||
164 | goto err; | ||
165 | |||
166 | if (out_data == NULL || out_len == NULL) | ||
167 | goto err; | ||
168 | if (*out_data != NULL || *out_len != 0) | ||
169 | goto err; | ||
170 | |||
171 | for (i = sizeof(uint64_t) - 1; i >= 0; i--) { | ||
172 | u8 = (val >> (i * 8)) & 0xff; | ||
173 | if (!started && i != 0 && u8 == 0) | ||
174 | continue; | ||
175 | if (!CBB_add_u8(&cbb, u8)) | ||
176 | goto err; | ||
177 | started = 1; | ||
141 | } | 178 | } |
142 | 179 | ||
143 | for (i = 0; i < sizeof(long); i++) { | 180 | if (!CBB_finish(&cbb, &data, &data_len)) |
144 | if (d == 0) | 181 | goto err; |
145 | break; | 182 | if (data_len > INT_MAX) |
146 | buf[i] = (int)d & 0xff; | 183 | goto err; |
147 | d >>= 8; | 184 | |
185 | *out_data = data; | ||
186 | *out_len = (int)data_len; | ||
187 | data = NULL; | ||
188 | |||
189 | ret = 1; | ||
190 | err: | ||
191 | CBB_cleanup(&cbb); | ||
192 | freezero(data, data_len); | ||
193 | |||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | int | ||
198 | asn1_aint_get_int64(CBS *cbs, int negative, int64_t *out_val) | ||
199 | { | ||
200 | uint64_t val; | ||
201 | |||
202 | if (!asn1_aint_get_uint64(cbs, &val)) | ||
203 | return 0; | ||
204 | |||
205 | if (negative) { | ||
206 | if (val > (uint64_t)INT64_MIN) { | ||
207 | ASN1error(ASN1_R_TOO_SMALL); | ||
208 | return 0; | ||
209 | } | ||
210 | *out_val = -(int64_t)val; | ||
211 | } else { | ||
212 | if (val > (uint64_t)INT64_MAX) { | ||
213 | ASN1error(ASN1_R_TOO_LARGE); | ||
214 | return 0; | ||
215 | } | ||
216 | *out_val = (int64_t)val; | ||
148 | } | 217 | } |
149 | j = 0; | 218 | |
150 | for (k = i - 1; k >= 0; k--) | 219 | return 1; |
151 | a->data[j++] = buf[k]; | ||
152 | a->length = j; | ||
153 | return (1); | ||
154 | } | 220 | } |
155 | 221 | ||
156 | /* | 222 | int |
157 | * XXX this particular API is a gibbering eidrich horror that makes it | 223 | ASN1_INTEGER_get_uint64(uint64_t *out_val, const ASN1_INTEGER *aint) |
158 | * impossible to determine valid return cases from errors.. "a bit | ||
159 | * ugly" is preserved for posterity, unfortunately this is probably | ||
160 | * unfixable without changing public API | ||
161 | */ | ||
162 | long | ||
163 | ASN1_INTEGER_get(const ASN1_INTEGER *a) | ||
164 | { | 224 | { |
165 | int neg = 0, i; | 225 | uint64_t val; |
166 | unsigned long r = 0; | 226 | CBS cbs; |
167 | 227 | ||
168 | if (a == NULL) | 228 | *out_val = 0; |
169 | return (0L); | ||
170 | i = a->type; | ||
171 | if (i == V_ASN1_NEG_INTEGER) | ||
172 | neg = 1; | ||
173 | else if (i != V_ASN1_INTEGER) | ||
174 | return -1; | ||
175 | 229 | ||
176 | if (!ASN1_INTEGER_valid(a)) | 230 | if (aint == NULL || aint->length < 0) |
177 | return -1; /* XXX best effort */ | 231 | return 0; |
178 | 232 | ||
179 | if (a->length > (int)sizeof(long)) { | 233 | if (aint->type == V_ASN1_NEG_INTEGER) { |
180 | /* hmm... a bit ugly, return all ones */ | 234 | ASN1error(ASN1_R_ILLEGAL_NEGATIVE_VALUE); |
181 | return -1; | 235 | return 0; |
182 | } | 236 | } |
183 | if (a->data == NULL) | 237 | if (aint->type != V_ASN1_INTEGER) { |
238 | ASN1error(ASN1_R_WRONG_INTEGER_TYPE); | ||
184 | return 0; | 239 | return 0; |
240 | } | ||
241 | |||
242 | CBS_init(&cbs, aint->data, aint->length); | ||
243 | |||
244 | if (!asn1_aint_get_uint64(&cbs, &val)) | ||
245 | return 0; | ||
246 | |||
247 | *out_val = val; | ||
248 | |||
249 | return 1; | ||
250 | } | ||
251 | |||
252 | int | ||
253 | ASN1_INTEGER_set_uint64(ASN1_INTEGER *aint, uint64_t val) | ||
254 | { | ||
255 | asn1_aint_clear(aint); | ||
185 | 256 | ||
186 | for (i = 0; i < a->length; i++) { | 257 | return asn1_aint_set_uint64(val, &aint->data, &aint->length); |
187 | r <<= 8; | 258 | } |
188 | r |= (unsigned char)a->data[i]; | 259 | |
260 | int | ||
261 | ASN1_INTEGER_get_int64(int64_t *out_val, const ASN1_INTEGER *aint) | ||
262 | { | ||
263 | CBS cbs; | ||
264 | |||
265 | *out_val = 0; | ||
266 | |||
267 | if (aint == NULL || aint->length < 0) | ||
268 | return 0; | ||
269 | |||
270 | if (aint->type != V_ASN1_INTEGER && | ||
271 | aint->type != V_ASN1_NEG_INTEGER) { | ||
272 | ASN1error(ASN1_R_WRONG_INTEGER_TYPE); | ||
273 | return 0; | ||
189 | } | 274 | } |
190 | 275 | ||
191 | if (r > LONG_MAX) | 276 | CBS_init(&cbs, aint->data, aint->length); |
277 | |||
278 | return asn1_aint_get_int64(&cbs, (aint->type == V_ASN1_NEG_INTEGER), | ||
279 | out_val); | ||
280 | } | ||
281 | |||
282 | int | ||
283 | ASN1_INTEGER_set_int64(ASN1_INTEGER *aint, int64_t val) | ||
284 | { | ||
285 | asn1_aint_clear(aint); | ||
286 | |||
287 | if (val < 0) { | ||
288 | aint->type = V_ASN1_NEG_INTEGER; | ||
289 | val = -val; | ||
290 | } | ||
291 | |||
292 | return asn1_aint_set_uint64((uint64_t)val, &aint->data, &aint->length); | ||
293 | } | ||
294 | |||
295 | long | ||
296 | ASN1_INTEGER_get(const ASN1_INTEGER *aint) | ||
297 | { | ||
298 | int64_t val; | ||
299 | |||
300 | if (!ASN1_INTEGER_get_int64(&val, aint)) | ||
192 | return -1; | 301 | return -1; |
302 | if (val < LONG_MIN || val > LONG_MAX) { | ||
303 | /* hmm... a bit ugly, return all ones */ | ||
304 | return -1; | ||
305 | } | ||
306 | |||
307 | return (long)val; | ||
308 | } | ||
193 | 309 | ||
194 | if (neg) | 310 | int |
195 | return -(long)r; | 311 | ASN1_INTEGER_set(ASN1_INTEGER *aint, long val) |
196 | return (long)r; | 312 | { |
313 | return ASN1_INTEGER_set_int64(aint, val); | ||
197 | } | 314 | } |
198 | 315 | ||
199 | ASN1_INTEGER * | 316 | ASN1_INTEGER * |