mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-10-07 04:02:18 +03:00
775 lines
24 KiB
C
775 lines
24 KiB
C
/*
|
|
* Copyright (C) 2004, 2006, 2007 Free Software Foundation
|
|
* Copyright (C) 2000,2001 Fabio Fiorina
|
|
*
|
|
* 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 <int.h>
|
|
#include "parser_aux.h"
|
|
#include "gstr.h"
|
|
#include "structure.h"
|
|
#include "element.h"
|
|
|
|
|
|
|
|
char MHD__asn1_identifierMissing[MAX_NAME_SIZE + 1]; /* identifier name not found */
|
|
|
|
/***********************************************/
|
|
/* Type: list_type */
|
|
/* Description: type used in the list during */
|
|
/* the structure creation. */
|
|
/***********************************************/
|
|
typedef struct list_struct
|
|
{
|
|
node_asn *node;
|
|
struct list_struct *next;
|
|
} list_type;
|
|
|
|
|
|
/* Pointer to the first element of the list */
|
|
list_type *MHD_firstElement = NULL;
|
|
|
|
/******************************************************/
|
|
/* Function : MHD__asn1_add_node */
|
|
/* Description: creates a new NODE_ASN element and */
|
|
/* puts it in the list pointed by MHD_firstElement. */
|
|
/* Parameters: */
|
|
/* type: type of the new element (see TYPE_ */
|
|
/* and CONST_ constants). */
|
|
/* Return: pointer to the new element. */
|
|
/******************************************************/
|
|
node_asn *
|
|
MHD__asn1_add_node (unsigned int type)
|
|
{
|
|
list_type *listElement;
|
|
node_asn *punt;
|
|
|
|
punt = (node_asn *) MHD__asn1_calloc (1, sizeof (node_asn));
|
|
if (punt == NULL)
|
|
return NULL;
|
|
|
|
listElement = (list_type *) MHD__asn1_malloc (sizeof (list_type));
|
|
if (listElement == NULL)
|
|
{
|
|
MHD__asn1_free (punt);
|
|
return NULL;
|
|
}
|
|
|
|
listElement->node = punt;
|
|
listElement->next = MHD_firstElement;
|
|
MHD_firstElement = listElement;
|
|
|
|
punt->type = type;
|
|
|
|
return punt;
|
|
}
|
|
|
|
/**
|
|
* MHD__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 differents 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.
|
|
*
|
|
* Return value: the searching result. NULL if not found.
|
|
**/
|
|
ASN1_TYPE
|
|
MHD__asn1_find_node (ASN1_TYPE 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)
|
|
{ /* has *pointer got a name ? */
|
|
n_end = strchr (n_start, '.'); /* search the first dot */
|
|
if (n_end)
|
|
{
|
|
memcpy (n, n_start, n_end - n_start);
|
|
n[n_end - n_start] = 0;
|
|
n_start = n_end;
|
|
n_start++;
|
|
}
|
|
else
|
|
{
|
|
MHD__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;
|
|
} /* while */
|
|
|
|
if (p == NULL)
|
|
return NULL;
|
|
}
|
|
else
|
|
{ /* *pointer doesn't have a name */
|
|
if (n_start[0] == 0)
|
|
return p;
|
|
}
|
|
|
|
while (n_start)
|
|
{ /* Has the end of NAME been reached? */
|
|
n_end = strchr (n_start, '.'); /* search the next dot */
|
|
if (n_end)
|
|
{
|
|
memcpy (n, n_start, n_end - n_start);
|
|
n[n_end - n_start] = 0;
|
|
n_start = n_end;
|
|
n_start++;
|
|
}
|
|
else
|
|
{
|
|
MHD__asn1_str_cpy (n, sizeof (n), n_start);
|
|
n_start = NULL;
|
|
}
|
|
|
|
if (p->down == NULL)
|
|
return NULL;
|
|
|
|
p = p->down;
|
|
|
|
/* The identifier "?LAST" indicates the last element
|
|
in the right chain. */
|
|
if (!strcmp (n, "?LAST"))
|
|
{
|
|
if (p == NULL)
|
|
return NULL;
|
|
while (p->right)
|
|
p = p->right;
|
|
}
|
|
else
|
|
{ /* no "?LAST" */
|
|
while (p)
|
|
{
|
|
if ((p->name) && (!strcmp (p->name, n)))
|
|
break;
|
|
else
|
|
p = p->right;
|
|
}
|
|
if (p == NULL)
|
|
return NULL;
|
|
}
|
|
} /* while */
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__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. */
|
|
/******************************************************************/
|
|
node_asn *
|
|
MHD__asn1_set_value (node_asn * node, const void *_value, unsigned int len)
|
|
{
|
|
const unsigned char *value = _value;
|
|
|
|
if (node == NULL)
|
|
return node;
|
|
if (node->value)
|
|
{
|
|
MHD__asn1_free (node->value);
|
|
node->value = NULL;
|
|
node->value_len = 0;
|
|
}
|
|
if (!len)
|
|
return node;
|
|
node->value = (unsigned char *) MHD__asn1_malloc (len);
|
|
if (node->value == NULL)
|
|
return NULL;
|
|
node->value_len = len;
|
|
|
|
memcpy (node->value, value, len);
|
|
return node;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__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. */
|
|
/******************************************************************/
|
|
node_asn *
|
|
MHD__asn1_set_name (node_asn * node, const char *name)
|
|
{
|
|
if (node == NULL)
|
|
return node;
|
|
|
|
if (node->name)
|
|
{
|
|
MHD__asn1_free (node->name);
|
|
node->name = NULL;
|
|
}
|
|
|
|
if (name == NULL)
|
|
return node;
|
|
|
|
if (strlen (name))
|
|
{
|
|
node->name = (char *) MHD__asn1_strdup (name);
|
|
if (node->name == NULL)
|
|
return NULL;
|
|
}
|
|
else
|
|
node->name = NULL;
|
|
return node;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__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. */
|
|
/******************************************************************/
|
|
node_asn *
|
|
MHD__asn1_set_right (node_asn * node, node_asn * right)
|
|
{
|
|
if (node == NULL)
|
|
return node;
|
|
node->right = right;
|
|
if (right)
|
|
right->left = node;
|
|
return node;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__asn1_set_down */
|
|
/* Description: sets the field DOWN in a NODE_ASN element. */
|
|
/* Parameters: */
|
|
/* node: element pointer. */
|
|
/* down: pointer to a NODE_ASN element that you want be pointed */
|
|
/* by NODE. */
|
|
/* Return: pointer to *NODE. */
|
|
/******************************************************************/
|
|
node_asn *
|
|
MHD__asn1_set_down (node_asn * node, node_asn * down)
|
|
{
|
|
if (node == NULL)
|
|
return node;
|
|
node->down = down;
|
|
if (down)
|
|
down->left = node;
|
|
return node;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__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. */
|
|
/******************************************************************/
|
|
void
|
|
MHD__asn1_remove_node (node_asn * node)
|
|
{
|
|
if (node == NULL)
|
|
return;
|
|
|
|
if (node->name != NULL)
|
|
MHD__asn1_free (node->name);
|
|
if (node->value != NULL)
|
|
MHD__asn1_free (node->value);
|
|
MHD__asn1_free (node);
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__asn1_find_up */
|
|
/* Description: return the father of the NODE_ASN element. */
|
|
/* Parameters: */
|
|
/* node: NODE_ASN element pointer. */
|
|
/* Return: Null if not found. */
|
|
/******************************************************************/
|
|
node_asn *
|
|
MHD__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;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__asn1_delete_list */
|
|
/* Description: deletes the list elements (not the elements */
|
|
/* pointed by them). */
|
|
/******************************************************************/
|
|
void
|
|
MHD__asn1_delete_list (void)
|
|
{
|
|
list_type *listElement;
|
|
|
|
while (MHD_firstElement)
|
|
{
|
|
listElement = MHD_firstElement;
|
|
MHD_firstElement = MHD_firstElement->next;
|
|
MHD__asn1_free (listElement);
|
|
}
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__asn1_delete_list_and nodes */
|
|
/* Description: deletes the list elements and the elements */
|
|
/* pointed by them. */
|
|
/******************************************************************/
|
|
void
|
|
MHD__asn1_delete_list_and_nodes (void)
|
|
{
|
|
list_type *listElement;
|
|
|
|
while (MHD_firstElement)
|
|
{
|
|
listElement = MHD_firstElement;
|
|
MHD_firstElement = MHD_firstElement->next;
|
|
MHD__asn1_remove_node (listElement->node);
|
|
MHD__asn1_free (listElement);
|
|
}
|
|
}
|
|
|
|
|
|
char *
|
|
MHD__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;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__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 */
|
|
/******************************************************************/
|
|
MHD__asn1_retCode
|
|
MHD__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)
|
|
{
|
|
MHD__asn1_convert_integer ((const char *) p->value, val,
|
|
sizeof (val), &len);
|
|
MHD__asn1_octet_der (val, len, val2, &len);
|
|
MHD__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 = MHD__asn1_find_up (p);
|
|
if (p == node)
|
|
{
|
|
p = NULL;
|
|
break;
|
|
}
|
|
if (p->right)
|
|
{
|
|
p = p->right;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ASN1_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__asn1_expand_object_id */
|
|
/* Description: expand the IDs of an OBJECT IDENTIFIER constant. */
|
|
/* Parameters: */
|
|
/* node: root of an ASN1 element. */
|
|
/* Return: */
|
|
/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
|
|
/* otherwise ASN1_SUCCESS */
|
|
/******************************************************************/
|
|
MHD__asn1_retCode
|
|
MHD__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, tlen;
|
|
|
|
if (node == NULL)
|
|
return ASN1_ELEMENT_NOT_FOUND;
|
|
|
|
MHD__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]))
|
|
{
|
|
MHD__asn1_str_cpy (name2, sizeof (name2), name_root);
|
|
MHD__asn1_str_cat (name2, sizeof (name2), ".");
|
|
MHD__asn1_str_cat (name2, sizeof (name2),
|
|
(const char *) p2->value);
|
|
p3 = MHD__asn1_find_node (node, name2);
|
|
if (!p3 || (type_field (p3->type) != TYPE_OBJECT_ID) ||
|
|
!(p3->type & CONST_ASSIGN))
|
|
return ASN1_ELEMENT_NOT_FOUND;
|
|
MHD__asn1_set_down (p, p2->right);
|
|
MHD__asn1_remove_node (p2);
|
|
p2 = p;
|
|
p4 = p3->down;
|
|
while (p4)
|
|
{
|
|
if (type_field (p4->type) == TYPE_CONSTANT)
|
|
{
|
|
p5 = MHD__asn1_add_node_only (TYPE_CONSTANT);
|
|
MHD__asn1_set_name (p5, p4->name);
|
|
tlen = strlen ((const char *) p4->value);
|
|
if (tlen > 0)
|
|
MHD__asn1_set_value (p5, p4->value, tlen + 1);
|
|
if (p2 == p)
|
|
{
|
|
MHD__asn1_set_right (p5, p->down);
|
|
MHD__asn1_set_down (p, p5);
|
|
}
|
|
else
|
|
{
|
|
MHD__asn1_set_right (p5, p2->right);
|
|
MHD__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 = MHD__asn1_find_up (p);
|
|
}
|
|
|
|
|
|
/*******************************/
|
|
/* expand DEFAULT */
|
|
/*******************************/
|
|
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))
|
|
{
|
|
MHD__asn1_str_cpy (name2, sizeof (name2), name_root);
|
|
MHD__asn1_str_cat (name2, sizeof (name2), ".");
|
|
MHD__asn1_str_cat (name2, sizeof (name2),
|
|
(const char *) p2->value);
|
|
p3 = MHD__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])
|
|
MHD__asn1_str_cat (name2, sizeof (name2), ".");
|
|
MHD__asn1_str_cat (name2, sizeof (name2),
|
|
(const char *) p4->value);
|
|
}
|
|
p4 = p4->right;
|
|
}
|
|
tlen = strlen (name2);
|
|
if (tlen > 0)
|
|
MHD__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->right)
|
|
p = p->right;
|
|
else
|
|
move = UP;
|
|
}
|
|
if (move == UP)
|
|
p = MHD__asn1_find_up (p);
|
|
}
|
|
|
|
return ASN1_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* Function : MHD__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 MHD__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 */
|
|
/******************************************************************/
|
|
MHD__asn1_retCode
|
|
MHD__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)
|
|
{
|
|
MHD__asn1_str_cpy (name2, sizeof (name2), node->name);
|
|
MHD__asn1_str_cat (name2, sizeof (name2), ".");
|
|
MHD__asn1_str_cat (name2, sizeof (name2), (const char *) p->value);
|
|
p2 = MHD__asn1_find_node (node, name2);
|
|
if (p2 == NULL)
|
|
{
|
|
strcpy (MHD__asn1_identifierMissing, (const char *) 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))
|
|
{
|
|
MHD__asn1_str_cpy (name2, sizeof (name2), node->name);
|
|
MHD__asn1_str_cat (name2, sizeof (name2), ".");
|
|
MHD__asn1_str_cat (name2, sizeof (name2),
|
|
(const char *) p2->value);
|
|
strcpy (MHD__asn1_identifierMissing, (const char *) p2->value);
|
|
p2 = MHD__asn1_find_node (node, name2);
|
|
if (!p2 || (type_field (p2->type) != TYPE_OBJECT_ID) ||
|
|
!(p2->type & CONST_ASSIGN))
|
|
return ASN1_IDENTIFIER_NOT_FOUND;
|
|
else
|
|
MHD__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]))
|
|
{
|
|
MHD__asn1_str_cpy (name2, sizeof (name2), node->name);
|
|
MHD__asn1_str_cat (name2, sizeof (name2), ".");
|
|
MHD__asn1_str_cat (name2, sizeof (name2),
|
|
(const char *) p2->value);
|
|
strcpy (MHD__asn1_identifierMissing,
|
|
(const char *) p2->value);
|
|
p2 = MHD__asn1_find_node (node, name2);
|
|
if (!p2 || (type_field (p2->type) != TYPE_OBJECT_ID) ||
|
|
!(p2->type & CONST_ASSIGN))
|
|
return ASN1_IDENTIFIER_NOT_FOUND;
|
|
else
|
|
MHD__asn1_identifierMissing[0] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p->down)
|
|
{
|
|
p = p->down;
|
|
}
|
|
else if (p->right)
|
|
p = p->right;
|
|
else
|
|
{
|
|
while (1)
|
|
{
|
|
p = MHD__asn1_find_up (p);
|
|
if (p == node)
|
|
{
|
|
p = NULL;
|
|
break;
|
|
}
|
|
if (p->right)
|
|
{
|
|
p = p->right;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ASN1_SUCCESS;
|
|
}
|