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