Fix.
[libtasn1.git] / lib / parser_aux.c
blobb86d9ff65ec6414eaa4b2e0c2fdacec277bcba9a
1 /*
2 * Copyright (C) 2000,2001 Fabio Fiorina
3 * Copyright (C) 2004 Simon Josefsson
5 * This file is part of LIBASN1.
7 * The LIBTASN1 library is free software; you can redistribute it and/or
8 * 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,
13 * but 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 02110-1301, USA
22 #include <int.h>
23 #include <errors.h>
24 #include "parser_aux.h"
25 #include "der.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{
38 node_asn *node;
39 struct list_struct *next;
40 } list_type;
43 /* Pointer to the first element of the list */
44 list_type *firstElement=NULL;
46 /******************************************************/
47 /* Function : _asn1_add_node */
48 /* Description: creates a new NODE_ASN element and */
49 /* puts it in the list pointed by firstElement. */
50 /* Parameters: */
51 /* type: type of the new element (see TYPE_ */
52 /* and CONST_ constants). */
53 /* Return: pointer to the new element. */
54 /******************************************************/
55 node_asn *
56 _asn1_add_node(unsigned int type)
58 list_type *listElement;
59 node_asn *punt;
61 punt=(node_asn *) _asn1_malloc(sizeof(node_asn));
62 if (punt==NULL) return NULL;
64 listElement=(list_type *) _asn1_malloc(sizeof(list_type));
65 if(listElement==NULL){
66 _asn1_free(punt);
67 return NULL;
70 listElement->node=punt;
71 listElement->next=firstElement;
72 firstElement=listElement;
74 punt->left=NULL;
75 punt->name=NULL;
76 punt->type=type;
77 punt->value=NULL;
78 punt->down=NULL;
79 punt->right=NULL;
81 return punt;
84 /******************************************************************/
85 /* Function : _asn1_find_mode */
86 /* Description: searches an element called NAME starting from */
87 /* POINTER. The name is composed by differents */
88 /* identifiers separated by dots.When *POINTER has a */
89 /* name, the first identifier must be the name of */
90 /* *POINTER, otherwise it must be the name of one */
91 /* child of *POINTER. */
92 /* Parameters: */
93 /* pointer: NODE_ASN element pointer. */
94 /* name: null terminated string with the element's name to find.*/
95 /* Return: the searching result. NULL if not found. */
96 /******************************************************************/
97 node_asn *
98 _asn1_find_node(node_asn *pointer,const char *name)
100 node_asn *p;
101 char *n_end,n[MAX_NAME_SIZE+1];
102 const char *n_start;
104 if(pointer == NULL) return NULL;
106 if(name==NULL) return NULL;
108 p=pointer;
109 n_start=name;
111 if(p->name != NULL){ /* has *pointer got a name ? */
112 n_end=strchr(n_start,'.'); /* search the first dot */
113 if(n_end){
114 memcpy(n,n_start,n_end-n_start);
115 n[n_end-n_start]=0;
116 n_start=n_end;
117 n_start++;
119 else{
120 _asn1_str_cpy(n,sizeof(n),n_start);
121 n_start=NULL;
124 while(p){
125 if((p->name) && (!strcmp(p->name,n))) break;
126 else p=p->right;
127 } /* while */
129 if(p==NULL) return NULL;
131 else{ /* *pointer doesn't have a name */
132 if(n_start[0]==0)
133 return p;
136 while(n_start){ /* Has the end of NAME been reached? */
137 n_end=strchr(n_start,'.'); /* search the next dot */
138 if(n_end){
139 memcpy(n,n_start,n_end-n_start);
140 n[n_end-n_start]=0;
141 n_start=n_end;
142 n_start++;
144 else{
145 _asn1_str_cpy(n,sizeof(n),n_start);
146 n_start=NULL;
149 if(p->down==NULL) return NULL;
151 p=p->down;
153 /* The identifier "?LAST" indicates the last element
154 in the right chain. */
155 if(!strcmp(n,"?LAST")){
156 if(p==NULL) return NULL;
157 while(p->right) p=p->right;
159 else{ /* no "?LAST" */
160 while(p){
161 if((p->name) && (!strcmp(p->name,n))) break;
162 else p=p->right;
164 if(p==NULL) return NULL;
166 } /* while */
168 return p;
172 /******************************************************************/
173 /* Function : _asn1_set_value */
174 /* Description: sets the field VALUE in a NODE_ASN element. The */
175 /* previous value (if exist) will be lost */
176 /* Parameters: */
177 /* node: element pointer. */
178 /* value: pointer to the value that you want to set. */
179 /* len: character number of value. */
180 /* Return: pointer to the NODE_ASN element. */
181 /******************************************************************/
182 node_asn *
183 _asn1_set_value(node_asn *node,const unsigned char *value,unsigned int len)
186 if(node==NULL) return node;
187 if(node->value){
188 _asn1_free(node->value);
189 node->value=NULL;
191 if(!len) return node;
192 node->value=(unsigned char *) _asn1_malloc(len);
193 if (node->value==NULL) return NULL;
195 memcpy(node->value,value,len);
196 return node;
199 /******************************************************************/
200 /* Function : _asn1_set_name */
201 /* Description: sets the field NAME in a NODE_ASN element. The */
202 /* previous value (if exist) will be lost */
203 /* Parameters: */
204 /* node: element pointer. */
205 /* name: a null terminated string with the name that you want */
206 /* to set. */
207 /* Return: pointer to the NODE_ASN element. */
208 /******************************************************************/
209 node_asn *
210 _asn1_set_name(node_asn *node,const char *name)
212 if(node==NULL) return node;
214 if(node->name){
215 _asn1_free(node->name);
216 node->name=NULL;
219 if(name==NULL) return node;
221 if(strlen(name))
223 node->name=(char *) _asn1_strdup( name);
224 if (node->name==NULL) return NULL;
226 else node->name=NULL;
227 return node;
230 /******************************************************************/
231 /* Function : _asn1_set_right */
232 /* Description: sets the field RIGHT in a NODE_ASN element. */
233 /* Parameters: */
234 /* node: element pointer. */
235 /* right: pointer to a NODE_ASN element that you want be pointed*/
236 /* by NODE. */
237 /* Return: pointer to *NODE. */
238 /******************************************************************/
239 node_asn *
240 _asn1_set_right(node_asn *node,node_asn *right)
242 if(node==NULL) return node;
243 node->right=right;
244 if(right) right->left=node;
245 return node;
248 /******************************************************************/
249 /* Function : _asn1_get_right */
250 /* Description: returns the element pointed by the RIGHT field of */
251 /* a NODE_ASN element. */
252 /* Parameters: */
253 /* node: NODE_ASN element pointer. */
254 /* Return: field RIGHT of NODE. */
255 /******************************************************************/
256 node_asn *
257 _asn1_get_right(node_asn *node)
259 if(node==NULL) return NULL;
260 return node->right;
263 /******************************************************************/
264 /* Function : _asn1_get_last_right */
265 /* Description: return the last element along the right chain. */
266 /* Parameters: */
267 /* node: starting element pointer. */
268 /* Return: pointer to the last element along the right chain. */
269 /******************************************************************/
270 node_asn *
271 _asn1_get_last_right(node_asn *node)
273 node_asn *p;
275 if(node==NULL) return NULL;
276 p=node;
277 while(p->right) p=p->right;
278 return p;
281 /******************************************************************/
282 /* Function : _asn1_set_down */
283 /* Description: sets the field DOWN in a NODE_ASN element. */
284 /* Parameters: */
285 /* node: element pointer. */
286 /* down: pointer to a NODE_ASN element that you want be pointed */
287 /* by NODE. */
288 /* Return: pointer to *NODE. */
289 /******************************************************************/
290 node_asn *
291 _asn1_set_down(node_asn *node,node_asn *down)
293 if(node==NULL) return node;
294 node->down=down;
295 if(down) down->left=node;
296 return node;
299 /******************************************************************/
300 /* Function : _asn1_get_down */
301 /* Description: returns the element pointed by the DOWN field of */
302 /* a NODE_ASN element. */
303 /* Parameters: */
304 /* node: NODE_ASN element pointer. */
305 /* Return: field DOWN of NODE. */
306 /******************************************************************/
307 node_asn *
308 _asn1_get_down(node_asn *node)
310 if(node==NULL) return NULL;
311 return node->down;
314 /******************************************************************/
315 /* Function : _asn1_get_name */
316 /* Description: returns the name of a NODE_ASN element. */
317 /* Parameters: */
318 /* node: NODE_ASN element pointer. */
319 /* Return: a null terminated string. */
320 /******************************************************************/
321 char *
322 _asn1_get_name(node_asn *node)
324 if(node==NULL) return NULL;
325 return node->name;
328 /******************************************************************/
329 /* Function : _asn1_mod_type */
330 /* Description: change the field TYPE of an NODE_ASN element. */
331 /* The new value is the old one | (bitwise or) the */
332 /* paramener VALUE. */
333 /* Parameters: */
334 /* node: NODE_ASN element pointer. */
335 /* value: the integer value that must be or-ed with the current */
336 /* value of field TYPE. */
337 /* Return: NODE pointer. */
338 /******************************************************************/
339 node_asn *
340 _asn1_mod_type(node_asn *node,unsigned int value)
342 if(node==NULL) return node;
343 node->type|=value;
344 return node;
348 /******************************************************************/
349 /* Function : _asn1_remove_node */
350 /* Description: gets free the memory allocated for an NODE_ASN */
351 /* element (not the elements pointed by it). */
352 /* Parameters: */
353 /* node: NODE_ASN element pointer. */
354 /******************************************************************/
355 void
356 _asn1_remove_node(node_asn *node)
358 if(node==NULL) return;
360 if (node->name!=NULL)
361 _asn1_free(node->name);
362 if (node->value!=NULL)
363 _asn1_free(node->value);
364 _asn1_free(node);
367 /******************************************************************/
368 /* Function : _asn1_find_up */
369 /* Description: return the father of the NODE_ASN element. */
370 /* Parameters: */
371 /* node: NODE_ASN element pointer. */
372 /* Return: Null if not found. */
373 /******************************************************************/
374 node_asn *
375 _asn1_find_up(node_asn *node)
377 node_asn *p;
379 if(node==NULL) return NULL;
381 p=node;
383 while((p->left!=NULL) && (p->left->right==p)) p=p->left;
385 return p->left;
388 /******************************************************************/
389 /* Function : _asn1_delete_list */
390 /* Description: deletes the list elements (not the elements */
391 /* pointed by them). */
392 /******************************************************************/
393 void
394 _asn1_delete_list(void)
396 list_type *listElement;
398 while(firstElement){
399 listElement=firstElement;
400 firstElement=firstElement->next;
401 _asn1_free(listElement);
405 /******************************************************************/
406 /* Function : _asn1_delete_list_and nodes */
407 /* Description: deletes the list elements and the elements */
408 /* pointed by them. */
409 /******************************************************************/
410 void
411 _asn1_delete_list_and_nodes(void)
413 list_type *listElement;
415 while(firstElement){
416 listElement=firstElement;
417 firstElement=firstElement->next;
418 _asn1_remove_node(listElement->node);
419 _asn1_free(listElement);
424 char *
425 _asn1_ltostr(long v,char *str)
427 long d,r;
428 char temp[20];
429 int count,k,start;
431 if(v<0){
432 str[0]='-';
433 start=1;
434 v=-v;
436 else start=0;
438 count=0;
440 d=v/10;
441 r=v-d*10;
442 temp[start+count]='0'+(char)r;
443 count++;
444 v=d;
445 }while(v);
447 for(k=0;k<count;k++) str[k+start]=temp[start+count-k-1];
448 str[count+start]=0;
449 return str;
453 /******************************************************************/
454 /* Function : _asn1_change_integer_value */
455 /* Description: converts into DER coding the value assign to an */
456 /* INTEGER constant. */
457 /* Parameters: */
458 /* node: root of an ASN1element. */
459 /* Return: */
460 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
461 /* otherwise ASN1_SUCCESS */
462 /******************************************************************/
463 asn1_retCode
464 _asn1_change_integer_value(ASN1_TYPE node)
466 node_asn *p;
467 unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
468 unsigned char val2[SIZEOF_UNSIGNED_LONG_INT+1];
469 int len;
471 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
473 p=node;
474 while(p){
475 if((type_field(p->type)==TYPE_INTEGER) && (p->type&CONST_ASSIGN)){
476 if(p->value){
477 _asn1_convert_integer(p->value,val,sizeof(val), &len);
478 _asn1_octet_der(val,len,val2,&len);
479 _asn1_set_value(p,val2,len);
483 if(p->down){
484 p=p->down;
486 else{
487 if(p==node) p=NULL;
488 else if(p->right) p=p->right;
489 else{
490 while(1){
491 p=_asn1_find_up(p);
492 if(p==node){
493 p=NULL;
494 break;
496 if(p->right){
497 p=p->right;
498 break;
505 return ASN1_SUCCESS;
509 /******************************************************************/
510 /* Function : _asn1_expand_object_id */
511 /* Description: expand the IDs of an OBJECT IDENTIFIER constant. */
512 /* Parameters: */
513 /* node: root of an ASN1 element. */
514 /* Return: */
515 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
516 /* otherwise ASN1_SUCCESS */
517 /******************************************************************/
518 asn1_retCode
519 _asn1_expand_object_id(ASN1_TYPE node)
521 node_asn *p,*p2,*p3,*p4,*p5;
522 char name_root[MAX_NAME_SIZE],name2[2*MAX_NAME_SIZE+1];
523 int move, tlen;
525 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
527 _asn1_str_cpy(name_root, sizeof(name_root), node->name);
529 p=node;
530 move=DOWN;
532 while(!((p==node) && (move==UP))){
533 if(move!=UP){
534 if((type_field(p->type)==TYPE_OBJECT_ID) && (p->type&CONST_ASSIGN)){
535 p2=p->down;
536 if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
537 if(p2->value && !isdigit(p2->value[0])){
538 _asn1_str_cpy(name2, sizeof(name2), name_root);
539 _asn1_str_cat(name2, sizeof(name2), ".");
540 _asn1_str_cat(name2, sizeof(name2), p2->value);
541 p3=_asn1_find_node(node,name2);
542 if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
543 !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
544 _asn1_set_down(p,p2->right);
545 _asn1_remove_node(p2);
546 p2=p;
547 p4=p3->down;
548 while(p4){
549 if(type_field(p4->type)==TYPE_CONSTANT){
550 p5=_asn1_add_node_only(TYPE_CONSTANT);
551 _asn1_set_name(p5,p4->name);
552 tlen = strlen( p4->value);
553 if (tlen > 0)
554 _asn1_set_value(p5,p4->value,tlen+1);
555 if(p2==p){
556 _asn1_set_right(p5,p->down);
557 _asn1_set_down(p,p5);
559 else{
560 _asn1_set_right(p5,p2->right);
561 _asn1_set_right(p2,p5);
563 p2=p5;
565 p4=p4->right;
567 move=DOWN;
568 continue;
572 move=DOWN;
574 else move=RIGHT;
576 if(move==DOWN){
577 if(p->down) p=p->down;
578 else move=RIGHT;
581 if(p==node) {move=UP; continue;}
583 if(move==RIGHT){
584 if(p->right) p=p->right;
585 else move=UP;
587 if(move==UP) p=_asn1_find_up(p);
591 /*******************************/
592 /* expand DEFAULT */
593 /*******************************/
594 p=node;
595 move=DOWN;
597 while(!((p==node) && (move==UP))){
598 if(move!=UP){
599 if((type_field(p->type)==TYPE_OBJECT_ID) &&
600 (p->type&CONST_DEFAULT)){
601 p2=p->down;
602 if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
603 _asn1_str_cpy(name2, sizeof(name2), name_root);
604 _asn1_str_cat(name2, sizeof(name2), ".");
605 _asn1_str_cat(name2, sizeof(name2), p2->value);
606 p3=_asn1_find_node(node,name2);
607 if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
608 !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
609 p4=p3->down;
610 name2[0]=0;
611 while(p4){
612 if(type_field(p4->type)==TYPE_CONSTANT){
613 if(name2[0]) _asn1_str_cat(name2,sizeof(name2),".");
614 _asn1_str_cat(name2,sizeof(name2),p4->value);
616 p4=p4->right;
618 tlen = strlen(name2);
619 if (tlen > 0)
620 _asn1_set_value(p2,name2,tlen+1);
623 move=DOWN;
625 else move=RIGHT;
627 if(move==DOWN){
628 if(p->down) p=p->down;
629 else move=RIGHT;
632 if(p==node) {move=UP; continue;}
634 if(move==RIGHT){
635 if(p->right) p=p->right;
636 else move=UP;
638 if(move==UP) p=_asn1_find_up(p);
641 return ASN1_SUCCESS;
645 /******************************************************************/
646 /* Function : _asn1_type_set_config */
647 /* Description: sets the CONST_SET and CONST_NOT_USED properties */
648 /* in the fields of the SET elements. */
649 /* Parameters: */
650 /* node: root of an ASN1 element. */
651 /* Return: */
652 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
653 /* otherwise ASN1_SUCCESS */
654 /******************************************************************/
655 asn1_retCode
656 _asn1_type_set_config(ASN1_TYPE node)
658 node_asn *p,*p2;
659 int move;
661 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
663 p=node;
664 move=DOWN;
666 while(!((p==node) && (move==UP))){
667 if(move!=UP){
668 if(type_field(p->type)==TYPE_SET){
669 p2=p->down;
670 while(p2){
671 if(type_field(p2->type)!=TYPE_TAG)
672 p2->type|=CONST_SET|CONST_NOT_USED;
673 p2=p2->right;
676 move=DOWN;
678 else move=RIGHT;
680 if(move==DOWN){
681 if(p->down) p=p->down;
682 else move=RIGHT;
685 if(p==node) {move=UP; continue;}
687 if(move==RIGHT){
688 if(p->right) p=p->right;
689 else move=UP;
691 if(move==UP) p=_asn1_find_up(p);
694 return ASN1_SUCCESS;
698 /******************************************************************/
699 /* Function : _asn1_check_identifier */
700 /* Description: checks the definitions of all the identifiers */
701 /* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */
702 /* The _asn1_identifierMissing global variable is filled if */
703 /* necessary. */
704 /* Parameters: */
705 /* node: root of an ASN1 element. */
706 /* Return: */
707 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
708 /* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */
709 /* otherwise ASN1_SUCCESS */
710 /******************************************************************/
711 asn1_retCode
712 _asn1_check_identifier(ASN1_TYPE node)
714 node_asn *p,*p2;
715 char name2[MAX_NAME_SIZE*2+2];
717 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
719 p=node;
720 while(p){
721 if(type_field(p->type)==TYPE_IDENTIFIER){
722 _asn1_str_cpy(name2, sizeof(name2), node->name);
723 _asn1_str_cat(name2, sizeof(name2), ".");
724 _asn1_str_cat(name2, sizeof(name2), p->value);
725 p2=_asn1_find_node(node,name2);
726 if(p2==NULL){
727 strcpy(_asn1_identifierMissing,p->value);
728 return ASN1_IDENTIFIER_NOT_FOUND;
731 else if((type_field(p->type)==TYPE_OBJECT_ID) &&
732 (p->type&CONST_DEFAULT)){
733 p2=p->down;
734 if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
735 _asn1_str_cpy(name2, sizeof(name2), node->name);
736 _asn1_str_cat(name2, sizeof(name2), ".");
737 _asn1_str_cat(name2, sizeof(name2), p2->value);
738 strcpy(_asn1_identifierMissing,p2->value);
739 p2=_asn1_find_node(node,name2);
740 if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
741 !(p2->type&CONST_ASSIGN))
742 return ASN1_IDENTIFIER_NOT_FOUND;
743 else
744 _asn1_identifierMissing[0]=0;
747 else if((type_field(p->type)==TYPE_OBJECT_ID) &&
748 (p->type&CONST_ASSIGN)){
749 p2=p->down;
750 if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
751 if(p2->value && !isdigit(p2->value[0])){
752 _asn1_str_cpy(name2, sizeof(name2), node->name);
753 _asn1_str_cat(name2, sizeof(name2), ".");
754 _asn1_str_cat(name2, sizeof(name2), p2->value);
755 strcpy(_asn1_identifierMissing,p2->value);
756 p2=_asn1_find_node(node,name2);
757 if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
758 !(p2->type&CONST_ASSIGN))
759 return ASN1_IDENTIFIER_NOT_FOUND;
760 else
761 _asn1_identifierMissing[0]=0;
766 if(p->down){
767 p=p->down;
769 else if(p->right) p=p->right;
770 else{
771 while(1){
772 p=_asn1_find_up(p);
773 if(p==node){
774 p=NULL;
775 break;
777 if(p->right){
778 p=p->right;
779 break;
785 return ASN1_SUCCESS;
789 /******************************************************************/
790 /* Function : _asn1_set_default_tag */
791 /* Description: sets the default IMPLICIT or EXPLICIT property in */
792 /* the tagged elements that don't have this declaration. */
793 /* Parameters: */
794 /* node: pointer to a DEFINITIONS element. */
795 /* Return: */
796 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */
797 /* a DEFINITIONS element, */
798 /* otherwise ASN1_SUCCESS */
799 /******************************************************************/
800 asn1_retCode
801 _asn1_set_default_tag(ASN1_TYPE node)
803 node_asn *p;
805 if((node==NULL) || (type_field(node->type)!=TYPE_DEFINITIONS))
806 return ASN1_ELEMENT_NOT_FOUND;
808 p=node;
809 while(p){
810 if((type_field(p->type)==TYPE_TAG) &&
811 !(p->type&CONST_EXPLICIT) &&
812 !(p->type&CONST_IMPLICIT)){
813 if(node->type&CONST_EXPLICIT) p->type|=CONST_EXPLICIT;
814 else p->type|=CONST_IMPLICIT;
817 if(p->down){
818 p=p->down;
820 else if(p->right) p=p->right;
821 else{
822 while(1){
823 p=_asn1_find_up(p);
824 if(p==node){
825 p=NULL;
826 break;
828 if(p->right){
829 p=p->right;
830 break;
836 return ASN1_SUCCESS;
841 static const char*
842 parse_version_number( const char *s, int *number )
844 int val = 0;
846 if( *s == '0' && isdigit(s[1]) )
847 return NULL; /* leading zeros are not allowed */
848 for ( ; isdigit(*s); s++ ) {
849 val *= 10;
850 val += *s - '0';
852 *number = val;
853 return val < 0? NULL : s;
856 /* The parse version functions were copied from libgcrypt.
858 static const char *
859 parse_version_string( const char *s, int *major, int *minor, int *micro )
861 s = parse_version_number( s, major );
862 if( !s || *s != '.' )
863 return NULL;
864 s++;
865 s = parse_version_number( s, minor );
866 if( !s || *s != '.' )
867 return NULL;
868 s++;
869 s = parse_version_number( s, micro );
870 if( !s )
871 return NULL;
872 return s; /* patchlevel */
876 * asn1_check_version - check for library version
877 * @req_version: Required version number, or NULL.
879 * Check that the the version of the library is at minimum the
880 * requested one and return the version string; return %NULL if the
881 * condition is not satisfied. If a %NULL is passed to this function,
882 * no check is done, but the version string is simply returned.
884 * See %LIBTASN1_VERSION for a suitable @req_version string.
886 * Return value: Version string of run-time library, or %NULL if the
887 * run-time library does not meet the required version number.
889 const char *
890 asn1_check_version( const char *req_version )
892 const char *ver = LIBTASN1_VERSION;
893 int my_major, my_minor, my_micro;
894 int rq_major, rq_minor, rq_micro;
895 const char *my_plvl, *rq_plvl;
897 if ( !req_version )
898 return ver;
900 my_plvl = parse_version_string( ver, &my_major, &my_minor, &my_micro );
901 if ( !my_plvl )
902 return NULL; /* very strange our own version is bogus */
903 rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor,
904 &rq_micro );
905 if ( !rq_plvl )
906 return NULL; /* req version string is invalid */
908 if ( my_major > rq_major
909 || (my_major == rq_major && my_minor > rq_minor)
910 || (my_major == rq_major && my_minor == rq_minor
911 && my_micro > rq_micro)
912 || (my_major == rq_major && my_minor == rq_minor
913 && my_micro == rq_micro
914 && strcmp( my_plvl, rq_plvl ) >= 0) ) {
915 return ver;
917 return NULL;