Fix asn1_check_version to accept that (e.g.) 1.0 is more recent than 0.3.10.
[libtasn1.git] / lib / parser_aux.c
blob51169b14b47a0c694b6fa4cc7fa7e569cc6bfc4b
1 /*
2 * Copyright (C) 2004, 2006, 2007 Free Software Foundation
3 * Copyright (C) 2000,2001 Fabio Fiorina
5 * This file is part of LIBTASN1.
7 * The LIBTASN1 library is free software; you can redistribute it
8 * and/or modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA
23 #include <int.h>
24 #include <errors.h>
25 #include "parser_aux.h"
26 #include "gstr.h"
27 #include "structure.h"
28 #include "element.h"
30 char _asn1_identifierMissing[MAX_NAME_SIZE + 1]; /* identifier name not found */
32 /***********************************************/
33 /* Type: list_type */
34 /* Description: type used in the list during */
35 /* the structure creation. */
36 /***********************************************/
37 typedef struct list_struct
39 node_asn *node;
40 struct list_struct *next;
41 } list_type;
44 /* Pointer to the first element of the list */
45 list_type *firstElement = NULL;
47 /******************************************************/
48 /* Function : _asn1_add_node */
49 /* Description: creates a new NODE_ASN element and */
50 /* puts it in the list pointed by firstElement. */
51 /* Parameters: */
52 /* type: type of the new element (see TYPE_ */
53 /* and CONST_ constants). */
54 /* Return: pointer to the new element. */
55 /******************************************************/
56 node_asn *
57 _asn1_add_node (unsigned int type)
59 list_type *listElement;
60 node_asn *punt;
62 punt = (node_asn *) _asn1_calloc (1, sizeof (node_asn));
63 if (punt == NULL)
64 return NULL;
66 listElement = (list_type *) _asn1_malloc (sizeof (list_type));
67 if (listElement == NULL)
69 _asn1_free (punt);
70 return NULL;
73 listElement->node = punt;
74 listElement->next = firstElement;
75 firstElement = listElement;
77 punt->type = type;
79 return punt;
82 /**
83 * asn1_find_node:
84 * @pointer: NODE_ASN element pointer.
85 * @name: null terminated string with the element's name to find.
87 * Searches for an element called NAME starting from POINTER. The
88 * name is composed by differents identifiers separated by dots. When
89 * *POINTER has a name, the first identifier must be the name of
90 * *POINTER, otherwise it must be the name of one child of *POINTER.
92 * Return value: the searching result. NULL if not found.
93 **/
94 ASN1_TYPE
95 asn1_find_node (ASN1_TYPE pointer, const char *name)
97 node_asn *p;
98 char *n_end, n[MAX_NAME_SIZE + 1];
99 const char *n_start;
101 if (pointer == NULL)
102 return NULL;
104 if (name == NULL)
105 return NULL;
107 p = pointer;
108 n_start = name;
110 if (p->name != NULL)
111 { /* has *pointer got a name ? */
112 n_end = strchr (n_start, '.'); /* search the first dot */
113 if (n_end)
115 memcpy (n, n_start, n_end - n_start);
116 n[n_end - n_start] = 0;
117 n_start = n_end;
118 n_start++;
120 else
122 _asn1_str_cpy (n, sizeof (n), n_start);
123 n_start = NULL;
126 while (p)
128 if ((p->name) && (!strcmp (p->name, n)))
129 break;
130 else
131 p = p->right;
132 } /* while */
134 if (p == NULL)
135 return NULL;
137 else
138 { /* *pointer doesn't have a name */
139 if (n_start[0] == 0)
140 return p;
143 while (n_start)
144 { /* Has the end of NAME been reached? */
145 n_end = strchr (n_start, '.'); /* search the next dot */
146 if (n_end)
148 memcpy (n, n_start, n_end - n_start);
149 n[n_end - n_start] = 0;
150 n_start = n_end;
151 n_start++;
153 else
155 _asn1_str_cpy (n, sizeof (n), n_start);
156 n_start = NULL;
159 if (p->down == NULL)
160 return NULL;
162 p = p->down;
164 /* The identifier "?LAST" indicates the last element
165 in the right chain. */
166 if (!strcmp (n, "?LAST"))
168 if (p == NULL)
169 return NULL;
170 while (p->right)
171 p = p->right;
173 else
174 { /* no "?LAST" */
175 while (p)
177 if ((p->name) && (!strcmp (p->name, n)))
178 break;
179 else
180 p = p->right;
182 if (p == NULL)
183 return NULL;
185 } /* while */
187 return p;
191 /******************************************************************/
192 /* Function : _asn1_set_value */
193 /* Description: sets the field VALUE in a NODE_ASN element. The */
194 /* previous value (if exist) will be lost */
195 /* Parameters: */
196 /* node: element pointer. */
197 /* value: pointer to the value that you want to set. */
198 /* len: character number of value. */
199 /* Return: pointer to the NODE_ASN element. */
200 /******************************************************************/
201 node_asn *
202 _asn1_set_value (node_asn * node, const void *_value, unsigned int len)
204 const unsigned char *value = _value;
206 if (node == NULL)
207 return node;
208 if (node->value)
210 _asn1_free (node->value);
211 node->value = NULL;
212 node->value_len = 0;
214 if (!len)
215 return node;
216 node->value = (unsigned char *) _asn1_malloc (len);
217 if (node->value == NULL)
218 return NULL;
219 node->value_len = len;
221 memcpy (node->value, value, len);
222 return node;
225 /******************************************************************/
226 /* Function : _asn1_set_name */
227 /* Description: sets the field NAME in a NODE_ASN element. The */
228 /* previous value (if exist) will be lost */
229 /* Parameters: */
230 /* node: element pointer. */
231 /* name: a null terminated string with the name that you want */
232 /* to set. */
233 /* Return: pointer to the NODE_ASN element. */
234 /******************************************************************/
235 node_asn *
236 _asn1_set_name (node_asn * node, const char *name)
238 if (node == NULL)
239 return node;
241 if (node->name)
243 _asn1_free (node->name);
244 node->name = NULL;
247 if (name == NULL)
248 return node;
250 if (strlen (name))
252 node->name = (char *) _asn1_strdup (name);
253 if (node->name == NULL)
254 return NULL;
256 else
257 node->name = NULL;
258 return node;
261 /******************************************************************/
262 /* Function : _asn1_set_right */
263 /* Description: sets the field RIGHT in a NODE_ASN element. */
264 /* Parameters: */
265 /* node: element pointer. */
266 /* right: pointer to a NODE_ASN element that you want be pointed*/
267 /* by NODE. */
268 /* Return: pointer to *NODE. */
269 /******************************************************************/
270 node_asn *
271 _asn1_set_right (node_asn * node, node_asn * right)
273 if (node == NULL)
274 return node;
275 node->right = right;
276 if (right)
277 right->left = node;
278 return node;
281 /******************************************************************/
282 /* Function : _asn1_get_right */
283 /* Description: returns the element pointed by the RIGHT field of */
284 /* a NODE_ASN element. */
285 /* Parameters: */
286 /* node: NODE_ASN element pointer. */
287 /* Return: field RIGHT of NODE. */
288 /******************************************************************/
289 node_asn *
290 _asn1_get_right (node_asn * node)
292 if (node == NULL)
293 return NULL;
294 return node->right;
297 /******************************************************************/
298 /* Function : _asn1_get_last_right */
299 /* Description: return the last element along the right chain. */
300 /* Parameters: */
301 /* node: starting element pointer. */
302 /* Return: pointer to the last element along the right chain. */
303 /******************************************************************/
304 node_asn *
305 _asn1_get_last_right (node_asn * node)
307 node_asn *p;
309 if (node == NULL)
310 return NULL;
311 p = node;
312 while (p->right)
313 p = p->right;
314 return p;
317 /******************************************************************/
318 /* Function : _asn1_set_down */
319 /* Description: sets the field DOWN in a NODE_ASN element. */
320 /* Parameters: */
321 /* node: element pointer. */
322 /* down: pointer to a NODE_ASN element that you want be pointed */
323 /* by NODE. */
324 /* Return: pointer to *NODE. */
325 /******************************************************************/
326 node_asn *
327 _asn1_set_down (node_asn * node, node_asn * down)
329 if (node == NULL)
330 return node;
331 node->down = down;
332 if (down)
333 down->left = node;
334 return node;
337 /******************************************************************/
338 /* Function : _asn1_get_down */
339 /* Description: returns the element pointed by the DOWN field of */
340 /* a NODE_ASN element. */
341 /* Parameters: */
342 /* node: NODE_ASN element pointer. */
343 /* Return: field DOWN of NODE. */
344 /******************************************************************/
345 node_asn *
346 _asn1_get_down (node_asn * node)
348 if (node == NULL)
349 return NULL;
350 return node->down;
353 /******************************************************************/
354 /* Function : _asn1_get_name */
355 /* Description: returns the name of a NODE_ASN element. */
356 /* Parameters: */
357 /* node: NODE_ASN element pointer. */
358 /* Return: a null terminated string. */
359 /******************************************************************/
360 char *
361 _asn1_get_name (node_asn * node)
363 if (node == NULL)
364 return NULL;
365 return node->name;
368 /******************************************************************/
369 /* Function : _asn1_mod_type */
370 /* Description: change the field TYPE of an NODE_ASN element. */
371 /* The new value is the old one | (bitwise or) the */
372 /* paramener VALUE. */
373 /* Parameters: */
374 /* node: NODE_ASN element pointer. */
375 /* value: the integer value that must be or-ed with the current */
376 /* value of field TYPE. */
377 /* Return: NODE pointer. */
378 /******************************************************************/
379 node_asn *
380 _asn1_mod_type (node_asn * node, unsigned int value)
382 if (node == NULL)
383 return node;
384 node->type |= value;
385 return node;
389 /******************************************************************/
390 /* Function : _asn1_remove_node */
391 /* Description: gets free the memory allocated for an NODE_ASN */
392 /* element (not the elements pointed by it). */
393 /* Parameters: */
394 /* node: NODE_ASN element pointer. */
395 /******************************************************************/
396 void
397 _asn1_remove_node (node_asn * node)
399 if (node == NULL)
400 return;
402 if (node->name != NULL)
403 _asn1_free (node->name);
404 if (node->value != NULL)
405 _asn1_free (node->value);
406 _asn1_free (node);
409 /******************************************************************/
410 /* Function : _asn1_find_up */
411 /* Description: return the father of the NODE_ASN element. */
412 /* Parameters: */
413 /* node: NODE_ASN element pointer. */
414 /* Return: Null if not found. */
415 /******************************************************************/
416 node_asn *
417 _asn1_find_up (node_asn * node)
419 node_asn *p;
421 if (node == NULL)
422 return NULL;
424 p = node;
426 while ((p->left != NULL) && (p->left->right == p))
427 p = p->left;
429 return p->left;
432 /******************************************************************/
433 /* Function : _asn1_delete_list */
434 /* Description: deletes the list elements (not the elements */
435 /* pointed by them). */
436 /******************************************************************/
437 void
438 _asn1_delete_list (void)
440 list_type *listElement;
442 while (firstElement)
444 listElement = firstElement;
445 firstElement = firstElement->next;
446 _asn1_free (listElement);
450 /******************************************************************/
451 /* Function : _asn1_delete_list_and nodes */
452 /* Description: deletes the list elements and the elements */
453 /* pointed by them. */
454 /******************************************************************/
455 void
456 _asn1_delete_list_and_nodes (void)
458 list_type *listElement;
460 while (firstElement)
462 listElement = firstElement;
463 firstElement = firstElement->next;
464 _asn1_remove_node (listElement->node);
465 _asn1_free (listElement);
470 char *
471 _asn1_ltostr (long v, char *str)
473 long d, r;
474 char temp[20];
475 int count, k, start;
477 if (v < 0)
479 str[0] = '-';
480 start = 1;
481 v = -v;
483 else
484 start = 0;
486 count = 0;
489 d = v / 10;
490 r = v - d * 10;
491 temp[start + count] = '0' + (char) r;
492 count++;
493 v = d;
495 while (v);
497 for (k = 0; k < count; k++)
498 str[k + start] = temp[start + count - k - 1];
499 str[count + start] = 0;
500 return str;
504 /******************************************************************/
505 /* Function : _asn1_change_integer_value */
506 /* Description: converts into DER coding the value assign to an */
507 /* INTEGER constant. */
508 /* Parameters: */
509 /* node: root of an ASN1element. */
510 /* Return: */
511 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
512 /* otherwise ASN1_SUCCESS */
513 /******************************************************************/
514 asn1_retCode
515 _asn1_change_integer_value (ASN1_TYPE node)
517 node_asn *p;
518 unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
519 unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1];
520 int len;
522 if (node == NULL)
523 return ASN1_ELEMENT_NOT_FOUND;
525 p = node;
526 while (p)
528 if ((type_field (p->type) == TYPE_INTEGER) && (p->type & CONST_ASSIGN))
530 if (p->value)
532 _asn1_convert_integer (p->value, val, sizeof (val), &len);
533 asn1_octet_der (val, len, val2, &len);
534 _asn1_set_value (p, val2, len);
538 if (p->down)
540 p = p->down;
542 else
544 if (p == node)
545 p = NULL;
546 else if (p->right)
547 p = p->right;
548 else
550 while (1)
552 p = _asn1_find_up (p);
553 if (p == node)
555 p = NULL;
556 break;
558 if (p->right)
560 p = p->right;
561 break;
568 return ASN1_SUCCESS;
572 /******************************************************************/
573 /* Function : _asn1_expand_object_id */
574 /* Description: expand the IDs of an OBJECT IDENTIFIER constant. */
575 /* Parameters: */
576 /* node: root of an ASN1 element. */
577 /* Return: */
578 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
579 /* otherwise ASN1_SUCCESS */
580 /******************************************************************/
581 asn1_retCode
582 _asn1_expand_object_id (ASN1_TYPE node)
584 node_asn *p, *p2, *p3, *p4, *p5;
585 char name_root[MAX_NAME_SIZE], name2[2 * MAX_NAME_SIZE + 1];
586 int move, tlen;
588 if (node == NULL)
589 return ASN1_ELEMENT_NOT_FOUND;
591 _asn1_str_cpy (name_root, sizeof (name_root), node->name);
593 p = node;
594 move = DOWN;
596 while (!((p == node) && (move == UP)))
598 if (move != UP)
600 if ((type_field (p->type) == TYPE_OBJECT_ID)
601 && (p->type & CONST_ASSIGN))
603 p2 = p->down;
604 if (p2 && (type_field (p2->type) == TYPE_CONSTANT))
606 if (p2->value && !isdigit (p2->value[0]))
608 _asn1_str_cpy (name2, sizeof (name2), name_root);
609 _asn1_str_cat (name2, sizeof (name2), ".");
610 _asn1_str_cat (name2, sizeof (name2), p2->value);
611 p3 = asn1_find_node (node, name2);
612 if (!p3 || (type_field (p3->type) != TYPE_OBJECT_ID) ||
613 !(p3->type & CONST_ASSIGN))
614 return ASN1_ELEMENT_NOT_FOUND;
615 _asn1_set_down (p, p2->right);
616 _asn1_remove_node (p2);
617 p2 = p;
618 p4 = p3->down;
619 while (p4)
621 if (type_field (p4->type) == TYPE_CONSTANT)
623 p5 = _asn1_add_node_only (TYPE_CONSTANT);
624 _asn1_set_name (p5, p4->name);
625 tlen = strlen (p4->value);
626 if (tlen > 0)
627 _asn1_set_value (p5, p4->value, tlen + 1);
628 if (p2 == p)
630 _asn1_set_right (p5, p->down);
631 _asn1_set_down (p, p5);
633 else
635 _asn1_set_right (p5, p2->right);
636 _asn1_set_right (p2, p5);
638 p2 = p5;
640 p4 = p4->right;
642 move = DOWN;
643 continue;
647 move = DOWN;
649 else
650 move = RIGHT;
652 if (move == DOWN)
654 if (p->down)
655 p = p->down;
656 else
657 move = RIGHT;
660 if (p == node)
662 move = UP;
663 continue;
666 if (move == RIGHT)
668 if (p->right)
669 p = p->right;
670 else
671 move = UP;
673 if (move == UP)
674 p = _asn1_find_up (p);
678 /*******************************/
679 /* expand DEFAULT */
680 /*******************************/
681 p = node;
682 move = DOWN;
684 while (!((p == node) && (move == UP)))
686 if (move != UP)
688 if ((type_field (p->type) == TYPE_OBJECT_ID) &&
689 (p->type & CONST_DEFAULT))
691 p2 = p->down;
692 if (p2 && (type_field (p2->type) == TYPE_DEFAULT))
694 _asn1_str_cpy (name2, sizeof (name2), name_root);
695 _asn1_str_cat (name2, sizeof (name2), ".");
696 _asn1_str_cat (name2, sizeof (name2), p2->value);
697 p3 = asn1_find_node (node, name2);
698 if (!p3 || (type_field (p3->type) != TYPE_OBJECT_ID) ||
699 !(p3->type & CONST_ASSIGN))
700 return ASN1_ELEMENT_NOT_FOUND;
701 p4 = p3->down;
702 name2[0] = 0;
703 while (p4)
705 if (type_field (p4->type) == TYPE_CONSTANT)
707 if (name2[0])
708 _asn1_str_cat (name2, sizeof (name2), ".");
709 _asn1_str_cat (name2, sizeof (name2), p4->value);
711 p4 = p4->right;
713 tlen = strlen (name2);
714 if (tlen > 0)
715 _asn1_set_value (p2, name2, tlen + 1);
718 move = DOWN;
720 else
721 move = RIGHT;
723 if (move == DOWN)
725 if (p->down)
726 p = p->down;
727 else
728 move = RIGHT;
731 if (p == node)
733 move = UP;
734 continue;
737 if (move == RIGHT)
739 if (p->right)
740 p = p->right;
741 else
742 move = UP;
744 if (move == UP)
745 p = _asn1_find_up (p);
748 return ASN1_SUCCESS;
752 /******************************************************************/
753 /* Function : _asn1_type_set_config */
754 /* Description: sets the CONST_SET and CONST_NOT_USED properties */
755 /* in the fields of the SET elements. */
756 /* Parameters: */
757 /* node: root of an ASN1 element. */
758 /* Return: */
759 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
760 /* otherwise ASN1_SUCCESS */
761 /******************************************************************/
762 asn1_retCode
763 _asn1_type_set_config (ASN1_TYPE node)
765 node_asn *p, *p2;
766 int move;
768 if (node == NULL)
769 return ASN1_ELEMENT_NOT_FOUND;
771 p = node;
772 move = DOWN;
774 while (!((p == node) && (move == UP)))
776 if (move != UP)
778 if (type_field (p->type) == TYPE_SET)
780 p2 = p->down;
781 while (p2)
783 if (type_field (p2->type) != TYPE_TAG)
784 p2->type |= CONST_SET | CONST_NOT_USED;
785 p2 = p2->right;
788 move = DOWN;
790 else
791 move = RIGHT;
793 if (move == DOWN)
795 if (p->down)
796 p = p->down;
797 else
798 move = RIGHT;
801 if (p == node)
803 move = UP;
804 continue;
807 if (move == RIGHT)
809 if (p->right)
810 p = p->right;
811 else
812 move = UP;
814 if (move == UP)
815 p = _asn1_find_up (p);
818 return ASN1_SUCCESS;
822 /******************************************************************/
823 /* Function : _asn1_check_identifier */
824 /* Description: checks the definitions of all the identifiers */
825 /* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */
826 /* The _asn1_identifierMissing global variable is filled if */
827 /* necessary. */
828 /* Parameters: */
829 /* node: root of an ASN1 element. */
830 /* Return: */
831 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
832 /* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */
833 /* otherwise ASN1_SUCCESS */
834 /******************************************************************/
835 asn1_retCode
836 _asn1_check_identifier (ASN1_TYPE node)
838 node_asn *p, *p2;
839 char name2[MAX_NAME_SIZE * 2 + 2];
841 if (node == NULL)
842 return ASN1_ELEMENT_NOT_FOUND;
844 p = node;
845 while (p)
847 if (type_field (p->type) == TYPE_IDENTIFIER)
849 _asn1_str_cpy (name2, sizeof (name2), node->name);
850 _asn1_str_cat (name2, sizeof (name2), ".");
851 _asn1_str_cat (name2, sizeof (name2), p->value);
852 p2 = asn1_find_node (node, name2);
853 if (p2 == NULL)
855 strcpy (_asn1_identifierMissing, p->value);
856 return ASN1_IDENTIFIER_NOT_FOUND;
859 else if ((type_field (p->type) == TYPE_OBJECT_ID) &&
860 (p->type & CONST_DEFAULT))
862 p2 = p->down;
863 if (p2 && (type_field (p2->type) == TYPE_DEFAULT))
865 _asn1_str_cpy (name2, sizeof (name2), node->name);
866 _asn1_str_cat (name2, sizeof (name2), ".");
867 _asn1_str_cat (name2, sizeof (name2), p2->value);
868 strcpy (_asn1_identifierMissing, p2->value);
869 p2 = asn1_find_node (node, name2);
870 if (!p2 || (type_field (p2->type) != TYPE_OBJECT_ID) ||
871 !(p2->type & CONST_ASSIGN))
872 return ASN1_IDENTIFIER_NOT_FOUND;
873 else
874 _asn1_identifierMissing[0] = 0;
877 else if ((type_field (p->type) == TYPE_OBJECT_ID) &&
878 (p->type & CONST_ASSIGN))
880 p2 = p->down;
881 if (p2 && (type_field (p2->type) == TYPE_CONSTANT))
883 if (p2->value && !isdigit (p2->value[0]))
885 _asn1_str_cpy (name2, sizeof (name2), node->name);
886 _asn1_str_cat (name2, sizeof (name2), ".");
887 _asn1_str_cat (name2, sizeof (name2), p2->value);
888 strcpy (_asn1_identifierMissing, p2->value);
889 p2 = asn1_find_node (node, name2);
890 if (!p2 || (type_field (p2->type) != TYPE_OBJECT_ID) ||
891 !(p2->type & CONST_ASSIGN))
892 return ASN1_IDENTIFIER_NOT_FOUND;
893 else
894 _asn1_identifierMissing[0] = 0;
899 if (p->down)
901 p = p->down;
903 else if (p->right)
904 p = p->right;
905 else
907 while (1)
909 p = _asn1_find_up (p);
910 if (p == node)
912 p = NULL;
913 break;
915 if (p->right)
917 p = p->right;
918 break;
924 return ASN1_SUCCESS;
928 /******************************************************************/
929 /* Function : _asn1_set_default_tag */
930 /* Description: sets the default IMPLICIT or EXPLICIT property in */
931 /* the tagged elements that don't have this declaration. */
932 /* Parameters: */
933 /* node: pointer to a DEFINITIONS element. */
934 /* Return: */
935 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */
936 /* a DEFINITIONS element, */
937 /* otherwise ASN1_SUCCESS */
938 /******************************************************************/
939 asn1_retCode
940 _asn1_set_default_tag (ASN1_TYPE node)
942 node_asn *p;
944 if ((node == NULL) || (type_field (node->type) != TYPE_DEFINITIONS))
945 return ASN1_ELEMENT_NOT_FOUND;
947 p = node;
948 while (p)
950 if ((type_field (p->type) == TYPE_TAG) &&
951 !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT))
953 if (node->type & CONST_EXPLICIT)
954 p->type |= CONST_EXPLICIT;
955 else
956 p->type |= CONST_IMPLICIT;
959 if (p->down)
961 p = p->down;
963 else if (p->right)
964 p = p->right;
965 else
967 while (1)
969 p = _asn1_find_up (p);
970 if (p == node)
972 p = NULL;
973 break;
975 if (p->right)
977 p = p->right;
978 break;
984 return ASN1_SUCCESS;
989 static const char *
990 parse_version_number (const char *s, int *number)
992 int val = 0;
994 if (*s == '0' && isdigit (s[1]))
995 return NULL; /* leading zeros are not allowed */
996 for (; isdigit (*s); s++)
998 val *= 10;
999 val += *s - '0';
1001 *number = val;
1002 return val < 0 ? NULL : s;
1005 /* The parse version functions were copied from libgcrypt.
1007 static const char *
1008 parse_version_string (const char *s, int *major, int *minor, int *micro)
1010 s = parse_version_number (s, major);
1011 if (!s || *s != '.')
1012 return NULL;
1013 s++;
1014 s = parse_version_number (s, minor);
1015 if (!s)
1016 return NULL;
1017 if (*s != '.')
1019 *micro = 0;
1020 return s;
1022 s++;
1023 s = parse_version_number (s, micro);
1024 if (!s)
1025 return NULL;
1026 return s; /* patchlevel */
1030 * asn1_check_version - check for library version
1031 * @req_version: Required version number, or NULL.
1033 * Check that the the version of the library is at minimum the
1034 * requested one and return the version string; return %NULL if the
1035 * condition is not satisfied. If a %NULL is passed to this function,
1036 * no check is done, but the version string is simply returned.
1038 * See %LIBTASN1_VERSION for a suitable @req_version string.
1040 * Return value: Version string of run-time library, or %NULL if the
1041 * run-time library does not meet the required version number.
1043 const char *
1044 asn1_check_version (const char *req_version)
1046 const char *ver = LIBTASN1_VERSION;
1047 int my_major, my_minor, my_micro;
1048 int rq_major, rq_minor, rq_micro;
1049 const char *my_plvl, *rq_plvl;
1051 if (!req_version)
1052 return ver;
1054 my_plvl = parse_version_string (ver, &my_major, &my_minor, &my_micro);
1055 if (!my_plvl)
1056 return NULL; /* very strange our own version is bogus */
1057 rq_plvl = parse_version_string (req_version, &rq_major, &rq_minor,
1058 &rq_micro);
1059 if (!rq_plvl)
1060 return NULL; /* req version string is invalid */
1062 if (my_major > rq_major
1063 || (my_major == rq_major && my_minor > rq_minor)
1064 || (my_major == rq_major && my_minor == rq_minor
1065 && my_micro > rq_micro)
1066 || (my_major == rq_major && my_minor == rq_minor
1067 && my_micro == rq_micro && strcmp (my_plvl, rq_plvl) >= 0))
1069 return ver;
1071 return NULL;