Add BER decoding
authorFabio Fiorina <fiorinaf@gnutls.org>
Wed, 30 Jul 2003 19:50:34 +0000 (19:50 +0000)
committerFabio Fiorina <fiorinaf@gnutls.org>
Wed, 30 Jul 2003 19:50:34 +0000 (19:50 +0000)
18 files changed:
NEWS
configure.in
lib/Makefile.am
lib/coding.c
lib/decoding.c
lib/der.h
lib/element.c
lib/int.h
lib/libtasn1.h
src/CertificateExample.c
src/CrlExample.c
src/asn1Coding.c
src/asn1Decoding.c
src/asn1Parser.c
src/asn1c.c
tests/Test_parser.c
tests/Test_tree.asn
tests/Test_tree.c

diff --git a/NEWS b/NEWS
index be38cd2..041ea42 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,17 @@
+Version 0.2.5
+- Bug fix in ordering procedure for SET OF and SEQUENCE OF
+  types coding.
+- Manage structured format (BER encoding) in
+  asn1_der_decoding, asn1_decoding_element and 
+  asn1_der_decoding_startEnd for OCTET STRING type.
+- Manage SEQUENCE and SET empty structure. 
+- Manage "indefinite length method" in asn1_der_decoding,
+  asn1_decoding_element and asn1_der_decoding_startEnd 
+  for the following types:
+  SEQUENCE, SEQUENCE OF, SET, and SET OF.
+- Bug fix in asn1_read_value with NULL parameter in case
+  of BIT STRING
+
 Version 0.2.4
 - Bug fix in asn1_der_coding with NULL parameter
 - Manage DEFAULT option with OBJECT IDENTIFIER
index 261c3e9..a197fc3 100644 (file)
@@ -12,7 +12,7 @@ AC_DEFINE_UNQUOTED(T_OS, "$target_os")
 dnl libtasn1 Version
 ASN1_MAJOR_VERSION=0
 ASN1_MINOR_VERSION=2
-ASN1_MICRO_VERSION=4
+ASN1_MICRO_VERSION=5
 ASN1_VERSION=$ASN1_MAJOR_VERSION.$ASN1_MINOR_VERSION.$ASN1_MICRO_VERSION
 
 AC_DEFINE_UNQUOTED(ASN1_VERSION, "$ASN1_VERSION")
index 15d24b5..06738f5 100644 (file)
@@ -12,7 +12,7 @@ COBJECTS = ASN1.y decoding.c gstr.c errors.c parser_aux.c \
 
 libtasn1_la_SOURCES = $(COBJECTS) 
 
-libtasn1_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+libtasn1_la_LDFLAGS = -no-undefined -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
 
 asn1-api.tex: $(COBJECTS)
        @echo "% \\newpage" > asn1-api.tex
