#include <int.h>
#include <errors.h>
#include "parser_aux.h"
#include "der.h"
#include "gstr.h"
#include "structure.h"
#include "element.h"
char _asn1_identifierMissing[MAX_NAME_SIZE+1];
typedef struct list_struct{
node_asn *node;
struct list_struct *next;
} list_type;
list_type *firstElement=NULL;
node_asn *
_asn1_add_node(unsigned int type)
{
list_type *listElement;
node_asn *punt;
punt=(node_asn *) _asn1_malloc(sizeof(node_asn));
if (punt==NULL) return NULL;
listElement=(list_type *) _asn1_malloc(sizeof(list_type));
if(listElement==NULL){
_asn1_free(punt);
return NULL;
}
listElement->node=punt;
listElement->next=firstElement;
firstElement=listElement;
punt->left=NULL;
punt->name=NULL;
punt->type=type;
punt->value=NULL;
punt->down=NULL;
punt->right=NULL;
return punt;
}
node_asn *
_asn1_find_node(node_asn *pointer,const char *name)
{
node_asn *p;
char *n_end,n[MAX_NAME_SIZE+1];
const char *n_start;
if(pointer == NULL) return NULL;
if(name==NULL) return NULL;
p=pointer;
n_start=name;
if(p->name != NULL){
n_end=strchr(n_start,'.');
if(n_end){
memcpy(n,n_start,n_end-n_start);
n[n_end-n_start]=0;
n_start=n_end;
n_start++;
}
else{
_asn1_str_cpy(n,sizeof(n),n_start);
n_start=NULL;
}
while(p){
if((p->name) && (!strcmp(p->name,n))) break;
else p=p->right;
}
if(p==NULL) return NULL;
}
else{
if(n_start[0]==0)
return p;
}
while(n_start){
n_end=strchr(n_start,'.');
if(n_end){
memcpy(n,n_start,n_end-n_start);
n[n_end-n_start]=0;
n_start=n_end;
n_start++;
}
else{
_asn1_str_cpy(n,sizeof(n),n_start);
n_start=NULL;
}
if(p->down==NULL) return NULL;
p=p->down;
if(!strcmp(n,"?LAST")){
if(p==NULL) return NULL;
while(p->right) p=p->right;
}
else{
while(p){
if((p->name) && (!strcmp(p->name,n))) break;
else p=p->right;
}
if(p==NULL) return NULL;
}
}
return p;
}
node_asn *
_asn1_set_value(node_asn *node,const unsigned char *value,unsigned int len)
{
if(node==NULL) return node;
if(node->value){
_asn1_free(node->value);
node->value=NULL;
node->value_len = 0;
}
if(!len) return node;
node->value=(unsigned char *) _asn1_malloc(len);
if (node->value==NULL) return NULL;
node->value_len = len;
memcpy(node->value,value,len);
return node;
}
node_asn *
_asn1_set_name(node_asn *node,const char *name)
{
if(node==NULL) return node;
if(node->name){
_asn1_free(node->name);
node->name=NULL;
}
if(name==NULL) return node;
if(strlen(name))
{
node->name=(char *) _asn1_strdup( name);
if (node->name==NULL) return NULL;
}
else node->name=NULL;
return node;
}
node_asn *
_asn1_set_right(node_asn *node,node_asn *right)
{
if(node==NULL) return node;
node->right=right;
if(right) right->left=node;
return node;
}
node_asn *
_asn1_get_right(node_asn *node)
{
if(node==NULL) return NULL;
return node->right;
}
node_asn *
_asn1_get_last_right(node_asn *node)
{
node_asn *p;
if(node==NULL) return NULL;
p=node;
while(p->right) p=p->right;
return p;
}
node_asn *
_asn1_set_down(node_asn *node,node_asn *down)
{
if(node==NULL) return node;
node->down=down;
if(down) down->left=node;
return node;
}
node_asn *
_asn1_get_down(node_asn *node)
{
if(node==NULL) return NULL;
return node->down;
}
char *
_asn1_get_name(node_asn *node)
{
if(node==NULL) return NULL;
return node->name;
}
node_asn *
_asn1_mod_type(node_asn *node,unsigned int value)
{
if(node==NULL) return node;
node->type|=value;
return node;
}
void
_asn1_remove_node(node_asn *node)
{
if(node==NULL) return;
if (node->name!=NULL)
_asn1_free(node->name);
if (node->value!=NULL)
_asn1_free(node->value);
_asn1_free(node);
}
node_asn *
_asn1_find_up(node_asn *node)
{
node_asn *p;
if(node==NULL) return NULL;
p=node;
while((p->left!=NULL) && (p->left->right==p)) p=p->left;
return p->left;
}
void
_asn1_delete_list(void)
{
list_type *listElement;
while(firstElement){
listElement=firstElement;
firstElement=firstElement->next;
_asn1_free(listElement);
}
}
void
_asn1_delete_list_and_nodes(void)
{
list_type *listElement;
while(firstElement){
listElement=firstElement;
firstElement=firstElement->next;
_asn1_remove_node(listElement->node);
_asn1_free(listElement);
}
}
char *
_asn1_ltostr(long v,char *str)
{
long d,r;
char temp[20];
int count,k,start;
if(v<0){
str[0]='-';
start=1;
v=-v;
}
else start=0;
count=0;
do{
d=v/10;
r=v-d*10;
temp[start+count]='0'+(char)r;
count++;
v=d;
}while(v);
for(k=0;k<count;k++) str[k+start]=temp[start+count-k-1];
str[count+start]=0;
return str;
}
asn1_retCode
_asn1_change_integer_value(ASN1_TYPE node)
{
node_asn *p;
unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
unsigned char val2[SIZEOF_UNSIGNED_LONG_INT+1];
int len;
if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
p=node;
while(p){
if((type_field(p->type)==TYPE_INTEGER) && (p->type&CONST_ASSIGN)){
if(p->value){
_asn1_convert_integer(p->value,val,sizeof(val), &len);
_asn1_octet_der(val,len,val2,&len);
_asn1_set_value(p,val2,len);
}
}
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_expand_object_id(ASN1_TYPE node)
{
node_asn *p,*p2,*p3,*p4,*p5;
char name_root[MAX_NAME_SIZE],name2[2*MAX_NAME_SIZE+1];
int move;
if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
_asn1_str_cpy(name_root, sizeof(name_root), node->name);
p=node;
move=DOWN;
while(!((p==node) && (move==UP))){
if(move!=UP){
if((type_field(p->type)==TYPE_OBJECT_ID) && (p->type&CONST_ASSIGN)){
p2=p->down;
if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
if(p2->value && !isdigit(p2->value[0])){
_asn1_str_cpy(name2, sizeof(name2), name_root);
_asn1_str_cat(name2, sizeof(name2), ".");
_asn1_str_cat(name2, sizeof(name2), p2->value);
p3=_asn1_find_node(node,name2);
if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
!(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
_asn1_set_down(p,p2->right);
_asn1_remove_node(p2);
p2=p;
p4=p3->down;
while(p4){
if(type_field(p4->type)==TYPE_CONSTANT){
p5=_asn1_add_node_only(TYPE_CONSTANT);
_asn1_set_name(p5,p4->name);
_asn1_set_value(p5,p4->value,strlen(p4->value)+1);
if(p2==p){
_asn1_set_right(p5,p->down);
_asn1_set_down(p,p5);
}
else{
_asn1_set_right(p5,p2->right);
_asn1_set_right(p2,p5);
}
p2=p5;
}
p4=p4->right;
}
move=DOWN;
continue;
}
}
}
move=DOWN;
}
else move=RIGHT;
if(move==DOWN){
if(p->down) p=p->down;
else move=RIGHT;
}
if(p==node) {move=UP; continue;}
if(move==RIGHT){
if(p->right) p=p->right;
else move=UP;
}
if(move==UP) p=_asn1_find_up(p);
}
p=node;
move=DOWN;
while(!((p==node) && (move==UP))){
if(move!=UP){
if((type_field(p->type)==TYPE_OBJECT_ID) &&
(p->type&CONST_DEFAULT)){
p2=p->down;
if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
_asn1_str_cpy(name2, sizeof(name2), name_root);
_asn1_str_cat(name2, sizeof(name2), ".");
_asn1_str_cat(name2, sizeof(name2), p2->value);
p3=_asn1_find_node(node,name2);
if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
!(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
p4=p3->down;
name2[0]=0;
while(p4){
if(type_field(p4->type)==TYPE_CONSTANT){
if(name2[0]) _asn1_str_cat(name2,sizeof(name2),".");
_asn1_str_cat(name2,sizeof(name2),p4->value);
}
p4=p4->right;
}
_asn1_set_value(p2,name2,strlen(name2)+1);
}
}
move=DOWN;
}
else move=RIGHT;
if(move==DOWN){
if(p->down) p=p->down;
else move=RIGHT;
}
if(p==node) {move=UP; continue;}
if(move==RIGHT){
if(p->right) p=p->right;
else move=UP;
}
if(move==UP) p=_asn1_find_up(p);
}
return ASN1_SUCCESS;
}
asn1_retCode
_asn1_type_set_config(ASN1_TYPE node)
{
node_asn *p,*p2;
int move;
if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
p=node;
move=DOWN;
while(!((p==node) && (move==UP))){
if(move!=UP){
if(type_field(p->type)==TYPE_SET){
p2=p->down;
while(p2){
if(type_field(p2->type)!=TYPE_TAG)
p2->type|=CONST_SET|CONST_NOT_USED;
p2=p2->right;
}
}
move=DOWN;
}
else move=RIGHT;
if(move==DOWN){
if(p->down) p=p->down;
else move=RIGHT;
}
if(p==node) {move=UP; continue;}
if(move==RIGHT){
if(p->right) p=p->right;
else move=UP;
}
if(move==UP) p=_asn1_find_up(p);
}
return ASN1_SUCCESS;
}
asn1_retCode
_asn1_check_identifier(ASN1_TYPE node)
{
node_asn *p,*p2;
char name2[MAX_NAME_SIZE*2+2];
if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
p=node;
while(p){
if(type_field(p->type)==TYPE_IDENTIFIER){
_asn1_str_cpy(name2, sizeof(name2), node->name);
_asn1_str_cat(name2, sizeof(name2), ".");
_asn1_str_cat(name2, sizeof(name2), p->value);
p2=_asn1_find_node(node,name2);
if(p2==NULL){
strcpy(_asn1_identifierMissing,p->value);
return ASN1_IDENTIFIER_NOT_FOUND;
}
}
else if((type_field(p->type)==TYPE_OBJECT_ID) &&
(p->type&CONST_DEFAULT)){
p2=p->down;
if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
_asn1_str_cpy(name2, sizeof(name2), node->name);
_asn1_str_cat(name2, sizeof(name2), ".");
_asn1_str_cat(name2, sizeof(name2), p2->value);
strcpy(_asn1_identifierMissing,p2->value);
p2=_asn1_find_node(node,name2);
if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
!(p2->type&CONST_ASSIGN))
return ASN1_IDENTIFIER_NOT_FOUND;
else
_asn1_identifierMissing[0]=0;
}
}
else if((type_field(p->type)==TYPE_OBJECT_ID) &&
(p->type&CONST_ASSIGN)){
p2=p->down;
if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
if(p2->value && !isdigit(p2->value[0])){
_asn1_str_cpy(name2, sizeof(name2), node->name);
_asn1_str_cat(name2, sizeof(name2), ".");
_asn1_str_cat(name2, sizeof(name2), p2->value);
strcpy(_asn1_identifierMissing,p2->value);
p2=_asn1_find_node(node,name2);
if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
!(p2->type&CONST_ASSIGN))
return ASN1_IDENTIFIER_NOT_FOUND;
else
_asn1_identifierMissing[0]=0;
}
}
}
if(p->down){
p=p->down;
}
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_set_default_tag(ASN1_TYPE node)
{
node_asn *p;
if((node==NULL) || (type_field(node->type)!=TYPE_DEFINITIONS))
return ASN1_ELEMENT_NOT_FOUND;
p=node;
while(p){
if((type_field(p->type)==TYPE_TAG) &&
!(p->type&CONST_EXPLICIT) &&
!(p->type&CONST_IMPLICIT)){
if(node->type&CONST_EXPLICIT) p->type|=CONST_EXPLICIT;
else p->type|=CONST_IMPLICIT;
}
if(p->down){
p=p->down;
}
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;
}
static const char*
parse_version_number( const char *s, int *number )
{
int val = 0;
if( *s == '0' && isdigit(s[1]) )
return NULL;
for ( ; isdigit(*s); s++ ) {
val *= 10;
val += *s - '0';
}
*number = val;
return val < 0? NULL : s;
}
static const char *
parse_version_string( const char *s, int *major, int *minor, int *micro )
{
s = parse_version_number( s, major );
if( !s || *s != '.' )
return NULL;
s++;
s = parse_version_number( s, minor );
if( !s || *s != '.' )
return NULL;
s++;
s = parse_version_number( s, micro );
if( !s )
return NULL;
return s;
}
const char *
asn1_check_version( const char *req_version )
{
const char *ver = LIBTASN1_VERSION;
int my_major, my_minor, my_micro;
int rq_major, rq_minor, rq_micro;
const char *my_plvl, *rq_plvl;
if ( !req_version )
return ver;
my_plvl = parse_version_string( ver, &my_major, &my_minor, &my_micro );
if ( !my_plvl )
return NULL;
rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor,
&rq_micro );
if ( !rq_plvl )
return NULL;
if ( my_major > rq_major
|| (my_major == rq_major && my_minor > rq_minor)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro > rq_micro)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro == rq_micro
&& strcmp( my_plvl, rq_plvl ) >= 0) ) {
return ver;
}
return NULL;
}