]>
Commit | Line | Data |
---|---|---|
b1322259 | 1 | /* |
3c2bdd7d | 2 | * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
365a2d99 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
5 | * this file except in compliance with the License. You can obtain a copy |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
d02b48c6 RE |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
f9082268 | 11 | #include <limits.h> |
b39fc560 | 12 | #include "internal/cryptlib.h" |
ec577822 | 13 | #include <openssl/asn1.h> |
706457b7 | 14 | #include "asn1_local.h" |
d02b48c6 | 15 | |
0f113f3e | 16 | static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, |
79c7f74d | 17 | long max); |
d02b48c6 | 18 | static void asn1_put_length(unsigned char **pp, int length); |
d02b48c6 | 19 | |
875a644a | 20 | static int _asn1_check_infinite_end(const unsigned char **p, long len) |
0f113f3e MC |
21 | { |
22 | /* | |
23 | * If there is 0 or 1 byte left, the length check should pick things up | |
24 | */ | |
da42c2a3 | 25 | if (len <= 0) { |
1f06acc0 | 26 | return 1; |
da42c2a3 DDO |
27 | } else { |
28 | if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) { | |
29 | (*p) += 2; | |
30 | return 1; | |
31 | } | |
0f113f3e | 32 | } |
1f06acc0 | 33 | return 0; |
0f113f3e | 34 | } |
d02b48c6 | 35 | |
6343829a | 36 | int ASN1_check_infinite_end(unsigned char **p, long len) |
0f113f3e MC |
37 | { |
38 | return _asn1_check_infinite_end((const unsigned char **)p, len); | |
39 | } | |
d02b48c6 | 40 | |
6343829a | 41 | int ASN1_const_check_infinite_end(const unsigned char **p, long len) |
0f113f3e MC |
42 | { |
43 | return _asn1_check_infinite_end(p, len); | |
44 | } | |
875a644a | 45 | |
6343829a | 46 | int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, |
0f113f3e MC |
47 | int *pclass, long omax) |
48 | { | |
49 | int i, ret; | |
da42c2a3 | 50 | long len; |
0f113f3e MC |
51 | const unsigned char *p = *pp; |
52 | int tag, xclass, inf; | |
53 | long max = omax; | |
54 | ||
3e73111d DDO |
55 | if (omax <= 0) { |
56 | ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL); | |
57 | return 0x80; | |
58 | } | |
0f113f3e MC |
59 | ret = (*p & V_ASN1_CONSTRUCTED); |
60 | xclass = (*p & V_ASN1_PRIVATE); | |
61 | i = *p & V_ASN1_PRIMITIVE_TAG; | |
62 | if (i == V_ASN1_PRIMITIVE_TAG) { /* high-tag */ | |
63 | p++; | |
64 | if (--max == 0) | |
65 | goto err; | |
da42c2a3 | 66 | len = 0; |
0f113f3e | 67 | while (*p & 0x80) { |
da42c2a3 DDO |
68 | len <<= 7L; |
69 | len |= *(p++) & 0x7f; | |
0f113f3e MC |
70 | if (--max == 0) |
71 | goto err; | |
da42c2a3 | 72 | if (len > (INT_MAX >> 7L)) |
0f113f3e MC |
73 | goto err; |
74 | } | |
da42c2a3 DDO |
75 | len <<= 7L; |
76 | len |= *(p++) & 0x7f; | |
77 | tag = (int)len; | |
0f113f3e MC |
78 | if (--max == 0) |
79 | goto err; | |
80 | } else { | |
81 | tag = i; | |
82 | p++; | |
83 | if (--max == 0) | |
84 | goto err; | |
85 | } | |
86 | *ptag = tag; | |
87 | *pclass = xclass; | |
79c7f74d | 88 | if (!asn1_get_length(&p, &inf, plength, max)) |
0f113f3e MC |
89 | goto err; |
90 | ||
91 | if (inf && !(ret & V_ASN1_CONSTRUCTED)) | |
92 | goto err; | |
398e99fe | 93 | |
0f113f3e | 94 | if (*plength > (omax - (p - *pp))) { |
9311d0c4 | 95 | ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG); |
0f113f3e MC |
96 | /* |
97 | * Set this so that even if things are not long enough the values are | |
98 | * set correctly | |
99 | */ | |
100 | ret |= 0x80; | |
101 | } | |
102 | *pp = p; | |
1f06acc0 | 103 | return ret | inf; |
0f113f3e | 104 | err: |
9311d0c4 | 105 | ERR_raise(ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG); |
1f06acc0 | 106 | return 0x80; |
0f113f3e MC |
107 | } |
108 | ||
a9a157e7 P |
109 | /* |
110 | * Decode a length field. | |
111 | * The short form is a single byte defining a length 0 - 127. | |
112 | * The long form is a byte 0 - 127 with the top bit set and this indicates | |
113 | * the number of following octets that contain the length. These octets | |
114 | * are stored most significant digit first. | |
115 | */ | |
0f113f3e | 116 | static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, |
79c7f74d | 117 | long max) |
0f113f3e MC |
118 | { |
119 | const unsigned char *p = *pp; | |
120 | unsigned long ret = 0; | |
a9a157e7 | 121 | int i; |
0f113f3e MC |
122 | |
123 | if (max-- < 1) | |
79c7f74d | 124 | return 0; |
0f113f3e MC |
125 | if (*p == 0x80) { |
126 | *inf = 1; | |
0f113f3e MC |
127 | p++; |
128 | } else { | |
129 | *inf = 0; | |
130 | i = *p & 0x7f; | |
a9a157e7 P |
131 | if (*p++ & 0x80) { |
132 | if (max < i + 1) | |
0f113f3e MC |
133 | return 0; |
134 | /* Skip leading zeroes */ | |
a9a157e7 | 135 | while (i > 0 && *p == 0) { |
0f113f3e MC |
136 | p++; |
137 | i--; | |
138 | } | |
a9a157e7 | 139 | if (i > (int)sizeof(long)) |
0f113f3e | 140 | return 0; |
a9a157e7 P |
141 | while (i > 0) { |
142 | ret <<= 8; | |
143 | ret |= *p++; | |
144 | i--; | |
0f113f3e | 145 | } |
a9a157e7 P |
146 | if (ret > LONG_MAX) |
147 | return 0; | |
da42c2a3 | 148 | } else { |
0f113f3e | 149 | ret = i; |
da42c2a3 | 150 | } |
0f113f3e | 151 | } |
0f113f3e MC |
152 | *pp = p; |
153 | *rl = (long)ret; | |
79c7f74d | 154 | return 1; |
0f113f3e MC |
155 | } |
156 | ||
157 | /* | |
0f077b5f | 158 | * constructed == 2 for indefinite length constructed |
0f113f3e | 159 | */ |
6343829a | 160 | void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, |
0f113f3e MC |
161 | int xclass) |
162 | { | |
163 | unsigned char *p = *pp; | |
164 | int i, ttag; | |
165 | ||
166 | i = (constructed) ? V_ASN1_CONSTRUCTED : 0; | |
167 | i |= (xclass & V_ASN1_PRIVATE); | |
da42c2a3 | 168 | if (tag < 31) { |
0f113f3e | 169 | *(p++) = i | (tag & V_ASN1_PRIMITIVE_TAG); |
da42c2a3 | 170 | } else { |
0f113f3e MC |
171 | *(p++) = i | V_ASN1_PRIMITIVE_TAG; |
172 | for (i = 0, ttag = tag; ttag > 0; i++) | |
173 | ttag >>= 7; | |
174 | ttag = i; | |
175 | while (i-- > 0) { | |
176 | p[i] = tag & 0x7f; | |
177 | if (i != (ttag - 1)) | |
178 | p[i] |= 0x80; | |
179 | tag >>= 7; | |
180 | } | |
181 | p += ttag; | |
182 | } | |
183 | if (constructed == 2) | |
184 | *(p++) = 0x80; | |
185 | else | |
186 | asn1_put_length(&p, length); | |
187 | *pp = p; | |
188 | } | |
d02b48c6 | 189 | |
230fd6b7 | 190 | int ASN1_put_eoc(unsigned char **pp) |
0f113f3e MC |
191 | { |
192 | unsigned char *p = *pp; | |
da42c2a3 | 193 | |
0f113f3e MC |
194 | *p++ = 0; |
195 | *p++ = 0; | |
196 | *pp = p; | |
197 | return 2; | |
198 | } | |
230fd6b7 | 199 | |
6b691a5c | 200 | static void asn1_put_length(unsigned char **pp, int length) |
0f113f3e MC |
201 | { |
202 | unsigned char *p = *pp; | |
da42c2a3 DDO |
203 | int i, len; |
204 | ||
205 | if (length <= 127) { | |
0f113f3e | 206 | *(p++) = (unsigned char)length; |
da42c2a3 DDO |
207 | } else { |
208 | len = length; | |
209 | for (i = 0; len > 0; i++) | |
210 | len >>= 8; | |
0f113f3e | 211 | *(p++) = i | 0x80; |
da42c2a3 | 212 | len = i; |
0f113f3e MC |
213 | while (i-- > 0) { |
214 | p[i] = length & 0xff; | |
215 | length >>= 8; | |
216 | } | |
da42c2a3 | 217 | p += len; |
0f113f3e MC |
218 | } |
219 | *pp = p; | |
220 | } | |
d02b48c6 | 221 | |
6343829a | 222 | int ASN1_object_size(int constructed, int length, int tag) |
0f113f3e | 223 | { |
e9f17097 | 224 | int ret = 1; |
da42c2a3 | 225 | |
e9f17097 DSH |
226 | if (length < 0) |
227 | return -1; | |
0f113f3e MC |
228 | if (tag >= 31) { |
229 | while (tag > 0) { | |
230 | tag >>= 7; | |
231 | ret++; | |
232 | } | |
233 | } | |
e9f17097 DSH |
234 | if (constructed == 2) { |
235 | ret += 3; | |
236 | } else { | |
237 | ret++; | |
238 | if (length > 127) { | |
239 | int tmplen = length; | |
240 | while (tmplen > 0) { | |
241 | tmplen >>= 8; | |
242 | ret++; | |
243 | } | |
0f113f3e MC |
244 | } |
245 | } | |
e9f17097 DSH |
246 | if (ret >= INT_MAX - length) |
247 | return -1; | |
248 | return ret + length; | |
0f113f3e | 249 | } |
d02b48c6 | 250 | |
18f54773 | 251 | int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str) |
0f113f3e MC |
252 | { |
253 | if (str == NULL) | |
254 | return 0; | |
255 | dst->type = str->type; | |
256 | if (!ASN1_STRING_set(dst, str->data, str->length)) | |
257 | return 0; | |
4002da0f DSH |
258 | /* Copy flags but preserve embed value */ |
259 | dst->flags &= ASN1_STRING_FLAG_EMBED; | |
260 | dst->flags |= str->flags & ~ASN1_STRING_FLAG_EMBED; | |
0f113f3e MC |
261 | return 1; |
262 | } | |
18f54773 | 263 | |
6384e46d | 264 | ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str) |
0f113f3e MC |
265 | { |
266 | ASN1_STRING *ret; | |
da42c2a3 | 267 | |
0f113f3e MC |
268 | if (!str) |
269 | return NULL; | |
270 | ret = ASN1_STRING_new(); | |
90945fa3 | 271 | if (ret == NULL) |
0f113f3e MC |
272 | return NULL; |
273 | if (!ASN1_STRING_copy(ret, str)) { | |
274 | ASN1_STRING_free(ret); | |
275 | return NULL; | |
276 | } | |
277 | return ret; | |
278 | } | |
d02b48c6 | 279 | |
96218269 | 280 | int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in) |
0f113f3e MC |
281 | { |
282 | unsigned char *c; | |
283 | const char *data = _data; | |
96218269 | 284 | size_t len; |
0f113f3e | 285 | |
96218269 | 286 | if (len_in < 0) { |
0f113f3e | 287 | if (data == NULL) |
1f06acc0 | 288 | return 0; |
96218269 P |
289 | len = strlen(data); |
290 | } else { | |
291 | len = (size_t)len_in; | |
292 | } | |
293 | /* | |
294 | * Verify that the length fits within an integer for assignment to | |
295 | * str->length below. The additional 1 is subtracted to allow for the | |
296 | * '\0' terminator even though this isn't strictly necessary. | |
297 | */ | |
298 | if (len > INT_MAX - 1) { | |
9311d0c4 | 299 | ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE); |
96218269 | 300 | return 0; |
0f113f3e | 301 | } |
96218269 | 302 | if ((size_t)str->length <= len || str->data == NULL) { |
0f113f3e | 303 | c = str->data; |
e20fc2ee MC |
304 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
305 | /* No NUL terminator in fuzzing builds */ | |
306 | str->data = OPENSSL_realloc(c, len); | |
307 | #else | |
2d29e2df | 308 | str->data = OPENSSL_realloc(c, len + 1); |
e20fc2ee | 309 | #endif |
0f113f3e | 310 | if (str->data == NULL) { |
9311d0c4 | 311 | ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
0f113f3e | 312 | str->data = c; |
1f06acc0 | 313 | return 0; |
0f113f3e MC |
314 | } |
315 | } | |
316 | str->length = len; | |
317 | if (data != NULL) { | |
318 | memcpy(str->data, data, len); | |
e20fc2ee MC |
319 | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
320 | /* | |
321 | * Add a NUL terminator. This should not be necessary - but we add it as | |
322 | * a safety precaution | |
323 | */ | |
0f113f3e | 324 | str->data[len] = '\0'; |
e20fc2ee | 325 | #endif |
0f113f3e | 326 | } |
1f06acc0 | 327 | return 1; |
0f113f3e | 328 | } |
d02b48c6 | 329 | |
6343829a | 330 | void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len) |
0f113f3e | 331 | { |
b548a1f1 | 332 | OPENSSL_free(str->data); |
0f113f3e MC |
333 | str->data = data; |
334 | str->length = len; | |
335 | } | |
399a6f0b | 336 | |
6b691a5c | 337 | ASN1_STRING *ASN1_STRING_new(void) |
0f113f3e | 338 | { |
1f06acc0 | 339 | return ASN1_STRING_type_new(V_ASN1_OCTET_STRING); |
0f113f3e | 340 | } |
d02b48c6 | 341 | |
6b691a5c | 342 | ASN1_STRING *ASN1_STRING_type_new(int type) |
0f113f3e MC |
343 | { |
344 | ASN1_STRING *ret; | |
345 | ||
64b25758 | 346 | ret = OPENSSL_zalloc(sizeof(*ret)); |
0f113f3e | 347 | if (ret == NULL) { |
9311d0c4 | 348 | ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
1f06acc0 | 349 | return NULL; |
0f113f3e | 350 | } |
0f113f3e | 351 | ret->type = type; |
1f06acc0 | 352 | return ret; |
0f113f3e | 353 | } |
d02b48c6 | 354 | |
adf7e6d1 | 355 | void ossl_asn1_string_embed_free(ASN1_STRING *a, int embed) |
0f113f3e MC |
356 | { |
357 | if (a == NULL) | |
358 | return; | |
b548a1f1 | 359 | if (!(a->flags & ASN1_STRING_FLAG_NDEF)) |
0f113f3e | 360 | OPENSSL_free(a->data); |
6215f27a | 361 | if (embed == 0) |
47c9a1b5 | 362 | OPENSSL_free(a); |
0f113f3e | 363 | } |
d02b48c6 | 364 | |
6215f27a DSH |
365 | void ASN1_STRING_free(ASN1_STRING *a) |
366 | { | |
367 | if (a == NULL) | |
368 | return; | |
adf7e6d1 | 369 | ossl_asn1_string_embed_free(a, a->flags & ASN1_STRING_FLAG_EMBED); |
6215f27a DSH |
370 | } |
371 | ||
a8ae0891 DSH |
372 | void ASN1_STRING_clear_free(ASN1_STRING *a) |
373 | { | |
0dfb9398 RS |
374 | if (a == NULL) |
375 | return; | |
376 | if (a->data && !(a->flags & ASN1_STRING_FLAG_NDEF)) | |
a8ae0891 DSH |
377 | OPENSSL_cleanse(a->data, a->length); |
378 | ASN1_STRING_free(a); | |
379 | } | |
380 | ||
6384e46d | 381 | int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) |
0f113f3e MC |
382 | { |
383 | int i; | |
384 | ||
385 | i = (a->length - b->length); | |
386 | if (i == 0) { | |
387 | i = memcmp(a->data, b->data, a->length); | |
388 | if (i == 0) | |
1f06acc0 | 389 | return a->type - b->type; |
0f113f3e | 390 | else |
1f06acc0 | 391 | return i; |
da42c2a3 | 392 | } else { |
1f06acc0 | 393 | return i; |
da42c2a3 | 394 | } |
0f113f3e | 395 | } |
d02b48c6 | 396 | |
6343829a | 397 | int ASN1_STRING_length(const ASN1_STRING *x) |
0f113f3e | 398 | { |
f422a514 | 399 | return x->length; |
0f113f3e | 400 | } |
08e9c1af | 401 | |
08e9684c | 402 | #ifndef OPENSSL_NO_DEPRECATED_3_0 |
6343829a | 403 | void ASN1_STRING_length_set(ASN1_STRING *x, int len) |
0f113f3e | 404 | { |
f422a514 | 405 | x->length = len; |
0f113f3e | 406 | } |
08e9684c | 407 | #endif |
08e9c1af | 408 | |
08275a29 | 409 | int ASN1_STRING_type(const ASN1_STRING *x) |
0f113f3e | 410 | { |
f422a514 | 411 | return x->type; |
0f113f3e MC |
412 | } |
413 | ||
17ebf85a DSH |
414 | const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x) |
415 | { | |
416 | return x->data; | |
417 | } | |
418 | ||
da42c2a3 | 419 | #ifndef OPENSSL_NO_DEPRECATED_1_1_0 |
0f113f3e MC |
420 | unsigned char *ASN1_STRING_data(ASN1_STRING *x) |
421 | { | |
f422a514 | 422 | return x->data; |
0f113f3e | 423 | } |
17ebf85a | 424 | #endif |
da42c2a3 | 425 | |
cfd854a5 | 426 | /* |max_len| excludes NUL terminator and may be 0 to indicate no restriction */ |
adf7e6d1 | 427 | char *ossl_sk_ASN1_UTF8STRING2text(STACK_OF(ASN1_UTF8STRING) *text, |
cfd854a5 | 428 | const char *sep, size_t max_len) |
da42c2a3 DDO |
429 | { |
430 | int i; | |
431 | ASN1_UTF8STRING *current; | |
432 | size_t length = 0, sep_len; | |
433 | char *result = NULL; | |
434 | char *p; | |
435 | ||
cfd854a5 DDO |
436 | if (sep == NULL) |
437 | sep = ""; | |
da42c2a3 DDO |
438 | sep_len = strlen(sep); |
439 | ||
cfd854a5 | 440 | for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) { |
da42c2a3 DDO |
441 | current = sk_ASN1_UTF8STRING_value(text, i); |
442 | if (i > 0) | |
443 | length += sep_len; | |
444 | length += ASN1_STRING_length(current); | |
cfd854a5 | 445 | if (max_len != 0 && length > max_len) |
da42c2a3 DDO |
446 | return NULL; |
447 | } | |
448 | if ((result = OPENSSL_malloc(length + 1)) == NULL) | |
449 | return NULL; | |
450 | ||
cfd854a5 DDO |
451 | p = result; |
452 | for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) { | |
da42c2a3 DDO |
453 | current = sk_ASN1_UTF8STRING_value(text, i); |
454 | length = ASN1_STRING_length(current); | |
455 | if (i > 0 && sep_len > 0) { | |
cfd854a5 | 456 | strncpy(p, sep, sep_len + 1); /* using + 1 to silence gcc warning */ |
da42c2a3 DDO |
457 | p += sep_len; |
458 | } | |
459 | strncpy(p, (const char *)ASN1_STRING_get0_data(current), length); | |
460 | p += length; | |
461 | } | |
462 | *p = '\0'; | |
463 | ||
464 | return result; | |
465 | } |