/src/gnutls/lib/minitasn1/parser_aux.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2000-2025 Free Software Foundation, Inc. |
3 | | * |
4 | | * This file is part of LIBTASN1. |
5 | | * |
6 | | * The LIBTASN1 library is free software; you can redistribute it |
7 | | * and/or modify it under the terms of the GNU Lesser General Public |
8 | | * License as published by the Free Software Foundation; either |
9 | | * version 2.1 of the License, or (at your option) any later version. |
10 | | * |
11 | | * This library is distributed in the hope that it will be useful, but |
12 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | | * Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public |
17 | | * License along with this library; if not, see |
18 | | * <https://www.gnu.org/licenses/>. |
19 | | */ |
20 | | |
21 | | #include <config.h> |
22 | | |
23 | | #include <limits.h> /* WORD_BIT */ |
24 | | |
25 | | #include "int.h" |
26 | | #include "parser_aux.h" |
27 | | #include "gstr.h" |
28 | | #include "structure.h" |
29 | | #include "element.h" |
30 | | #include "c-ctype.h" |
31 | | |
32 | | char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */ |
33 | | |
34 | | /* Return a hash of the N bytes of X using the method described by |
35 | | Bruno Haible in https://www.haible.de/bruno/hashfunc.html. |
36 | | Note that while many hash functions reduce their result via modulo |
37 | | to a 0..table_size-1 range, this function does not do that. |
38 | | |
39 | | This implementation has been changed from size_t -> unsigned int. */ |
40 | | |
41 | | #ifdef __clang__ |
42 | | __attribute__((no_sanitize ("integer"))) |
43 | | #endif |
44 | | _GL_ATTRIBUTE_PURE static unsigned int _asn1_hash_name (const char *x) |
45 | 2.95k | { |
46 | 2.95k | const unsigned char *s = (unsigned char *) x; |
47 | 2.95k | unsigned h = 0; |
48 | | |
49 | 37.3k | while (*s) |
50 | 34.3k | h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9))); |
51 | | |
52 | 2.95k | return h; |
53 | 2.95k | } |
54 | | |
55 | | /******************************************************/ |
56 | | /* Function : _asn1_add_static_node */ |
57 | | /* Description: creates a new NODE_ASN element and */ |
58 | | /* puts it in the list pointed by e_list. */ |
59 | | /* Parameters: */ |
60 | | /* e_list: of type list_type; must be NULL initially */ |
61 | | /* type: type of the new element (see ASN1_ETYPE_ */ |
62 | | /* and CONST_ constants). */ |
63 | | /* Return: pointer to the new element. */ |
64 | | /******************************************************/ |
65 | | asn1_node |
66 | | _asn1_add_static_node (list_type **e_list, unsigned int type) |
67 | 2.34k | { |
68 | 2.34k | list_type *p; |
69 | 2.34k | asn1_node punt; |
70 | | |
71 | 2.34k | punt = calloc (1, sizeof (struct asn1_node_st)); |
72 | 2.34k | if (punt == NULL) |
73 | 0 | return NULL; |
74 | | |
75 | 2.34k | p = malloc (sizeof (list_type)); |
76 | 2.34k | if (p == NULL) |
77 | 0 | { |
78 | 0 | free (punt); |
79 | 0 | return NULL; |
80 | 0 | } |
81 | | |
82 | 2.34k | p->node = punt; |
83 | 2.34k | p->next = *e_list; |
84 | 2.34k | *e_list = p; |
85 | | |
86 | 2.34k | punt->type = type; |
87 | | |
88 | 2.34k | return punt; |
89 | 2.34k | } |
90 | | |
91 | | static int |
92 | | _asn1_add_static_node2 (list_type **e_list, asn1_node node) |
93 | 0 | { |
94 | 0 | list_type *p; |
95 | |
|
96 | 0 | p = malloc (sizeof (list_type)); |
97 | 0 | if (p == NULL) |
98 | 0 | { |
99 | 0 | return -1; |
100 | 0 | } |
101 | | |
102 | 0 | p->node = node; |
103 | 0 | p->next = *e_list; |
104 | 0 | *e_list = p; |
105 | |
|
106 | 0 | return 0; |
107 | 0 | } |
108 | | |
109 | | /** |
110 | | * asn1_find_node: |
111 | | * @pointer: NODE_ASN element pointer. |
112 | | * @name: null terminated string with the element's name to find. |
113 | | * |
114 | | * Searches for an element called @name starting from @pointer. The |
115 | | * name is composed by different identifiers separated by dots. When |
116 | | * *@pointer has a name, the first identifier must be the name of |
117 | | * *@pointer, otherwise it must be the name of one child of *@pointer. |
118 | | * |
119 | | * Returns: the search result, or %NULL if not found. |
120 | | **/ |
121 | | asn1_node |
122 | | asn1_find_node (asn1_node_const pointer, const char *name) |
123 | 556 | { |
124 | 556 | asn1_node_const p; |
125 | 556 | char *n_end, n[ASN1_MAX_NAME_SIZE + 1]; |
126 | 556 | const char *n_start; |
127 | 556 | unsigned int nsize; |
128 | 556 | unsigned int nhash; |
129 | 556 | const struct asn1_node_array_st *numbered_children; |
130 | | |
131 | 556 | if (pointer == NULL) |
132 | 0 | return NULL; |
133 | | |
134 | 556 | if (name == NULL) |
135 | 0 | return NULL; |
136 | | |
137 | 556 | p = pointer; |
138 | 556 | n_start = name; |
139 | | |
140 | 556 | if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?') |
141 | 0 | { /* ?CURRENT */ |
142 | 0 | n_start = strchr (n_start, '.'); |
143 | 0 | if (n_start) |
144 | 0 | n_start++; |
145 | 0 | } |
146 | 556 | else if (p->name[0] != 0) |
147 | 556 | { /* has *pointer got a name ? */ |
148 | 556 | n_end = strchr (n_start, '.'); /* search the first dot */ |
149 | 556 | if (n_end) |
150 | 556 | { |
151 | 556 | nsize = n_end - n_start; |
152 | 556 | if (nsize >= sizeof (n)) |
153 | 0 | return NULL; |
154 | | |
155 | 556 | memcpy (n, n_start, nsize); |
156 | 556 | n[nsize] = 0; |
157 | 556 | n_start = n_end; |
158 | 556 | n_start++; |
159 | | |
160 | 556 | nhash = _asn1_hash_name (n); |
161 | 556 | } |
162 | 0 | else |
163 | 0 | { |
164 | 0 | _asn1_str_cpy (n, sizeof (n), n_start); |
165 | 0 | nhash = _asn1_hash_name (n); |
166 | |
|
167 | 0 | n_start = NULL; |
168 | 0 | } |
169 | | |
170 | 556 | while (p) |
171 | 556 | { |
172 | 556 | if (nhash == p->name_hash && (!strcmp (p->name, n))) |
173 | 556 | break; |
174 | 0 | else |
175 | 0 | p = p->right; |
176 | 556 | } /* while */ |
177 | | |
178 | 556 | if (p == NULL) |
179 | 0 | return NULL; |
180 | 556 | } |
181 | 0 | else |
182 | 0 | { /* *pointer doesn't have a name */ |
183 | 0 | if (n_start[0] == 0) |
184 | 0 | return (asn1_node) p; |
185 | 0 | } |
186 | | |
187 | 1.11k | while (n_start) |
188 | 556 | { /* Has the end of NAME been reached? */ |
189 | 556 | n_end = strchr (n_start, '.'); /* search the next dot */ |
190 | 556 | if (n_end) |
191 | 0 | { |
192 | 0 | nsize = n_end - n_start; |
193 | 0 | if (nsize >= sizeof (n)) |
194 | 0 | return NULL; |
195 | | |
196 | 0 | memcpy (n, n_start, nsize); |
197 | 0 | n[nsize] = 0; |
198 | 0 | n_start = n_end; |
199 | 0 | n_start++; |
200 | |
|
201 | 0 | nhash = _asn1_hash_name (n); |
202 | 0 | } |
203 | 556 | else |
204 | 556 | { |
205 | 556 | _asn1_str_cpy (n, sizeof (n), n_start); |
206 | 556 | nhash = _asn1_hash_name (n); |
207 | 556 | n_start = NULL; |
208 | 556 | } |
209 | | |
210 | 556 | if (p->down == NULL) |
211 | 0 | return NULL; |
212 | | |
213 | 556 | numbered_children = &p->numbered_children; |
214 | 556 | p = p->down; |
215 | 556 | if (p == NULL) |
216 | 0 | return NULL; |
217 | | |
218 | | /* The identifier "?LAST" indicates the last element |
219 | | in the right chain. */ |
220 | 556 | if (n[0] == '?' && n[1] == 'L') /* ?LAST */ |
221 | 0 | { |
222 | 0 | while (p->right) |
223 | 0 | p = p->right; |
224 | 0 | } |
225 | 556 | else |
226 | 556 | { /* no "?LAST" */ |
227 | 556 | if (n[0] == '?' && c_isdigit (n[1])) |
228 | 0 | { |
229 | 0 | long position = strtol (n + 1, NULL, 10); |
230 | 0 | if (position > 0 && position < LONG_MAX) |
231 | 0 | p = _asn1_node_array_get (numbered_children, position - 1); |
232 | 0 | } |
233 | 22.8k | while (p) |
234 | 22.8k | { |
235 | 22.8k | if (p->name_hash == nhash && !strcmp (p->name, n)) |
236 | 556 | break; |
237 | 22.2k | else |
238 | 22.2k | p = p->right; |
239 | 22.8k | } |
240 | 556 | } |
241 | 556 | if (p == NULL) |
242 | 0 | return NULL; |
243 | 556 | } /* while */ |
244 | | |
245 | 556 | return (asn1_node) p; |
246 | 556 | } |
247 | | |
248 | | |
249 | | /******************************************************************/ |
250 | | /* Function : _asn1_set_value */ |
251 | | /* Description: sets the field VALUE in a NODE_ASN element. The */ |
252 | | /* previous value (if exist) will be lost */ |
253 | | /* Parameters: */ |
254 | | /* node: element pointer. */ |
255 | | /* value: pointer to the value that you want to set. */ |
256 | | /* len: character number of value. */ |
257 | | /* Return: pointer to the NODE_ASN element. */ |
258 | | /******************************************************************/ |
259 | | asn1_node |
260 | | _asn1_set_value (asn1_node node, const void *value, unsigned int len) |
261 | 964 | { |
262 | 964 | if (node == NULL) |
263 | 0 | return node; |
264 | 964 | if (node->value) |
265 | 0 | { |
266 | 0 | if (node->value != node->small_value) |
267 | 0 | free (node->value); |
268 | 0 | node->value = NULL; |
269 | 0 | node->value_len = 0; |
270 | 0 | } |
271 | | |
272 | 964 | if (!len) |
273 | 0 | return node; |
274 | | |
275 | 964 | if (len < sizeof (node->small_value)) |
276 | 644 | { |
277 | 644 | node->value = node->small_value; |
278 | 644 | } |
279 | 320 | else |
280 | 320 | { |
281 | 320 | node->value = malloc (len); |
282 | 320 | if (node->value == NULL) |
283 | 0 | return NULL; |
284 | 320 | } |
285 | 964 | node->value_len = len; |
286 | | |
287 | 964 | memcpy (node->value, value, len); |
288 | 964 | return node; |
289 | 964 | } |
290 | | |
291 | | /******************************************************************/ |
292 | | /* Function : _asn1_set_value_lv */ |
293 | | /* Description: sets the field VALUE in a NODE_ASN element. The */ |
294 | | /* previous value (if exist) will be lost. The value */ |
295 | | /* given is stored as an length-value format (LV */ |
296 | | /* Parameters: */ |
297 | | /* node: element pointer. */ |
298 | | /* value: pointer to the value that you want to set. */ |
299 | | /* len: character number of value. */ |
300 | | /* Return: pointer to the NODE_ASN element. */ |
301 | | /******************************************************************/ |
302 | | asn1_node |
303 | | _asn1_set_value_lv (asn1_node node, const void *value, unsigned int len) |
304 | 0 | { |
305 | 0 | int len2; |
306 | 0 | void *temp; |
307 | |
|
308 | 0 | if (node == NULL) |
309 | 0 | return node; |
310 | | |
311 | 0 | asn1_length_der (len, NULL, &len2); |
312 | 0 | temp = malloc (len + len2); |
313 | 0 | if (temp == NULL) |
314 | 0 | return NULL; |
315 | | |
316 | 0 | asn1_octet_der (value, len, temp, &len2); |
317 | 0 | return _asn1_set_value_m (node, temp, len2); |
318 | 0 | } |
319 | | |
320 | | /* the same as _asn1_set_value except that it sets an already malloc'ed |
321 | | * value. |
322 | | */ |
323 | | asn1_node |
324 | | _asn1_set_value_m (asn1_node node, void *value, unsigned int len) |
325 | 0 | { |
326 | 0 | if (node == NULL) |
327 | 0 | return node; |
328 | | |
329 | 0 | if (node->value) |
330 | 0 | { |
331 | 0 | if (node->value != node->small_value) |
332 | 0 | free (node->value); |
333 | 0 | node->value = NULL; |
334 | 0 | node->value_len = 0; |
335 | 0 | } |
336 | |
|
337 | 0 | if (!len) |
338 | 0 | return node; |
339 | | |
340 | 0 | node->value = value; |
341 | 0 | node->value_len = len; |
342 | |
|
343 | 0 | return node; |
344 | 0 | } |
345 | | |
346 | | /******************************************************************/ |
347 | | /* Function : _asn1_append_value */ |
348 | | /* Description: appends to the field VALUE in a NODE_ASN element. */ |
349 | | /* */ |
350 | | /* Parameters: */ |
351 | | /* node: element pointer. */ |
352 | | /* value: pointer to the value that you want to be appended. */ |
353 | | /* len: character number of value. */ |
354 | | /* Return: pointer to the NODE_ASN element. */ |
355 | | /******************************************************************/ |
356 | | asn1_node |
357 | | _asn1_append_value (asn1_node node, const void *value, unsigned int len) |
358 | 0 | { |
359 | 0 | if (node == NULL) |
360 | 0 | return node; |
361 | | |
362 | 0 | if (node->value == NULL) |
363 | 0 | return _asn1_set_value (node, value, len); |
364 | | |
365 | 0 | if (len == 0) |
366 | 0 | return node; |
367 | | |
368 | 0 | if (node->value == node->small_value) |
369 | 0 | { |
370 | | /* value is in node */ |
371 | 0 | int prev_len = node->value_len; |
372 | 0 | node->value_len += len; |
373 | 0 | node->value = malloc (node->value_len); |
374 | 0 | if (node->value == NULL) |
375 | 0 | { |
376 | 0 | node->value_len = 0; |
377 | 0 | return NULL; |
378 | 0 | } |
379 | | |
380 | 0 | if (prev_len > 0) |
381 | 0 | memcpy (node->value, node->small_value, prev_len); |
382 | |
|
383 | 0 | memcpy (&node->value[prev_len], value, len); |
384 | |
|
385 | 0 | return node; |
386 | 0 | } |
387 | 0 | else /* if (node->value != NULL && node->value != node->small_value) */ |
388 | 0 | { |
389 | | /* value is allocated */ |
390 | 0 | int prev_len = node->value_len; |
391 | 0 | node->value_len += len; |
392 | |
|
393 | 0 | node->value = _asn1_realloc (node->value, node->value_len); |
394 | 0 | if (node->value == NULL) |
395 | 0 | { |
396 | 0 | node->value_len = 0; |
397 | 0 | return NULL; |
398 | 0 | } |
399 | | |
400 | 0 | memcpy (&node->value[prev_len], value, len); |
401 | |
|
402 | 0 | return node; |
403 | 0 | } |
404 | 0 | } |
405 | | |
406 | | /******************************************************************/ |
407 | | /* Function : _asn1_set_name */ |
408 | | /* Description: sets the field NAME in a NODE_ASN element. The */ |
409 | | /* previous value (if exist) will be lost */ |
410 | | /* Parameters: */ |
411 | | /* node: element pointer. */ |
412 | | /* name: a null terminated string with the name that you want */ |
413 | | /* to set. */ |
414 | | /* Return: pointer to the NODE_ASN element. */ |
415 | | /******************************************************************/ |
416 | | asn1_node |
417 | | _asn1_set_name (asn1_node node, const char *name) |
418 | 1.84k | { |
419 | 1.84k | if (node == NULL) |
420 | 0 | return node; |
421 | | |
422 | 1.84k | _asn1_str_cpy (node->name, sizeof (node->name), name ? name : ""); |
423 | 1.84k | node->name_hash = _asn1_hash_name (node->name); |
424 | | |
425 | 1.84k | return node; |
426 | 1.84k | } |
427 | | |
428 | | /******************************************************************/ |
429 | | /* Function : _asn1_cpy_name */ |
430 | | /* Description: copies the field NAME in a NODE_ASN element. */ |
431 | | /* Parameters: */ |
432 | | /* dst: a dest element pointer. */ |
433 | | /* src: a source element pointer. */ |
434 | | /* Return: pointer to the NODE_ASN element. */ |
435 | | /******************************************************************/ |
436 | | asn1_node |
437 | | _asn1_cpy_name (asn1_node dst, asn1_node_const src) |
438 | 0 | { |
439 | 0 | if (dst == NULL) |
440 | 0 | return dst; |
441 | | |
442 | 0 | if (src == NULL) |
443 | 0 | { |
444 | 0 | dst->name[0] = 0; |
445 | 0 | dst->name_hash = _asn1_hash_name (dst->name); |
446 | 0 | return dst; |
447 | 0 | } |
448 | | |
449 | 0 | _asn1_str_cpy (dst->name, sizeof (dst->name), src->name); |
450 | 0 | dst->name_hash = src->name_hash; |
451 | |
|
452 | 0 | return dst; |
453 | 0 | } |
454 | | |
455 | | /******************************************************************/ |
456 | | /* Function : _asn1_set_right */ |
457 | | /* Description: sets the field RIGHT in a NODE_ASN element. */ |
458 | | /* Parameters: */ |
459 | | /* node: element pointer. */ |
460 | | /* right: pointer to a NODE_ASN element that you want be pointed*/ |
461 | | /* by NODE. */ |
462 | | /* Return: pointer to *NODE. */ |
463 | | /******************************************************************/ |
464 | | asn1_node |
465 | | _asn1_set_right (asn1_node node, asn1_node right) |
466 | 1.46k | { |
467 | 1.46k | if (node == NULL) |
468 | 0 | return node; |
469 | 1.46k | node->right = right; |
470 | 1.46k | if (right) |
471 | 1.46k | right->left = node; |
472 | 1.46k | return node; |
473 | 1.46k | } |
474 | | |
475 | | |
476 | | /******************************************************************/ |
477 | | /* Function : _asn1_get_last_right */ |
478 | | /* Description: return the last element along the right chain. */ |
479 | | /* Parameters: */ |
480 | | /* node: starting element pointer. */ |
481 | | /* Return: pointer to the last element along the right chain. */ |
482 | | /******************************************************************/ |
483 | | asn1_node |
484 | | _asn1_get_last_right (asn1_node_const node) |
485 | 0 | { |
486 | 0 | asn1_node_const p; |
487 | |
|
488 | 0 | if (node == NULL) |
489 | 0 | return NULL; |
490 | 0 | p = node; |
491 | 0 | while (p->right) |
492 | 0 | p = p->right; |
493 | 0 | return (asn1_node) p; |
494 | 0 | } |
495 | | |
496 | | /******************************************************************/ |
497 | | /* Function : _asn1_remove_node */ |
498 | | /* Description: gets free the memory allocated for an NODE_ASN */ |
499 | | /* element (not the elements pointed by it). */ |
500 | | /* Parameters: */ |
501 | | /* node: NODE_ASN element pointer. */ |
502 | | /* flags: ASN1_DELETE_FLAG_* */ |
503 | | /******************************************************************/ |
504 | | void |
505 | | _asn1_remove_node (asn1_node node, unsigned int flags) |
506 | 0 | { |
507 | 0 | if (node == NULL) |
508 | 0 | return; |
509 | | |
510 | 0 | if (node->value != NULL) |
511 | 0 | { |
512 | 0 | if (flags & ASN1_DELETE_FLAG_ZEROIZE) |
513 | 0 | { |
514 | 0 | safe_memset (node->value, 0, node->value_len); |
515 | 0 | } |
516 | |
|
517 | 0 | if (node->value != node->small_value) |
518 | 0 | free (node->value); |
519 | 0 | } |
520 | |
|
521 | 0 | free (node->numbered_children.nodes); |
522 | 0 | free (node); |
523 | 0 | } |
524 | | |
525 | | /******************************************************************/ |
526 | | /* Function : _asn1_find_up */ |
527 | | /* Description: return the father of the NODE_ASN element. */ |
528 | | /* Parameters: */ |
529 | | /* node: NODE_ASN element pointer. */ |
530 | | /* Return: Null if not found. */ |
531 | | /******************************************************************/ |
532 | | asn1_node |
533 | | _asn1_find_up (asn1_node_const node) |
534 | 4.38k | { |
535 | 4.38k | asn1_node_const p; |
536 | | |
537 | 4.38k | if (node == NULL) |
538 | 0 | return NULL; |
539 | | |
540 | 4.38k | p = node; |
541 | | |
542 | 11.7k | while ((p->left != NULL) && (p->left->right == p)) |
543 | 7.32k | p = p->left; |
544 | | |
545 | 4.38k | return p->left; |
546 | 4.38k | } |
547 | | |
548 | | static unsigned |
549 | | _asn1_is_up (asn1_node_const up_cand, asn1_node_const down) |
550 | 0 | { |
551 | 0 | asn1_node_const d, u; |
552 | |
|
553 | 0 | if (up_cand == NULL || down == NULL) |
554 | 0 | return 0; |
555 | | |
556 | 0 | d = down; |
557 | |
|
558 | 0 | while ((u = _asn1_find_up (d)) != NULL && u != d) |
559 | 0 | { |
560 | 0 | if (u == up_cand) |
561 | 0 | return 1; |
562 | 0 | d = u; |
563 | 0 | } |
564 | | |
565 | 0 | return 0; |
566 | 0 | } |
567 | | |
568 | | /******************************************************************/ |
569 | | /* Function : _asn1_delete_node_from_list */ |
570 | | /* Description: deletes the list element given */ |
571 | | /******************************************************************/ |
572 | | void |
573 | | _asn1_delete_node_from_list (list_type *list, asn1_node node) |
574 | 0 | { |
575 | 0 | list_type *p = list; |
576 | |
|
577 | 0 | while (p) |
578 | 0 | { |
579 | 0 | if (p->node == node) |
580 | 0 | p->node = NULL; |
581 | 0 | p = p->next; |
582 | 0 | } |
583 | 0 | } |
584 | | |
585 | | /******************************************************************/ |
586 | | /* Function : _asn1_delete_list */ |
587 | | /* Description: deletes the list elements (not the elements */ |
588 | | /* pointed by them). */ |
589 | | /******************************************************************/ |
590 | | void |
591 | | _asn1_delete_list (list_type *e_list) |
592 | 8 | { |
593 | 8 | list_type *p; |
594 | | |
595 | 2.35k | while (e_list) |
596 | 2.34k | { |
597 | 2.34k | p = e_list; |
598 | 2.34k | e_list = e_list->next; |
599 | 2.34k | free (p); |
600 | 2.34k | } |
601 | 8 | } |
602 | | |
603 | | /******************************************************************/ |
604 | | /* Function : _asn1_delete_list_and nodes */ |
605 | | /* Description: deletes the list elements and the elements */ |
606 | | /* pointed by them. */ |
607 | | /******************************************************************/ |
608 | | void |
609 | | _asn1_delete_list_and_nodes (list_type *e_list) |
610 | 0 | { |
611 | 0 | list_type *p; |
612 | |
|
613 | 0 | while (e_list) |
614 | 0 | { |
615 | 0 | p = e_list; |
616 | 0 | e_list = e_list->next; |
617 | 0 | _asn1_remove_node (p->node, 0); |
618 | 0 | free (p); |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | | |
623 | | char * |
624 | | _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]) |
625 | 0 | { |
626 | 0 | uint64_t d, r; |
627 | 0 | char temp[LTOSTR_MAX_SIZE]; |
628 | 0 | int count, k, start; |
629 | 0 | uint64_t val; |
630 | |
|
631 | 0 | if (v < 0) |
632 | 0 | { |
633 | 0 | str[0] = '-'; |
634 | 0 | start = 1; |
635 | 0 | val = -((uint64_t) v); |
636 | 0 | } |
637 | 0 | else |
638 | 0 | { |
639 | 0 | val = v; |
640 | 0 | start = 0; |
641 | 0 | } |
642 | |
|
643 | 0 | count = 0; |
644 | 0 | do |
645 | 0 | { |
646 | 0 | d = val / 10; |
647 | 0 | r = val - d * 10; |
648 | 0 | temp[start + count] = '0' + (char) r; |
649 | 0 | count++; |
650 | 0 | val = d; |
651 | 0 | } |
652 | 0 | while (val && ((start + count) < LTOSTR_MAX_SIZE - 1)); |
653 | |
|
654 | 0 | for (k = 0; k < count; k++) |
655 | 0 | str[k + start] = temp[start + count - k - 1]; |
656 | 0 | str[count + start] = 0; |
657 | 0 | return str; |
658 | 0 | } |
659 | | |
660 | | |
661 | | /******************************************************************/ |
662 | | /* Function : _asn1_change_integer_value */ |
663 | | /* Description: converts into DER coding the value assign to an */ |
664 | | /* INTEGER constant. */ |
665 | | /* Parameters: */ |
666 | | /* node: root of an ASN1element. */ |
667 | | /* Return: */ |
668 | | /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ |
669 | | /* otherwise ASN1_SUCCESS */ |
670 | | /******************************************************************/ |
671 | | int |
672 | | _asn1_change_integer_value (asn1_node node) |
673 | 8 | { |
674 | 8 | asn1_node p; |
675 | 8 | unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; |
676 | 8 | unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1]; |
677 | 8 | int len; |
678 | | |
679 | 8 | if (node == NULL) |
680 | 0 | return ASN1_ELEMENT_NOT_FOUND; |
681 | | |
682 | 8 | p = node; |
683 | 2.35k | while (p) |
684 | 2.34k | { |
685 | 2.34k | if ((type_field (p->type) == ASN1_ETYPE_INTEGER) |
686 | 2.34k | && (p->type & CONST_ASSIGN)) |
687 | 0 | { |
688 | 0 | if (p->value) |
689 | 0 | { |
690 | 0 | _asn1_convert_integer (p->value, val, sizeof (val), &len); |
691 | 0 | asn1_octet_der (val, len, val2, &len); |
692 | 0 | _asn1_set_value (p, val2, len); |
693 | 0 | } |
694 | 0 | } |
695 | | |
696 | 2.34k | if (p->down) |
697 | 876 | { |
698 | 876 | p = p->down; |
699 | 876 | } |
700 | 1.47k | else |
701 | 1.47k | { |
702 | 1.47k | if (p == node) |
703 | 0 | p = NULL; |
704 | 1.47k | else if (p->right) |
705 | 800 | p = p->right; |
706 | 672 | else |
707 | 672 | { |
708 | 876 | while (1) |
709 | 876 | { |
710 | 876 | p = _asn1_find_up (p); |
711 | 876 | if (p == node) |
712 | 8 | { |
713 | 8 | p = NULL; |
714 | 8 | break; |
715 | 8 | } |
716 | 868 | if (p && p->right) |
717 | 664 | { |
718 | 664 | p = p->right; |
719 | 664 | break; |
720 | 664 | } |
721 | 868 | } |
722 | 672 | } |
723 | 1.47k | } |
724 | 2.34k | } |
725 | | |
726 | 8 | return ASN1_SUCCESS; |
727 | 8 | } |
728 | | |
729 | 0 | #define MAX_CONSTANTS 1024 |
730 | | /******************************************************************/ |
731 | | /* Function : _asn1_expand_object_id */ |
732 | | /* Description: expand the IDs of an OBJECT IDENTIFIER constant. */ |
733 | | /* Parameters: */ |
734 | | /* list: root of an object list */ |
735 | | /* node: root of an ASN1 element. */ |
736 | | /* Return: */ |
737 | | /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ |
738 | | /* otherwise ASN1_SUCCESS */ |
739 | | /******************************************************************/ |
740 | | int |
741 | | _asn1_expand_object_id (list_type **list, asn1_node node) |
742 | 8 | { |
743 | 8 | asn1_node p, p2, p3, p4, p5; |
744 | 8 | char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1]; |
745 | 8 | int move, tlen, tries; |
746 | 8 | unsigned max_constants; |
747 | | |
748 | 8 | if (node == NULL) |
749 | 0 | return ASN1_ELEMENT_NOT_FOUND; |
750 | | |
751 | 8 | _asn1_str_cpy (name_root, sizeof (name_root), node->name); |
752 | | |
753 | 8 | p = node; |
754 | 8 | move = DOWN; |
755 | 8 | tries = 0; |
756 | | |
757 | 3.22k | while (!((p == node) && (move == UP))) |
758 | 3.21k | { |
759 | 3.21k | if (move != UP) |
760 | 2.34k | { |
761 | 2.34k | if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) |
762 | 2.34k | && (p->type & CONST_ASSIGN)) |
763 | 4 | { |
764 | 4 | p2 = p->down; |
765 | 4 | if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) |
766 | 4 | { |
767 | 4 | if (p2->value && !c_isdigit (p2->value[0])) |
768 | 0 | { |
769 | 0 | _asn1_str_cpy (name2, sizeof (name2), name_root); |
770 | 0 | _asn1_str_cat (name2, sizeof (name2), "."); |
771 | 0 | _asn1_str_cat (name2, sizeof (name2), |
772 | 0 | (char *) p2->value); |
773 | 0 | p3 = asn1_find_node (node, name2); |
774 | 0 | if (!p3 || _asn1_is_up (p2, p3) || |
775 | 0 | (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) || |
776 | 0 | !(p3->type & CONST_ASSIGN)) |
777 | 0 | return ASN1_ELEMENT_NOT_FOUND; |
778 | | |
779 | 0 | _asn1_set_down (p, p2->right); |
780 | 0 | if (p2->down) |
781 | 0 | _asn1_delete_structure (*list, &p2->down, 0); |
782 | 0 | _asn1_delete_node_from_list (*list, p2); |
783 | 0 | _asn1_remove_node (p2, 0); |
784 | 0 | p2 = p; |
785 | 0 | p4 = p3->down; |
786 | 0 | max_constants = 0; |
787 | 0 | while (p4) |
788 | 0 | { |
789 | 0 | if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) |
790 | 0 | { |
791 | 0 | max_constants++; |
792 | 0 | if (max_constants == MAX_CONSTANTS) |
793 | 0 | return ASN1_RECURSION; |
794 | | |
795 | 0 | p5 = |
796 | 0 | _asn1_add_single_node (ASN1_ETYPE_CONSTANT); |
797 | 0 | _asn1_set_name (p5, p4->name); |
798 | 0 | if (p4->value) |
799 | 0 | { |
800 | 0 | tlen = _asn1_strlen (p4->value); |
801 | 0 | if (tlen > 0) |
802 | 0 | _asn1_set_value (p5, p4->value, tlen + 1); |
803 | 0 | } |
804 | 0 | _asn1_add_static_node2 (list, p5); |
805 | |
|
806 | 0 | if (p2 == p) |
807 | 0 | { |
808 | 0 | _asn1_set_right (p5, p->down); |
809 | 0 | _asn1_set_down (p, p5); |
810 | 0 | } |
811 | 0 | else |
812 | 0 | { |
813 | 0 | _asn1_set_right (p5, p2->right); |
814 | 0 | _asn1_set_right (p2, p5); |
815 | 0 | } |
816 | 0 | p2 = p5; |
817 | 0 | } |
818 | 0 | p4 = p4->right; |
819 | 0 | } |
820 | 0 | move = DOWN; |
821 | |
|
822 | 0 | tries++; |
823 | 0 | if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION) |
824 | 0 | return ASN1_RECURSION; |
825 | | |
826 | 0 | continue; |
827 | 0 | } |
828 | 4 | } |
829 | 4 | } |
830 | 2.34k | move = DOWN; |
831 | 2.34k | } |
832 | 868 | else |
833 | 868 | move = RIGHT; |
834 | | |
835 | 3.21k | tries = 0; |
836 | 3.21k | if (move == DOWN) |
837 | 2.34k | { |
838 | 2.34k | if (p->down) |
839 | 876 | p = p->down; |
840 | 1.47k | else |
841 | 1.47k | move = RIGHT; |
842 | 2.34k | } |
843 | | |
844 | 3.21k | if (p == node) |
845 | 0 | { |
846 | 0 | move = UP; |
847 | 0 | continue; |
848 | 0 | } |
849 | | |
850 | 3.21k | if (move == RIGHT) |
851 | 2.34k | { |
852 | 2.34k | if (p && p->right) |
853 | 1.46k | p = p->right; |
854 | 876 | else |
855 | 876 | move = UP; |
856 | 2.34k | } |
857 | 3.21k | if (move == UP) |
858 | 876 | p = _asn1_find_up (p); |
859 | 3.21k | } |
860 | | |
861 | | /*******************************/ |
862 | | /* expand DEFAULT */ |
863 | | /*******************************/ |
864 | 8 | p = node; |
865 | 8 | move = DOWN; |
866 | | |
867 | 3.22k | while (!((p == node) && (move == UP))) |
868 | 3.21k | { |
869 | 3.21k | if (move != UP) |
870 | 2.34k | { |
871 | 2.34k | if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && |
872 | 2.34k | (p->type & CONST_DEFAULT)) |
873 | 0 | { |
874 | 0 | p2 = p->down; |
875 | 0 | if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) |
876 | 0 | { |
877 | 0 | _asn1_str_cpy (name2, sizeof (name2), name_root); |
878 | 0 | _asn1_str_cat (name2, sizeof (name2), "."); |
879 | 0 | if (p2->value) |
880 | 0 | _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); |
881 | 0 | p3 = asn1_find_node (node, name2); |
882 | 0 | if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) |
883 | 0 | || !(p3->type & CONST_ASSIGN)) |
884 | 0 | return ASN1_ELEMENT_NOT_FOUND; |
885 | 0 | p4 = p3->down; |
886 | 0 | name2[0] = 0; |
887 | 0 | while (p4) |
888 | 0 | { |
889 | 0 | if (type_field (p4->type) == ASN1_ETYPE_CONSTANT) |
890 | 0 | { |
891 | 0 | if (p4->value == NULL) |
892 | 0 | return ASN1_VALUE_NOT_FOUND; |
893 | | |
894 | 0 | if (name2[0]) |
895 | 0 | _asn1_str_cat (name2, sizeof (name2), "."); |
896 | 0 | _asn1_str_cat (name2, sizeof (name2), |
897 | 0 | (char *) p4->value); |
898 | 0 | } |
899 | 0 | p4 = p4->right; |
900 | 0 | } |
901 | 0 | tlen = strlen (name2); |
902 | 0 | if (tlen > 0) |
903 | 0 | _asn1_set_value (p2, name2, tlen + 1); |
904 | 0 | } |
905 | 0 | } |
906 | 2.34k | move = DOWN; |
907 | 2.34k | } |
908 | 868 | else |
909 | 868 | move = RIGHT; |
910 | | |
911 | 3.21k | if (move == DOWN) |
912 | 2.34k | { |
913 | 2.34k | if (p->down) |
914 | 876 | p = p->down; |
915 | 1.47k | else |
916 | 1.47k | move = RIGHT; |
917 | 2.34k | } |
918 | | |
919 | 3.21k | if (p == node) |
920 | 0 | { |
921 | 0 | move = UP; |
922 | 0 | continue; |
923 | 0 | } |
924 | | |
925 | 3.21k | if (move == RIGHT) |
926 | 2.34k | { |
927 | 2.34k | if (p && p->right) |
928 | 1.46k | p = p->right; |
929 | 876 | else |
930 | 876 | move = UP; |
931 | 2.34k | } |
932 | 3.21k | if (move == UP) |
933 | 876 | p = _asn1_find_up (p); |
934 | 3.21k | } |
935 | | |
936 | 8 | return ASN1_SUCCESS; |
937 | 8 | } |
938 | | |
939 | | |
940 | | /******************************************************************/ |
941 | | /* Function : _asn1_type_set_config */ |
942 | | /* Description: sets the CONST_SET and CONST_NOT_USED properties */ |
943 | | /* in the fields of the SET elements. */ |
944 | | /* Parameters: */ |
945 | | /* node: root of an ASN1 element. */ |
946 | | /* Return: */ |
947 | | /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ |
948 | | /* otherwise ASN1_SUCCESS */ |
949 | | /******************************************************************/ |
950 | | int |
951 | | _asn1_type_set_config (asn1_node node) |
952 | 0 | { |
953 | 0 | asn1_node p, p2; |
954 | 0 | int move; |
955 | |
|
956 | 0 | if (node == NULL) |
957 | 0 | return ASN1_ELEMENT_NOT_FOUND; |
958 | | |
959 | 0 | p = node; |
960 | 0 | move = DOWN; |
961 | |
|
962 | 0 | while (!((p == node) && (move == UP))) |
963 | 0 | { |
964 | 0 | if (move != UP) |
965 | 0 | { |
966 | 0 | if (type_field (p->type) == ASN1_ETYPE_SET) |
967 | 0 | { |
968 | 0 | p2 = p->down; |
969 | 0 | while (p2) |
970 | 0 | { |
971 | 0 | if (type_field (p2->type) != ASN1_ETYPE_TAG) |
972 | 0 | p2->type |= CONST_SET | CONST_NOT_USED; |
973 | 0 | p2 = p2->right; |
974 | 0 | } |
975 | 0 | } |
976 | 0 | move = DOWN; |
977 | 0 | } |
978 | 0 | else |
979 | 0 | move = RIGHT; |
980 | |
|
981 | 0 | if (move == DOWN) |
982 | 0 | { |
983 | 0 | if (p->down) |
984 | 0 | p = p->down; |
985 | 0 | else |
986 | 0 | move = RIGHT; |
987 | 0 | } |
988 | |
|
989 | 0 | if (p == node) |
990 | 0 | { |
991 | 0 | move = UP; |
992 | 0 | continue; |
993 | 0 | } |
994 | | |
995 | 0 | if (move == RIGHT) |
996 | 0 | { |
997 | 0 | if (p && p->right) |
998 | 0 | p = p->right; |
999 | 0 | else |
1000 | 0 | move = UP; |
1001 | 0 | } |
1002 | 0 | if (move == UP) |
1003 | 0 | p = _asn1_find_up (p); |
1004 | 0 | } |
1005 | |
|
1006 | 0 | return ASN1_SUCCESS; |
1007 | 0 | } |
1008 | | |
1009 | | |
1010 | | /******************************************************************/ |
1011 | | /* Function : _asn1_check_identifier */ |
1012 | | /* Description: checks the definitions of all the identifiers */ |
1013 | | /* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */ |
1014 | | /* The _asn1_identifierMissing global variable is filled if */ |
1015 | | /* necessary. */ |
1016 | | /* Parameters: */ |
1017 | | /* node: root of an ASN1 element. */ |
1018 | | /* Return: */ |
1019 | | /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */ |
1020 | | /* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */ |
1021 | | /* otherwise ASN1_SUCCESS */ |
1022 | | /******************************************************************/ |
1023 | | int |
1024 | | _asn1_check_identifier (asn1_node_const node) |
1025 | 8 | { |
1026 | 8 | asn1_node_const p, p2; |
1027 | 8 | char name2[ASN1_MAX_NAME_SIZE * 2 + 2]; |
1028 | | |
1029 | 8 | if (node == NULL) |
1030 | 0 | return ASN1_ELEMENT_NOT_FOUND; |
1031 | | |
1032 | 8 | p = node; |
1033 | 2.35k | while (p) |
1034 | 2.34k | { |
1035 | 2.34k | if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER) |
1036 | 556 | { |
1037 | 556 | _asn1_str_cpy (name2, sizeof (name2), node->name); |
1038 | 556 | _asn1_str_cat (name2, sizeof (name2), "."); |
1039 | 556 | _asn1_str_cat (name2, sizeof (name2), (char *) p->value); |
1040 | 556 | p2 = asn1_find_node (node, name2); |
1041 | 556 | if (p2 == NULL) |
1042 | 0 | { |
1043 | 0 | if (p->value) |
1044 | 0 | _asn1_str_cpy (_asn1_identifierMissing, |
1045 | 0 | sizeof (_asn1_identifierMissing), |
1046 | 0 | (char *) p->value); |
1047 | 0 | else |
1048 | 0 | _asn1_strcpy (_asn1_identifierMissing, "(null)"); |
1049 | 0 | return ASN1_IDENTIFIER_NOT_FOUND; |
1050 | 0 | } |
1051 | 556 | } |
1052 | 1.79k | else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && |
1053 | 1.79k | (p->type & CONST_DEFAULT)) |
1054 | 0 | { |
1055 | 0 | p2 = p->down; |
1056 | 0 | if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT)) |
1057 | 0 | { |
1058 | 0 | _asn1_str_cpy (name2, sizeof (name2), node->name); |
1059 | 0 | if (p2->value) |
1060 | 0 | { |
1061 | 0 | _asn1_str_cat (name2, sizeof (name2), "."); |
1062 | 0 | _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); |
1063 | 0 | _asn1_str_cpy (_asn1_identifierMissing, |
1064 | 0 | sizeof (_asn1_identifierMissing), |
1065 | 0 | (char *) p2->value); |
1066 | 0 | } |
1067 | 0 | else |
1068 | 0 | _asn1_strcpy (_asn1_identifierMissing, "(null)"); |
1069 | |
|
1070 | 0 | p2 = asn1_find_node (node, name2); |
1071 | 0 | if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) || |
1072 | 0 | !(p2->type & CONST_ASSIGN)) |
1073 | 0 | return ASN1_IDENTIFIER_NOT_FOUND; |
1074 | 0 | else |
1075 | 0 | _asn1_identifierMissing[0] = 0; |
1076 | 0 | } |
1077 | 0 | } |
1078 | 1.79k | else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && |
1079 | 1.79k | (p->type & CONST_ASSIGN)) |
1080 | 4 | { |
1081 | 4 | p2 = p->down; |
1082 | 4 | if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT)) |
1083 | 4 | { |
1084 | 4 | if (p2->value && !c_isdigit (p2->value[0])) |
1085 | 0 | { |
1086 | 0 | _asn1_str_cpy (name2, sizeof (name2), node->name); |
1087 | 0 | _asn1_str_cat (name2, sizeof (name2), "."); |
1088 | 0 | _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); |
1089 | 0 | _asn1_str_cpy (_asn1_identifierMissing, |
1090 | 0 | sizeof (_asn1_identifierMissing), |
1091 | 0 | (char *) p2->value); |
1092 | |
|
1093 | 0 | p2 = asn1_find_node (node, name2); |
1094 | 0 | if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) |
1095 | 0 | || !(p2->type & CONST_ASSIGN)) |
1096 | 0 | return ASN1_IDENTIFIER_NOT_FOUND; |
1097 | 0 | else |
1098 | 0 | _asn1_identifierMissing[0] = 0; |
1099 | 0 | } |
1100 | 4 | } |
1101 | 4 | } |
1102 | | |
1103 | 2.34k | if (p->down) |
1104 | 876 | { |
1105 | 876 | p = p->down; |
1106 | 876 | } |
1107 | 1.47k | else if (p->right) |
1108 | 800 | p = p->right; |
1109 | 672 | else |
1110 | 672 | { |
1111 | 876 | while (p) |
1112 | 876 | { |
1113 | 876 | p = _asn1_find_up (p); |
1114 | 876 | if (p == node) |
1115 | 8 | { |
1116 | 8 | p = NULL; |
1117 | 8 | break; |
1118 | 8 | } |
1119 | 868 | if (p && p->right) |
1120 | 664 | { |
1121 | 664 | p = p->right; |
1122 | 664 | break; |
1123 | 664 | } |
1124 | 868 | } |
1125 | 672 | } |
1126 | 2.34k | } |
1127 | | |
1128 | 8 | return ASN1_SUCCESS; |
1129 | 8 | } |
1130 | | |
1131 | | |
1132 | | /******************************************************************/ |
1133 | | /* Function : _asn1_set_default_tag */ |
1134 | | /* Description: sets the default IMPLICIT or EXPLICIT property in */ |
1135 | | /* the tagged elements that don't have this declaration. */ |
1136 | | /* Parameters: */ |
1137 | | /* node: pointer to a DEFINITIONS element. */ |
1138 | | /* Return: */ |
1139 | | /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */ |
1140 | | /* a DEFINITIONS element, */ |
1141 | | /* otherwise ASN1_SUCCESS */ |
1142 | | /******************************************************************/ |
1143 | | int |
1144 | | _asn1_set_default_tag (asn1_node node) |
1145 | 0 | { |
1146 | 0 | asn1_node p; |
1147 | |
|
1148 | 0 | if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS)) |
1149 | 0 | return ASN1_ELEMENT_NOT_FOUND; |
1150 | | |
1151 | 0 | p = node; |
1152 | 0 | while (p) |
1153 | 0 | { |
1154 | 0 | if ((type_field (p->type) == ASN1_ETYPE_TAG) && |
1155 | 0 | !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT)) |
1156 | 0 | { |
1157 | 0 | if (node->type & CONST_EXPLICIT) |
1158 | 0 | p->type |= CONST_EXPLICIT; |
1159 | 0 | else |
1160 | 0 | p->type |= CONST_IMPLICIT; |
1161 | 0 | } |
1162 | |
|
1163 | 0 | if (p->down) |
1164 | 0 | { |
1165 | 0 | p = p->down; |
1166 | 0 | } |
1167 | 0 | else if (p->right) |
1168 | 0 | p = p->right; |
1169 | 0 | else |
1170 | 0 | { |
1171 | 0 | while (1) |
1172 | 0 | { |
1173 | 0 | p = _asn1_find_up (p); |
1174 | 0 | if (p == node) |
1175 | 0 | { |
1176 | 0 | p = NULL; |
1177 | 0 | break; |
1178 | 0 | } |
1179 | 0 | if (p && p->right) |
1180 | 0 | { |
1181 | 0 | p = p->right; |
1182 | 0 | break; |
1183 | 0 | } |
1184 | 0 | } |
1185 | 0 | } |
1186 | 0 | } |
1187 | |
|
1188 | 0 | return ASN1_SUCCESS; |
1189 | 0 | } |