index ed38411..d46dc7b 100644 (file)
@@ -111,7 +111,7 @@ _asn1_tag_der(unsigned char class,unsigned int tag_value,unsigned char *ans,int
   int k;
   unsigned char temp[SIZEOF_UNSIGNED_INT];
 
-  if(tag_value<30){
+  if(tag_value<31){
     /* short form */
     ans[0]=(class&0xE0) + ((unsigned char)(tag_value&0x1F));
     *ans_len=1;
@@ -592,8 +592,8 @@ _asn1_ordering_set(unsigned char *der,node_asn *node)
        if (temp==NULL) return;
        
        memcpy(temp,der+counter,p_vet->end-counter);
-       memmove(der+counter,der+p_vet->end,p2_vet->end-p_vet->end);
-       memcpy(der+p_vet->end,temp,p_vet->end-counter);
+       memcpy(der+counter,der+p_vet->end,p2_vet->end-p_vet->end);
+       memcpy(der+counter+p2_vet->end-p_vet->end,temp,p_vet->end-counter);
        _asn1_afree(temp);
        
        tag=p_vet->value;
@@ -693,9 +693,9 @@ _asn1_ordering_set_of(unsigned char *der,node_asn *node)
        temp=(unsigned char *)_asn1_alloca(p_vet->end-counter);
        if (temp==NULL) return;
        
-       memcpy(temp,der+counter,p_vet->end-counter);
-       memmove(der+counter,der+p_vet->end,p2_vet->end-p_vet->end);
-       memcpy(der+p_vet->end,temp,p_vet->end-counter);
+       memcpy(temp,der+counter,(p_vet->end)-counter);
+       memcpy(der+counter,der+(p_vet->end),(p2_vet->end)-(p_vet->end));
+       memcpy(der+counter+(p2_vet->end)-(p_vet->end),temp,(p_vet->end)-counter);
        _asn1_afree(temp);
        
        p_vet->end=counter+(p2_vet->end-p_vet->end);
@@ -740,7 +740,7 @@ asn1_retCode
 asn1_der_coding(ASN1_TYPE element,const char *name,unsigned char *der,int *len,
                 char *ErrorDescription)
 {
-  node_asn *node,*p;
+  node_asn *node,*p,*p2;
   char temp[SIZEOF_UNSIGNED_LONG_INT*3+1];
   int counter,counter_old,len2,len3,move,max_len,max_len_old;
   asn1_retCode ris;
@@ -875,7 +875,21 @@ asn1_der_coding(ASN1_TYPE element,const char *name,unsigned char *der,int *len,
       if(move!=UP){
        _asn1_ltostr(counter,temp);
        _asn1_set_value(p,temp,strlen(temp)+1);
-       move=DOWN;
+       if(p->down==NULL){
+         move=UP;
+         continue;
+       }
+       else{
+         p2=p->down;
+         while(p2 && (type_field(p2->type)==TYPE_TAG)) p2=p2->right;
+         if(p2){
+           p=p2;
+           move=RIGHT;
+           continue;
+         }
+         move=UP;
+         continue;
+       }
       }
       else{   /* move==UP */
        len2=strtol(p->value,NULL,10);
@@ -892,7 +906,7 @@ asn1_der_coding(ASN1_TYPE element,const char *name,unsigned char *der,int *len,
        move=RIGHT;
       }
       break;
-    case TYPE_SEQUENCE_OF: case TYPE_SET_OF: 
+    case TYPE_SEQUENCE_OF: case TYPE_SET_OF:
       if(move!=UP){
        _asn1_ltostr(counter,temp);
        _asn1_set_value(p,temp,strlen(temp)+1);
index 29dc9c9..3e3e9d8 100644 (file)
@@ -17,7 +17,7 @@
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  */
-
 
 /*****************************************************/
 /* File: decoding.c                                  */
@@ -45,7 +45,7 @@ _asn1_error_description_tag_error(node_asn *node,char *ErrorDescription)
 }
 
   
-unsigned long
+signed long
 _asn1_get_length_der(const unsigned char *der,int  *len)
 {
   unsigned long ans;
@@ -60,9 +60,14 @@ _asn1_get_length_der(const unsigned char *der,int  *len)
     /* Long form */
     k=der[0]&0x7F;
     punt=1;
-    ans=0;
-    while(punt<=k) ans=ans*256+der[punt++];
-    
+    if(k){  /* definite length method */
+      ans=0;
+      while(punt<=k) ans=ans*256+der[punt++];
+    }
+    else{  /* indefinite lenght method */
+      ans=-1;
+    }
+
     *len=punt;
     return ans;
   }
@@ -170,17 +175,17 @@ _asn1_get_bit_der(const unsigned char *der,int *der_len,unsigned char *str, int
 {
   int len_len,len_byte;
 
-  if(str==NULL) return ASN1_SUCCESS;
   len_byte=_asn1_get_length_der(der,&len_len)-1;
 
   *der_len=len_byte+len_len+1;  
+  *bit_len=len_byte*8-der[len_len];
+
   if (str_size >= len_byte)
        memcpy(str,der+len_len+1,len_byte);
   else {
        return ASN1_MEM_ERROR;
   }
-  *bit_len=len_byte*8-der[len_len];
-
   return ASN1_SUCCESS;
 }
 
@@ -195,7 +200,9 @@ _asn1_extract_tag_der(node_asn *node,const unsigned char *der,int *der_len)
   unsigned long tag,tag_implicit=0;
   unsigned char class,class2,class_implicit=0;
 
+
   counter=is_tag_implicit=0;
+
   if(node->type&CONST_TAG){
     p=node->down;
     while(p){
@@ -239,7 +246,15 @@ _asn1_extract_tag_der(node_asn *node,const unsigned char *der,int *der_len)
 
   if(is_tag_implicit){
     tag=_asn1_get_tag_der(der+counter,&class,&len2);
-    if((class!=class_implicit) || (tag!=tag_implicit)) return ASN1_TAG_ERROR;
+    if((class!=class_implicit) || (tag!=tag_implicit)){
+      if(type_field(node->type)==TYPE_OCTET_STRING){
+       class_implicit |= STRUCTURED;
+       if((class!=class_implicit) || (tag!=tag_implicit))
+         return ASN1_TAG_ERROR;
+      }
+      else
+       return ASN1_TAG_ERROR;
+    }
   }
   else{
     if(type_field(node->type)==TYPE_TAG){
@@ -275,7 +290,8 @@ _asn1_extract_tag_der(node_asn *node,const unsigned char *der,int *der_len)
       }
       break;
     case TYPE_OCTET_STRING:
-      if((class!=UNIVERSAL) || (tag!=TAG_OCTET_STRING)) return ASN1_DER_ERROR;
+      if(((class!=UNIVERSAL) && (class!=(UNIVERSAL|STRUCTURED)))
+        || (tag!=TAG_OCTET_STRING)) return ASN1_DER_ERROR;
       break;
     case TYPE_GENERALSTRING:
       if((class!=UNIVERSAL) || (tag!=TAG_GENERALSTRING)) return ASN1_DER_ERROR;
@@ -352,6 +368,119 @@ _asn1_delete_not_used(node_asn *node)
 }
 
 
+asn1_retCode
+_asn1_get_octet_string(const unsigned char* der,node_asn *node,int* len)
+{
+  int len2,len3,counter,counter2,counter_end,tot_len,indefinite;
+  char *temp,*temp2;
+
+  counter=0;
+
+  if(*(der-1) & STRUCTURED){
+    tot_len=0;
+    indefinite=_asn1_get_length_der(der,&len3);
+
+    counter+=len3;
+    if(indefinite>=0) indefinite+=len3;
+    while(1){
+      if(counter>(*len)) return ASN1_DER_ERROR;
+
+      if(indefinite==-1){
+       if((der[counter]==0) && (der[counter+1]==0)){
+         counter+=2;
+         break;
+       }
+      }
+      else if(counter>=indefinite) break;
+
+      if(der[counter] != TAG_OCTET_STRING) return ASN1_DER_ERROR;
+       
+      counter++;
+
+      len2=_asn1_get_length_der(der+counter,&len3);
+      if(len2 <= 0) return ASN1_DER_ERROR;
+
+      counter+=len3+len2;
+      tot_len+=len2;
+    }
+
+    /* copy */
+    if(node){
+      _asn1_length_der(tot_len,NULL,&len2);
+      temp=(unsigned char *)_asn1_alloca(len2+tot_len);
+      if (temp==NULL){
+       return ASN1_MEM_ALLOC_ERROR;
+      }
+      
+      _asn1_length_der(tot_len,temp,&len2);
+      tot_len+=len2;
+      temp2=temp+len2;
+      len2=_asn1_get_length_der(der,&len3);
+      counter2=len3+1;
+
+      if(indefinite==-1) counter_end=counter-2;
+      else counter_end=counter;
+      
+      while(counter2<counter_end){
+       len2=_asn1_get_length_der(der+counter2,&len3);  
+       memcpy(temp2,der+counter2+len3,len2);
+       temp2+=len2;
+       counter2+=len2+len3+1;
+      }
+      _asn1_set_value(node,temp,tot_len);
+      _asn1_afree(temp);
+    }
+  }
+  else{  /* NOT STRUCTURED */
+    len2=_asn1_get_length_der(der,&len3);
+    if(node)
+      _asn1_set_value(node,der,len3+len2);
+    counter=len3+len2;
+  }   
+
+  *len=counter;
+  return ASN1_SUCCESS;
+
+}
+
+
+asn1_retCode
+_asn1_get_indefinite_length_string(const unsigned char* der,int* len)
+{
+  int len2,len3,counter,indefinite;
+  unsigned int tag;
+  unsigned char class;
+
+  counter=indefinite=0;
+
+  while(1){
+    if((*len)<counter) return ASN1_DER_ERROR;
+
+    if((der[counter]==0) && (der[counter+1]==0)){
+      counter+=2;
+      indefinite--;
+      if(indefinite<=0) break;
+      else continue;
+    }
+
+    tag=_asn1_get_tag_der(der+counter,&class,&len2);
+    counter+=len2;
+    len2=_asn1_get_length_der(der+counter,&len3);
+    if(len2 == -1){
+      indefinite++;
+      counter+=1;
+    }
+    else{
+      counter+=len2+len3;
+    }
+  }
+
+  *len=counter;
+  return ASN1_SUCCESS;
+
+}
+
 
 /**
   * asn1_der_decoding - Fill the structure *ELEMENT with values of a DER encoding string.
@@ -383,6 +512,7 @@ asn1_der_decoding(ASN1_TYPE *element,const unsigned char *der,int len,
   int counter,len2,len3,len4,move,ris;
   unsigned char class,*temp2;
   unsigned int tag;
+  int indefinite;
 
   node=*element;
 
@@ -398,12 +528,19 @@ asn1_der_decoding(ASN1_TYPE *element,const unsigned char *der,int len,
   p=node;
   while(1){
     ris=ASN1_SUCCESS;
-
     if(move!=UP){
       if(p->type&CONST_SET){
        p2=_asn1_find_up(p);
        len2=strtol(p2->value,NULL,10);
-       if(counter==len2){
+       if(len2==-1){
+         if(!der[counter] && !der[counter+1]){
+           p=p2;
+           move=UP;
+           counter+=2;
+           continue;
+         }
+       }
+       else if(counter==len2){
          p=p2;
          move=UP;
          continue;
@@ -439,9 +576,29 @@ asn1_der_decoding(ASN1_TYPE *element,const unsigned char *der,int len,
        }
       }
 
+      if((p->type&CONST_OPTION) || (p->type&CONST_DEFAULT)){
+       p2=_asn1_find_up(p);
+       len2=strtol(p2->value,NULL,10);
+       if(counter==len2){
+         if(p->right){
+           p2=p->right;
+           move=RIGHT;
+         }
+         else move=UP;
+
+         if(p->type&CONST_OPTION) asn1_delete_structure(&p);
+
+         p=p2;
+         continue;
+       }
+      }
+
       if(type_field(p->type)==TYPE_CHOICE){
        while(p->down){
-         ris=_asn1_extract_tag_der(p->down,der+counter,&len2);
+         if(counter<len)
+           ris=_asn1_extract_tag_der(p->down,der+counter,&len2);
+         else
+           ris=ASN1_DER_ERROR;
          if(ris==ASN1_SUCCESS){
            while(p->down->right){
              p2=p->down->right;
@@ -458,19 +615,23 @@ asn1_der_decoding(ASN1_TYPE *element,const unsigned char *der,int len,
            asn1_delete_structure(&p2);
          }
        }
-       if(p->down==NULL){
-         asn1_delete_structure(element);
-         return ASN1_DER_ERROR;
+
+        if(p->down==NULL){
+         if(!(p->type&CONST_OPTION)){
+           asn1_delete_structure(element);
+           return ASN1_DER_ERROR;
+         }
        }
-       p=p->down;
+       else
+         p=p->down;
       }
 
       if((p->type&CONST_OPTION) || (p->type&CONST_DEFAULT)){
        p2=_asn1_find_up(p);
        len2=strtol(p2->value,NULL,10);
-       if(counter>=len2) ris=ASN1_TAG_ERROR;
+       if((len2!=-1) && (counter>len2)) ris=ASN1_TAG_ERROR;
       }
-
+     
       if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,&len2);
       if(ris!=ASN1_SUCCESS){
        if(p->type&CONST_OPTION){
@@ -530,9 +691,10 @@ asn1_der_decoding(ASN1_TYPE *element,const unsigned char *der,int len,
        move=RIGHT;
        break;
       case TYPE_OCTET_STRING:
-       len2=_asn1_get_length_der(der+counter,&len3);
-       _asn1_set_value(p,der+counter,len3+len2);
-       counter+=len3+len2;
+       len3=len-counter;
+       ris=_asn1_get_octet_string(der+counter,p,&len3);
+       if(ris != ASN1_SUCCESS) return ris; 
+       counter+=len3;
        move=RIGHT;
        break;
       case TYPE_GENERALSTRING:
@@ -551,42 +713,89 @@ asn1_der_decoding(ASN1_TYPE *element,const unsigned char *der,int len,
        if(move==UP){
          len2=strtol(p->value,NULL,10);
          _asn1_set_value(p,NULL,0);
-         if(len2!=counter){
-           asn1_delete_structure(element);
-           return ASN1_DER_ERROR;
+         if(len2==-1){ /* indefinite length method */
+           if((der[counter]) || der[counter+1]){
+             asn1_delete_structure(element);
+             return ASN1_DER_ERROR;
+           }
+           counter+=2;
+         }
+         else{ /* definite length method */
+           if(len2!=counter){
+             asn1_delete_structure(element);
+             return ASN1_DER_ERROR;
+           }
          }
          move=RIGHT;
        }
        else{   /* move==DOWN || move==RIGHT */
          len3=_asn1_get_length_der(der+counter,&len2);
          counter+=len2;
-         _asn1_ltostr(counter+len3,temp);
-         _asn1_set_value(p,temp,strlen(temp)+1);
-         move=DOWN; 
+         if(len3>0){
+           _asn1_ltostr(counter+len3,temp);
+           _asn1_set_value(p,temp,strlen(temp)+1);
+           move=DOWN; 
+         }
+         else if(len3==0){
+           p2=p->down;
+           while(p2){
+             if(type_field(p2->type)!=TYPE_TAG){
+               p3=p2->right;
+               asn1_delete_structure(&p2);
+               p2=p3;
+             }
+             else
+               p2=p2->right;
+           }
+           move=RIGHT;
+         }
+         else{ /* indefinite length method */
+           _asn1_set_value(p,"-1",3);
+           move=DOWN; 
+         }
        }
        break;
       case TYPE_SEQUENCE_OF: case TYPE_SET_OF:
        if(move==UP){
          len2=strtol(p->value,NULL,10);
-         if(len2>counter){
-           _asn1_append_sequence_set(p);
-           p=p->down;
-           while(p->right) p=p->right;
-           move=RIGHT;
-           continue;
+         if(len2==-1){ /* indefinite length method */
+           if((counter+2)>len) return ASN1_DER_ERROR;
+           if((der[counter]) || der[counter+1]){
+             _asn1_append_sequence_set(p);
+             p=p->down;
+             while(p->right) p=p->right;
+             move=RIGHT;
+             continue;
+           }
+           _asn1_set_value(p,NULL,0);
+           counter+=2;
          }
-         _asn1_set_value(p,NULL,0);
-         if(len2!=counter){
-           asn1_delete_structure(element);
-           return ASN1_DER_ERROR;
+         else{ /* definite length method */
+           if(len2>counter){
+             _asn1_append_sequence_set(p);
+             p=p->down;
+             while(p->right) p=p->right;
+             move=RIGHT;
+             continue;
+           }
+           _asn1_set_value(p,NULL,0);
+           if(len2!=counter){
+             asn1_delete_structure(element);
+             return ASN1_DER_ERROR;
+           }
          }
        }
        else{   /* move==DOWN || move==RIGHT */
          len3=_asn1_get_length_der(der+counter,&len2);
          counter+=len2;
          if(len3){
+           if(len3>0){ /* definite length method */
            _asn1_ltostr(counter+len3,temp);
            _asn1_set_value(p,temp,strlen(temp)+1);
+           }
+           else { /* indefinite length method */
+             _asn1_set_value(p,"-1",3);              
+           }
            p2=p->down;
            while((type_field(p2->type)==TYPE_TAG) || (type_field(p2->type)==TYPE_SIZE)) p2=p2->right;
            if(p2->right==NULL) _asn1_append_sequence_set(p);
@@ -596,19 +805,60 @@ asn1_der_decoding(ASN1_TYPE *element,const unsigned char *der,int len,
        move=RIGHT;
        break;
       case TYPE_ANY:
+       /* Check indefinite lenth method in a EXPLICIT TAG */
+       if((p->type&CONST_TAG) && (der[counter-1]==0x80))
+         indefinite=1;
+       else
+         indefinite=0;
+
        tag=_asn1_get_tag_der(der+counter,&class,&len2);
-       len2+=_asn1_get_length_der(der+counter+len2,&len3);
-       _asn1_length_der(len2+len3,NULL,&len4);
-       temp2=(unsigned char *)_asn1_alloca(len2+len3+len4);
-        if (temp2==NULL){
-         asn1_delete_structure(element);
-         return ASN1_MEM_ALLOC_ERROR;
-       }
+       len4=_asn1_get_length_der(der+counter+len2,&len3);
+       
+       if(len4 != -1){
+         len2+=len4;
+         _asn1_length_der(len2+len3,NULL,&len4);
+         temp2=(unsigned char *)_asn1_alloca(len2+len3+len4);
+         if (temp2==NULL){
+           asn1_delete_structure(element);
+           return ASN1_MEM_ALLOC_ERROR;
+         }
         
-       _asn1_octet_der(der+counter,len2+len3,temp2,&len4);
-       _asn1_set_value(p,temp2,len4);
-       _asn1_afree(temp2);
-       counter+=len2+len3;
+         _asn1_octet_der(der+counter,len2+len3,temp2,&len4);
+         _asn1_set_value(p,temp2,len4);
+         _asn1_afree(temp2);
+         counter+=len2+len3;
+       }
+       else{ /* indefinite length */
+         len2=len-counter;
+         ris=_asn1_get_indefinite_length_string(der+counter,&len2);
+         if(ris != ASN1_SUCCESS){
+           asn1_delete_structure(element);
+           return ris;
+         }
+         _asn1_length_der(len2,NULL,&len4);
+         temp2=(unsigned char *)_asn1_alloca(len2+len4);
+         if (temp2==NULL){
+           asn1_delete_structure(element);
+           return ASN1_MEM_ALLOC_ERROR;
+         }
+        
+         _asn1_octet_der(der+counter,len2,temp2,&len4);
+         _asn1_set_value(p,temp2,len4);
+         _asn1_afree(temp2);
+         counter+=len2;
+       }
+
+       /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
+          a indefinite length method. */
+       if(indefinite){
+         if(!der[counter] && !der[counter+1]){ 
+           counter+=2;
+         }
+         else{
+           asn1_delete_structure(element);
+           return ASN1_DER_ERROR;
+         }
+       }
        move=RIGHT;
        break;
       default:
@@ -681,6 +931,7 @@ asn1_der_decoding_element(ASN1_TYPE *structure,const char *elementName,
   int counter,len2,len3,len4,move,ris;
   unsigned char class,*temp2;
   unsigned int tag;
+  int indefinite;
 
   node=*structure;
 
@@ -770,9 +1021,29 @@ asn1_der_decoding_element(ASN1_TYPE *structure,const char *elementName,
        }
       }
 
+      if((p->type&CONST_OPTION) || (p->type&CONST_DEFAULT)){
+       p2=_asn1_find_up(p);
+       len2=strtol(p2->value,NULL,10);
+       if(counter==len2){
+         if(p->right){
+           p2=p->right;
+           move=RIGHT;
+         }
+         else move=UP;
+
+         if(p->type&CONST_OPTION) asn1_delete_structure(&p);
+
+         p=p2;
+         continue;
+       }
+      }
+
       if(type_field(p->type)==TYPE_CHOICE){
        while(p->down){
-         ris=_asn1_extract_tag_der(p->down,der+counter,&len2);
+         if(counter<len)
+           ris=_asn1_extract_tag_der(p->down,der+counter,&len2);
+         else
+           ris=ASN1_DER_ERROR;
          if(ris==ASN1_SUCCESS){
            while(p->down->right){
              p2=p->down->right;
@@ -789,17 +1060,21 @@ asn1_der_decoding_element(ASN1_TYPE *structure,const char *elementName,
            asn1_delete_structure(&p2);
          }
        }
-       if(p->down==NULL){
-         asn1_delete_structure(structure);
-         return ASN1_DER_ERROR;
+
+       if(p->down==NULL){
+         if(!(p->type&CONST_OPTION)){
+           asn1_delete_structure(structure);
+           return ASN1_DER_ERROR;
+         }
        }
-       p=p->down;
+       else
+         p=p->down;
       }
 
       if((p->type&CONST_OPTION) || (p->type&CONST_DEFAULT)){
        p2=_asn1_find_up(p);
        len2=strtol(p2->value,NULL,10);
-       if(counter>=len2) ris=ASN1_TAG_ERROR;
+       if(counter>len2) ris=ASN1_TAG_ERROR;
       }
 
       if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,&len2);
@@ -895,13 +1170,16 @@ asn1_der_decoding_element(ASN1_TYPE *structure,const char *elementName,
        move=RIGHT;
        break;
       case TYPE_OCTET_STRING:
-       len2=_asn1_get_length_der(der+counter,&len3);
+       len3=len-counter;
        if(state==FOUND){
-         _asn1_set_value(p,der+counter,len3+len2);
-        
+         ris=_asn1_get_octet_string(der+counter,p,&len3);
          if(p==nodeFound) state=EXIT;
        }
-       counter+=len3+len2;
+       else
+         ris=_asn1_get_octet_string(der+counter,NULL,&len3);
+
+       if(ris != ASN1_SUCCESS) return ris; 
+       counter+=len3;
        move=RIGHT;
        break;
       case TYPE_GENERALSTRING:
@@ -927,14 +1205,21 @@ asn1_der_decoding_element(ASN1_TYPE *structure,const char *elementName,
       case TYPE_SEQUENCE:  case TYPE_SET:
        if(move==UP){
          len2=strtol(p->value,NULL,10);
-          _asn1_set_value(p,NULL,0);
-         if(len2!=counter){
-           asn1_delete_structure(structure);
-           return ASN1_DER_ERROR;
+         _asn1_set_value(p,NULL,0);
+         if(len2==-1){ /* indefinite length method */
+           if((der[counter]) || der[counter+1]){
+             asn1_delete_structure(structure);
+             return ASN1_DER_ERROR;
+           }
+           counter+=2;
          }
-         
-         if(p==nodeFound) state=EXIT;
-
+         else{ /* definite length method */
+           if(len2!=counter){
+             asn1_delete_structure(structure);
+             return ASN1_DER_ERROR;
+           }
+         }
+         if(p==nodeFound) state=EXIT;    
          move=RIGHT;
        }
        else{   /* move==DOWN || move==RIGHT */
@@ -946,11 +1231,29 @@ asn1_der_decoding_element(ASN1_TYPE *structure,const char *elementName,
          else { /*  state==SAME_BRANCH or state==FOUND */
            len3=_asn1_get_length_der(der+counter,&len2);
            counter+=len2;
-           _asn1_ltostr(counter+len3,temp);
-           _asn1_set_value(p,temp,strlen(temp)+1);
-           move=DOWN;
+           if(len3>0){
+             _asn1_ltostr(counter+len3,temp);
+             _asn1_set_value(p,temp,strlen(temp)+1);
+             move=DOWN;
+           }
+           else if(len3==0){
+             p2=p->down;
+             while(p2){
+               if(type_field(p2->type)!=TYPE_TAG){
+                 p3=p2->right;
+                 asn1_delete_structure(&p2);
+               p2=p3;
+               }
+               else
+                 p2=p2->right;
+             }
+             move=RIGHT;
+           }
+           else{ /* indefinite length method */
+             _asn1_set_value(p,"-1",3);
+             move=DOWN;
+           } 
          }
-
        }
        break;
       case TYPE_SEQUENCE_OF: case TYPE_SET_OF:
@@ -994,26 +1297,73 @@ asn1_der_decoding_element(ASN1_TYPE *structure,const char *elementName,
        
        break;
       case TYPE_ANY:
+       /* Check indefinite lenth method in a EXPLICIT TAG */
+       if((p->type&CONST_TAG) && (der[counter-1]==0x80))
+         indefinite=1;
+       else
+         indefinite=0;
+
        tag=_asn1_get_tag_der(der+counter,&class,&len2);
-       len2+=_asn1_get_length_der(der+counter+len2,&len3);
-       if(state==FOUND){
-         _asn1_length_der(len2+len3,NULL,&len4);
-         temp2=(unsigned char *)_asn1_alloca(len2+len3+len4);
-         if (temp2==NULL){
+       len4=_asn1_get_length_der(der+counter+len2,&len3);
+       
+       if(len4 != -1){
+         len2+=len4;
+         if(state==FOUND){
+           _asn1_length_der(len2+len3,NULL,&len4);
+           temp2=(unsigned char *)_asn1_alloca(len2+len3+len4);
+           if (temp2==NULL){
+             asn1_delete_structure(structure);
+             return ASN1_MEM_ALLOC_ERROR;
+           }
+           
+           _asn1_octet_der(der+counter,len2+len3,temp2,&len4);
+           _asn1_set_value(p,temp2,len4);
+           _asn1_afree(temp2);
+
+           if(p==nodeFound) state=EXIT;
+         }
+         counter+=len2+len3;
+       }
+       else{ /* indefinite length */
+         len2=len-counter;
+         ris=_asn1_get_indefinite_length_string(der+counter,&len2);
+         if(ris != ASN1_SUCCESS){
            asn1_delete_structure(structure);
-           return ASN1_MEM_ALLOC_ERROR;
+           return ris;
          }
+         
+         if(state==FOUND){
+           _asn1_length_der(len2,NULL,&len4);
+           temp2=(unsigned char *)_asn1_alloca(len2+len4);
+           if (temp2==NULL){
+             asn1_delete_structure(structure);
+             return ASN1_MEM_ALLOC_ERROR;
+           }
         
-       _asn1_octet_der(der+counter,len2+len3,temp2,&len4);
-       _asn1_set_value(p,temp2,len4);
-       _asn1_afree(temp2);
-       
-       if(p==nodeFound) state=EXIT;
+           _asn1_octet_der(der+counter,len2,temp2,&len4);
+           _asn1_set_value(p,temp2,len4);
+           _asn1_afree(temp2);
+
+           if(p==nodeFound) state=EXIT;
+         }
+
+         counter+=len2;
        }
 
-       counter+=len2+len3;
+       /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
+          a indefinite length method. */
+       if(indefinite){
+         if(!der[counter] && !der[counter+1]){ 
+           counter+=2;
+         }
+         else{
+           asn1_delete_structure(structure);
+           return ASN1_DER_ERROR;
+         }
+       }
        move=RIGHT;
        break;
+
       default:
        move=(move==UP)?RIGHT:DOWN;
        break;
@@ -1150,9 +1500,10 @@ asn1_der_decoding_startEnd(ASN1_TYPE element,const unsigned char *der,int len,
                           const char *name_element,int *start, int *end)
 {
   node_asn *node,*node_to_find,*p,*p2,*p3;
-  int counter,len2,len3,move,ris;
+  int counter,len2,len3,len4,move,ris;
   unsigned char class;
   unsigned int tag;
+  int indefinite;
 
   node=element;
 
@@ -1180,7 +1531,15 @@ asn1_der_decoding_startEnd(ASN1_TYPE element,const unsigned char *der,int len,
       if(p->type&CONST_SET){
        p2=_asn1_find_up(p);
        len2=strtol(p2->value,NULL,10);
-       if(counter==len2){
+       if(len2==-1){
+         if(!der[counter] && !der[counter+1]){
+           p=p2;
+           move=UP;
+           counter+=2;
+           continue;
+         }
+       }
+       else if(counter==len2){
          p=p2;
          move=UP;
          continue;
@@ -1258,8 +1617,10 @@ asn1_der_decoding_startEnd(ASN1_TYPE element,const unsigned char *der,int len,
        move=RIGHT;
        break;
       case TYPE_OCTET_STRING:
-       len2=_asn1_get_length_der(der+counter,&len3);
-       counter+=len3+len2;
+       len3=len-counter;
+       ris=_asn1_get_octet_string(der+counter,NULL,&len3);
+       if(ris != ASN1_SUCCESS) return ris; 
+       counter+=len3;
        move=RIGHT;
        break;
       case TYPE_GENERALSTRING:
@@ -1276,28 +1637,64 @@ asn1_der_decoding_startEnd(ASN1_TYPE element,const unsigned char *der,int len,
        if(move!=UP){
          len3=_asn1_get_length_der(der+counter,&len2);
          counter+=len2;
-         move=DOWN; 
+         if(len3==0) move=RIGHT;
+         else move=DOWN; 
+       }
+       else{
+         if(!der[counter] && !der[counter+1]) /* indefinite length method */
+           counter+=2;
+         move=RIGHT;
        }
-       else move=RIGHT;
        break;
       case TYPE_SEQUENCE_OF: case TYPE_SET_OF:
        if(move!=UP){
          len3=_asn1_get_length_der(der+counter,&len2);
          counter+=len2;
-         if(len3){
+         if((len3==-1) && !der[counter] && !der[counter+1])
+           counter+=2;
+         else if(len3){
            p2=p->down;
            while((type_field(p2->type)==TYPE_TAG) || 
                  (type_field(p2->type)==TYPE_SIZE)) p2=p2->right;
            p=p2;
          }
        }
+       else{
+         if(!der[counter] && !der[counter+1]) /* indefinite length method */
+           counter+=2;
+       }
        move=RIGHT;
        break;
       case TYPE_ANY:
+       /* Check indefinite lenth method in a EXPLICIT TAG */
+       if((p->type&CONST_TAG) && (der[counter-1]==0x80))
+         indefinite=1;
+       else
+         indefinite=0;
+
        tag=_asn1_get_tag_der(der+counter,&class,&len2);
-       len2+=_asn1_get_length_der(der+counter+len2,&len3);
-       counter+=len3+len2;
-       move=RIGHT;
+       len4=_asn1_get_length_der(der+counter+len2,&len3);
+       
+       if(len4 != -1){
+         counter+=len2+len4+len3;
+       }
+       else{ /* indefinite length */
+         len2=len-counter;
+         ris=_asn1_get_indefinite_length_string(der+counter,&len2);
+         if(ris != ASN1_SUCCESS)
+           return ris;
+         counter+=len2;
+       }
+
+       /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
+          a indefinite length method. */
+       if(indefinite){
+         if(!der[counter] && !der[counter+1])
+           counter+=2;
+         else
+           return ASN1_DER_ERROR;
+       }
+       move=RIGHT;
        break;
       default:
        move=(move==UP)?RIGHT:DOWN;
index 078b53c..3af8cc7 100644 (file)
--- a/lib/der.h
+++ b/lib/der.h
@@ -44,7 +44,7 @@ asn1_retCode _asn1_get_bit_der(const unsigned char *der,
                 int *der_len,unsigned char *str, int str_size, 
                 int *bit_len);
 
-unsigned long _asn1_get_length_der(const unsigned char *der,int  *len);
+signed long _asn1_get_length_der(const unsigned char *der,int  *len);
 
 void _asn1_length_der(unsigned long len,unsigned char *ans,int *ans_len);
 
index 207ff67..c2a71d9 100644 (file)
 void
 _asn1_hierarchical_name(node_asn *node,char *name,int name_size)
 {
-  char *aux;
   node_asn *p;
-  
+  char tmp_name[64];
+
   p=node;
 
   name[0]=0;
 
   while(p != NULL){
     if(p->name != NULL){
-      aux=(char*)malloc(strlen(name)+1);
-      strcpy(aux,name);
+      _asn1_str_cpy(tmp_name,sizeof(tmp_name),name),
+
       _asn1_str_cpy(name,name_size,p->name);
       _asn1_str_cat(name,name_size,".");
-      _asn1_str_cat(name,name_size,aux);
-      free(aux);
+      _asn1_str_cat(name,name_size,tmp_name);
     }
     p=_asn1_find_up(p);
   }
-  name[strlen(name)-1]=0;
+
+  if(name[0]==0) _asn1_str_cpy(name,name_size,"ROOT");
 }
 
 
@@ -141,7 +141,7 @@ _asn1_append_sequence_set(node_asn *node)
     _asn1_ltostr(n,temp+1);
   } 
   _asn1_set_name(p2,temp);
-  p2->type |= CONST_OPTION;
+  /*  p2->type |= CONST_OPTION; */
 
   return ASN1_SUCCESS;
 }
index 0daed1d..9aa0543 100644 (file)
--- a/lib/int.h
+++ b/lib/int.h
@@ -32,7 +32,7 @@
 
 #include <mem.h>
 
-#define LIBTASN1_VERSION "0.2.4"
+#define LIBTASN1_VERSION "0.2.5"
 
 #define MAX32 4294967295
 #define MAX24 16777215
index 89f73e1..e1bb380 100644 (file)
@@ -28,7 +28,7 @@
 extern "C" {
 #endif
 
-#define LIBTASN1_VERSION "0.2.4"
+#define LIBTASN1_VERSION "0.2.5"
 
 #include <sys/types.h>
 #include <time.h>
index fc60cf9..1c1c868 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include "libtasn1.h"
 
 
index 2eba8c9..8c5d400 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include "libtasn1.h"
 
 
index 0480c77..aaefe07 100644 (file)
@@ -28,7 +28,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <libtasn1.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include <config.h>
 
 #ifdef HAVE_UNISTD_H
index 780ab9c..903e145 100644 (file)
@@ -28,7 +28,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <libtasn1.h>
-#include <malloc.h>
+#include <stdlib.h>
 #include <config.h>
 
 #ifdef HAVE_UNISTD_H
@@ -92,8 +92,9 @@ main(int argc,char *argv[])
  char errorDescription[MAX_ERROR_DESCRIPTION_SIZE];
  int asn1_result=ASN1_SUCCESS;
  FILE *inputFile;
- unsigned char der[1024];
+ unsigned char der[100*1024];
  int  der_len=0;
+ /* FILE *outputFile; */ 
 
  opterr=0; /* disable error messages from getopt */
 
@@ -192,7 +193,7 @@ main(int argc,char *argv[])
 
 
  inputFile=fopen(inputFileDerName,"r");
+
  if(inputFile==NULL){
    printf("asn1Decoding: file '%s' not found\n",inputFileDerName);
    asn1_delete_structure(&definitions);
@@ -203,13 +204,33 @@ main(int argc,char *argv[])
    exit(1);
  }
 
- while(fscanf(inputFile,"%c",der+der_len) != EOF)
-   der_len++;
 
+ /*****************************************/
+ /* ONLY FOR TEST                         */
+ /*****************************************/
+ /*
+ der_len=0;
+ outputFile=fopen("data.p12","w");
+ while(fscanf(inputFile,"%c",der+der_len) != EOF){
+   if((der_len>=0x11) && (der_len<=(0xe70)))
+     fprintf(outputFile,"%c",der[der_len]);
+   der_len++;
+ }
+ fclose(outputFile);
  fclose(inputFile);
+ */
+ while(fscanf(inputFile,"%c",der+der_len) != EOF){
+   der_len++;
+ }
+ fclose(inputFile);
+
     
  asn1_result=asn1_create_element(definitions,typeName,&structure);
 
+ /* asn1_print_structure(stdout,structure,"",ASN1_PRINT_ALL); */
+
+
  if(asn1_result != ASN1_SUCCESS){
    printf("Structure creation: %s\n",libtasn1_strerror(asn1_result));
    asn1_delete_structure(&definitions);
@@ -228,6 +249,21 @@ main(int argc,char *argv[])
  printf("\nDECODING RESULT:\n");
  asn1_print_structure(stdout,structure,"",ASN1_PRINT_NAME_TYPE_VALUE);
 
+ /*****************************************/
+ /* ONLY FOR TEST                         */
+ /*****************************************/
+ /*
+ der_len=10000;
+ option_index=0;
+ asn1_result=asn1_read_value(structure,"?2.content",der,&der_len);
+ outputFile=fopen("encryptedData.p12","w");
+ while(der_len>0){
+   fprintf(outputFile,"%c",der[option_index]);
+   der_len--;
+   option_index++;
+ }
+ fclose(outputFile);
+ */
 
  asn1_delete_structure(&definitions);
  asn1_delete_structure(&structure);
@@ -246,3 +282,5 @@ main(int argc,char *argv[])
 
 
 
+
+
index e071ad9..009ccff 100644 (file)
@@ -28,7 +28,7 @@
 #include <stdio.h>\r
 #include <string.h>\r
 #include <libtasn1.h>\r
-#include <malloc.h>\r
+#include <stdlib.h>\r
 #include <config.h>\r
 \r
 #ifdef HAVE_UNISTD_H\r
index 8c9b43f..dc75dd9 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include "libtasn1.h"
 
 int
index 5d6b638..7a0688e 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include "libtasn1.h"
 
 typedef struct{
index a918456..a294ebf 100644 (file)
@@ -9,6 +9,48 @@ DEFINITIONS IMPLICIT TAGS ::=
 
 BEGIN
 
+KrbError ::= [APPLICATION 30] SEQUENCE {
+    pvno[0]   INTEGER
+}
+
+
+CertTemplate ::= SEQUENCE {
+    version      [0] INTEGER               OPTIONAL,
+    issuer       [3] Name                  OPTIONAL,
+    validity     [4] INTEGER               OPTIONAL
+}
+
+Name            ::=   CHOICE {
+    rdnSequence  RDNSequence }
+
+RDNSequence     ::=   RelativeDistinguishedName
+
+RelativeDistinguishedName  ::=
+
+                    SET SIZE (1 .. MAX) OF AttributeTypeAndValue
+
+AttributeTypeAndValue           ::=     SEQUENCE {
+        type    AttributeType,
+        value   AttributeValue }
+
+AttributeType           ::=   OBJECT IDENTIFIER
+AttributeValue          ::=   ANY
+
+
+sequenceEmpty ::= SEQUENCE{
+  int1   INTEGER,
+  seq1   [1] IMPLICIT Sequence_octetTest1,
+  set1   [2] EXPLICIT SET OF INTEGER
+}
+
+
+IndefiniteLengthTest ::= SEQUENCE{
+  seq1   [1] IMPLICIT Sequence_octetTest1,
+  set1   SET OF OBJECT IDENTIFIER,
+  int1   INTEGER
+}
+
+
 OidTest ::= SEQUENCE{
    oid3 [3]   OBJECT IDENTIFIER DEFAULT id-Test,
    oid  [1]   OBJECT IDENTIFIER DEFAULT id-anyTest2,
@@ -56,7 +98,7 @@ DHParameter ::= SEQUENCE {
 id-octetTest1 OBJECT IDENTIFIER  ::=  {1 2 3 4}
 
 Sequence_octetTest1 ::= SEQUENCE{
-    int     INTEGER
+    int     INTEGER OPTIONAL
 }
 
 
@@ -112,6 +154,7 @@ X520LocalityName ::= CHOICE {
 
 id-Test OBJECT IDENTIFIER  ::=  {1 2 29 2}
 
+
 END
 
 
index 0252ffd..ea367c1 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
 #include "libtasn1.h"
 
 #include "Test_tree_asn1_tab.c"
@@ -54,6 +55,8 @@
 #define ACT_OID_2_STRUCTURE    16
 #define ACT_READ_LENGTH        17
 #define ACT_ENCODING_LENGTH    18
+#define ACT_READ_BIT           19
+#define ACT_SET_DER            20
 
 
 typedef struct{
@@ -69,6 +72,95 @@ test_type test_array[]={
 
   {ACT_DELETE,"","",0,ASN1_ELEMENT_NOT_FOUND},
 
+  /* Test: APPLICATION 30 */
+  {ACT_CREATE,"TEST_TREE.KrbError",0,0,ASN1_SUCCESS},
+  {ACT_WRITE,"pvno","5",0,ASN1_SUCCESS},
+  {ACT_ENCODING_LENGTH,"",0,5,ASN1_MEM_ERROR},
+  {ACT_ENCODING,"",0,4,ASN1_MEM_ERROR},
+  {ACT_ENCODING,"",0,5,ASN1_SUCCESS},
+  {ACT_PRINT_DER,0,0,0,ASN1_SUCCESS},
+  {ACT_CREATE,"TEST_TREE.KrbError",0,0,ASN1_SUCCESS},
+  {ACT_DECODING,0,0,0,ASN1_SUCCESS},
+  {ACT_VISIT,"","",ASN1_PRINT_ALL,ASN1_SUCCESS},
+  {ACT_DELETE,"","",0,ASN1_SUCCESS},
+
+  /* Test: CHOICE */
+  {ACT_CREATE,"TEST_TREE.CertTemplate",0,0,ASN1_SUCCESS},
+  {ACT_WRITE,"version",0,0,ASN1_SUCCESS},
+  {ACT_WRITE,"validity",0,0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer","rdnSequence",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.type","2.5.4.3",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.value","\x0c\x18\x71\x75\x61\x73\x61\x72\x2e\x6c\x61\x73\x2e\x69\x63\x2e\x75\x6e\x69\x63\x61\x6d\x70\x2e\x62\x72",26,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.type","2.5.4.7",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.value","\x0c\x08\x43\x61\x6d\x70\x69\x6e\x61\x73",10,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.type","2.5.4.6",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.value","\x13\x06\x42\x72\x61\x73\x69\x6c",8,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.type","2.5.4.10",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.value","\x0c\x02\x49\x43",4,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.type","2.5.4.11",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.value","\x0c\x03\x4c\x41\x53",5,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.type","2.5.4.8",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.value","\x0c\x09\x53\x61\x6f\x20\x50\x61\x75\x6c\x6f",11,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.type","1.2.840.113549.1.9.1",0,ASN1_SUCCESS},
+  {ACT_WRITE,"issuer.rdnSequence.?LAST.value","\x16\x19\x65\x64\x75\x61\x72\x64\x6f\x40\x6c\x61\x73\x2e\x69\x63\x2e\x75\x6e\x69\x63\x61\x6d\x70\x2e\x62\x72",27,ASN1_SUCCESS},
+  {ACT_VISIT,"","",ASN1_PRINT_ALL,ASN1_SUCCESS},
+  {ACT_ENCODING_LENGTH,"",0,152,ASN1_MEM_ERROR},
+  {ACT_ENCODING,"",0,151,ASN1_MEM_ERROR},
+  {ACT_ENCODING,"",0,152,ASN1_SUCCESS},
+  {ACT_PRINT_DER,0,0,0,ASN1_SUCCESS},
+  {ACT_DELETE,"","",0,ASN1_SUCCESS},
+  {ACT_CREATE,"TEST_TREE.CertTemplate",0,0,ASN1_SUCCESS},
+  {ACT_DECODING,0,0,0,ASN1_SUCCESS},
+  {ACT_VISIT,"","",ASN1_PRINT_ALL,ASN1_SUCCESS},
+  {ACT_DELETE,"","",0,ASN1_SUCCESS},
+
+  /* Test: Empty sequnces */
+  {ACT_CREATE,"TEST_TREE.sequenceEmpty",0,0,ASN1_SUCCESS},
+  {ACT_WRITE,"int1","1",0,ASN1_SUCCESS},
+  {ACT_WRITE,"seq1.int",NULL,0,ASN1_SUCCESS},
+  {ACT_ENCODING_LENGTH,"",0,11,ASN1_MEM_ERROR},
+  {ACT_ENCODING,"",0,10,ASN1_MEM_ERROR},
+  {ACT_ENCODING,"",0,11,ASN1_SUCCESS},
+  {ACT_PRINT_DER,0,0,0,ASN1_SUCCESS},
+  {ACT_DELETE,"","",0,ASN1_SUCCESS},
+  {ACT_CREATE,"TEST_TREE.sequenceEmpty",0,0,ASN1_SUCCESS},
+  {ACT_DECODING,0,0,0,ASN1_SUCCESS},
+  {ACT_DECODING_START_END,"seq1","START",5,ASN1_SUCCESS},
+  {ACT_DECODING_START_END,"seq1","END",6,ASN1_SUCCESS},
+  {ACT_DECODING_START_END,"set1","START",7,ASN1_SUCCESS},
+  {ACT_DECODING_START_END,"set1","END",10,ASN1_SUCCESS},
+  {ACT_VISIT,"","",ASN1_PRINT_ALL,ASN1_SUCCESS},
+  {ACT_DELETE,"","",0,ASN1_SUCCESS},
+
+  /* Test: Indefinite Length */
+  {ACT_CREATE,"TEST_TREE.IndefiniteLengthTest",0,0,ASN1_SUCCESS},
+  {ACT_WRITE,"int1","1",0,ASN1_SUCCESS},
+  {ACT_WRITE,"seq1.int","2",0,ASN1_SUCCESS},
+  {ACT_WRITE,"set1","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"set1.?LAST","1.2.3.4",0,ASN1_SUCCESS},
+  {ACT_WRITE,"set1","NEW",0,ASN1_SUCCESS},
+  {ACT_WRITE,"set1.?LAST","1.2.5.6",0,ASN1_SUCCESS},
+  {ACT_ENCODING,"",0,255,ASN1_SUCCESS},
+  {ACT_PRINT_DER,0,0,0,ASN1_SUCCESS},
+  {ACT_SET_DER,"\x30\x18\xa1\x80\x02\x01\x02\x00\x00\x31\x80\x06\x03\x2a\x03\x04\x06\x03\x2a\x05\x06\x00\x00\x02\x01\x01",
+   0,26,ASN1_SUCCESS},
+  {ACT_DELETE,"","",0,ASN1_SUCCESS},
+  {ACT_CREATE,"TEST_TREE.IndefiniteLengthTest",0,0,ASN1_SUCCESS},
+  {ACT_DECODING,0,0,0,ASN1_SUCCESS},
+  {ACT_DECODING_START_END,"seq1","START",2,ASN1_SUCCESS},
+  {ACT_DECODING_START_END,"seq1","END",8,ASN1_SUCCESS},
+  {ACT_DECODING_START_END,"set1","START",9,ASN1_SUCCESS},
+  {ACT_DECODING_START_END,"set1","END",22,ASN1_SUCCESS},
+  {ACT_VISIT,"","",ASN1_PRINT_ALL,ASN1_SUCCESS},
+  {ACT_DELETE,"","",0,ASN1_SUCCESS},
+
   /* Test: OID */
   {ACT_CREATE,"TEST_TREE.OidTest",0,0,ASN1_SUCCESS},
   {ACT_READ_LENGTH,"oid",NULL,9,ASN1_MEM_ERROR},
@@ -116,6 +208,8 @@ test_type test_array[]={
   {ACT_READ_LENGTH,"enum",NULL,1,ASN1_MEM_ERROR},
   {ACT_READ_LENGTH,"any",NULL,3,ASN1_MEM_ERROR},
   {ACT_READ_LENGTH,"gen",NULL,5,ASN1_MEM_ERROR},
+  {ACT_READ_LENGTH,"bit",NULL,10,ASN1_MEM_ERROR},
+  {ACT_READ_BIT,"bit","1\xC0",10,ASN1_SUCCESS},
   {ACT_ENCODING_LENGTH,"",0,79,ASN1_MEM_ERROR},
   {ACT_ENCODING,"",0,78,ASN1_MEM_ERROR},
   {ACT_ENCODING,"",0,79,ASN1_SUCCESS},
@@ -317,7 +411,7 @@ main(int argc,char *argv[])
   printf(    "/****************************************/\n\n");
 
   /* Check version */
-  if(asn1_check_version("0.2.4")==NULL)
+  if(asn1_check_version("0.2.5")==NULL)
     printf("\nLibrary version check ERROR:\n actual version: %s\n\n",asn1_check_version(NULL));
 
   if(1)
@@ -365,6 +459,7 @@ main(int argc,char *argv[])
        result=asn1_write_value(asn1_element,test->par1,test->par2,test->par3);
       break;
     case ACT_READ:
+    case ACT_READ_BIT:
       valueLen=test->par3;
       result=asn1_read_value(asn1_element,test->par1,value,&valueLen);
       break;
@@ -424,6 +519,11 @@ main(int argc,char *argv[])
       printf("\n\n");
       result=ASN1_SUCCESS;
       break;
+    case ACT_SET_DER:
+      der_len=test->par3;
+      memcpy(der,test->par1,der_len);
+      result=ASN1_SUCCESS;
+      break;
     case ACT_NUMBER_OF_ELEMENTS:
       result=asn1_number_of_elements(asn1_element,test->par1,&valueLen);
       break;
@@ -442,6 +542,7 @@ main(int argc,char *argv[])
     case ACT_PRINT_DER:
     case ACT_EXPAND_ANY:
     case ACT_EXPAND_OCTET:
+    case ACT_SET_DER:
       if(result != test->errorNumber){
        errorCounter++;
        printf("ERROR N. %d:\n",errorCounter);
@@ -531,7 +632,15 @@ main(int argc,char *argv[])
 
     case ACT_READ:
     case ACT_READ_DEFINITIONS:
-      for(k=0;k<valueLen;k++) 
+    case ACT_READ_BIT:
+      if(test->action==ACT_READ_BIT){
+       if((valueLen-(valueLen/8.0))==0) tag=valueLen/8;
+       else tag=(valueLen/8)+1;
+       if((test->par3-(test->par3/8.0))==0) class=test->par3/8;
+       else class=(test->par3/8)+1;
+      }
+
+      for(k=0;k<class;k++) 
        if(test->par2[k] != value[k]){
          k=-1;
          break;