6f33563fae61ded8b27adbbc0204d829ec7cbfd5
[platform/upstream/libtasn1.git] / lib / parser_aux.c
1 /*
2  *      Copyright (C) 2000,2001 Fabio Fiorina
3  *
4  * This file is part of LIBASN1.
5  *
6  * The LIBTASN1 library is free software; you can redistribute it and/or
7  * 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,
12  * but 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19  */
20
21 #include <int.h>
22 #include <errors.h>
23 #include "parser_aux.h"
24 #include "der.h"
25 #include "gstr.h"
26 #include "structure.h"
27 #include "element.h"
28
29 char _asn1_identifierMissing[MAX_NAME_SIZE+1]; /* identifier name not found */
30
31 /***********************************************/
32 /* Type: list_type                             */
33 /* Description: type used in the list during   */
34 /* the structure creation.                     */
35 /***********************************************/
36 typedef struct list_struct{
37   node_asn           *node;
38   struct list_struct *next;
39 } list_type;
40
41
42 /* Pointer to the first element of the list */
43 list_type *firstElement=NULL;
44
45 /******************************************************/
46 /* Function : _asn1_add_node                          */
47 /* Description: creates a new NODE_ASN element and    */
48 /* puts it in the list pointed by firstElement.       */
49 /* Parameters:                                        */
50 /*   type: type of the new element (see TYPE_         */
51 /*         and CONST_ constants).                     */
52 /* Return: pointer to the new element.                */
53 /******************************************************/
54 node_asn *
55 _asn1_add_node(unsigned int type)
56 {
57   list_type *listElement;
58   node_asn *punt;
59
60   punt=(node_asn *) _asn1_malloc(sizeof(node_asn));
61   if (punt==NULL) return NULL;
62   
63   listElement=(list_type *) _asn1_malloc(sizeof(list_type));
64   if(listElement==NULL){
65     _asn1_free(punt);
66     return NULL;
67   }
68
69   listElement->node=punt;
70   listElement->next=firstElement;
71   firstElement=listElement;
72
73   punt->left=NULL;
74   punt->name=NULL;
75   punt->type=type; 
76   punt->value=NULL;
77   punt->down=NULL;
78   punt->right=NULL; 
79
80   return punt;
81 }
82
83 /******************************************************************/
84 /* Function : _asn1_find_mode                                     */
85 /* Description: searches an element called NAME starting from     */
86 /*              POINTER. The name is composed by differents       */
87 /*              identifiers separated by dots.When *POINTER has a */
88 /*              name, the first identifier must be the name of    */
89 /*              *POINTER, otherwise it must be the name of one    */
90 /*              child of *POINTER.                                */
91 /* Parameters:                                                    */
92 /*   pointer: NODE_ASN element pointer.                           */
93 /*   name: null terminated string with the element's name to find.*/
94 /* Return: the searching result. NULL if not find.                */
95 /******************************************************************/
96 node_asn *
97 _asn1_find_node(node_asn *pointer,const char *name)
98 {
99   node_asn *p;
100   char *n_end,n[MAX_NAME_SIZE+1];
101   const char *n_start;
102
103   if(pointer == NULL) return NULL;
104
105   if(name==NULL) return NULL;
106
107   p=pointer;
108   n_start=name;
109
110   if(p->name != NULL){ /* has *pointer a name ? */
111     n_end=strchr(n_start,'.');     /* search the first dot */
112     if(n_end){
113       memcpy(n,n_start,n_end-n_start);
114       n[n_end-n_start]=0;
115       n_start=n_end;
116       n_start++;
117     }
118     else{
119       _asn1_str_cpy(n,sizeof(n),n_start);
120       n_start=NULL;
121     }
122     
123     while(p){
124       if((p->name) && (!strcmp(p->name,n))) break;
125       else p=p->right;
126     } /* while */
127     
128     if(p==NULL) return NULL;
129   }
130   else{ /* *pointer doesn't have a name */
131     if(n_start[0]==0)
132       return p;
133   }
134
135   while(n_start){   /* Has the end of NAME been reached? */
136     n_end=strchr(n_start,'.');    /* search the next dot */
137     if(n_end){
138       memcpy(n,n_start,n_end-n_start);
139       n[n_end-n_start]=0;
140       n_start=n_end;
141       n_start++;
142     }
143     else{
144       _asn1_str_cpy(n,sizeof(n),n_start);
145       n_start=NULL;
146     }
147
148     if(p->down==NULL) return NULL;
149
150     p=p->down;
151
152     /* The identifier "?LAST" indicates the last element 
153        in the right chain. */
154     if(!strcmp(n,"?LAST")){
155       if(p==NULL) return NULL;
156       while(p->right) p=p->right;
157     }
158     else{   /* no "?LAST" */
159       while(p){
160         if((p->name) && (!strcmp(p->name,n))) break;
161         else p=p->right;
162       }
163       if(p==NULL) return NULL;
164     }
165   } /* while */
166
167   return p;
168 }
169
170
171 /******************************************************************/
172 /* Function : _asn1_set_value                                     */
173 /* Description: sets the field VALUE in a NODE_ASN element. The   */
174 /*              previus value (if exist) will be lost             */
175 /* Parameters:                                                    */
176 /*   node: element pointer.                                       */
177 /*   value: pointer to the value that you want to set.            */
178 /*   len: character number of value.                              */
179 /* Return: pointer to the NODE_ASN element.                       */
180 /******************************************************************/
181 node_asn *
182 _asn1_set_value(node_asn *node,const unsigned char *value,unsigned int len)
183 {
184
185   if(node==NULL) return node;
186   if(node->value){
187     _asn1_free(node->value);
188     node->value=NULL;  
189   }
190   if(!len) return node;
191   node->value=(unsigned char *) _asn1_malloc(len);
192   if (node->value==NULL) return NULL;
193   
194   memcpy(node->value,value,len);
195   return node;
196 }
197
198 /******************************************************************/
199 /* Function : _asn1_set_name                                      */
200 /* Description: sets the field NAME in a NODE_ASN element. The    */
201 /*              previus value (if exist) will be lost             */
202 /* Parameters:                                                    */
203 /*   node: element pointer.                                       */
204 /*   name: a null terminated string with the name that you want   */
205 /*         to set.                                                */
206 /* Return: pointer to the NODE_ASN element.                       */
207 /******************************************************************/
208 node_asn *
209 _asn1_set_name(node_asn *node,const char *name)
210 {
211   if(node==NULL) return node;
212
213   if(node->name){
214     _asn1_free(node->name);
215     node->name=NULL;
216   }
217
218   if(name==NULL) return node;
219
220   if(strlen(name))
221         {
222         node->name=(char *) _asn1_strdup( name);
223         if (node->name==NULL) return NULL;
224       }
225   else node->name=NULL;
226   return node;
227 }
228
229 /******************************************************************/
230 /* Function : _asn1_set_right                                     */
231 /* Description: sets the field RIGHT in a NODE_ASN element.       */
232 /* Parameters:                                                    */
233 /*   node: element pointer.                                       */
234 /*   right: pointer to a NODE_ASN element that you want be pointed*/
235 /*          by NODE.                                              */
236 /* Return: pointer to *NODE.                                      */
237 /******************************************************************/
238 node_asn *
239 _asn1_set_right(node_asn *node,node_asn *right)
240 {
241   if(node==NULL) return node;
242   node->right=right;
243   if(right) right->left=node;
244   return node;
245 }
246
247 /******************************************************************/
248 /* Function : _asn1_get_right                                     */
249 /* Description: returns the element pointed by the RIGHT field of */
250 /*              a NODE_ASN element.                               */
251 /* Parameters:                                                    */
252 /*   node: NODE_ASN element pointer.                              */
253 /* Return: field RIGHT of NODE.                                   */
254 /******************************************************************/
255 node_asn *
256 _asn1_get_right(node_asn *node)
257 {
258   if(node==NULL) return NULL;
259   return node->right;
260 }
261
262 /******************************************************************/
263 /* Function : _asn1_get_last_right                                */
264 /* Description: return the last element along the right chain.    */
265 /* Parameters:                                                    */
266 /*   node: starting element pointer.                              */
267 /* Return: pointer to the last element along the right chain.     */
268 /******************************************************************/
269 node_asn *
270 _asn1_get_last_right(node_asn *node)
271 {
272   node_asn *p;
273
274   if(node==NULL) return NULL;
275   p=node;
276   while(p->right) p=p->right;
277   return p;
278 }
279
280 /******************************************************************/
281 /* Function : _asn1_set_down                                      */
282 /* Description: sets the field DOWN in a NODE_ASN element.        */
283 /* Parameters:                                                    */
284 /*   node: element pointer.                                       */
285 /*   down: pointer to a NODE_ASN element that you want be pointed */
286 /*          by NODE.                                              */
287 /* Return: pointer to *NODE.                                      */
288 /******************************************************************/
289 node_asn *
290 _asn1_set_down(node_asn *node,node_asn *down)
291 {
292   if(node==NULL) return node;
293   node->down=down;
294   if(down) down->left=node;
295   return node;
296 }
297
298 /******************************************************************/
299 /* Function : _asn1_get_down                                      */
300 /* Description: returns the element pointed by the DOWN field of  */
301 /*              a NODE_ASN element.                               */
302 /* Parameters:                                                    */
303 /*   node: NODE_ASN element pointer.                              */
304 /* Return: field DOWN of NODE.                                    */
305 /******************************************************************/
306 node_asn *
307 _asn1_get_down(node_asn *node)
308 {
309   if(node==NULL) return NULL;
310   return node->down;
311 }
312
313 /******************************************************************/
314 /* Function : _asn1_get_name                                      */
315 /* Description: returns the name of a NODE_ASN element.           */
316 /* Parameters:                                                    */
317 /*   node: NODE_ASN element pointer.                              */
318 /* Return: a null terminated string.                              */
319 /******************************************************************/
320 char *
321 _asn1_get_name(node_asn *node)
322 {
323   if(node==NULL) return NULL;
324   return node->name;
325 }
326
327 /******************************************************************/
328 /* Function : _asn1_mod_type                                      */
329 /* Description: change the field TYPE of an NODE_ASN element.     */
330 /*              The new value is the old one | (bitwise or) the   */
331 /*              paramener VALUE.                                  */
332 /* Parameters:                                                    */
333 /*   node: NODE_ASN element pointer.                              */
334 /*   value: the integer value that must be or-ed with the current */
335 /*          value of field TYPE.                                  */
336 /* Return: NODE pointer.                                          */
337 /******************************************************************/
338 node_asn *
339 _asn1_mod_type(node_asn *node,unsigned int value)
340 {
341   if(node==NULL) return node;
342   node->type|=value;
343   return node;
344 }
345
346
347 /******************************************************************/
348 /* Function : _asn1_remove_node                                   */
349 /* Description: gets free the memory allocated for an NODE_ASN    */
350 /*              element (not the elements pointed by it).         */
351 /* Parameters:                                                    */
352 /*   node: NODE_ASN element pointer.                              */
353 /******************************************************************/
354 void
355 _asn1_remove_node(node_asn *node)
356 {
357   if(node==NULL) return;
358
359   if (node->name!=NULL)
360           _asn1_free(node->name);
361   if (node->value!=NULL)
362           _asn1_free(node->value);
363   _asn1_free(node);
364 }
365
366 /******************************************************************/
367 /* Function : _asn1_find_up                                       */
368 /* Description: return the father of the NODE_ASN element.        */
369 /* Parameters:                                                    */
370 /*   node: NODE_ASN element pointer.                              */
371 /* Return: Null if not found.                                     */ 
372 /******************************************************************/
373 node_asn *
374 _asn1_find_up(node_asn *node)
375 {
376   node_asn *p;
377
378   if(node==NULL) return NULL;
379
380   p=node;
381
382   while((p->left!=NULL) && (p->left->right==p)) p=p->left;
383
384   return p->left;
385 }
386
387 /******************************************************************/
388 /* Function : _asn1_delete_list                                   */
389 /* Description: deletes the list elements (not the elements       */
390 /*  pointed by them).                                             */
391 /******************************************************************/
392 void
393 _asn1_delete_list(void)
394 {
395   list_type *listElement;
396
397   while(firstElement){
398     listElement=firstElement;
399     firstElement=firstElement->next;
400     _asn1_free(listElement);
401   }
402 }
403
404 /******************************************************************/
405 /* Function : _asn1_delete_list_and nodes                         */
406 /* Description: deletes the list elements and the elements        */
407 /*  pointed by them.                                              */
408 /******************************************************************/
409 void
410 _asn1_delete_list_and_nodes(void)
411 {
412   list_type *listElement;
413
414   while(firstElement){
415     listElement=firstElement;
416     firstElement=firstElement->next;
417     _asn1_remove_node(listElement->node);
418     _asn1_free(listElement);
419   }
420 }
421
422
423 char *
424 _asn1_ltostr(long v,char *str)
425 {
426   long d,r;
427   char temp[20];
428   int count,k,start;
429
430   if(v<0){
431     str[0]='-';
432     start=1;
433     v=-v;
434   }
435   else start=0;
436
437   count=0;
438   do{
439     d=v/10;
440     r=v-d*10;
441     temp[start+count]='0'+(char)r;
442     count++;
443     v=d;
444   }while(v);
445
446   for(k=0;k<count;k++) str[k+start]=temp[start+count-k-1];
447   str[count+start]=0;
448   return str;
449 }
450
451
452 /******************************************************************/
453 /* Function : _asn1_change_integer_value                          */
454 /* Description: converts into DER coding the value assign to an   */
455 /*   INTEGER constant.                                            */
456 /* Parameters:                                                    */
457 /*   node: root of an ASN1element.                                */
458 /* Return:                                                        */
459 /*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
460 /*   otherwise ASN1_SUCCESS                                             */
461 /******************************************************************/
462 asn1_retCode 
463 _asn1_change_integer_value(ASN1_TYPE node)
464 {
465   node_asn *p;
466   unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
467   unsigned char val2[SIZEOF_UNSIGNED_LONG_INT+1];
468   int len;
469
470   if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
471
472   p=node;
473   while(p){
474     if((type_field(p->type)==TYPE_INTEGER) && (p->type&CONST_ASSIGN)){
475       if(p->value){
476         _asn1_convert_integer(p->value,val,sizeof(val), &len);  
477         _asn1_octet_der(val,len,val2,&len);
478         _asn1_set_value(p,val2,len);
479       }
480     }
481
482     if(p->down){
483       p=p->down;
484     }
485     else{
486       if(p==node) p=NULL;
487       else if(p->right) p=p->right;
488       else{
489         while(1){
490           p=_asn1_find_up(p);
491           if(p==node){
492             p=NULL;
493             break;
494           }
495           if(p->right){
496             p=p->right;
497             break;
498           }
499         }
500       }
501     }
502   }
503
504   return ASN1_SUCCESS;
505 }
506
507
508 /******************************************************************/
509 /* Function : _asn1_expand_object_id                              */
510 /* Description: expand the IDs of an OBJECT IDENTIFIER constant.  */
511 /* Parameters:                                                    */
512 /*   node: root of an ASN1 element.                               */
513 /* Return:                                                        */
514 /*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
515 /*   otherwise ASN1_SUCCESS                                             */
516 /******************************************************************/
517 asn1_retCode
518 _asn1_expand_object_id(ASN1_TYPE node)
519 {
520   node_asn *p,*p2,*p3,*p4,*p5;
521   char name_root[MAX_NAME_SIZE],name2[2*MAX_NAME_SIZE+1];
522   int move;
523  
524   if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
525
526   _asn1_str_cpy(name_root, sizeof(name_root), node->name);
527
528   p=node;
529   move=DOWN;
530
531   while(!((p==node) && (move==UP))){
532     if(move!=UP){
533       if((type_field(p->type)==TYPE_OBJECT_ID) && (p->type&CONST_ASSIGN)){
534         p2=p->down;
535         if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
536           if(p2->value && !isdigit(p2->value[0])){
537             _asn1_str_cpy(name2, sizeof(name2), name_root);
538             _asn1_str_cat(name2, sizeof(name2), ".");
539             _asn1_str_cat(name2, sizeof(name2), p2->value);
540             p3=_asn1_find_node(node,name2);
541             if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
542                !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
543             _asn1_set_down(p,p2->right);
544             _asn1_remove_node(p2);
545             p2=p;
546             p4=p3->down;
547             while(p4){
548               if(type_field(p4->type)==TYPE_CONSTANT){
549                 p5=_asn1_add_node_only(TYPE_CONSTANT);
550                 _asn1_set_name(p5,p4->name);
551                 _asn1_set_value(p5,p4->value,strlen(p4->value)+1);
552                 if(p2==p){
553                   _asn1_set_right(p5,p->down);
554                   _asn1_set_down(p,p5);
555                 }
556                 else{
557                   _asn1_set_right(p5,p2->right);
558                   _asn1_set_right(p2,p5);
559                 }
560                 p2=p5;
561               }
562               p4=p4->right;
563             }
564             move=DOWN;
565             continue;
566           }
567         }
568       }
569       move=DOWN;
570     }
571     else move=RIGHT;
572
573     if(move==DOWN){
574       if(p->down) p=p->down;
575       else move=RIGHT;
576     }
577     
578     if(p==node) {move=UP; continue;}
579
580     if(move==RIGHT){
581       if(p->right) p=p->right;
582       else move=UP;
583     }
584     if(move==UP) p=_asn1_find_up(p);
585   }
586
587
588   /*******************************/
589   /*       expand DEFAULT        */
590   /*******************************/
591   p=node;
592   move=DOWN;
593
594   while(!((p==node) && (move==UP))){
595     if(move!=UP){
596       if((type_field(p->type)==TYPE_OBJECT_ID) && 
597          (p->type&CONST_DEFAULT)){
598         p2=p->down;
599         if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
600           _asn1_str_cpy(name2, sizeof(name2), name_root);
601           _asn1_str_cat(name2, sizeof(name2), ".");
602           _asn1_str_cat(name2, sizeof(name2), p2->value);
603           p3=_asn1_find_node(node,name2);
604           if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
605              !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
606           p4=p3->down;
607           name2[0]=0;
608           while(p4){
609             if(type_field(p4->type)==TYPE_CONSTANT){
610               if(name2[0]) _asn1_str_cat(name2,sizeof(name2),".");
611               _asn1_str_cat(name2,sizeof(name2),p4->value);
612             }
613             p4=p4->right;
614           }
615           _asn1_set_value(p2,name2,strlen(name2)+1);
616         }
617       }
618       move=DOWN;
619     }
620     else move=RIGHT;
621
622     if(move==DOWN){
623       if(p->down) p=p->down;
624       else move=RIGHT;
625     }
626     
627     if(p==node) {move=UP; continue;}
628
629     if(move==RIGHT){
630       if(p->right) p=p->right;
631       else move=UP;
632     }
633     if(move==UP) p=_asn1_find_up(p);
634   }
635
636   return ASN1_SUCCESS;
637 }
638
639
640 /******************************************************************/
641 /* Function : _asn1_type_set_config                               */
642 /* Description: sets the CONST_SET and CONST_NOT_USED properties  */
643 /*   in the fields of the SET elements.                           */
644 /* Parameters:                                                    */
645 /*   node: root of an ASN1 element.                               */
646 /* Return:                                                        */
647 /*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
648 /*   otherwise ASN1_SUCCESS                                             */
649 /******************************************************************/
650 asn1_retCode 
651 _asn1_type_set_config(ASN1_TYPE node)
652 {
653   node_asn *p,*p2;
654   int move;
655  
656   if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
657
658   p=node;
659   move=DOWN;
660
661   while(!((p==node) && (move==UP))){
662     if(move!=UP){
663       if(type_field(p->type)==TYPE_SET){
664         p2=p->down;
665         while(p2){
666           if(type_field(p2->type)!=TYPE_TAG) 
667             p2->type|=CONST_SET|CONST_NOT_USED;
668           p2=p2->right;
669         }
670       }
671       move=DOWN;
672     }
673     else move=RIGHT;
674
675     if(move==DOWN){
676       if(p->down) p=p->down;
677       else move=RIGHT;
678     }
679
680     if(p==node) {move=UP; continue;}
681
682     if(move==RIGHT){
683       if(p->right) p=p->right;
684       else move=UP;
685     }
686     if(move==UP) p=_asn1_find_up(p);
687   }
688
689   return ASN1_SUCCESS;
690 }
691
692
693 /******************************************************************/
694 /* Function : _asn1_check_identifier                              */
695 /* Description: checks the definitions of all the identifiers     */
696 /*   and the first element of an OBJECT_ID (e.g. {pkix 0 4}).     */
697 /*   The _asn1_identifierMissing global variable is filled if     */
698 /*   necessary.                                                   */
699 /* Parameters:                                                    */
700 /*   node: root of an ASN1 element.                               */
701 /* Return:                                                        */
702 /*   ASN1_ELEMENT_NOT_FOUND      if NODE is NULL,                 */
703 /*   ASN1_IDENTIFIER_NOT_FOUND   if an identifier is not defined, */
704 /*   otherwise ASN1_SUCCESS                                       */
705 /******************************************************************/
706 asn1_retCode 
707 _asn1_check_identifier(ASN1_TYPE node)
708 {
709   node_asn *p,*p2;
710   char name2[MAX_NAME_SIZE*2+2];
711
712   if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
713
714   p=node;
715   while(p){
716     if(type_field(p->type)==TYPE_IDENTIFIER){
717       _asn1_str_cpy(name2, sizeof(name2), node->name);
718       _asn1_str_cat(name2, sizeof(name2), ".");
719       _asn1_str_cat(name2, sizeof(name2), p->value);
720       p2=_asn1_find_node(node,name2);
721       if(p2==NULL){
722         strcpy(_asn1_identifierMissing,p->value);
723         return ASN1_IDENTIFIER_NOT_FOUND;
724       } 
725     }
726     else if((type_field(p->type)==TYPE_OBJECT_ID) && 
727             (p->type&CONST_DEFAULT)){
728       p2=p->down;
729       if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
730         _asn1_str_cpy(name2, sizeof(name2), node->name);
731         _asn1_str_cat(name2, sizeof(name2), ".");
732         _asn1_str_cat(name2, sizeof(name2), p2->value);
733         strcpy(_asn1_identifierMissing,p2->value);
734         p2=_asn1_find_node(node,name2);
735         if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
736            !(p2->type&CONST_ASSIGN))
737           return ASN1_IDENTIFIER_NOT_FOUND;
738         else
739           _asn1_identifierMissing[0]=0;
740       }
741     }
742     else if((type_field(p->type)==TYPE_OBJECT_ID) && 
743             (p->type&CONST_ASSIGN)){
744       p2=p->down;
745       if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
746         if(p2->value && !isdigit(p2->value[0])){
747           _asn1_str_cpy(name2, sizeof(name2), node->name);
748           _asn1_str_cat(name2, sizeof(name2), ".");
749           _asn1_str_cat(name2, sizeof(name2), p2->value);
750           strcpy(_asn1_identifierMissing,p2->value);
751           p2=_asn1_find_node(node,name2);
752           if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
753              !(p2->type&CONST_ASSIGN))
754             return ASN1_IDENTIFIER_NOT_FOUND;
755           else
756             _asn1_identifierMissing[0]=0;
757         }
758       }
759     }
760     
761     if(p->down){
762       p=p->down;
763     }
764     else if(p->right) p=p->right;
765     else{
766       while(1){
767         p=_asn1_find_up(p);
768         if(p==node){
769           p=NULL;
770           break;
771         }
772         if(p->right){
773           p=p->right;
774           break;
775         }
776       }
777     }
778   }
779
780   return ASN1_SUCCESS;
781 }
782
783
784 /******************************************************************/
785 /* Function : _asn1_set_default_tag                               */
786 /* Description: sets the default IMPLICIT or EXPLICIT property in */
787 /*   the tagged elements that don't have this declaration.        */
788 /* Parameters:                                                    */
789 /*   node: pointer to a DEFINITIONS element.                      */
790 /* Return:                                                        */
791 /*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to    */
792 /*     a DEFINITIONS element,                                     */
793 /*   otherwise ASN1_SUCCESS                                             */
794 /******************************************************************/
795 asn1_retCode 
796 _asn1_set_default_tag(ASN1_TYPE node)
797 {
798   node_asn *p;
799
800   if((node==NULL) || (type_field(node->type)!=TYPE_DEFINITIONS))
801     return ASN1_ELEMENT_NOT_FOUND; 
802
803   p=node;
804   while(p){
805     if((type_field(p->type)==TYPE_TAG) &&
806             !(p->type&CONST_EXPLICIT) &&
807             !(p->type&CONST_IMPLICIT)){
808       if(node->type&CONST_EXPLICIT) p->type|=CONST_EXPLICIT;
809       else p->type|=CONST_IMPLICIT;
810     }
811
812     if(p->down){
813       p=p->down;
814     }
815     else if(p->right) p=p->right;
816     else{
817       while(1){
818           p=_asn1_find_up(p);
819           if(p==node){
820             p=NULL;
821             break;
822           }
823           if(p->right){
824             p=p->right;
825             break;
826           }
827       }
828     }
829   }
830
831   return ASN1_SUCCESS;
832 }
833
834
835
836 static const char*
837 parse_version_number( const char *s, int *number )
838 {
839     int val = 0;
840
841     if( *s == '0' && isdigit(s[1]) )
842         return NULL; /* leading zeros are not allowed */
843     for ( ; isdigit(*s); s++ ) {
844         val *= 10;
845         val += *s - '0';
846     }
847     *number = val;
848     return val < 0? NULL : s;
849 }
850
851 /* The parse version functions were copied from libgcrypt.
852  */
853 static const char *
854 parse_version_string( const char *s, int *major, int *minor, int *micro )
855 {
856     s = parse_version_number( s, major );
857     if( !s || *s != '.' )
858         return NULL;
859     s++;
860     s = parse_version_number( s, minor );
861     if( !s || *s != '.' )
862         return NULL;
863     s++;
864     s = parse_version_number( s, micro );
865     if( !s )
866         return NULL;
867     return s; /* patchlevel */
868 }
869
870 /**
871   * asn1_check_version - This function checks the library's version
872   * @req_version: the version to check
873   *
874   * Check that the the version of the library is at minimum the requested one
875   * and return the version string; return NULL if the condition is not
876   * satisfied.  If a NULL is passed to this function, no check is done,
877   * but the version string is simply returned.
878   *
879   **/
880 const char *
881 asn1_check_version( const char *req_version )
882 {
883     const char *ver = LIBTASN1_VERSION;
884     int my_major, my_minor, my_micro;
885     int rq_major, rq_minor, rq_micro;
886     const char *my_plvl, *rq_plvl;
887
888     if ( !req_version )
889         return ver;
890
891     my_plvl = parse_version_string( ver, &my_major, &my_minor, &my_micro );
892     if ( !my_plvl )
893         return NULL;  /* very strange our own version is bogus */
894     rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor,
895                                                                 &rq_micro );
896     if ( !rq_plvl )
897         return NULL;  /* req version string is invalid */
898
899     if ( my_major > rq_major
900         || (my_major == rq_major && my_minor > rq_minor)
901         || (my_major == rq_major && my_minor == rq_minor
902                                  && my_micro > rq_micro)
903         || (my_major == rq_major && my_minor == rq_minor
904                                  && my_micro == rq_micro
905                                  && strcmp( my_plvl, rq_plvl ) >= 0) ) {
906         return ver;
907     }
908     return NULL;
909 }
910
911