#include <int.h>
#include <errors.h>
#include "der.h"
#include "parser_aux.h"
#include <gstr.h>
#include "element.h"
#define MAX_TAG_LEN 16
void
_asn1_error_description_value_not_found(node_asn *node,char *ErrorDescription)
{
if (ErrorDescription == NULL) return;
Estrcpy(ErrorDescription,":: value of element '");
_asn1_hierarchical_name(node,ErrorDescription+strlen(ErrorDescription),
MAX_ERROR_DESCRIPTION_SIZE-40);
Estrcat(ErrorDescription,"' not found");
}
void
_asn1_length_der(unsigned long len,unsigned char *ans,int *ans_len)
{
int k;
unsigned char temp[SIZEOF_UNSIGNED_LONG_INT];
if(len<128){
if(ans!=NULL) ans[0]=(unsigned char)len;
*ans_len=1;
}
else{
k=0;
while(len){
temp[k++]=len&0xFF;
len=len>>8;
}
*ans_len=k+1;
if(ans!=NULL){
ans[0]=((unsigned char)k&0x7F)+128;
while(k--) ans[*ans_len-1-k]=temp[k];
}
}
}
void
_asn1_tag_der(unsigned char class,unsigned int tag_value,unsigned char *ans,int *ans_len)
{
int k;
unsigned char temp[SIZEOF_UNSIGNED_INT];
if(tag_value<31){
ans[0]=(class&0xE0) + ((unsigned char)(tag_value&0x1F));
*ans_len=1;
}
else{
ans[0]=(class&0xE0) + 31;
k=0;
while(tag_value){
temp[k++]=tag_value&0x7F;
tag_value=tag_value>>7;
}
*ans_len=k+1;
while(k--) ans[*ans_len-1-k]=temp[k]+128;
ans[*ans_len-1]-=128;
}
}
void
_asn1_octet_der(const unsigned char *str,int str_len,unsigned char *der,int *der_len)
{
int len_len;
if(der==NULL || str_len <= 0) return;
_asn1_length_der(str_len,der,&len_len);
memcpy(der+len_len,str,str_len);
*der_len=str_len+len_len;
}
asn1_retCode
_asn1_time_der(unsigned char *str,unsigned char *der,int *der_len)
{
int len_len;
int max_len;
max_len=*der_len;
_asn1_length_der(strlen(str),(max_len>0)?der:NULL,&len_len);
if((len_len+(int)strlen(str))<=max_len)
memcpy(der+len_len,str,strlen(str));
*der_len=len_len+strlen(str);
if((*der_len)>max_len) return ASN1_MEM_ERROR;
return ASN1_SUCCESS;
}
asn1_retCode
_asn1_objectid_der(unsigned char *str,unsigned char *der,int *der_len)
{
int len_len,counter,k,first,max_len;
char *temp,*n_end,*n_start;
unsigned char bit7;
unsigned long val,val1=0;
max_len=*der_len;
temp=(char *) _asn1_alloca(strlen(str)+2);
if(temp==NULL) return ASN1_MEM_ALLOC_ERROR;
strcpy(temp, str);
strcat(temp, ".");
counter=0;
n_start=temp;
while((n_end=strchr(n_start,'.'))){
*n_end=0;
val=strtoul(n_start,NULL,10);
counter++;
if(counter==1) val1=val;
else if(counter==2){
if(max_len>0)
der[0]=40*val1+val;
*der_len=1;
}
else{
first=0;
for(k=4;k>=0;k--){
bit7=(val>>(k*7))&0x7F;
if(bit7 || first || !k){
if(k) bit7|=0x80;
if(max_len>(*der_len))
der[*der_len]=bit7;
(*der_len)++;
first=1;
}
}
}
n_start=n_end+1;
}
_asn1_length_der(*der_len,NULL,&len_len);
if(max_len>=(*der_len+len_len)){
memmove(der+len_len,der,*der_len);
_asn1_length_der(*der_len,der,&len_len);
}
*der_len+=len_len;
_asn1_afree(temp);
if(max_len<(*der_len)) return ASN1_MEM_ERROR;
return ASN1_SUCCESS;
}
char bit_mask[]={0xFF,0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80};
void
_asn1_bit_der(const unsigned char *str,int bit_len,unsigned char *der,int *der_len)
{
int len_len,len_byte,len_pad;
if(der==NULL) return;
len_byte=bit_len>>3;
len_pad=8-(bit_len&7);
if(len_pad==8) len_pad=0;
else len_byte++;
_asn1_length_der(len_byte+1,der,&len_len);
der[len_len]=len_pad;
memcpy(der+len_len+1,str,len_byte);
der[len_len+len_byte]&=bit_mask[len_pad];
*der_len=len_byte+len_len+1;
}
asn1_retCode
_asn1_complete_explicit_tag(node_asn *node,unsigned char *der,int *counter,int *max_len)
{
node_asn *p;
int is_tag_implicit,len2,len3;
unsigned char temp[SIZEOF_UNSIGNED_INT];
is_tag_implicit=0;
if(node->type&CONST_TAG){
p=node->down;
while(p->right)
p=p->right;
while(p && p!=node->down->left){
if(type_field(p->type)==TYPE_TAG){
if(p->type&CONST_EXPLICIT){
len2=strtol(p->name,NULL,10);
_asn1_set_name(p,NULL);
_asn1_length_der(*counter-len2,temp,&len3);
if(len3<=(*max_len)){
memmove(der+len2+len3,der+len2,*counter-len2);
memcpy(der+len2,temp,len3);
}
*max_len -= len3;
*counter+=len3;
is_tag_implicit=0;
}
else{
if(!is_tag_implicit){
is_tag_implicit=1;
}
}
}
p=p->left;
}
}
if(*max_len<0) return ASN1_MEM_ERROR;
return ASN1_SUCCESS;
}
asn1_retCode
_asn1_insert_tag_der(node_asn *node,unsigned char *der,int *counter,int *max_len)
{
node_asn *p;
int tag_len,is_tag_implicit;
unsigned char class,class_implicit=0,temp[SIZEOF_UNSIGNED_INT*3+1];
unsigned long tag_implicit=0;
char tag_der[MAX_TAG_LEN];
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) class=APPLICATION;
else if(p->type&CONST_UNIVERSAL) class=UNIVERSAL;
else if(p->type&CONST_PRIVATE) class=PRIVATE;
else class=CONTEXT_SPECIFIC;
if(p->type&CONST_EXPLICIT){
if(is_tag_implicit)
_asn1_tag_der(class_implicit,tag_implicit,tag_der,&tag_len);
else
_asn1_tag_der(class|STRUCTURED,strtoul(p->value,NULL,10),tag_der,&tag_len);
*max_len -= tag_len;
if(*max_len>=0)
memcpy(der+*counter,tag_der,tag_len);
*counter+=tag_len;
_asn1_ltostr(*counter,temp);
_asn1_set_name(p,temp);
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)) class|=STRUCTURED;
class_implicit=class;
tag_implicit=strtoul(p->value,NULL,10);
is_tag_implicit=1;
}
}
}
p=p->right;
}
}
if(is_tag_implicit){
_asn1_tag_der(class_implicit,tag_implicit,tag_der,&tag_len);
}
else{
switch(type_field(node->type)){
case TYPE_NULL:
_asn1_tag_der(UNIVERSAL,TAG_NULL,tag_der,&tag_len);
break;
case TYPE_BOOLEAN:
_asn1_tag_der(UNIVERSAL,TAG_BOOLEAN,tag_der,&tag_len);
break;
case TYPE_INTEGER:
_asn1_tag_der(UNIVERSAL,TAG_INTEGER,tag_der,&tag_len);
break;
case TYPE_ENUMERATED:
_asn1_tag_der(UNIVERSAL,TAG_ENUMERATED,tag_der,&tag_len);
break;
case TYPE_OBJECT_ID:
_asn1_tag_der(UNIVERSAL,TAG_OBJECT_ID,tag_der,&tag_len);
break;
case TYPE_TIME:
if(node->type&CONST_UTC){
_asn1_tag_der(UNIVERSAL,TAG_UTCTime,tag_der,&tag_len);
}
else _asn1_tag_der(UNIVERSAL,TAG_GENERALIZEDTime,tag_der,&tag_len);
break;
case TYPE_OCTET_STRING:
_asn1_tag_der(UNIVERSAL,TAG_OCTET_STRING,tag_der,&tag_len);
break;
case TYPE_GENERALSTRING:
_asn1_tag_der(UNIVERSAL,TAG_GENERALSTRING,tag_der,&tag_len);
break;
case TYPE_BIT_STRING:
_asn1_tag_der(UNIVERSAL,TAG_BIT_STRING,tag_der,&tag_len);
break;
case TYPE_SEQUENCE: case TYPE_SEQUENCE_OF:
_asn1_tag_der(UNIVERSAL|STRUCTURED,TAG_SEQUENCE,tag_der,&tag_len);
break;
case TYPE_SET: case TYPE_SET_OF:
_asn1_tag_der(UNIVERSAL|STRUCTURED,TAG_SET,tag_der,&tag_len);
break;
case TYPE_TAG:
tag_len=0;
break;
case TYPE_CHOICE:
tag_len=0;
break;
case TYPE_ANY:
tag_len=0;
break;
default:
return ASN1_GENERIC_ERROR;
}
}
*max_len -= tag_len;
if(*max_len>=0)
memcpy(der+*counter,tag_der,tag_len);
*counter+=tag_len;
if(*max_len<0) return ASN1_MEM_ERROR;
return ASN1_SUCCESS;
}
void
_asn1_ordering_set(unsigned char *der, int der_len, node_asn *node)
{
struct vet{
int end;
unsigned long value;
struct vet *next,*prev;
};
int counter,len,len2;
struct vet *first,*last,*p_vet,*p2_vet;
node_asn *p;
unsigned char class,*temp;
unsigned long tag;
counter=0;
if(type_field(node->type)!=TYPE_SET) return;
p=node->down;
while((type_field(p->type)==TYPE_TAG) || (type_field(p->type)==TYPE_SIZE)) p=p->right;
if((p==NULL) || (p->right==NULL)) return;
first=last=NULL;
while(p){
p_vet=(struct vet *)_asn1_alloca( sizeof(struct vet));
if (p_vet==NULL) return;
p_vet->next=NULL;
p_vet->prev=last;
if(first==NULL) first=p_vet;
else last->next=p_vet;
last=p_vet;
if (_asn1_get_tag_der(der+counter, der_len-counter,&class,&len2, &tag)!=ASN1_SUCCESS)
return;
p_vet->value=(class<<24)|tag;
counter+=len2;
len2=_asn1_get_length_der(der+counter,der_len-counter,&len);
if (len2<0) return;
counter+=len+len2;
p_vet->end=counter;
p=p->right;
}
p_vet=first;
while(p_vet){
p2_vet=p_vet->next;
counter=0;
while(p2_vet){
if(p_vet->value>p2_vet->value){
temp=(unsigned char *)_asn1_alloca( p_vet->end-counter);
if (temp==NULL) return;
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);
tag=p_vet->value;
p_vet->value=p2_vet->value;
p2_vet->value=tag;
p_vet->end=counter+(p2_vet->end-p_vet->end);
}
counter=p_vet->end;
p2_vet=p2_vet->next;
p_vet=p_vet->next;
}
if(p_vet!=first) p_vet->prev->next=NULL;
else first=NULL;
_asn1_afree(p_vet);
p_vet=first;
}
}
void
_asn1_ordering_set_of(unsigned char *der, int der_len, node_asn *node)
{
struct vet{
int end;
struct vet *next,*prev;
};
int counter,len,len2,change;
struct vet *first,*last,*p_vet,*p2_vet;
node_asn *p;
unsigned char *temp,class;
unsigned long k,max;
counter=0;
if(type_field(node->type)!=TYPE_SET_OF) return;
p=node->down;
while((type_field(p->type)==TYPE_TAG) || (type_field(p->type)==TYPE_SIZE)) p=p->right;
p=p->right;
if((p==NULL) || (p->right==NULL)) return;
first=last=NULL;
while(p){
p_vet=(struct vet *)_asn1_alloca(sizeof(struct vet));
if (p_vet==NULL) return;
p_vet->next=NULL;
p_vet->prev=last;
if(first==NULL) first=p_vet;
else last->next=p_vet;
last=p_vet;
if (der_len-counter > 0) {
if (_asn1_get_tag_der(der+counter, der_len - counter, &class,&len,NULL)!=ASN1_SUCCESS)
return;
counter+=len;
len2=_asn1_get_length_der(der+counter,der_len-counter,&len);
if (len2<0) return;
counter+=len+len2;
}
p_vet->end=counter;
p=p->right;
}
p_vet=first;
while(p_vet){
p2_vet=p_vet->next;
counter=0;
while(p2_vet){
if((p_vet->end-counter)>(p2_vet->end-p_vet->end))
max=p_vet->end-counter;
else
max=p2_vet->end-p_vet->end;
change=-1;
for(k=0;k<max;k++)
if(der[counter+k]>der[p_vet->end+k]){change=1;break;}
else if(der[counter+k]<der[p_vet->end+k]){change=0;break;}
if((change==-1) && ((p_vet->end-counter)>(p2_vet->end-p_vet->end)))
change=1;
if(change==1){
temp=(unsigned char *)_asn1_alloca(p_vet->end-counter);
if (temp==NULL) return;
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);
}
counter=p_vet->end;
p2_vet=p2_vet->next;
p_vet=p_vet->next;
}
if(p_vet!=first) p_vet->prev->next=NULL;
else first=NULL;
_asn1_afree(p_vet);
p_vet=first;
}
}
asn1_retCode
asn1_der_coding(ASN1_TYPE element,const char *name,void *ider,int *len,
char *ErrorDescription)
{
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;
unsigned char* der = ider;
node=_asn1_find_node(element,name);
if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
max_len=*len;
counter=0;
move=DOWN;
p=node;
while(1){
counter_old=counter;
max_len_old=max_len;
if(move!=UP){
ris=_asn1_insert_tag_der(p,der,&counter,&max_len);
}
switch(type_field(p->type)){
case TYPE_NULL:
max_len--;
if(max_len>=0)
der[counter++]=0;
move=RIGHT;
break;
case TYPE_BOOLEAN:
if((p->type&CONST_DEFAULT) && (p->value==NULL)){
counter=counter_old;
max_len=max_len_old;
}
else{
if(p->value==NULL){
_asn1_error_description_value_not_found(p,ErrorDescription);
return ASN1_VALUE_NOT_FOUND;
}
max_len -= 2;
if(max_len>=0){
der[counter++]=1;
if(p->value[0]=='F') der[counter++]=0;
else der[counter++]=0xFF;
}
else
counter+=2;
}
move=RIGHT;
break;
case TYPE_INTEGER: case TYPE_ENUMERATED:
if((p->type&CONST_DEFAULT) && (p->value==NULL)){
counter=counter_old;
max_len=max_len_old;
}
else{
if(p->value==NULL){
_asn1_error_description_value_not_found(p,ErrorDescription);
return ASN1_VALUE_NOT_FOUND;
}
len2=_asn1_get_length_der(p->value,p->value_len, &len3);
if (len2<0) return ASN1_DER_ERROR;
max_len -= len2+len3;
if(max_len>=0)
memcpy(der+counter,p->value,len3+len2);
counter+=len3+len2;
}
move=RIGHT;
break;
case TYPE_OBJECT_ID:
if((p->type&CONST_DEFAULT) && (p->value==NULL)){
counter=counter_old;
max_len=max_len_old;
}
else{
if(p->value==NULL){
_asn1_error_description_value_not_found(p,ErrorDescription);
return ASN1_VALUE_NOT_FOUND;
}
len2=max_len;
ris=_asn1_objectid_der(p->value,der+counter,&len2);
if(ris==ASN1_MEM_ALLOC_ERROR) return ris;
max_len-=len2;
counter+=len2;
}
move=RIGHT;
break;
case TYPE_TIME:
if(p->value==NULL){
_asn1_error_description_value_not_found(p,ErrorDescription);
return ASN1_VALUE_NOT_FOUND;
}
len2=max_len;
ris=_asn1_time_der(p->value,der+counter,&len2);
max_len-=len2;
counter+=len2;
move=RIGHT;
break;
case TYPE_OCTET_STRING:
if(p->value==NULL){
_asn1_error_description_value_not_found(p,ErrorDescription);
return ASN1_VALUE_NOT_FOUND;
}
len2=_asn1_get_length_der(p->value,p->value_len,&len3);
if (len2<0) return ASN1_DER_ERROR;
max_len-=len2+len3;
if(max_len>=0)
memcpy(der+counter,p->value,len3+len2);
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_GENERALSTRING:
if(p->value==NULL){
_asn1_error_description_value_not_found(p,ErrorDescription);
return ASN1_VALUE_NOT_FOUND;
}
len2=_asn1_get_length_der(p->value,p->value_len,&len3);
if (len2<0) return ASN1_DER_ERROR;
max_len-=len2+len3;
if(max_len>=0)
memcpy(der+counter,p->value,len3+len2);
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_BIT_STRING:
if(p->value==NULL){
_asn1_error_description_value_not_found(p,ErrorDescription);
return ASN1_VALUE_NOT_FOUND;
}
len2=_asn1_get_length_der(p->value,p->value_len,&len3);
if (len2<0) return ASN1_DER_ERROR;
max_len-=len2+len3;
if(max_len>=0)
memcpy(der+counter,p->value,len3+len2);
counter+=len3+len2;
move=RIGHT;
break;
case TYPE_SEQUENCE: case TYPE_SET:
if(move!=UP){
_asn1_ltostr(counter,temp);
_asn1_set_value(p,temp,strlen(temp)+1);
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{
len2=strtol(p->value,NULL,10);
_asn1_set_value(p,NULL,0);
if((type_field(p->type)==TYPE_SET) && (max_len>=0))
_asn1_ordering_set(der+len2, max_len-len2,p);
_asn1_length_der(counter-len2,temp,&len3);
max_len-=len3;
if(max_len>=0){
memmove(der+len2+len3,der+len2,counter-len2);
memcpy(der+len2,temp,len3);
}
counter+=len3;
move=RIGHT;
}
break;
case TYPE_SEQUENCE_OF: case TYPE_SET_OF:
if(move!=UP){
_asn1_ltostr(counter,temp);
_asn1_set_value(p,temp,strlen(temp)+1);
p=p->down;
while((type_field(p->type)==TYPE_TAG) || (type_field(p->type)==TYPE_SIZE)) p=p->right;
if(p->right){
p=p->right;
move=RIGHT;
continue;
}
else p=_asn1_find_up(p);
move=UP;
}
if(move==UP){
len2=strtol(p->value,NULL,10);
_asn1_set_value(p,NULL,0);
if((type_field(p->type)==TYPE_SET_OF) && (max_len-len2>0)) {
_asn1_ordering_set_of(der+len2, max_len-len2,p);
}
_asn1_length_der(counter-len2,temp,&len3);
max_len-=len3;
if(max_len>=0){
memmove(der+len2+len3,der+len2,counter-len2);
memcpy(der+len2,temp,len3);
}
counter+=len3;
move=RIGHT;
}
break;
case TYPE_ANY:
if(p->value==NULL){
_asn1_error_description_value_not_found(p,ErrorDescription);
return ASN1_VALUE_NOT_FOUND;
}
len2=_asn1_get_length_der(p->value,p->value_len,&len3);
if (len2<0) return ASN1_DER_ERROR;
max_len-=len2;
if(max_len>=0)
memcpy(der+counter,p->value+len3,len2);
counter+=len2;
move=RIGHT;
break;
default:
move=(move==UP)?RIGHT:DOWN;
break;
}
if((move!=DOWN) && (counter!=counter_old)){
ris=_asn1_complete_explicit_tag(p,der,&counter,&max_len);
}
if(p==node && move!=DOWN) break;
if(move==DOWN){
if(p->down) p=p->down;
else move=RIGHT;
}
if(move==RIGHT){
if(p->right) p=p->right;
else move=UP;
}
if(move==UP) p=_asn1_find_up(p);
}
*len=counter;
if(max_len<0) return ASN1_MEM_ERROR;
return ASN1_SUCCESS;
}