| /* | |
| * Copyright (C) 2002-2025 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, see | |
| * <https://www.gnu.org/licenses/>. | |
| */ | |
| #include <config.h> | |
| /*****************************************************/ | |
| /* File: structure.c */ | |
| /* Description: Functions to create and delete an */ | |
| /* ASN1 tree. */ | |
| /*****************************************************/ | |
| #include "int.h" | |
| #include "structure.h" | |
| #include "parser_aux.h" | |
| #include "gstr.h" | |
| #include "c-ctype.h" | |
| #include "element.h" | |
| #include <limits.h> | |
| extern char _asn1_identifierMissing[]; | |
| /******************************************************/ | |
| /* Function : _asn1_add_single_node */ | |
| /* Description: creates a new NODE_ASN element. */ | |
| /* Parameters: */ | |
| /* type: type of the new element (see ASN1_ETYPE_ */ | |
| /* and CONST_ constants). */ | |
| /* Return: pointer to the new element. */ | |
| /******************************************************/ | |
| asn1_node | |
| _asn1_add_single_node (unsigned int type) | |
| { | |
| asn1_node punt; | |
| punt = calloc (1, sizeof (struct asn1_node_st)); | |
| if (punt == NULL) | |
| return NULL; | |
| punt->type = type; | |
| return punt; | |
| } | |
| /******************************************************************/ | |
| /* Function : _asn1_find_left */ | |
| /* Description: returns the NODE_ASN element with RIGHT field that*/ | |
| /* points the element NODE. */ | |
| /* Parameters: */ | |
| /* node: NODE_ASN element pointer. */ | |
| /* Return: NULL if not found. */ | |
| /******************************************************************/ | |
| asn1_node | |
| _asn1_find_left (asn1_node_const node) | |
| { | |
| if ((node == NULL) || (node->left == NULL) || (node->left->down == node)) | |
| return NULL; | |
| return node->left; | |
| } | |
| int | |
| _asn1_create_static_structure (asn1_node_const pointer, | |
| char *output_file_name, char *vector_name) | |
| { | |
| FILE *file; | |
| asn1_node_const p; | |
| unsigned long t; | |
| file = fopen (output_file_name, "w"); | |
| if (file == NULL) | |
| return ASN1_FILE_NOT_FOUND; | |
| fprintf (file, "#if HAVE_CONFIG_H\n"); | |
| fprintf (file, "# include \"config.h\"\n"); | |
| fprintf (file, "#endif\n\n"); | |
| fprintf (file, "#include <libtasn1.h>\n\n"); | |
| fprintf (file, "const asn1_static_node %s[] = {\n", vector_name); | |
| p = pointer; | |
| while (p) | |
| { | |
| fprintf (file, " { "); | |
| if (p->name[0] != 0) | |
| fprintf (file, "\"%s\", ", p->name); | |
| else | |
| fprintf (file, "NULL, "); | |
| t = p->type; | |
| if (p->down) | |
| t |= CONST_DOWN; | |
| if (p->right) | |
| t |= CONST_RIGHT; | |
| fprintf (file, "%lu, ", t); | |
| if (p->value) | |
| fprintf (file, "\"%s\"},\n", p->value); | |
| else | |
| fprintf (file, "NULL },\n"); | |
| if (p->down) | |
| { | |
| p = p->down; | |
| } | |
| else if (p->right) | |
| { | |
| p = p->right; | |
| } | |
| else | |
| { | |
| while (1) | |
| { | |
| p = _asn1_find_up (p); | |
| if (p == pointer) | |
| { | |
| p = NULL; | |
| break; | |
| } | |
| if (p->right) | |
| { | |
| p = p->right; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| fprintf (file, " { NULL, 0, NULL }\n};\n"); | |
| fclose (file); | |
| return ASN1_SUCCESS; | |
| } | |
| /** | |
| * asn1_array2tree: | |
| * @array: specify the array that contains ASN.1 declarations | |
| * @definitions: return the pointer to the structure created by | |
| * *ARRAY ASN.1 declarations | |
| * @errorDescription: return the error description. | |
| * | |
| * Creates the structures needed to manage the ASN.1 definitions. | |
| * @array is a vector created by asn1_parser2array(). | |
| * | |
| * Returns: %ASN1_SUCCESS if structure was created correctly, | |
| * %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL, | |
| * %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier | |
| * that is not defined (see @errorDescription for more information), | |
| * %ASN1_ARRAY_ERROR if the array pointed by @array is wrong. | |
| **/ | |
| int | |
| asn1_array2tree (const asn1_static_node *array, asn1_node *definitions, | |
| char *errorDescription) | |
| { | |
| asn1_node p, p_last = NULL; | |
| unsigned long k; | |
| int move; | |
| int result; | |
| unsigned int type; | |
| list_type *e_list = NULL; | |
| if (errorDescription) | |
| errorDescription[0] = 0; | |
| if (*definitions != NULL) | |
| return ASN1_ELEMENT_NOT_EMPTY; | |
| move = UP; | |
| for (k = 0; array[k].value || array[k].type || array[k].name; k++) | |
| { | |
| type = convert_old_type (array[k].type); | |
| p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN)); | |
| if (array[k].name) | |
| _asn1_set_name (p, array[k].name); | |
| if (array[k].value) | |
| _asn1_set_value (p, array[k].value, strlen (array[k].value) + 1); | |
| if (*definitions == NULL) | |
| *definitions = p; | |
| if (move == DOWN) | |
| { | |
| if (p_last && p_last->down) | |
| _asn1_delete_structure (e_list, &p_last->down, 0); | |
| _asn1_set_down (p_last, p); | |
| } | |
| else if (move == RIGHT) | |
| { | |
| if (p_last && p_last->right) | |
| _asn1_delete_structure (e_list, &p_last->right, 0); | |
| _asn1_set_right (p_last, p); | |
| } | |
| p_last = p; | |
| if (type & CONST_DOWN) | |
| move = DOWN; | |
| else if (type & CONST_RIGHT) | |
| move = RIGHT; | |
| else | |
| { | |
| while (p_last != *definitions) | |
| { | |
| p_last = _asn1_find_up (p_last); | |
| if (p_last == NULL) | |
| break; | |
| if (p_last->type & CONST_RIGHT) | |
| { | |
| p_last->type &= ~CONST_RIGHT; | |
| move = RIGHT; | |
| break; | |
| } | |
| } /* while */ | |
| } | |
| } /* while */ | |
| if (p_last == *definitions) | |
| { | |
| result = _asn1_check_identifier (*definitions); | |
| if (result == ASN1_SUCCESS) | |
| { | |
| _asn1_change_integer_value (*definitions); | |
| result = _asn1_expand_object_id (&e_list, *definitions); | |
| } | |
| } | |
| else | |
| { | |
| result = ASN1_ARRAY_ERROR; | |
| } | |
| if (errorDescription != NULL) | |
| { | |
| if (result == ASN1_IDENTIFIER_NOT_FOUND) | |
| { | |
| Estrcpy (errorDescription, ":: identifier '"); | |
| Estrcat (errorDescription, _asn1_identifierMissing); | |
| Estrcat (errorDescription, "' not found"); | |
| } | |
| else | |
| errorDescription[0] = 0; | |
| } | |
| if (result != ASN1_SUCCESS) | |
| { | |
| _asn1_delete_list_and_nodes (e_list); | |
| *definitions = NULL; | |
| } | |
| else | |
| _asn1_delete_list (e_list); | |
| return result; | |
| } | |
| /** | |
| * asn1_delete_structure: | |
| * @structure: pointer to the structure that you want to delete. | |
| * | |
| * Deletes the structure *@structure. At the end, *@structure is set | |
| * to NULL. | |
| * | |
| * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if | |
| * *@structure was NULL. | |
| **/ | |
| int | |
| asn1_delete_structure (asn1_node *structure) | |
| { | |
| return _asn1_delete_structure (NULL, structure, 0); | |
| } | |
| /** | |
| * asn1_delete_structure2: | |
| * @structure: pointer to the structure that you want to delete. | |
| * @flags: additional flags (see %ASN1_DELETE_FLAG_ZEROIZE) | |
| * | |
| * Deletes the structure *@structure. At the end, *@structure is set | |
| * to NULL. | |
| * | |
| * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if | |
| * *@structure was NULL. | |
| **/ | |
| int | |
| asn1_delete_structure2 (asn1_node *structure, unsigned int flags) | |
| { | |
| return _asn1_delete_structure (NULL, structure, flags); | |
| } | |
| int | |
| _asn1_delete_structure (list_type *e_list, asn1_node *structure, | |
| unsigned int flags) | |
| { | |
| asn1_node p, p2, p3; | |
| if (*structure == NULL) | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| p = *structure; | |
| while (p) | |
| { | |
| if (p->down) | |
| { | |
| p = p->down; | |
| } | |
| else | |
| { /* no down */ | |
| p2 = p->right; | |
| if (p != *structure) | |
| { | |
| p3 = _asn1_find_up (p); | |
| _asn1_set_down (p3, p2); | |
| if (e_list) | |
| _asn1_delete_node_from_list (e_list, p); | |
| _asn1_remove_node (p, flags); | |
| p = p3; | |
| } | |
| else | |
| { /* p==root */ | |
| p3 = _asn1_find_left (p); | |
| if (!p3) | |
| { | |
| p3 = _asn1_find_up (p); | |
| if (p3) | |
| _asn1_set_down (p3, p2); | |
| else | |
| { | |
| if (p->right) | |
| p->right->left = NULL; | |
| } | |
| } | |
| else | |
| _asn1_set_right (p3, p2); | |
| if (e_list) | |
| _asn1_delete_node_from_list (e_list, p); | |
| _asn1_remove_node (p, flags); | |
| p = NULL; | |
| } | |
| } | |
| } | |
| *structure = NULL; | |
| return ASN1_SUCCESS; | |
| } | |
| /** | |
| * asn1_delete_element: | |
| * @structure: pointer to the structure that contains the element you | |
| * want to delete. | |
| * @element_name: element's name you want to delete. | |
| * | |
| * Deletes the element named *@element_name inside *@structure. | |
| * | |
| * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if | |
| * the @element_name was not found. | |
| **/ | |
| int | |
| asn1_delete_element (asn1_node structure, const char *element_name) | |
| { | |
| asn1_node p2, p3, source_node; | |
| source_node = asn1_find_node (structure, element_name); | |
| if (source_node == NULL) | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| if (source_node->parent | |
| && source_node->name[0] == '?' && c_isdigit (source_node->name[1])) | |
| { | |
| long position = strtol (source_node->name + 1, NULL, 10); | |
| if (position > 0 && position < LONG_MAX) | |
| _asn1_node_array_set (&source_node->parent->numbered_children, | |
| position - 1, NULL); | |
| } | |
| p2 = source_node->right; | |
| p3 = _asn1_find_left (source_node); | |
| if (!p3) | |
| { | |
| p3 = _asn1_find_up (source_node); | |
| if (p3) | |
| _asn1_set_down (p3, p2); | |
| else if (source_node->right) | |
| source_node->right->left = NULL; | |
| } | |
| else | |
| _asn1_set_right (p3, p2); | |
| return asn1_delete_structure (&source_node); | |
| } | |
| #ifndef __clang_analyzer__ | |
| asn1_node | |
| _asn1_copy_structure3 (asn1_node_const source_node) | |
| { | |
| asn1_node_const p_s; | |
| asn1_node dest_node, p_d, p_d_prev; | |
| int move; | |
| if (source_node == NULL) | |
| return NULL; | |
| dest_node = _asn1_add_single_node (source_node->type); | |
| if (dest_node == NULL) | |
| return dest_node; | |
| p_s = source_node; | |
| p_d = dest_node; | |
| move = DOWN; | |
| do | |
| { | |
| if (move != UP) | |
| { | |
| if (p_s->name[0] != 0) | |
| _asn1_cpy_name (p_d, p_s); | |
| if (p_s->value) | |
| _asn1_set_value (p_d, p_s->value, p_s->value_len); | |
| if (p_s->down) | |
| { | |
| p_s = p_s->down; | |
| p_d_prev = p_d; | |
| p_d = _asn1_add_single_node (p_s->type); | |
| _asn1_set_down (p_d_prev, p_d); | |
| continue; | |
| } | |
| p_d->start = p_s->start; | |
| p_d->end = p_s->end; | |
| } | |
| if (p_s == source_node) | |
| break; | |
| if (p_s->right) | |
| { | |
| move = RIGHT; | |
| p_s = p_s->right; | |
| p_d_prev = p_d; | |
| p_d = _asn1_add_single_node (p_s->type); | |
| _asn1_set_right (p_d_prev, p_d); | |
| } | |
| else | |
| { | |
| move = UP; | |
| p_s = _asn1_find_up (p_s); | |
| p_d = _asn1_find_up (p_d); | |
| } | |
| } | |
| while (p_s != source_node); | |
| return dest_node; | |
| } | |
| #else | |
| /* Non-production code */ | |
| asn1_node | |
| _asn1_copy_structure3 (asn1_node_const source_node) | |
| { | |
| return NULL; | |
| } | |
| #endif /* __clang_analyzer__ */ | |
| static asn1_node | |
| _asn1_copy_structure2 (asn1_node_const root, const char *source_name) | |
| { | |
| asn1_node source_node; | |
| source_node = asn1_find_node (root, source_name); | |
| return _asn1_copy_structure3 (source_node); | |
| } | |
| static int | |
| _asn1_type_choice_config (asn1_node node) | |
| { | |
| asn1_node p, p2, p3, p4; | |
| int move, tlen; | |
| 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_CHOICE) | |
| && (p->type & CONST_TAG)) | |
| { | |
| p2 = p->down; | |
| while (p2) | |
| { | |
| if (type_field (p2->type) != ASN1_ETYPE_TAG) | |
| { | |
| p2->type |= CONST_TAG; | |
| p3 = _asn1_find_left (p2); | |
| while (p3) | |
| { | |
| if (type_field (p3->type) == ASN1_ETYPE_TAG) | |
| { | |
| p4 = _asn1_add_single_node (p3->type); | |
| tlen = _asn1_strlen (p3->value); | |
| if (tlen > 0) | |
| _asn1_set_value (p4, p3->value, tlen + 1); | |
| _asn1_set_right (p4, p2->down); | |
| _asn1_set_down (p2, p4); | |
| } | |
| p3 = _asn1_find_left (p3); | |
| } | |
| } | |
| p2 = p2->right; | |
| } | |
| p->type &= ~(CONST_TAG); | |
| p2 = p->down; | |
| while (p2) | |
| { | |
| p3 = p2->right; | |
| if (type_field (p2->type) == ASN1_ETYPE_TAG) | |
| asn1_delete_structure (&p2); | |
| p2 = p3; | |
| } | |
| } | |
| 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; | |
| } | |
| static int | |
| _asn1_expand_identifier (asn1_node *node, asn1_node_const root) | |
| { | |
| asn1_node p, p2, p3; | |
| char name2[ASN1_MAX_NAME_SIZE + 2]; | |
| 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_IDENTIFIER) | |
| { | |
| snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value); | |
| p2 = _asn1_copy_structure2 (root, name2); | |
| if (p2 == NULL) | |
| { | |
| return ASN1_IDENTIFIER_NOT_FOUND; | |
| } | |
| _asn1_cpy_name (p2, p); | |
| p2->right = p->right; | |
| p2->left = p->left; | |
| if (p->right) | |
| p->right->left = p2; | |
| p3 = p->down; | |
| if (p3) | |
| { | |
| while (p3->right) | |
| p3 = p3->right; | |
| _asn1_set_right (p3, p2->down); | |
| _asn1_set_down (p2, p->down); | |
| } | |
| p3 = _asn1_find_left (p); | |
| if (p3) | |
| _asn1_set_right (p3, p2); | |
| else | |
| { | |
| p3 = _asn1_find_up (p); | |
| if (p3) | |
| _asn1_set_down (p3, p2); | |
| else | |
| { | |
| p2->left = NULL; | |
| } | |
| } | |
| if (p->type & CONST_SIZE) | |
| p2->type |= CONST_SIZE; | |
| if (p->type & CONST_TAG) | |
| p2->type |= CONST_TAG; | |
| if (p->type & CONST_OPTION) | |
| p2->type |= CONST_OPTION; | |
| if (p->type & CONST_DEFAULT) | |
| p2->type |= CONST_DEFAULT; | |
| if (p->type & CONST_SET) | |
| p2->type |= CONST_SET; | |
| if (p->type & CONST_NOT_USED) | |
| p2->type |= CONST_NOT_USED; | |
| if (p == *node) | |
| *node = p2; | |
| _asn1_remove_node (p, 0); | |
| p = p2; | |
| 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); | |
| } | |
| return ASN1_SUCCESS; | |
| } | |
| /** | |
| * asn1_create_element: | |
| * @definitions: pointer to the structure returned by "parser_asn1" function | |
| * @source_name: the name of the type of the new structure (must be | |
| * inside p_structure). | |
| * @element: pointer to the structure created. | |
| * | |
| * Creates a structure of type @source_name. Example using | |
| * "pkix.asn": | |
| * | |
| * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr); | |
| * | |
| * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if | |
| * @source_name is not known. | |
| **/ | |
| int | |
| asn1_create_element (asn1_node_const definitions, const char *source_name, | |
| asn1_node *element) | |
| { | |
| asn1_node dest_node; | |
| int res; | |
| dest_node = _asn1_copy_structure2 (definitions, source_name); | |
| if (dest_node == NULL) | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| _asn1_set_name (dest_node, ""); | |
| res = _asn1_expand_identifier (&dest_node, definitions); | |
| _asn1_type_choice_config (dest_node); | |
| *element = dest_node; | |
| return res; | |
| } | |
| /** | |
| * asn1_print_structure: | |
| * @out: pointer to the output file (e.g. stdout). | |
| * @structure: pointer to the structure that you want to visit. | |
| * @name: an element of the structure | |
| * @mode: specify how much of the structure to print, can be | |
| * %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE, | |
| * %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL. | |
| * | |
| * Prints on the @out file descriptor the structure's tree starting | |
| * from the @name element inside the structure @structure. | |
| **/ | |
| void | |
| asn1_print_structure (FILE *out, asn1_node_const structure, const char *name, | |
| int mode) | |
| { | |
| asn1_node_const p, root; | |
| int k, indent = 0, len, len2, len3; | |
| if (out == NULL) | |
| return; | |
| root = asn1_find_node (structure, name); | |
| if (root == NULL) | |
| return; | |
| p = root; | |
| while (p) | |
| { | |
| if (mode == ASN1_PRINT_ALL) | |
| { | |
| for (k = 0; k < indent; k++) | |
| fprintf (out, " "); | |
| fprintf (out, "name:"); | |
| if (p->name[0] != 0) | |
| fprintf (out, "%s ", p->name); | |
| else | |
| fprintf (out, "NULL "); | |
| } | |
| else | |
| { | |
| switch (type_field (p->type)) | |
| { | |
| case ASN1_ETYPE_CONSTANT: | |
| case ASN1_ETYPE_TAG: | |
| case ASN1_ETYPE_SIZE: | |
| break; | |
| default: | |
| for (k = 0; k < indent; k++) | |
| fprintf (out, " "); | |
| fprintf (out, "name:"); | |
| if (p->name[0] != 0) | |
| fprintf (out, "%s ", p->name); | |
| else | |
| fprintf (out, "NULL "); | |
| } | |
| } | |
| if (mode != ASN1_PRINT_NAME) | |
| { | |
| unsigned type = type_field (p->type); | |
| switch (type) | |
| { | |
| case ASN1_ETYPE_CONSTANT: | |
| if (mode == ASN1_PRINT_ALL) | |
| fprintf (out, "type:CONST"); | |
| break; | |
| case ASN1_ETYPE_TAG: | |
| if (mode == ASN1_PRINT_ALL) | |
| fprintf (out, "type:TAG"); | |
| break; | |
| case ASN1_ETYPE_SIZE: | |
| if (mode == ASN1_PRINT_ALL) | |
| fprintf (out, "type:SIZE"); | |
| break; | |
| case ASN1_ETYPE_DEFAULT: | |
| fprintf (out, "type:DEFAULT"); | |
| break; | |
| case ASN1_ETYPE_IDENTIFIER: | |
| fprintf (out, "type:IDENTIFIER"); | |
| break; | |
| case ASN1_ETYPE_ANY: | |
| fprintf (out, "type:ANY"); | |
| break; | |
| case ASN1_ETYPE_CHOICE: | |
| fprintf (out, "type:CHOICE"); | |
| break; | |
| case ASN1_ETYPE_DEFINITIONS: | |
| fprintf (out, "type:DEFINITIONS"); | |
| break; | |
| CASE_HANDLED_ETYPES: | |
| fprintf (out, "%s", _asn1_tags[type].desc); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL)) | |
| { | |
| switch (type_field (p->type)) | |
| { | |
| case ASN1_ETYPE_CONSTANT: | |
| if (mode == ASN1_PRINT_ALL) | |
| if (p->value) | |
| fprintf (out, " value:%s", p->value); | |
| break; | |
| case ASN1_ETYPE_TAG: | |
| if (mode == ASN1_PRINT_ALL) | |
| if (p->value) | |
| fprintf (out, " value:%s", p->value); | |
| break; | |
| case ASN1_ETYPE_SIZE: | |
| if (mode == ASN1_PRINT_ALL) | |
| if (p->value) | |
| fprintf (out, " value:%s", p->value); | |
| break; | |
| case ASN1_ETYPE_DEFAULT: | |
| if (p->value) | |
| fprintf (out, " value:%s", p->value); | |
| else if (p->type & CONST_TRUE) | |
| fprintf (out, " value:TRUE"); | |
| else if (p->type & CONST_FALSE) | |
| fprintf (out, " value:FALSE"); | |
| break; | |
| case ASN1_ETYPE_IDENTIFIER: | |
| if (p->value) | |
| fprintf (out, " value:%s", p->value); | |
| break; | |
| case ASN1_ETYPE_INTEGER: | |
| if (p->value) | |
| { | |
| len2 = -1; | |
| len = asn1_get_length_der (p->value, p->value_len, &len2); | |
| fprintf (out, " value:0x"); | |
| if (len > 0) | |
| for (k = 0; k < len; k++) | |
| fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); | |
| } | |
| break; | |
| case ASN1_ETYPE_ENUMERATED: | |
| if (p->value) | |
| { | |
| len2 = -1; | |
| len = asn1_get_length_der (p->value, p->value_len, &len2); | |
| fprintf (out, " value:0x"); | |
| if (len > 0) | |
| for (k = 0; k < len; k++) | |
| fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); | |
| } | |
| break; | |
| case ASN1_ETYPE_BOOLEAN: | |
| if (p->value) | |
| { | |
| if (p->value[0] == 'T') | |
| fprintf (out, " value:TRUE"); | |
| else if (p->value[0] == 'F') | |
| fprintf (out, " value:FALSE"); | |
| } | |
| break; | |
| case ASN1_ETYPE_BIT_STRING: | |
| if (p->value) | |
| { | |
| len2 = -1; | |
| len = asn1_get_length_der (p->value, p->value_len, &len2); | |
| if (len > 0) | |
| { | |
| fprintf (out, " value(%i):", | |
| (len - 1) * 8 - (p->value[len2])); | |
| for (k = 1; k < len; k++) | |
| fprintf (out, "%02x", | |
| (unsigned) (p->value)[k + len2]); | |
| } | |
| } | |
| break; | |
| case ASN1_ETYPE_GENERALIZED_TIME: | |
| case ASN1_ETYPE_UTC_TIME: | |
| if (p->value) | |
| { | |
| fprintf (out, " value:"); | |
| for (k = 0; k < p->value_len; k++) | |
| fprintf (out, "%c", (p->value)[k]); | |
| } | |
| break; | |
| case ASN1_ETYPE_GENERALSTRING: | |
| case ASN1_ETYPE_NUMERIC_STRING: | |
| case ASN1_ETYPE_IA5_STRING: | |
| case ASN1_ETYPE_TELETEX_STRING: | |
| case ASN1_ETYPE_PRINTABLE_STRING: | |
| case ASN1_ETYPE_UNIVERSAL_STRING: | |
| case ASN1_ETYPE_UTF8_STRING: | |
| case ASN1_ETYPE_VISIBLE_STRING: | |
| if (p->value) | |
| { | |
| len2 = -1; | |
| len = asn1_get_length_der (p->value, p->value_len, &len2); | |
| fprintf (out, " value:"); | |
| if (len > 0) | |
| for (k = 0; k < len; k++) | |
| fprintf (out, "%c", (p->value)[k + len2]); | |
| } | |
| break; | |
| case ASN1_ETYPE_BMP_STRING: | |
| case ASN1_ETYPE_OCTET_STRING: | |
| if (p->value) | |
| { | |
| len2 = -1; | |
| len = asn1_get_length_der (p->value, p->value_len, &len2); | |
| fprintf (out, " value:"); | |
| if (len > 0) | |
| for (k = 0; k < len; k++) | |
| fprintf (out, "%02x", (unsigned) (p->value)[k + len2]); | |
| } | |
| break; | |
| case ASN1_ETYPE_OBJECT_ID: | |
| if (p->value) | |
| fprintf (out, " value:%s", p->value); | |
| break; | |
| case ASN1_ETYPE_ANY: | |
| if (p->value) | |
| { | |
| len3 = -1; | |
| len2 = asn1_get_length_der (p->value, p->value_len, &len3); | |
| fprintf (out, " value:"); | |
| if (len2 > 0) | |
| for (k = 0; k < len2; k++) | |
| fprintf (out, "%02x", (unsigned) (p->value)[k + len3]); | |
| } | |
| break; | |
| case ASN1_ETYPE_SET: | |
| case ASN1_ETYPE_SET_OF: | |
| case ASN1_ETYPE_CHOICE: | |
| case ASN1_ETYPE_DEFINITIONS: | |
| case ASN1_ETYPE_SEQUENCE_OF: | |
| case ASN1_ETYPE_SEQUENCE: | |
| case ASN1_ETYPE_NULL: | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| if (mode == ASN1_PRINT_ALL) | |
| { | |
| if (p->type & 0x1FFFFF00) | |
| { | |
| fprintf (out, " attr:"); | |
| if (p->type & CONST_UNIVERSAL) | |
| fprintf (out, "UNIVERSAL,"); | |
| if (p->type & CONST_PRIVATE) | |
| fprintf (out, "PRIVATE,"); | |
| if (p->type & CONST_APPLICATION) | |
| fprintf (out, "APPLICATION,"); | |
| if (p->type & CONST_EXPLICIT) | |
| fprintf (out, "EXPLICIT,"); | |
| if (p->type & CONST_IMPLICIT) | |
| fprintf (out, "IMPLICIT,"); | |
| if (p->type & CONST_TAG) | |
| fprintf (out, "TAG,"); | |
| if (p->type & CONST_DEFAULT) | |
| fprintf (out, "DEFAULT,"); | |
| if (p->type & CONST_TRUE) | |
| fprintf (out, "TRUE,"); | |
| if (p->type & CONST_FALSE) | |
| fprintf (out, "FALSE,"); | |
| if (p->type & CONST_LIST) | |
| fprintf (out, "LIST,"); | |
| if (p->type & CONST_MIN_MAX) | |
| fprintf (out, "MIN_MAX,"); | |
| if (p->type & CONST_OPTION) | |
| fprintf (out, "OPTION,"); | |
| if (p->type & CONST_1_PARAM) | |
| fprintf (out, "1_PARAM,"); | |
| if (p->type & CONST_SIZE) | |
| fprintf (out, "SIZE,"); | |
| if (p->type & CONST_DEFINED_BY) | |
| fprintf (out, "DEF_BY,"); | |
| if (p->type & CONST_GENERALIZED) | |
| fprintf (out, "GENERALIZED,"); | |
| if (p->type & CONST_UTC) | |
| fprintf (out, "UTC,"); | |
| if (p->type & CONST_SET) | |
| fprintf (out, "SET,"); | |
| if (p->type & CONST_NOT_USED) | |
| fprintf (out, "NOT_USED,"); | |
| if (p->type & CONST_ASSIGN) | |
| fprintf (out, "ASSIGNMENT,"); | |
| } | |
| } | |
| if (mode == ASN1_PRINT_ALL) | |
| { | |
| fprintf (out, "\n"); | |
| } | |
| else | |
| { | |
| switch (type_field (p->type)) | |
| { | |
| case ASN1_ETYPE_CONSTANT: | |
| case ASN1_ETYPE_TAG: | |
| case ASN1_ETYPE_SIZE: | |
| break; | |
| default: | |
| fprintf (out, "\n"); | |
| } | |
| } | |
| if (p->down) | |
| { | |
| p = p->down; | |
| indent += 2; | |
| } | |
| else if (p == root) | |
| { | |
| p = NULL; | |
| break; | |
| } | |
| else if (p->right) | |
| p = p->right; | |
| else | |
| { | |
| while (1) | |
| { | |
| p = _asn1_find_up (p); | |
| if (p == root) | |
| { | |
| p = NULL; | |
| break; | |
| } | |
| indent -= 2; | |
| if (p->right) | |
| { | |
| p = p->right; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * asn1_number_of_elements: | |
| * @element: pointer to the root of an ASN1 structure. | |
| * @name: the name of a sub-structure of ROOT. | |
| * @num: pointer to an integer where the result will be stored | |
| * | |
| * Counts the number of elements of a sub-structure called NAME with | |
| * names equal to "?1","?2", ... | |
| * | |
| * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if | |
| * @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL. | |
| **/ | |
| int | |
| asn1_number_of_elements (asn1_node_const element, const char *name, int *num) | |
| { | |
| asn1_node_const node, p; | |
| if (num == NULL) | |
| return ASN1_GENERIC_ERROR; | |
| *num = 0; | |
| node = asn1_find_node (element, name); | |
| if (node == NULL) | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| p = node->down; | |
| while (p) | |
| { | |
| if (p->name[0] == '?') | |
| (*num)++; | |
| p = p->right; | |
| } | |
| return ASN1_SUCCESS; | |
| } | |
| /** | |
| * asn1_find_structure_from_oid: | |
| * @definitions: ASN1 definitions | |
| * @oidValue: value of the OID to search (e.g. "1.2.3.4"). | |
| * | |
| * Search the structure that is defined just after an OID definition. | |
| * | |
| * Returns: %NULL when @oidValue not found, otherwise the pointer to a | |
| * constant string that contains the element name defined just after | |
| * the OID. | |
| **/ | |
| const char * | |
| asn1_find_structure_from_oid (asn1_node_const definitions, | |
| const char *oidValue) | |
| { | |
| char name[2 * ASN1_MAX_NAME_SIZE + 2]; | |
| char value[ASN1_MAX_NAME_SIZE]; | |
| asn1_node p; | |
| int len; | |
| int result; | |
| const char *definitionsName; | |
| if ((definitions == NULL) || (oidValue == NULL)) | |
| return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ | |
| definitionsName = definitions->name; | |
| /* search the OBJECT_ID into definitions */ | |
| p = definitions->down; | |
| while (p) | |
| { | |
| if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) && | |
| (p->type & CONST_ASSIGN)) | |
| { | |
| snprintf (name, sizeof (name), "%s.%s", definitionsName, p->name); | |
| len = ASN1_MAX_NAME_SIZE; | |
| result = asn1_read_value (definitions, name, value, &len); | |
| if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value))) | |
| { | |
| p = p->right; | |
| if (p == NULL) /* reach the end of ASN1 definitions */ | |
| return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ | |
| return p->name; | |
| } | |
| } | |
| p = p->right; | |
| } | |
| return NULL; /* ASN1_ELEMENT_NOT_FOUND; */ | |
| } | |
| /** | |
| * asn1_copy_node: | |
| * @dst: Destination asn1 node. | |
| * @dst_name: Field name in destination node. | |
| * @src: Source asn1 node. | |
| * @src_name: Field name in source node. | |
| * | |
| * Create a deep copy of a asn1_node variable. That | |
| * function requires @dst to be expanded using asn1_create_element(). | |
| * | |
| * Returns: Return %ASN1_SUCCESS on success. | |
| **/ | |
| int | |
| asn1_copy_node (asn1_node dst, const char *dst_name, | |
| asn1_node_const src, const char *src_name) | |
| { | |
| int result; | |
| asn1_node dst_node; | |
| void *data = NULL; | |
| int size = 0; | |
| result = asn1_der_coding (src, src_name, NULL, &size, NULL); | |
| if (result != ASN1_MEM_ERROR) | |
| return result; | |
| data = malloc (size); | |
| if (data == NULL) | |
| return ASN1_MEM_ERROR; | |
| result = asn1_der_coding (src, src_name, data, &size, NULL); | |
| if (result != ASN1_SUCCESS) | |
| { | |
| free (data); | |
| return result; | |
| } | |
| dst_node = asn1_find_node (dst, dst_name); | |
| if (dst_node == NULL) | |
| { | |
| free (data); | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| } | |
| result = asn1_der_decoding (&dst_node, data, size, NULL); | |
| free (data); | |
| return result; | |
| } | |
| /** | |
| * asn1_dup_node: | |
| * @src: Source asn1 node. | |
| * @src_name: Field name in source node. | |
| * | |
| * Create a deep copy of a asn1_node variable. This function | |
| * will return an exact copy of the provided structure. | |
| * | |
| * Returns: Return %NULL on failure. | |
| **/ | |
| asn1_node | |
| asn1_dup_node (asn1_node_const src, const char *src_name) | |
| { | |
| return _asn1_copy_structure2 (src, src_name); | |
| } |