#include <int.h>
#include <errors.h>
#include "der.h"
#include "parser_aux.h"
#include <gstr.h>
#include "structure.h"
#include "element.h"
void
_asn1_error_description_tag_error(node_asn *node,char *ErrorDescription)
{
Estrcpy(ErrorDescription,":: tag error near element '");
_asn1_hierarchical_name(node,ErrorDescription+strlen(ErrorDescription),
MAX_ERROR_DESCRIPTION_SIZE-40);
Estrcat(ErrorDescription,"'");
}
signed long
_asn1_get_length_der(const unsigned char *der, int der_len, int *len)
{
unsigned long ans;
int k,punt;
*len = 0;
if (der_len <= 0) return 0;
if(!(der[0]&128)){
*len=1;
return der[0];
}
else{
k=der[0]&0x7F;
punt=1;
if(k){
ans=0;
while(punt<=k && punt < der_len) {
unsigned long last = ans;
ans=ans*256+der[punt++];
if (ans < last)
return -2;
}
}
else{
ans=-1;
}
*len=punt;
return ans;
}
}
int
_asn1_get_tag_der(const unsigned char *der, int der_len,
unsigned char *class,int *len, unsigned long *tag)
{
int punt,ris;
if (der==NULL || der_len <= 0 || len == NULL) return ASN1_DER_ERROR;
*class=der[0]&0xE0;
if((der[0]&0x1F)!=0x1F){
*len=1;
ris=der[0]&0x1F;
}
else{
punt=1;
ris=0;
while(punt <= der_len && der[punt]&128)
{
int last = ris;
ris=ris*128+(der[punt++]&0x7F);
if (ris < last)
return ASN1_DER_ERROR;
}
if (punt >= der_len)
return ASN1_DER_ERROR;
{
int last = ris;
ris=ris*128+(der[punt++]&0x7F);
if (ris < last)
return ASN1_DER_ERROR;
}
*len=punt;
}
if (tag) *tag = ris;
return ASN1_SUCCESS;
}
int
_asn1_get_octet_der(const unsigned char *der, int der_len, int *ret_len,unsigned char *str,int str_size, int *str_len)
{
int len_len;
if (der_len <= 0) return ASN1_GENERIC_ERROR;
*str_len=_asn1_get_length_der(der, der_len, &len_len);
if (*str_len < 0)
return ASN1_DER_ERROR;
*ret_len=*str_len+len_len;
if ( str_size >= *str_len)
memcpy(str,der+len_len,*str_len);
else {
return ASN1_MEM_ERROR;
}
return ASN1_SUCCESS;
}
int
_asn1_get_time_der(const unsigned char *der, int der_len, int *ret_len,unsigned char *str,int str_size)
{
int len_len,str_len;
if(der_len <=0 || str==NULL) return ASN1_DER_ERROR;
str_len=_asn1_get_length_der(der, der_len, &len_len);
if (str_len < 0 || str_size < str_len)
return ASN1_DER_ERROR;
memcpy(str,der+len_len,str_len);
str[str_len]=0;
*ret_len=str_len+len_len;
return ASN1_SUCCESS;
}
void
_asn1_get_objectid_der(const unsigned char *der,int der_len, int *ret_len,unsigned char *str, int str_size)
{
int len_len,len,k;
char temp[20];
unsigned long val,val1;
*ret_len = 0;
if (str && str_size > 0) str[0] = 0;
if(str==NULL || der_len <= 0) return;
len=_asn1_get_length_der(der,der_len, &len_len);
if (len < 0 || len > der_len || len_len > der_len) return;
val1=der[len_len]/40;
val=der[len_len]-val1*40;
_asn1_str_cpy(str, str_size, _asn1_ltostr(val1,temp));
_asn1_str_cat(str, str_size, ".");
_asn1_str_cat(str, str_size, _asn1_ltostr(val,temp));
val=0;
for(k=1;k<len;k++){
val=val<<7;
val|=der[len_len+k]&0x7F;
if(!(der[len_len+k]&0x80)){
_asn1_str_cat(str, str_size,".");
_asn1_str_cat(str, str_size,_asn1_ltostr(val,temp));
val=0;
}
}
*ret_len=len+len_len;
}
int
_asn1_get_bit_der(const unsigned char *der, int der_len,
int *ret_len,unsigned char *str, int str_size, int *bit_len)
{
int len_len,len_byte;
if (der_len <=0) return ASN1_GENERIC_ERROR;
len_byte=_asn1_get_length_der(der,der_len,&len_len)-1;
if (len_byte < 0)
return ASN1_DER_ERROR;
*ret_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;
}
return ASN1_SUCCESS;
}
int
_asn1_extract_tag_der(node_asn *node,const unsigned char *der, int der_len,int *ret_len)
{
node_asn *p;
int counter,len2,len3,is_tag_implicit;
unsigned long tag,tag_implicit=0;
unsigned char class,class2,class_implicit=0;
if (der_len <= 0) return ASN1_GENERIC_ERROR;
counter=is_tag_implicit=0;
if(node->type&CONST_TAG){
p=node->down;
while(p){
if(type_field(p->type)==TYPE_TAG){
if(p->type&CONST_APPLICATION) class2=APPLICATION;
else if(p->type&CONST_UNIVERSAL) class2=UNIVERSAL;
else if(p->type&CONST_PRIVATE) class2=PRIVATE;
else class2=CONTEXT_SPECIFIC;
if(p->type&CONST_EXPLICIT){
if (_asn1_get_tag_der(der+counter, der_len-counter,&class,&len2, &tag)!=ASN1_SUCCESS)
return ASN1_DER_ERROR;
if (counter+len2 > der_len)
return ASN1_DER_ERROR;
counter+=len2;
len3=_asn1_get_length_der(der+counter,der_len-counter, &len2);
if (len3 < 0)
return ASN1_DER_ERROR;
counter+=len2;
if(!is_tag_implicit){
if((class!=(class2|STRUCTURED)) || (tag!=strtoul(p->value,NULL,10)))
return ASN1_TAG_ERROR;
}
else{
if((class!=class_implicit) || (tag!=tag_implicit))
return ASN1_TAG_ERROR;
}
is_tag_implicit=0;
}
else{
if(!is_tag_implicit){
if((type_field(node->type)==TYPE_SEQUENCE) ||
(type_field(node->type)==TYPE_SEQUENCE_OF) ||
(type_field(node->type)==TYPE_SET) ||
(type_field(node->type)==TYPE_SET_OF)) class2|=STRUCTURED;
class_implicit=class2;
tag_implicit=strtoul(p->value,NULL,10);
is_tag_implicit=1;
}
}
}
p=p->right;
}
}
if(is_tag_implicit){
if (_asn1_get_tag_der(der+counter, der_len-counter,&class,&len2, &tag)!=ASN1_SUCCESS)
return ASN1_DER_ERROR;
if (counter+len2 > der_len)
return ASN1_DER_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){
counter=0;
*ret_len=counter;
return ASN1_SUCCESS;
}
if (_asn1_get_tag_der(der+counter, der_len-counter,&class,&len2,&tag)!=ASN1_SUCCESS)
return ASN1_DER_ERROR;
if (counter+len2 > der_len)
return ASN1_DER_ERROR;
switch(type_field(node->type)){
case TYPE_NULL:
if((class!=UNIVERSAL) || (tag!=TAG_NULL)) return ASN1_DER_ERROR;
break;
case TYPE_BOOLEAN:
if((class!=UNIVERSAL) || (tag!=TAG_BOOLEAN)) return ASN1_DER_ERROR;
break;
case TYPE_INTEGER:
if((class!=UNIVERSAL) || (tag!=TAG_INTEGER)) return ASN1_DER_ERROR;
break;
case TYPE_ENUMERATED:
if((class!=UNIVERSAL) || (tag!=TAG_ENUMERATED)) return ASN1_DER_ERROR;
break;
case TYPE_OBJECT_ID:
if((class!=UNIVERSAL) || (tag!=TAG_OBJECT_ID)) return ASN1_DER_ERROR;
break;
case TYPE_TIME:
if(node->type&CONST_UTC){
if((class!=UNIVERSAL) || (tag!=TAG_UTCTime)) return ASN1_DER_ERROR;
}
else{
if((class!=UNIVERSAL) || (tag!=TAG_GENERALIZEDTime))
return ASN1_DER_ERROR;
}
break;
case TYPE_OCTET_STRING:
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;
break;
case TYPE_BIT_STRING:
if((class!=UNIVERSAL) || (tag!=TAG_BIT_STRING)) return ASN1_DER_ERROR;
break;
case TYPE_SEQUENCE: case TYPE_SEQUENCE_OF:
if((class!=(UNIVERSAL|STRUCTURED)) || (tag!=TAG_SEQUENCE))
return ASN1_DER_ERROR;
break;
case TYPE_SET: case TYPE_SET_OF:
if((class!=(UNIVERSAL|STRUCTURED)) || (tag!=TAG_SET))
return ASN1_DER_ERROR;
break;
case TYPE_ANY:
counter-=len2;
break;
default:
return ASN1_DER_ERROR;
break;
}
}
counter+=len2;
*ret_len=counter;
return ASN1_SUCCESS;
}
int
_asn1_delete_not_used(node_asn *node)
{
node_asn *p,*p2;
if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
p=node;
while(p){
if(p->type&CONST_NOT_USED){
p2=NULL;
if(p!=node){
p2=_asn1_find_left(p);
if(!p2) p2=_asn1_find_up(p);
}
asn1_delete_structure(&p);
p=p2;
}
if(!p) break;
if(p->down){
p=p->down;
}
else{
if(p==node) p=NULL;
else if(p->right) p=p->right;
else{
while(1){
p=_asn1_find_up(p);
if(p==node){
p=NULL;
break;
}
if(p->right){
p=p->right;
break;
}
}
}
}
}
return ASN1_SUCCESS;
}
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, *len, &len3);
if (indefinite < -1)
return ASN1_DER_ERROR;
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,*len-counter, &len3);
if(len2 <= 0) return ASN1_DER_ERROR;
counter+=len3+len2;
tot_len+=len2;
}
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,*len,&len3);
if(len2 < -1) return ASN1_DER_ERROR;
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, *len-counter, &len3);
if(len2 < -1) return ASN1_DER_ERROR;
memcpy(temp2,der+counter2+len3,len2);
temp2+=len2;
counter2+=len2+len3+1;
}
_asn1_set_value(node,temp,tot_len);
_asn1_afree(temp);
}
}
else{
len2=_asn1_get_length_der(der, *len, &len3);
if(len2 < 0) return ASN1_DER_ERROR;
if (len3+len2 > *len) return ASN1_DER_ERROR;
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 long 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;
}
if(_asn1_get_tag_der(der+counter, *len-counter,&class,&len2,&tag)!=ASN1_SUCCESS)
return ASN1_DER_ERROR;
if (counter+len2 > *len)
return ASN1_DER_ERROR;
counter+=len2;
len2=_asn1_get_length_der(der+counter, *len-counter,&len3);
if(len2 < -1) return ASN1_DER_ERROR;
if(len2 == -1){
indefinite++;
counter+=1;
}
else{
counter+=len2+len3;
}
}
*len=counter;
return ASN1_SUCCESS;
}
asn1_retCode
asn1_der_decoding(ASN1_TYPE *element,const void *ider,int len,
char *errorDescription)
{
node_asn *node,*p,*p2,*p3;
char temp[128];
int counter,len2,len3,len4,move,ris;
unsigned char class,*temp2;
unsigned long tag;
int indefinite, result;
const unsigned char* der = ider;
node=*element;
if(node==ASN1_TYPE_EMPTY) return ASN1_ELEMENT_NOT_FOUND;
if(node->type&CONST_OPTION){
asn1_delete_structure(element);
return ASN1_GENERIC_ERROR;
}
counter=0;
move=DOWN;
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(len2==-1){
if(!der[counter] && !der[counter+1]){
p=p2;
move=UP;
counter+=2;
continue;
}
}
else if(counter==len2){
p=p2;
move=UP;
continue;
}
else if(counter>len2){
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
p2=p2->down;
while(p2){
if((p2->type&CONST_SET) && (p2->type&CONST_NOT_USED)){
if(type_field(p2->type)!=TYPE_CHOICE)
ris=_asn1_extract_tag_der(p2,der+counter,len-counter, &len2);
else{
p3=p2->down;
while(p3){
ris=_asn1_extract_tag_der(p3,der+counter,len-counter, &len2);
if(ris==ASN1_SUCCESS) break;
p3=p3->right;
}
}
if(ris==ASN1_SUCCESS){
p2->type&=~CONST_NOT_USED;
p=p2;
break;
}
}
p2=p2->right;
}
if(p2==NULL){
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
}
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){
if(counter<len)
ris=_asn1_extract_tag_der(p->down,der+counter,len-counter,&len2);
else
ris=ASN1_DER_ERROR;
if(ris==ASN1_SUCCESS){
while(p->down->right){
p2=p->down->right;
asn1_delete_structure(&p2);
}
break;
}
else if(ris==ASN1_ERROR_TYPE_ANY){
asn1_delete_structure(element);
return ASN1_ERROR_TYPE_ANY;
}
else{
p2=p->down;
asn1_delete_structure(&p2);
}
}
if(p->down==NULL){
if(!(p->type&CONST_OPTION)){
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
}
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((len2!=-1) && (counter>len2)) ris=ASN1_TAG_ERROR;
}
if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,len-counter,&len2);
if(ris!=ASN1_SUCCESS){
if(p->type&CONST_OPTION){
p->type|=CONST_NOT_USED;
move=RIGHT;
}
else if(p->type&CONST_DEFAULT) {
_asn1_set_value(p,NULL,0);
move=RIGHT;
}
else {
if (errorDescription!=NULL)
_asn1_error_description_tag_error(p,errorDescription);
asn1_delete_structure(element);
return ASN1_TAG_ERROR;
}
}
else counter+=len2;
}
if(ris==ASN1_SUCCESS){
switch(type_field(p->type)){
case TYPE_NULL:
if(der[counter]){
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
counter++;
move=RIGHT;
break;
case TYPE_BOOLEAN:
if(der[counter++]!=1){
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
if(der[counter++]==0) _asn1_set_value(p,"F",1);
else _asn1_set_value(p,"T",1);
move=RIGHT;
break;
case TYPE_INTEGER: case TYPE_ENUMERATED:
len2=_asn1_get_length_der(der+counter,len-counter, &len3);
if(len2 < 0) return ASN1_DER_ERROR;
if (len2+len3 > len-counter) return ASN1_DER_ERROR;
_asn1_set_value(p,der+counter,len3+len2);
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_OBJECT_ID:
_asn1_get_objectid_der(der+counter,len-counter,&len2, temp, sizeof(temp));
_asn1_set_value(p,temp,strlen(temp)+1);
counter+=len2;
move=RIGHT;
break;
case TYPE_TIME:
result = _asn1_get_time_der(der+counter,len-counter,&len2,temp,sizeof(temp)-1);
if (result != ASN1_SUCCESS) {
asn1_delete_structure(element);
return result;
}
_asn1_set_value(p,temp,strlen(temp)+1);
counter+=len2;
move=RIGHT;
break;
case TYPE_OCTET_STRING:
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:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
if (len3+len2 > len-counter) return ASN1_DER_ERROR;
_asn1_set_value(p,der+counter,len3+len2);
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_BIT_STRING:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
if (len3+len2 > len-counter) return ASN1_DER_ERROR;
_asn1_set_value(p,der+counter,len3+len2);
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_SEQUENCE: case TYPE_SET:;
if(move==UP){
len2=strtol(p->value,NULL,10);
_asn1_set_value(p,NULL,0);
if(len2==-1){
if (len-counter+1 > 0) {
if((der[counter]) || der[counter+1]){
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
} else return ASN1_DER_ERROR;
counter+=2;
}
else{
if(len2!=counter){
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
}
move=RIGHT;
}
else{
len3=_asn1_get_length_der(der+counter,len-counter,&len2);
if(len3 < -1) return ASN1_DER_ERROR;
counter+=len2;
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{
_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==-1){
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;
}
else{
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{
len3=_asn1_get_length_der(der+counter,len-counter,&len2);
if(len3 < -1) return ASN1_DER_ERROR;
counter+=len2;
if(len3){
if(len3>0){
_asn1_ltostr(counter+len3,temp);
_asn1_set_value(p,temp,strlen(temp)+1);
}
else {
_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);
p=p2;
}
}
move=RIGHT;
break;
case TYPE_ANY:
if((p->type&CONST_TAG) && (der[counter-1]==0x80))
indefinite=1;
else
indefinite=0;
if(_asn1_get_tag_der(der+counter,len-counter,&class,&len2,&tag)!=ASN1_SUCCESS)
return ASN1_DER_ERROR;
if (counter+len2 > len)
return ASN1_DER_ERROR;
len4=_asn1_get_length_der(der+counter+len2,len-counter-len2,&len3);
if(len4 < -1) return ASN1_DER_ERROR;
if(len4 > len-counter+len2+len3) return ASN1_DER_ERROR;
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;
}
else{
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;
}
if(indefinite){
if(!der[counter] && !der[counter+1]){
counter+=2;
}
else{
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
}
move=RIGHT;
break;
default:
move=(move==UP)?RIGHT:DOWN;
break;
}
}
if(p==node && move!=DOWN) break;
if(move==DOWN){
if(p->down) p=p->down;
else move=RIGHT;
}
if((move==RIGHT) && !(p->type&CONST_SET)){
if(p->right) p=p->right;
else move=UP;
}
if(move==UP) p=_asn1_find_up(p);
}
_asn1_delete_not_used(*element);
if(counter != len){
asn1_delete_structure(element);
return ASN1_DER_ERROR;
}
return ASN1_SUCCESS;
}
#define FOUND 1
#define SAME_BRANCH 2
#define OTHER_BRANCH 3
#define EXIT 4
asn1_retCode
asn1_der_decoding_element(ASN1_TYPE *structure,const char *elementName,
const void *ider,int len,char *errorDescription)
{
node_asn *node,*p,*p2,*p3,*nodeFound=ASN1_TYPE_EMPTY;
char temp[128],currentName[MAX_NAME_SIZE*10],*dot_p,*char_p;
int nameLen=MAX_NAME_SIZE*10-1,state;
int counter,len2,len3,len4,move,ris;
unsigned char class,*temp2;
unsigned long tag;
int indefinite, result;
const unsigned char* der = ider;
node=*structure;
if(node==ASN1_TYPE_EMPTY) return ASN1_ELEMENT_NOT_FOUND;
if(elementName == NULL){
asn1_delete_structure(structure);
return ASN1_ELEMENT_NOT_FOUND;
}
if(node->type&CONST_OPTION){
asn1_delete_structure(structure);
return ASN1_GENERIC_ERROR;
}
if((*structure)->name){
nameLen-=strlen((*structure)->name);
if(nameLen>0) strcpy(currentName,(*structure)->name);
else{
asn1_delete_structure(structure);
return ASN1_MEM_ERROR;
}
if(!(strcmp(currentName,elementName))){
state=FOUND;
nodeFound=*structure;
}
else if(!memcmp(currentName,elementName,strlen(currentName)))
state=SAME_BRANCH;
else
state=OTHER_BRANCH;
}
else{
currentName[0]=0;
if(elementName[0]==0){
state=FOUND;
nodeFound=*structure;
}
else{
state=SAME_BRANCH;
}
}
counter=0;
move=DOWN;
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){
p=p2;
move=UP;
continue;
}
else if(counter>len2){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
p2=p2->down;
while(p2){
if((p2->type&CONST_SET) && (p2->type&CONST_NOT_USED)){
if(type_field(p2->type)!=TYPE_CHOICE)
ris=_asn1_extract_tag_der(p2,der+counter,len-counter,&len2);
else{
p3=p2->down;
while(p3){
ris=_asn1_extract_tag_der(p3,der+counter,len-counter,&len2);
if(ris==ASN1_SUCCESS) break;
p3=p3->right;
}
}
if(ris==ASN1_SUCCESS){
p2->type&=~CONST_NOT_USED;
p=p2;
break;
}
}
p2=p2->right;
}
if(p2==NULL){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
}
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){
if(counter<len)
ris=_asn1_extract_tag_der(p->down,der+counter,len-counter,&len2);
else
ris=ASN1_DER_ERROR;
if(ris==ASN1_SUCCESS){
while(p->down->right){
p2=p->down->right;
asn1_delete_structure(&p2);
}
break;
}
else if(ris==ASN1_ERROR_TYPE_ANY){
asn1_delete_structure(structure);
return ASN1_ERROR_TYPE_ANY;
}
else{
p2=p->down;
asn1_delete_structure(&p2);
}
}
if(p->down==NULL){
if(!(p->type&CONST_OPTION)){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
}
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(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,len-counter,&len2);
if(ris!=ASN1_SUCCESS){
if(p->type&CONST_OPTION){
p->type|=CONST_NOT_USED;
move=RIGHT;
}
else if(p->type&CONST_DEFAULT) {
_asn1_set_value(p,NULL,0);
move=RIGHT;
}
else {
if (errorDescription!=NULL)
_asn1_error_description_tag_error(p,errorDescription);
asn1_delete_structure(structure);
return ASN1_TAG_ERROR;
}
}
else counter+=len2;
}
if(ris==ASN1_SUCCESS){
switch(type_field(p->type)){
case TYPE_NULL:
if(der[counter]){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
if(p==nodeFound) state=EXIT;
counter++;
move=RIGHT;
break;
case TYPE_BOOLEAN:
if(der[counter++]!=1){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
if(state==FOUND){
if(der[counter++]==0) _asn1_set_value(p,"F",1);
else _asn1_set_value(p,"T",1);
if(p==nodeFound) state=EXIT;
}
else
counter++;
move=RIGHT;
break;
case TYPE_INTEGER: case TYPE_ENUMERATED:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
if(state==FOUND){
if (len3+len2 > len-counter) return ASN1_DER_ERROR;
_asn1_set_value(p,der+counter,len3+len2);
if(p==nodeFound) state=EXIT;
}
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_OBJECT_ID:
if(state==FOUND){
_asn1_get_objectid_der(der+counter,len-counter,&len2, temp, sizeof(temp));
_asn1_set_value(p,temp,strlen(temp)+1);
if(p==nodeFound) state=EXIT;
}
else{
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
len2+=len3;
}
counter+=len2;
move=RIGHT;
break;
case TYPE_TIME:
if(state==FOUND){
result = _asn1_get_time_der(der+counter,len-counter,&len2,temp,sizeof(temp)-1);
if (result != ASN1_SUCCESS) {
asn1_delete_structure(structure);
return result;
}
_asn1_set_value(p,temp,strlen(temp)+1);
if(p==nodeFound) state=EXIT;
}
else{
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
len2+=len3;
}
counter+=len2;
move=RIGHT;
break;
case TYPE_OCTET_STRING:
len3=len-counter;
if(state==FOUND){
ris=_asn1_get_octet_string(der+counter,p,&len3);
if(p==nodeFound) state=EXIT;
}
else
ris=_asn1_get_octet_string(der+counter,NULL,&len3);
if(ris != ASN1_SUCCESS) return ris;
counter+=len3;
move=RIGHT;
break;
case TYPE_GENERALSTRING:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
if(state==FOUND){
if (len3+len2 > len-counter) return ASN1_DER_ERROR;
_asn1_set_value(p,der+counter,len3+len2);
if(p==nodeFound) state=EXIT;
}
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_BIT_STRING:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
if(state==FOUND){
if (len3+len2 > len-counter) return ASN1_DER_ERROR;
_asn1_set_value(p,der+counter,len3+len2);
if(p==nodeFound) state=EXIT;
}
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_SEQUENCE: case TYPE_SET:
if(move==UP){
len2=strtol(p->value,NULL,10);
_asn1_set_value(p,NULL,0);
if(len2==-1){
if((der[counter]) || der[counter+1]){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
counter+=2;
}
else{
if(len2!=counter){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
}
if(p==nodeFound) state=EXIT;
move=RIGHT;
}
else{
if(state==OTHER_BRANCH){
len3=_asn1_get_length_der(der+counter,len-counter,&len2);
if(len3 < 0) return ASN1_DER_ERROR;
counter+=len2+len3;
move=RIGHT;
}
else {
len3=_asn1_get_length_der(der+counter,len-counter,&len2);
if(len3 < 0) return ASN1_DER_ERROR;
counter+=len2;
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{
_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;
}
_asn1_set_value(p,NULL,0);
if(len2!=counter){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
if(p==nodeFound) state=EXIT;
}
else{
if(state==OTHER_BRANCH){
len3=_asn1_get_length_der(der+counter,len-counter,&len2);
if(len3 < 0) return ASN1_DER_ERROR;
counter+=len2+len3;
move=RIGHT;
}
else{
len3=_asn1_get_length_der(der+counter,len-counter,&len2);
if(len3 < 0) return ASN1_DER_ERROR;
counter+=len2;
if(len3){
_asn1_ltostr(counter+len3,temp);
_asn1_set_value(p,temp,strlen(temp)+1);
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);
p=p2;
state=FOUND;
}
}
}
break;
case TYPE_ANY:
if((p->type&CONST_TAG) && (der[counter-1]==0x80))
indefinite=1;
else
indefinite=0;
if(_asn1_get_tag_der(der+counter, len-counter,&class,&len2,&tag)!=ASN1_SUCCESS)
return ASN1_DER_ERROR;
if (counter+len2 > len)
return ASN1_DER_ERROR;
len4=_asn1_get_length_der(der+counter+len2,len-counter-len2,&len3);
if(len4 < -1) return ASN1_DER_ERROR;
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{
len2=len-counter;
ris=_asn1_get_indefinite_length_string(der+counter,&len2);
if(ris != ASN1_SUCCESS){
asn1_delete_structure(structure);
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,temp2,&len4);
_asn1_set_value(p,temp2,len4);
_asn1_afree(temp2);
if(p==nodeFound) state=EXIT;
}
counter+=len2;
}
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;
}
}
if((p==node && move!=DOWN) || (state==EXIT)) break;
if(move==DOWN){
if(p->down){
p=p->down;
if(state != FOUND){
nameLen-=strlen(p->name)+1;
if(nameLen>0){
if(currentName[0]) strcat(currentName,".");
strcat(currentName,p->name);
}
else{
asn1_delete_structure(structure);
return ASN1_MEM_ERROR;
}
if(!(strcmp(currentName,elementName))){
state=FOUND;
nodeFound=p;
}
else if(!memcmp(currentName,elementName,strlen(currentName)))
state=SAME_BRANCH;
else
state=OTHER_BRANCH;
}
}
else move=RIGHT;
}
if((move==RIGHT) && !(p->type&CONST_SET)){
if(p->right){
p=p->right;
if(state != FOUND){
dot_p=char_p=currentName;
while((char_p=strchr(char_p,'.'))){
dot_p=char_p++;
dot_p++;
}
nameLen+=strlen(currentName)-(dot_p-currentName);
*dot_p=0;
nameLen-=strlen(p->name);
if(nameLen>0) strcat(currentName,p->name);
else{
asn1_delete_structure(structure);
return ASN1_MEM_ERROR;
}
if(!(strcmp(currentName,elementName))){
state=FOUND;
nodeFound=p;
}
else if(!memcmp(currentName,elementName,strlen(currentName)))
state=SAME_BRANCH;
else
state=OTHER_BRANCH;
}
}
else move=UP;
}
if(move==UP){
p=_asn1_find_up(p);
if(state != FOUND){
dot_p=char_p=currentName;
while((char_p=strchr(char_p,'.'))){
dot_p=char_p++;
dot_p++;
}
nameLen+=strlen(currentName)-(dot_p-currentName);
*dot_p=0;
if(!(strcmp(currentName,elementName))){
state=FOUND;
nodeFound=p;
}
else if(!memcmp(currentName,elementName,strlen(currentName)))
state=SAME_BRANCH;
else
state=OTHER_BRANCH;
}
}
}
_asn1_delete_not_used(*structure);
if(counter > len){
asn1_delete_structure(structure);
return ASN1_DER_ERROR;
}
return ASN1_SUCCESS;
}
asn1_retCode
asn1_der_decoding_startEnd(ASN1_TYPE element,const void *ider,int len,
const char *name_element,int *start, int *end)
{
node_asn *node,*node_to_find,*p,*p2,*p3;
int counter,len2,len3,len4,move,ris;
unsigned char class;
unsigned long tag;
int indefinite;
const unsigned char* der = ider;
node=element;
if(node==ASN1_TYPE_EMPTY) return ASN1_ELEMENT_NOT_FOUND;
node_to_find=_asn1_find_node(node,name_element);
if(node_to_find==NULL) return ASN1_ELEMENT_NOT_FOUND;
if(node_to_find==node){
*start=0;
*end=len-1;
return ASN1_SUCCESS;
}
if(node->type&CONST_OPTION) return ASN1_GENERIC_ERROR;
counter=0;
move=DOWN;
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(len2==-1){
if(!der[counter] && !der[counter+1]){
p=p2;
move=UP;
counter+=2;
continue;
}
}
else if(counter==len2){
p=p2;
move=UP;
continue;
}
else if(counter>len2) return ASN1_DER_ERROR;
p2=p2->down;
while(p2){
if((p2->type&CONST_SET) && (p2->type&CONST_NOT_USED)){
if(type_field(p2->type)!=TYPE_CHOICE)
ris=_asn1_extract_tag_der(p2,der+counter,len-counter,&len2);
else{
p3=p2->down;
ris=_asn1_extract_tag_der(p3,der+counter,len-counter,&len2);
}
if(ris==ASN1_SUCCESS){
p2->type&=~CONST_NOT_USED;
p=p2;
break;
}
}
p2=p2->right;
}
if(p2==NULL) return ASN1_DER_ERROR;
}
if(p==node_to_find) *start=counter;
if(type_field(p->type)==TYPE_CHOICE){
p=p->down;
ris=_asn1_extract_tag_der(p,der+counter,len-counter,&len2);
if(p==node_to_find) *start=counter;
}
if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,len-counter,&len2);
if(ris!=ASN1_SUCCESS){
if(p->type&CONST_OPTION){
p->type|=CONST_NOT_USED;
move=RIGHT;
}
else if(p->type&CONST_DEFAULT) {
move=RIGHT;
}
else {
return ASN1_TAG_ERROR;
}
}
else counter+=len2;
}
if(ris==ASN1_SUCCESS){
switch(type_field(p->type)){
case TYPE_NULL:
if(der[counter]) return ASN1_DER_ERROR;
counter++;
move=RIGHT;
break;
case TYPE_BOOLEAN:
if(der[counter++]!=1) return ASN1_DER_ERROR;
counter++;
move=RIGHT;
break;
case TYPE_INTEGER: case TYPE_ENUMERATED:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_OBJECT_ID:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
counter+=len2+len3;
move=RIGHT;
break;
case TYPE_TIME:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
counter+=len2+len3;
move=RIGHT;
break;
case TYPE_OCTET_STRING:
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:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_BIT_STRING:
len2=_asn1_get_length_der(der+counter,len-counter,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_SEQUENCE: case TYPE_SET:
if(move!=UP){
len3=_asn1_get_length_der(der+counter,len-counter,&len2);
if(len3 < -1) return ASN1_DER_ERROR;
counter+=len2;
if(len3==0) move=RIGHT;
else move=DOWN;
}
else{
if(!der[counter] && !der[counter+1])
counter+=2;
move=RIGHT;
}
break;
case TYPE_SEQUENCE_OF: case TYPE_SET_OF:
if(move!=UP){
len3=_asn1_get_length_der(der+counter,len-counter,&len2);
if(len3 < -1) return ASN1_DER_ERROR;
counter+=len2;
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])
counter+=2;
}
move=RIGHT;
break;
case TYPE_ANY:
if((p->type&CONST_TAG) && (der[counter-1]==0x80))
indefinite=1;
else
indefinite=0;
if (_asn1_get_tag_der(der+counter, len-counter,&class,&len2,&tag)!=ASN1_SUCCESS)
return ASN1_DER_ERROR;
if (counter+len2 > len)
return ASN1_DER_ERROR;
len4=_asn1_get_length_der(der+counter+len2,len-counter-len2,&len3);
if(len4 < -1) return ASN1_DER_ERROR;
if(len4 != -1){
counter+=len2+len4+len3;
}
else{
len2=len-counter;
ris=_asn1_get_indefinite_length_string(der+counter,&len2);
if(ris != ASN1_SUCCESS)
return ris;
counter+=len2;
}
if(indefinite){
if(!der[counter] && !der[counter+1])
counter+=2;
else
return ASN1_DER_ERROR;
}
move=RIGHT;
break;
default:
move=(move==UP)?RIGHT:DOWN;
break;
}
}
if((p==node_to_find) && (move==RIGHT)){
*end=counter-1;
return ASN1_SUCCESS;
}
if(p==node && move!=DOWN) break;
if(move==DOWN){
if(p->down) p=p->down;
else move=RIGHT;
}
if((move==RIGHT) && !(p->type&CONST_SET)){
if(p->right) p=p->right;
else move=UP;
}
if(move==UP) p=_asn1_find_up(p);
}
return ASN1_ELEMENT_NOT_FOUND;
}
asn1_retCode
asn1_expand_any_defined_by(ASN1_TYPE definitions,ASN1_TYPE *element)
{
char definitionsName[MAX_NAME_SIZE],name[2*MAX_NAME_SIZE+1],value[MAX_NAME_SIZE];
asn1_retCode retCode=ASN1_SUCCESS,result;
int len,len2,len3;
ASN1_TYPE p,p2,p3,aux=ASN1_TYPE_EMPTY;
char errorDescription[MAX_ERROR_DESCRIPTION_SIZE];
if((definitions==ASN1_TYPE_EMPTY) || (*element==ASN1_TYPE_EMPTY))
return ASN1_ELEMENT_NOT_FOUND;
strcpy(definitionsName,definitions->name);
strcat(definitionsName,".");
p=*element;
while(p){
switch(type_field(p->type)){
case TYPE_ANY:
if((p->type&CONST_DEFINED_BY) && (p->value)){
p2=p->down;
while((p2) && (type_field(p2->type)!=TYPE_CONSTANT))
p2=p2->right;
if(!p2){
retCode=ASN1_ERROR_TYPE_ANY;
break;
}
p3=_asn1_find_up(p);
if(!p3){
retCode=ASN1_ERROR_TYPE_ANY;
break;
}
p3=p3->down;
while(p3){
if((p3->name) && !(strcmp(p3->name,p2->name))) break;
p3=p3->right;
}
if((!p3) || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
(p3->value==NULL)){
p3=_asn1_find_up(p);
p3=_asn1_find_up(p3);
if(!p3){
retCode=ASN1_ERROR_TYPE_ANY;
break;
}
p3=p3->down;
while(p3){
if((p3->name) && !(strcmp(p3->name,p2->name))) break;
p3=p3->right;
}
if((!p3) || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
(p3->value==NULL)){
retCode=ASN1_ERROR_TYPE_ANY;
break;
}
}
p2=definitions->down;
while(p2){
if((type_field(p2->type)==TYPE_OBJECT_ID) &&
(p2->type & CONST_ASSIGN)){
strcpy(name,definitionsName);
strcat(name,p2->name);
len=MAX_NAME_SIZE;
result=asn1_read_value(definitions,name,value,&len);
if((result == ASN1_SUCCESS) && (!strcmp(p3->value,value))){
p2=p2->right;
while((p2) && (p2->type & CONST_ASSIGN))
p2=p2->right;
if(p2){
strcpy(name,definitionsName);
strcat(name,p2->name);
result=asn1_create_element(definitions,name,&aux);
if(result == ASN1_SUCCESS){
_asn1_set_name(aux,p->name);
len2=_asn1_get_length_der(p->value,p->value_len,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
result=asn1_der_decoding(&aux,p->value+len3,len2,
errorDescription);
if(result == ASN1_SUCCESS){
_asn1_set_right(aux,p->right);
_asn1_set_right(p,aux);
result=asn1_delete_structure(&p);
if(result == ASN1_SUCCESS){
p=aux;
aux=ASN1_TYPE_EMPTY;
break;
}
else{
asn1_delete_structure(&aux);
retCode=result;
break;
}
}
else{
retCode=result;
break;
}
}
else{
retCode=result;
break;
}
}
else{
retCode=ASN1_ERROR_TYPE_ANY;
break;
}
}
}
p2=p2->right;
}
if(!p2){
retCode=ASN1_ERROR_TYPE_ANY;
break;
}
}
break;
default:
break;
}
if(p->down){
p=p->down;
}
else if(p==*element){
p=NULL;
break;
}
else if(p->right) p=p->right;
else{
while(1){
p=_asn1_find_up(p);
if(p==*element){
p=NULL;
break;
}
if(p->right){
p=p->right;
break;
}
}
}
}
return retCode;
}
asn1_retCode
asn1_expand_octet_string(ASN1_TYPE definitions,ASN1_TYPE *element,
const char *octetName,const char *objectName)
{
char name[2*MAX_NAME_SIZE+1],value[MAX_NAME_SIZE];
asn1_retCode retCode=ASN1_SUCCESS,result;
int len,len2,len3;
ASN1_TYPE p2,aux=ASN1_TYPE_EMPTY;
ASN1_TYPE octetNode=ASN1_TYPE_EMPTY,objectNode=ASN1_TYPE_EMPTY;
char errorDescription[MAX_ERROR_DESCRIPTION_SIZE];
if((definitions==ASN1_TYPE_EMPTY) || (*element==ASN1_TYPE_EMPTY))
return ASN1_ELEMENT_NOT_FOUND;
octetNode=_asn1_find_node(*element,octetName);
if(octetNode==ASN1_TYPE_EMPTY)
return ASN1_ELEMENT_NOT_FOUND;
if(type_field(octetNode->type)!=TYPE_OCTET_STRING)
return ASN1_ELEMENT_NOT_FOUND;
if(octetNode->value==NULL)
return ASN1_VALUE_NOT_FOUND;
objectNode=_asn1_find_node(*element,objectName);
if(objectNode==ASN1_TYPE_EMPTY)
return ASN1_ELEMENT_NOT_FOUND;
if(type_field(objectNode->type)!=TYPE_OBJECT_ID)
return ASN1_ELEMENT_NOT_FOUND;
if(objectNode->value==NULL)
return ASN1_VALUE_NOT_FOUND;
p2=definitions->down;
while(p2){
if((type_field(p2->type)==TYPE_OBJECT_ID) &&
(p2->type & CONST_ASSIGN)){
strcpy(name,definitions->name);
strcat(name,".");
strcat(name,p2->name);
len = sizeof(value);
result=asn1_read_value(definitions,name,value,&len);
if((result == ASN1_SUCCESS) && (!strcmp(objectNode->value,value))){
p2=p2->right;
while((p2) && (p2->type & CONST_ASSIGN))
p2=p2->right;
if(p2){
strcpy(name,definitions->name);
strcat(name,".");
strcat(name,p2->name);
result=asn1_create_element(definitions,name,&aux);
if(result == ASN1_SUCCESS){
_asn1_set_name(aux,octetNode->name);
len2=_asn1_get_length_der(octetNode->value,octetNode->value_len,&len3);
if(len2 < 0) return ASN1_DER_ERROR;
result=asn1_der_decoding(&aux,octetNode->value+len3,len2,
errorDescription);
if(result == ASN1_SUCCESS){
_asn1_set_right(aux,octetNode->right);
_asn1_set_right(octetNode,aux);
result=asn1_delete_structure(&octetNode);
if(result == ASN1_SUCCESS){
aux=ASN1_TYPE_EMPTY;
break;
}
else{
asn1_delete_structure(&aux);
retCode=result;
break;
}
}
else{
retCode=result;
break;
}
}
else{
retCode=result;
break;
}
}
else{
retCode=ASN1_VALUE_NOT_VALID;
break;
}
}
}
p2=p2->right;
}
if(!p2) retCode=ASN1_VALUE_NOT_VALID;
return retCode;
}