blob: c99c5a4cb09b36df9551607e12d9c21e2b741899 [file] [log] [blame]
/*
* Copyright (C) 2000-2021 Free Software Foundation, Inc.
*
* This file is part of LIBTASN1.
*
* The LIBTASN1 library is free software; you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include <limits.h> // WORD_BIT
#include "int.h"
#include "parser_aux.h"
#include "gstr.h"
#include "structure.h"
#include "element.h"
#include "c-ctype.h"
char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */
/* Return a hash of the N bytes of X using the method described by
Bruno Haible in https://www.haible.de/bruno/hashfunc.html.
Note that while many hash functions reduce their result via modulo
to a 0..table_size-1 range, this function does not do that.
This implementation has been changed from size_t -> unsigned int. */
#ifdef __clang__
__attribute__((no_sanitize ("integer")))
#endif
_GL_ATTRIBUTE_PURE static unsigned int _asn1_hash_name (const char *x)
{
const unsigned char *s = (unsigned char *) x;
unsigned h = 0;
while (*s)
h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9)));
return h;
}
/******************************************************/
/* Function : _asn1_add_static_node */
/* Description: creates a new NODE_ASN element and */
/* puts it in the list pointed by e_list. */
/* Parameters: */
/* e_list: of type list_type; must be NULL initially */
/* type: type of the new element (see ASN1_ETYPE_ */
/* and CONST_ constants). */
/* Return: pointer to the new element. */
/******************************************************/
asn1_node
_asn1_add_static_node (list_type ** e_list, unsigned int type)
{
list_type *p;
asn1_node punt;
punt = calloc (1, sizeof (struct asn1_node_st));
if (punt == NULL)
return NULL;
p = malloc (sizeof (list_type));
if (p == NULL)
{
free (punt);
return NULL;
}
p->node = punt;
p->next = *e_list;
*e_list = p;
punt->type = type;
return punt;
}
static int
_asn1_add_static_node2 (list_type ** e_list, asn1_node node)
{
list_type *p;
p = malloc (sizeof (list_type));
if (p == NULL)
{
return -1;
}
p->node = node;
p->next = *e_list;
*e_list = p;
return 0;
}
/**
* asn1_find_node:
* @pointer: NODE_ASN element pointer.
* @name: null terminated string with the element's name to find.
*
* Searches for an element called @name starting from @pointer. The
* name is composed by different identifiers separated by dots. When
* *@pointer has a name, the first identifier must be the name of
* *@pointer, otherwise it must be the name of one child of *@pointer.
*
* Returns: the search result, or %NULL if not found.
**/
asn1_node
asn1_find_node (asn1_node_const pointer, const char *name)
{
asn1_node_const p;
char *n_end, n[ASN1_MAX_NAME_SIZE + 1];
const char *n_start;
unsigned int nsize;
unsigned int nhash;
if (pointer == NULL)
return NULL;
if (name == NULL)
return NULL;
p = pointer;
n_start = name;
if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?')
{ /* ?CURRENT */
n_start = strchr (n_start, '.');
if (n_start)
n_start++;
}
else if (p->name[0] != 0)
{ /* has *pointer got a name ? */
n_end = strchr (n_start, '.'); /* search the first dot */
if (n_end)
{
nsize = n_end - n_start;
if (nsize >= sizeof (n))
return NULL;
memcpy (n, n_start, nsize);
n[nsize] = 0;
n_start = n_end;
n_start++;
nhash = _asn1_hash_name (n);
}
else
{
_asn1_str_cpy (n, sizeof (n), n_start);
nhash = _asn1_hash_name (n);
n_start = NULL;
}
while (p)
{
if (nhash == p->name_hash && (!strcmp (p->name, n)))
break;
else
p = p->right;
} /* while */
if (p == NULL)
return NULL;
}
else
{ /* *pointer doesn't have a name */
if (n_start[0] == 0)
return (asn1_node) p;
}
while (n_start)
{ /* Has the end of NAME been reached? */
n_end = strchr (n_start, '.'); /* search the next dot */
if (n_end)
{
nsize = n_end - n_start;
if (nsize >= sizeof (n))
return NULL;
memcpy (n, n_start, nsize);
n[nsize] = 0;
n_start = n_end;
n_start++;
nhash = _asn1_hash_name (n);
}
else
{
_asn1_str_cpy (n, sizeof (n), n_start);
nhash = _asn1_hash_name (n);
n_start = NULL;
}
if (p->down == NULL)
return NULL;
p = p->down;
if (p == NULL)
return NULL;
/* The identifier "?LAST" indicates the last element
in the right chain. */
if (n[0] == '?' && n[1] == 'L') /* ?LAST */
{
while (p->right)
p = p->right;
}
else
{ /* no "?LAST" */
while (p)
{
if (p->name_hash == nhash && !strcmp (p->name, n))
break;
else
p = p->right;
}
}
if (p == NULL)
return NULL;
} /* while */
return (asn1_node) p;
}
/******************************************************************/
/* Function : _asn1_set_value */
/* Description: sets the field VALUE in a NODE_ASN element. The */
/* previous value (if exist) will be lost */
/* Parameters: */
/* node: element pointer. */
/* value: pointer to the value that you want to set. */
/* len: character number of value. */
/* Return: pointer to the NODE_ASN element. */
/******************************************************************/
asn1_node
_asn1_set_value (asn1_node node, const void *value, unsigned int len)
{
if (node == NULL)
return node;
if (node->value)
{
if (node->value != node->small_value)
free (node->value);
node->value = NULL;
node->value_len = 0;
}
if (!len)
return node;
if (len < sizeof (node->small_value))
{
node->value = node->small_value;
}
else
{
node->value = malloc (len);
if (node->value == NULL)
return NULL;
}
node->value_len = len;
memcpy (node->value, value, len);
return node;
}
/******************************************************************/
/* Function : _asn1_set_value_lv */
/* Description: sets the field VALUE in a NODE_ASN element. The */
/* previous value (if exist) will be lost. The value */
/* given is stored as an length-value format (LV */
/* Parameters: */
/* node: element pointer. */
/* value: pointer to the value that you want to set. */
/* len: character number of value. */
/* Return: pointer to the NODE_ASN element. */
/******************************************************************/
asn1_node
_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len)
{
int len2;
void *temp;
if (node == NULL)
return node;
asn1_length_der (len, NULL, &len2);
temp = malloc (len + len2);
if (temp == NULL)
return NULL;
asn1_octet_der (value, len, temp, &len2);
return _asn1_set_value_m (node, temp, len2);
}
/* the same as _asn1_set_value except that it sets an already malloc'ed
* value.
*/
asn1_node
_asn1_set_value_m (asn1_node node, void *value, unsigned int len)
{
if (node == NULL)
return node;
if (node->value)
{
if (node->value != node->small_value)
free (node->value);
node->value = NULL;
node->value_len = 0;
}
if (!len)
return node;
node->value = value;
node->value_len = len;
return node;
}
/******************************************************************/
/* Function : _asn1_append_value */
/* Description: appends to the field VALUE in a NODE_ASN element. */
/* */
/* Parameters: */
/* node: element pointer. */
/* value: pointer to the value that you want to be appended. */
/* len: character number of value. */
/* Return: pointer to the NODE_ASN element. */
/******************************************************************/
asn1_node
_asn1_append_value (asn1_node node, const void *value, unsigned int len)
{
if (node == NULL)
return node;
if (node->value == NULL)
return _asn1_set_value (node, value, len);
if (len == 0)
return node;
if (node->value == node->small_value)
{
/* value is in node */
int prev_len = node->value_len;
node->value_len += len;
node->value = malloc (node->value_len);
if (node->value == NULL)
{
node->value_len = 0;
return NULL;
}
if (prev_len > 0)
memcpy (node->value, node->small_value, prev_len);
memcpy (&node->value[prev_len], value, len);
return node;
}
else /* if (node->value != NULL && node->value != node->small_value) */
{
/* value is allocated */
int prev_len = node->value_len;
node->value_len += len;
node->value = _asn1_realloc (node->value, node->value_len);
if (node->value == NULL)
{
node->value_len = 0;
return NULL;
}
memcpy (&node->value[prev_len], value, len);
return node;
}
}
/******************************************************************/
/* Function : _asn1_set_name */
/* Description: sets the field NAME in a NODE_ASN element. The */
/* previous value (if exist) will be lost */
/* Parameters: */
/* node: element pointer. */
/* name: a null terminated string with the name that you want */
/* to set. */
/* Return: pointer to the NODE_ASN element. */
/******************************************************************/
asn1_node
_asn1_set_name (asn1_node node, const char *name)
{
if (node == NULL)
return node;
_asn1_str_cpy (node->name, sizeof (node->name), name ? name : "");
node->name_hash = _asn1_hash_name (node->name);
return node;
}
/******************************************************************/
/* Function : _asn1_cpy_name */
/* Description: copies the field NAME in a NODE_ASN element. */
/* Parameters: */
/* dst: a dest element pointer. */
/* src: a source element pointer. */
/* Return: pointer to the NODE_ASN element. */
/******************************************************************/
asn1_node
_asn1_cpy_name (asn1_node dst, asn1_node_const src)
{
if (dst == NULL)
return dst;
if (src == NULL)
{
dst->name[0] = 0;
dst->name_hash = _asn1_hash_name (dst->name);
return dst;
}
_asn1_str_cpy (dst->name, sizeof (dst->name), src->name);
dst->name_hash = src->name_hash;
return dst;
}
/******************************************************************/
/* Function : _asn1_set_right */
/* Description: sets the field RIGHT in a NODE_ASN element. */
/* Parameters: */
/* node: element pointer. */
/* right: pointer to a NODE_ASN element that you want be pointed*/
/* by NODE. */
/* Return: pointer to *NODE. */
/******************************************************************/
asn1_node
_asn1_set_right (asn1_node node, asn1_node right)
{
if (node == NULL)
return node;
node->right = right;
if (right)
right->left = node;
return node;
}
/******************************************************************/
/* Function : _asn1_get_last_right */
/* Description: return the last element along the right chain. */
/* Parameters: */
/* node: starting element pointer. */
/* Return: pointer to the last element along the right chain. */
/******************************************************************/
asn1_node
_asn1_get_last_right (asn1_node_const node)
{
asn1_node_const p;
if (node == NULL)
return NULL;
p = node;
while (p->right)
p = p->right;
return (asn1_node) p;
}
/******************************************************************/
/* Function : _asn1_remove_node */
/* Description: gets free the memory allocated for an NODE_ASN */
/* element (not the elements pointed by it). */
/* Parameters: */
/* node: NODE_ASN element pointer. */
/* flags: ASN1_DELETE_FLAG_* */
/******************************************************************/
void
_asn1_remove_node (asn1_node node, unsigned int flags)
{
if (node == NULL)
return;
if (node->value != NULL)
{
if (flags & ASN1_DELETE_FLAG_ZEROIZE)
{
safe_memset (node->value, 0, node->value_len);
}
if (node->value != node->small_value)
free (node->value);
}
free (node);
}
/******************************************************************/
/* Function : _asn1_find_up */
/* Description: return the father of the NODE_ASN element. */
/* Parameters: */
/* node: NODE_ASN element pointer. */
/* Return: Null if not found. */
/******************************************************************/
asn1_node
_asn1_find_up (asn1_node_const node)
{
asn1_node_const p;
if (node == NULL)
return NULL;
p = node;
while ((p->left != NULL) && (p->left->right == p))
p = p->left;
return p->left;
}
static unsigned
_asn1_is_up (asn1_node_const up_cand, asn1_node_const down)
{
asn1_node_const d, u;
if (up_cand == NULL || down == NULL)
return 0;
d = down;
while ((u = _asn1_find_up (d)) != NULL && u != d)
{
if (u == up_cand)
return 1;
d = u;
}
return 0;
}
/******************************************************************/
/* Function : _asn1_delete_node_from_list */
/* Description: deletes the list element given */
/******************************************************************/
void
_asn1_delete_node_from_list (list_type * list, asn1_node node)
{
list_type *p = list;
while (p)
{
if (p->node == node)
p->node = NULL;
p = p->next;
}
}
/******************************************************************/
/* Function : _asn1_delete_list */
/* Description: deletes the list elements (not the elements */
/* pointed by them). */
/******************************************************************/
void
_asn1_delete_list (list_type * e_list)
{
list_type *p;
while (e_list)
{
p = e_list;
e_list = e_list->next;
free (p);
}
}
/******************************************************************/
/* Function : _asn1_delete_list_and nodes */
/* Description: deletes the list elements and the elements */
/* pointed by them. */
/******************************************************************/
void
_asn1_delete_list_and_nodes (list_type * e_list)
{
list_type *p;
while (e_list)
{
p = e_list;
e_list = e_list->next;
_asn1_remove_node (p->node, 0);
free (p);
}
}
char *
_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
{
uint64_t d, r;
char temp[LTOSTR_MAX_SIZE];
int count, k, start;
uint64_t val;
if (v < 0)
{
str[0] = '-';
start = 1;
val = -((uint64_t) v);
}
else
{
val = v;
start = 0;
}
count = 0;
do
{
d = val / 10;
r = val - d * 10;
temp[start + count] = '0' + (char) r;
count++;
val = d;
}
while (val && ((start + count) < LTOSTR_MAX_SIZE - 1));
for (k = 0; k < count; k++)
str[k + start] = temp[start + count - k - 1];
str[count + start] = 0;
return str;
}
/******************************************************************/
/* Function : _asn1_change_integer_value */
/* Description: converts into DER coding the value assign to an */
/* INTEGER constant. */
/* Parameters: */
/* node: root of an ASN1element. */
/* Return: */
/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
/* otherwise ASN1_SUCCESS */
/******************************************************************/
int
_asn1_change_integer_value (asn1_node node)
{
asn1_node 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) == ASN1_ETYPE_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 && p->right)
{
p = p->right;
break;
}
}
}
}
}
return ASN1_SUCCESS;
}
#define MAX_CONSTANTS 1024
/******************************************************************/
/* Function : _asn1_expand_object_id */
/* Description: expand the IDs of an OBJECT IDENTIFIER constant. */
/* Parameters: */
/* list: root of an object list */
/* node: root of an ASN1 element. */
/* Return: */
/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
/* otherwise ASN1_SUCCESS */
/******************************************************************/
int
_asn1_expand_object_id (list_type ** list, asn1_node node)
{
asn1_node p, p2, p3, p4, p5;
char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1];
int move, tlen, tries;
unsigned max_constants;
if (node == NULL)
return ASN1_ELEMENT_NOT_FOUND;
_asn1_str_cpy (name_root, sizeof (name_root), node->name);
p = node;
move = DOWN;
tries = 0;
while (!((p == node) && (move == UP)))
{
if (move != UP)
{
if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID)
&& (p->type & CONST_ASSIGN))
{
p2 = p->down;
if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
{
if (p2->value && !c_isdigit (p2->value[0]))
{
_asn1_str_cpy (name2, sizeof (name2), name_root);
_asn1_str_cat (name2, sizeof (name2), ".");
_asn1_str_cat (name2, sizeof (name2),
(char *) p2->value);
p3 = asn1_find_node (node, name2);
if (!p3 || _asn1_is_up (p2, p3) ||
(type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
!(p3->type & CONST_ASSIGN))
return ASN1_ELEMENT_NOT_FOUND;
_asn1_set_down (p, p2->right);
if (p2->down)
_asn1_delete_structure (*list, &p2->down, 0);
_asn1_delete_node_from_list (*list, p2);
_asn1_remove_node (p2, 0);
p2 = p;
p4 = p3->down;
max_constants = 0;
while (p4)
{
if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
{
max_constants++;
if (max_constants == MAX_CONSTANTS)
return ASN1_RECURSION;
p5 =
_asn1_add_single_node (ASN1_ETYPE_CONSTANT);
_asn1_set_name (p5, p4->name);
if (p4->value)
{
tlen = _asn1_strlen (p4->value);
if (tlen > 0)
_asn1_set_value (p5, p4->value, tlen + 1);
}
_asn1_add_static_node2 (list, p5);
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;
tries++;
if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION)
return ASN1_RECURSION;
continue;
}
}
}
move = DOWN;
}
else
move = RIGHT;
tries = 0;
if (move == DOWN)
{
if (p->down)
p = p->down;
else
move = RIGHT;
}
if (p == node)
{
move = UP;
continue;
}
if (move == RIGHT)
{
if (p && p->right)
p = p->right;
else
move = UP;
}
if (move == UP)
p = _asn1_find_up (p);
}
/*******************************/
/* expand DEFAULT */
/*******************************/
p = node;
move = DOWN;
while (!((p == node) && (move == UP)))
{
if (move != UP)
{
if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
(p->type & CONST_DEFAULT))
{
p2 = p->down;
if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
{
_asn1_str_cpy (name2, sizeof (name2), name_root);
_asn1_str_cat (name2, sizeof (name2), ".");
if (p2->value)
_asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
p3 = asn1_find_node (node, name2);
if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
|| !(p3->type & CONST_ASSIGN))
return ASN1_ELEMENT_NOT_FOUND;
p4 = p3->down;
name2[0] = 0;
while (p4)
{
if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
{
if (p4->value == NULL)
return ASN1_VALUE_NOT_FOUND;
if (name2[0])
_asn1_str_cat (name2, sizeof (name2), ".");
_asn1_str_cat (name2, sizeof (name2),
(char *) p4->value);
}
p4 = p4->right;
}
tlen = strlen (name2);
if (tlen > 0)
_asn1_set_value (p2, name2, tlen + 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 && p->right)
p = p->right;
else
move = UP;
}
if (move == UP)
p = _asn1_find_up (p);
}
return ASN1_SUCCESS;
}
/******************************************************************/
/* Function : _asn1_type_set_config */
/* Description: sets the CONST_SET and CONST_NOT_USED properties */
/* in the fields of the SET elements. */
/* Parameters: */
/* node: root of an ASN1 element. */
/* Return: */
/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
/* otherwise ASN1_SUCCESS */
/******************************************************************/
int
_asn1_type_set_config (asn1_node node)
{
asn1_node 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) == ASN1_ETYPE_SET)
{
p2 = p->down;
while (p2)
{
if (type_field (p2->type) != ASN1_ETYPE_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 && p->right)
p = p->right;
else
move = UP;
}
if (move == UP)
p = _asn1_find_up (p);
}
return ASN1_SUCCESS;
}
/******************************************************************/
/* Function : _asn1_check_identifier */
/* Description: checks the definitions of all the identifiers */
/* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */
/* The _asn1_identifierMissing global variable is filled if */
/* necessary. */
/* Parameters: */
/* node: root of an ASN1 element. */
/* Return: */
/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
/* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */
/* otherwise ASN1_SUCCESS */
/******************************************************************/
int
_asn1_check_identifier (asn1_node_const node)
{
asn1_node_const p, p2;
char name2[ASN1_MAX_NAME_SIZE * 2 + 2];
if (node == NULL)
return ASN1_ELEMENT_NOT_FOUND;
p = node;
while (p)
{
if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
{
_asn1_str_cpy (name2, sizeof (name2), node->name);
_asn1_str_cat (name2, sizeof (name2), ".");
_asn1_str_cat (name2, sizeof (name2), (char *) p->value);
p2 = asn1_find_node (node, name2);
if (p2 == NULL)
{
if (p->value)
_asn1_str_cpy (_asn1_identifierMissing,
sizeof (_asn1_identifierMissing),
(char *) p->value);
else
_asn1_strcpy (_asn1_identifierMissing, "(null)");
return ASN1_IDENTIFIER_NOT_FOUND;
}
}
else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
(p->type & CONST_DEFAULT))
{
p2 = p->down;
if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
{
_asn1_str_cpy (name2, sizeof (name2), node->name);
if (p2->value)
{
_asn1_str_cat (name2, sizeof (name2), ".");
_asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
_asn1_str_cpy (_asn1_identifierMissing,
sizeof (_asn1_identifierMissing),
(char *) p2->value);
}
else
_asn1_strcpy (_asn1_identifierMissing, "(null)");
p2 = asn1_find_node (node, name2);
if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ||
!(p2->type & CONST_ASSIGN))
return ASN1_IDENTIFIER_NOT_FOUND;
else
_asn1_identifierMissing[0] = 0;
}
}
else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
(p->type & CONST_ASSIGN))
{
p2 = p->down;
if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
{
if (p2->value && !c_isdigit (p2->value[0]))
{
_asn1_str_cpy (name2, sizeof (name2), node->name);
_asn1_str_cat (name2, sizeof (name2), ".");
_asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
_asn1_str_cpy (_asn1_identifierMissing,
sizeof (_asn1_identifierMissing),
(char *) p2->value);
p2 = asn1_find_node (node, name2);
if (!p2 || (type_field (p2->type) != ASN1_ETYPE_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 (p)
{
p = _asn1_find_up (p);
if (p == node)
{
p = NULL;
break;
}
if (p && p->right)
{
p = p->right;
break;
}
}
}
}
return ASN1_SUCCESS;
}
/******************************************************************/
/* Function : _asn1_set_default_tag */
/* Description: sets the default IMPLICIT or EXPLICIT property in */
/* the tagged elements that don't have this declaration. */
/* Parameters: */
/* node: pointer to a DEFINITIONS element. */
/* Return: */
/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */
/* a DEFINITIONS element, */
/* otherwise ASN1_SUCCESS */
/******************************************************************/
int
_asn1_set_default_tag (asn1_node node)
{
asn1_node p;
if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS))
return ASN1_ELEMENT_NOT_FOUND;
p = node;
while (p)
{
if ((type_field (p->type) == ASN1_ETYPE_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 && p->right)
{
p = p->right;
break;
}
}
}
}
return ASN1_SUCCESS;
}