| /* | |
| * Copyright (C) 2000-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: element.c */ | |
| /* Description: Functions with the read and write */ | |
| /* functions. */ | |
| /*****************************************************/ | |
| #include "int.h" | |
| #include "parser_aux.h" | |
| #include "gstr.h" | |
| #include "structure.h" | |
| #include "c-ctype.h" | |
| #include "element.h" | |
| #include <limits.h> | |
| #include "intprops.h" | |
| void | |
| _asn1_hierarchical_name (asn1_node_const node, char *name, int name_size) | |
| { | |
| asn1_node_const p; | |
| char tmp_name[64]; | |
| p = node; | |
| name[0] = 0; | |
| while (p != NULL) | |
| { | |
| if (p->name[0] != 0) | |
| { | |
| _asn1_str_cpy (tmp_name, sizeof (tmp_name), name), | |
| _asn1_str_cpy (name, name_size, p->name); | |
| _asn1_str_cat (name, name_size, "."); | |
| _asn1_str_cat (name, name_size, tmp_name); | |
| } | |
| p = _asn1_find_up (p); | |
| } | |
| if (name[0] == 0) | |
| _asn1_str_cpy (name, name_size, "ROOT"); | |
| } | |
| /******************************************************************/ | |
| /* Function : _asn1_convert_integer */ | |
| /* Description: converts an integer from a null terminated string */ | |
| /* to der decoding. The conversion from a null */ | |
| /* terminated string to an integer is made with */ | |
| /* the 'strtol' function. */ | |
| /* Parameters: */ | |
| /* value: null terminated string to convert. */ | |
| /* value_out: conversion result (memory must be already */ | |
| /* allocated). */ | |
| /* value_out_size: number of bytes of value_out. */ | |
| /* len: number of significant byte of value_out. */ | |
| /* Return: ASN1_MEM_ERROR or ASN1_SUCCESS */ | |
| /******************************************************************/ | |
| int | |
| _asn1_convert_integer (const unsigned char *value, unsigned char *value_out, | |
| int value_out_size, int *len) | |
| { | |
| char negative; | |
| unsigned char val[SIZEOF_UNSIGNED_LONG_INT]; | |
| long valtmp; | |
| int k, k2; | |
| valtmp = _asn1_strtol (value, NULL, 10); | |
| for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) | |
| { | |
| val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF; | |
| } | |
| if (val[0] & 0x80) | |
| negative = 1; | |
| else | |
| negative = 0; | |
| for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++) | |
| { | |
| if (negative && (val[k] != 0xFF)) | |
| break; | |
| else if (!negative && val[k]) | |
| break; | |
| } | |
| if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80))) | |
| k--; | |
| *len = SIZEOF_UNSIGNED_LONG_INT - k; | |
| if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size) | |
| /* VALUE_OUT is too short to contain the value conversion */ | |
| return ASN1_MEM_ERROR; | |
| if (value_out != NULL) | |
| { | |
| for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++) | |
| value_out[k2 - k] = val[k2]; | |
| } | |
| #if 0 | |
| printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len); | |
| for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++) | |
| printf (", vOut[%d]=%d", k, value_out[k]); | |
| printf ("\n"); | |
| #endif | |
| return ASN1_SUCCESS; | |
| } | |
| int | |
| _asn1_node_array_set (struct asn1_node_array_st *array, size_t position, | |
| asn1_node node) | |
| { | |
| if (position >= array->size) | |
| { | |
| size_t new_size = position, i; | |
| asn1_node *new_nodes; | |
| if (INT_MULTIPLY_OVERFLOW (new_size, 2)) | |
| return ASN1_GENERIC_ERROR; | |
| new_size *= 2; | |
| if (INT_ADD_OVERFLOW (new_size, 1)) | |
| return ASN1_GENERIC_ERROR; | |
| new_size += 1; | |
| if (INT_MULTIPLY_OVERFLOW (new_size, sizeof (*new_nodes))) | |
| return ASN1_GENERIC_ERROR; | |
| new_nodes = realloc (array->nodes, new_size * sizeof (*new_nodes)); | |
| if (!new_nodes) | |
| return ASN1_MEM_ALLOC_ERROR; | |
| for (i = array->size; i < new_size; i++) | |
| new_nodes[i] = NULL; | |
| array->nodes = new_nodes; | |
| array->size = new_size; | |
| } | |
| array->nodes[position] = node; | |
| return ASN1_SUCCESS; | |
| } | |
| /* Appends a new element into the sequence (or set) defined by this | |
| * node. The new element will have a name of '?number', where number | |
| * is a monotonically increased serial number. | |
| * | |
| * The last element in the list may be provided in @pcache, to avoid | |
| * traversing the list, an expensive operation in long lists. | |
| * | |
| * On success it returns in @pcache the added element (which is the | |
| * tail in the list of added elements). | |
| */ | |
| int | |
| _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache) | |
| { | |
| asn1_node p, p2; | |
| char temp[LTOSTR_MAX_SIZE + 1]; | |
| long n; | |
| int result; | |
| if (!node || !(node->down)) | |
| return ASN1_GENERIC_ERROR; | |
| p = node->down; | |
| while ((type_field (p->type) == ASN1_ETYPE_TAG) | |
| || (type_field (p->type) == ASN1_ETYPE_SIZE)) | |
| p = p->right; | |
| p2 = _asn1_copy_structure3 (p); | |
| if (p2 == NULL) | |
| return ASN1_GENERIC_ERROR; | |
| if (pcache == NULL || pcache->tail == NULL || pcache->head != node) | |
| { | |
| while (p->right) | |
| { | |
| p = p->right; | |
| } | |
| } | |
| else | |
| { | |
| p = pcache->tail; | |
| } | |
| _asn1_set_right (p, p2); | |
| if (pcache) | |
| { | |
| pcache->head = node; | |
| pcache->tail = p2; | |
| } | |
| n = 0; | |
| if (p->name[0] != 0) | |
| { | |
| n = strtol (p->name + 1, NULL, 10); | |
| if (n <= 0 || n >= LONG_MAX - 1) | |
| return ASN1_GENERIC_ERROR; | |
| } | |
| temp[0] = '?'; | |
| _asn1_ltostr (n + 1, temp + 1); | |
| _asn1_set_name (p2, temp); | |
| /* p2->type |= CONST_OPTION; */ | |
| result = _asn1_node_array_set (&node->numbered_children, n, p2); | |
| if (result != ASN1_SUCCESS) | |
| return result; | |
| p2->parent = node; | |
| return ASN1_SUCCESS; | |
| } | |
| /** | |
| * asn1_write_value: | |
| * @node_root: pointer to a structure | |
| * @name: the name of the element inside the structure that you want to set. | |
| * @ivalue: vector used to specify the value to set. If len is >0, | |
| * VALUE must be a two's complement form integer. if len=0 *VALUE | |
| * must be a null terminated string with an integer value. | |
| * @len: number of bytes of *value to use to set the value: | |
| * value[0]..value[len-1] or 0 if value is a null terminated string | |
| * | |
| * Set the value of one element inside a structure. | |
| * | |
| * If an element is OPTIONAL and you want to delete it, you must use | |
| * the value=NULL and len=0. Using "pkix.asn": | |
| * | |
| * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID", | |
| * NULL, 0); | |
| * | |
| * Description for each type: | |
| * | |
| * INTEGER: VALUE must contain a two's complement form integer. | |
| * | |
| * value[0]=0xFF , len=1 -> integer=-1. | |
| * value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1. | |
| * value[0]=0x01 , len=1 -> integer= 1. | |
| * value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1. | |
| * value="123" , len=0 -> integer= 123. | |
| * | |
| * ENUMERATED: As INTEGER (but only with not negative numbers). | |
| * | |
| * BOOLEAN: VALUE must be the null terminated string "TRUE" or | |
| * "FALSE" and LEN != 0. | |
| * | |
| * value="TRUE" , len=1 -> boolean=TRUE. | |
| * value="FALSE" , len=1 -> boolean=FALSE. | |
| * | |
| * OBJECT IDENTIFIER: VALUE must be a null terminated string with | |
| * each number separated by a dot (e.g. "1.2.3.543.1"). LEN != 0. | |
| * | |
| * value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha. | |
| * | |
| * UTCTime: VALUE must be a null terminated string in one of these | |
| * formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ", | |
| * "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'", | |
| * "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'". LEN != 0. | |
| * | |
| * value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998 | |
| * at 12h 00m Greenwich Mean Time | |
| * | |
| * GeneralizedTime: VALUE must be in one of this format: | |
| * "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ", | |
| * "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'", | |
| * "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s | |
| * indicates the seconds with any precision like "10.1" or "01.02". | |
| * LEN != 0 | |
| * | |
| * value="2001010112001.12-0700" , len=1 -> time=Jannuary | |
| * 1st, 2001 at 12h 00m 01.12s Pacific Daylight Time | |
| * | |
| * OCTET STRING: VALUE contains the octet string and LEN is the | |
| * number of octets. | |
| * | |
| * value="$\backslash$x01$\backslash$x02$\backslash$x03" , | |
| * len=3 -> three bytes octet string | |
| * | |
| * GeneralString: VALUE contains the generalstring and LEN is the | |
| * number of octets. | |
| * | |
| * value="$\backslash$x01$\backslash$x02$\backslash$x03" , | |
| * len=3 -> three bytes generalstring | |
| * | |
| * BIT STRING: VALUE contains the bit string organized by bytes and | |
| * LEN is the number of bits. | |
| * | |
| * value="$\backslash$xCF" , len=6 -> bit string="110011" (six | |
| * bits) | |
| * | |
| * CHOICE: if NAME indicates a choice type, VALUE must specify one of | |
| * the alternatives with a null terminated string. LEN != 0. Using | |
| * "pkix.asn"\: | |
| * | |
| * result=asn1_write_value(cert, | |
| * "certificate1.tbsCertificate.subject", "rdnSequence", | |
| * 1); | |
| * | |
| * ANY: VALUE indicates the der encoding of a structure. LEN != 0. | |
| * | |
| * SEQUENCE OF: VALUE must be the null terminated string "NEW" and | |
| * LEN != 0. With this instruction another element is appended in | |
| * the sequence. The name of this element will be "?1" if it's the | |
| * first one, "?2" for the second and so on. | |
| * | |
| * Using "pkix.asn"\: | |
| * | |
| * result=asn1_write_value(cert, | |
| * "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1); | |
| * | |
| * SET OF: the same as SEQUENCE OF. Using "pkix.asn": | |
| * | |
| * result=asn1_write_value(cert, | |
| * "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1); | |
| * | |
| * Returns: %ASN1_SUCCESS if the value was set, | |
| * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and | |
| * %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format. | |
| **/ | |
| int | |
| asn1_write_value (asn1_node node_root, const char *name, | |
| const void *ivalue, int len) | |
| { | |
| asn1_node node, p, p2; | |
| unsigned char *temp, *value_temp = NULL, *default_temp = NULL; | |
| int len2, k, k2, negative; | |
| size_t i; | |
| const unsigned char *value = ivalue; | |
| unsigned int type; | |
| node = asn1_find_node (node_root, name); | |
| if (node == NULL) | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0)) | |
| { | |
| asn1_delete_structure (&node); | |
| return ASN1_SUCCESS; | |
| } | |
| type = type_field (node->type); | |
| if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) | |
| && (value == NULL) && (len == 0)) | |
| { | |
| p = node->down; | |
| while ((type_field (p->type) == ASN1_ETYPE_TAG) | |
| || (type_field (p->type) == ASN1_ETYPE_SIZE)) | |
| p = p->right; | |
| while (p->right) | |
| asn1_delete_structure (&p->right); | |
| return ASN1_SUCCESS; | |
| } | |
| /* Don't allow element deletion for other types */ | |
| if (value == NULL) | |
| { | |
| return ASN1_VALUE_NOT_VALID; | |
| } | |
| switch (type) | |
| { | |
| case ASN1_ETYPE_BOOLEAN: | |
| if (!_asn1_strcmp (value, "TRUE")) | |
| { | |
| if (node->type & CONST_DEFAULT) | |
| { | |
| p = node->down; | |
| while (type_field (p->type) != ASN1_ETYPE_DEFAULT) | |
| p = p->right; | |
| if (p->type & CONST_TRUE) | |
| _asn1_set_value (node, NULL, 0); | |
| else | |
| _asn1_set_value (node, "T", 1); | |
| } | |
| else | |
| _asn1_set_value (node, "T", 1); | |
| } | |
| else if (!_asn1_strcmp (value, "FALSE")) | |
| { | |
| if (node->type & CONST_DEFAULT) | |
| { | |
| p = node->down; | |
| while (type_field (p->type) != ASN1_ETYPE_DEFAULT) | |
| p = p->right; | |
| if (p->type & CONST_FALSE) | |
| _asn1_set_value (node, NULL, 0); | |
| else | |
| _asn1_set_value (node, "F", 1); | |
| } | |
| else | |
| _asn1_set_value (node, "F", 1); | |
| } | |
| else | |
| return ASN1_VALUE_NOT_VALID; | |
| break; | |
| case ASN1_ETYPE_INTEGER: | |
| case ASN1_ETYPE_ENUMERATED: | |
| if (len == 0) | |
| { | |
| if ((c_isdigit (value[0])) || (value[0] == '-')) | |
| { | |
| value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); | |
| if (value_temp == NULL) | |
| return ASN1_MEM_ALLOC_ERROR; | |
| _asn1_convert_integer (value, value_temp, | |
| SIZEOF_UNSIGNED_LONG_INT, &len); | |
| } | |
| else | |
| { /* is an identifier like v1 */ | |
| if (!(node->type & CONST_LIST)) | |
| return ASN1_VALUE_NOT_VALID; | |
| p = node->down; | |
| while (p) | |
| { | |
| if (type_field (p->type) == ASN1_ETYPE_CONSTANT) | |
| { | |
| if (!_asn1_strcmp (p->name, value)) | |
| { | |
| value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); | |
| if (value_temp == NULL) | |
| return ASN1_MEM_ALLOC_ERROR; | |
| _asn1_convert_integer (p->value, | |
| value_temp, | |
| SIZEOF_UNSIGNED_LONG_INT, | |
| &len); | |
| break; | |
| } | |
| } | |
| p = p->right; | |
| } | |
| if (p == NULL) | |
| return ASN1_VALUE_NOT_VALID; | |
| } | |
| } | |
| else | |
| { /* len != 0 */ | |
| value_temp = malloc (len); | |
| if (value_temp == NULL) | |
| return ASN1_MEM_ALLOC_ERROR; | |
| memcpy (value_temp, value, len); | |
| } | |
| if (value_temp[0] & 0x80) | |
| negative = 1; | |
| else | |
| negative = 0; | |
| if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED)) | |
| { | |
| free (value_temp); | |
| return ASN1_VALUE_NOT_VALID; | |
| } | |
| for (k = 0; k < len - 1; k++) | |
| if (negative && (value_temp[k] != 0xFF)) | |
| break; | |
| else if (!negative && value_temp[k]) | |
| break; | |
| if ((negative && !(value_temp[k] & 0x80)) || | |
| (!negative && (value_temp[k] & 0x80))) | |
| k--; | |
| _asn1_set_value_lv (node, value_temp + k, len - k); | |
| if (node->type & CONST_DEFAULT) | |
| { | |
| p = node->down; | |
| while (type_field (p->type) != ASN1_ETYPE_DEFAULT) | |
| p = p->right; | |
| if ((c_isdigit (p->value[0])) || (p->value[0] == '-')) | |
| { | |
| default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); | |
| if (default_temp == NULL) | |
| { | |
| free (value_temp); | |
| return ASN1_MEM_ALLOC_ERROR; | |
| } | |
| _asn1_convert_integer (p->value, default_temp, | |
| SIZEOF_UNSIGNED_LONG_INT, &len2); | |
| } | |
| else | |
| { /* is an identifier like v1 */ | |
| if (!(node->type & CONST_LIST)) | |
| { | |
| free (value_temp); | |
| return ASN1_VALUE_NOT_VALID; | |
| } | |
| p2 = node->down; | |
| while (p2) | |
| { | |
| if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) | |
| { | |
| if (!_asn1_strcmp (p2->name, p->value)) | |
| { | |
| default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT); | |
| if (default_temp == NULL) | |
| { | |
| free (value_temp); | |
| return ASN1_MEM_ALLOC_ERROR; | |
| } | |
| _asn1_convert_integer (p2->value, | |
| default_temp, | |
| SIZEOF_UNSIGNED_LONG_INT, | |
| &len2); | |
| break; | |
| } | |
| } | |
| p2 = p2->right; | |
| } | |
| if (p2 == NULL) | |
| { | |
| free (value_temp); | |
| return ASN1_VALUE_NOT_VALID; | |
| } | |
| } | |
| if ((len - k) == len2) | |
| { | |
| for (k2 = 0; k2 < len2; k2++) | |
| if (value_temp[k + k2] != default_temp[k2]) | |
| { | |
| break; | |
| } | |
| if (k2 == len2) | |
| _asn1_set_value (node, NULL, 0); | |
| } | |
| free (default_temp); | |
| } | |
| free (value_temp); | |
| break; | |
| case ASN1_ETYPE_OBJECT_ID: | |
| for (i = 0; i < _asn1_strlen (value); i++) | |
| if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+')) | |
| return ASN1_VALUE_NOT_VALID; | |
| if (node->type & CONST_DEFAULT) | |
| { | |
| p = node->down; | |
| while (type_field (p->type) != ASN1_ETYPE_DEFAULT) | |
| p = p->right; | |
| if (!_asn1_strcmp (value, p->value)) | |
| { | |
| _asn1_set_value (node, NULL, 0); | |
| break; | |
| } | |
| } | |
| _asn1_set_value (node, value, _asn1_strlen (value) + 1); | |
| break; | |
| case ASN1_ETYPE_UTC_TIME: | |
| { | |
| len = _asn1_strlen (value); | |
| if (len < 11) | |
| return ASN1_VALUE_NOT_VALID; | |
| for (k = 0; k < 10; k++) | |
| if (!c_isdigit (value[k])) | |
| return ASN1_VALUE_NOT_VALID; | |
| switch (len) | |
| { | |
| case 11: | |
| if (value[10] != 'Z') | |
| return ASN1_VALUE_NOT_VALID; | |
| break; | |
| case 13: | |
| if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) || | |
| (value[12] != 'Z')) | |
| return ASN1_VALUE_NOT_VALID; | |
| break; | |
| case 15: | |
| if ((value[10] != '+') && (value[10] != '-')) | |
| return ASN1_VALUE_NOT_VALID; | |
| for (k = 11; k < 15; k++) | |
| if (!c_isdigit (value[k])) | |
| return ASN1_VALUE_NOT_VALID; | |
| break; | |
| case 17: | |
| if ((!c_isdigit (value[10])) || (!c_isdigit (value[11]))) | |
| return ASN1_VALUE_NOT_VALID; | |
| if ((value[12] != '+') && (value[12] != '-')) | |
| return ASN1_VALUE_NOT_VALID; | |
| for (k = 13; k < 17; k++) | |
| if (!c_isdigit (value[k])) | |
| return ASN1_VALUE_NOT_VALID; | |
| break; | |
| default: | |
| return ASN1_VALUE_NOT_FOUND; | |
| } | |
| _asn1_set_value (node, value, len); | |
| } | |
| break; | |
| case ASN1_ETYPE_GENERALIZED_TIME: | |
| len = _asn1_strlen (value); | |
| _asn1_set_value (node, value, len); | |
| break; | |
| case ASN1_ETYPE_OCTET_STRING: | |
| 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_BMP_STRING: | |
| case ASN1_ETYPE_UTF8_STRING: | |
| case ASN1_ETYPE_VISIBLE_STRING: | |
| if (len == 0) | |
| len = _asn1_strlen (value); | |
| _asn1_set_value_lv (node, value, len); | |
| break; | |
| case ASN1_ETYPE_BIT_STRING: | |
| if (len == 0) | |
| len = _asn1_strlen (value); | |
| asn1_length_der ((len >> 3) + 2, NULL, &len2); | |
| temp = malloc ((len >> 3) + 2 + len2); | |
| if (temp == NULL) | |
| return ASN1_MEM_ALLOC_ERROR; | |
| asn1_bit_der (value, len, temp, &len2); | |
| _asn1_set_value_m (node, temp, len2); | |
| temp = NULL; | |
| break; | |
| case ASN1_ETYPE_CHOICE: | |
| p = node->down; | |
| while (p) | |
| { | |
| if (!_asn1_strcmp (p->name, value)) | |
| { | |
| p2 = node->down; | |
| while (p2) | |
| { | |
| if (p2 != p) | |
| { | |
| asn1_delete_structure (&p2); | |
| p2 = node->down; | |
| } | |
| else | |
| p2 = p2->right; | |
| } | |
| break; | |
| } | |
| p = p->right; | |
| } | |
| if (!p) | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| break; | |
| case ASN1_ETYPE_ANY: | |
| _asn1_set_value_lv (node, value, len); | |
| break; | |
| case ASN1_ETYPE_SEQUENCE_OF: | |
| case ASN1_ETYPE_SET_OF: | |
| if (_asn1_strcmp (value, "NEW")) | |
| return ASN1_VALUE_NOT_VALID; | |
| _asn1_append_sequence_set (node, NULL); | |
| break; | |
| default: | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| break; | |
| } | |
| return ASN1_SUCCESS; | |
| } | |
| #define PUT_VALUE( ptr, ptr_size, data, data_size) \ | |
| *len = data_size; \ | |
| if (ptr_size < data_size) { \ | |
| return ASN1_MEM_ERROR; \ | |
| } else { \ | |
| if (ptr && data_size > 0) \ | |
| memcpy (ptr, data, data_size); \ | |
| } | |
| #define PUT_STR_VALUE( ptr, ptr_size, data) \ | |
| *len = _asn1_strlen (data) + 1; \ | |
| if (ptr_size < *len) { \ | |
| return ASN1_MEM_ERROR; \ | |
| } else { \ | |
| /* this strcpy is checked */ \ | |
| if (ptr) { \ | |
| _asn1_strcpy (ptr, data); \ | |
| } \ | |
| } | |
| #define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \ | |
| *len = data_size + 1; \ | |
| if (ptr_size < *len) { \ | |
| return ASN1_MEM_ERROR; \ | |
| } else { \ | |
| /* this strcpy is checked */ \ | |
| if (ptr) { \ | |
| if (data_size > 0) \ | |
| memcpy (ptr, data, data_size); \ | |
| ptr[data_size] = 0; \ | |
| } \ | |
| } | |
| #define ADD_STR_VALUE( ptr, ptr_size, data) \ | |
| *len += _asn1_strlen(data); \ | |
| if (ptr_size < (int) *len) { \ | |
| (*len)++; \ | |
| return ASN1_MEM_ERROR; \ | |
| } else { \ | |
| /* this strcat is checked */ \ | |
| if (ptr) _asn1_strcat (ptr, data); \ | |
| } | |
| /** | |
| * asn1_read_value: | |
| * @root: pointer to a structure. | |
| * @name: the name of the element inside a structure that you want to read. | |
| * @ivalue: vector that will contain the element's content, must be a | |
| * pointer to memory cells already allocated (may be %NULL). | |
| * @len: number of bytes of *value: value[0]..value[len-1]. Initially | |
| * holds the sizeof value. | |
| * | |
| * Returns the value of one element inside a structure. | |
| * If an element is OPTIONAL and this returns | |
| * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present | |
| * in the der encoding that created the structure. The first element | |
| * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and | |
| * so on. If the @root provided is a node to specific sequence element, | |
| * then the keyword "?CURRENT" is also acceptable and indicates the | |
| * current sequence element of this node. | |
| * | |
| * Note that there can be valid values with length zero. In these case | |
| * this function will succeed and @len will be zero. | |
| * | |
| * INTEGER: VALUE will contain a two's complement form integer. | |
| * | |
| * integer=-1 -> value[0]=0xFF , len=1. | |
| * integer=1 -> value[0]=0x01 , len=1. | |
| * | |
| * ENUMERATED: As INTEGER (but only with not negative numbers). | |
| * | |
| * BOOLEAN: VALUE will be the null terminated string "TRUE" or | |
| * "FALSE" and LEN=5 or LEN=6. | |
| * | |
| * OBJECT IDENTIFIER: VALUE will be a null terminated string with | |
| * each number separated by a dot (i.e. "1.2.3.543.1"). | |
| * | |
| * LEN = strlen(VALUE)+1 | |
| * | |
| * UTCTime: VALUE will be a null terminated string in one of these | |
| * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". | |
| * LEN=strlen(VALUE)+1. | |
| * | |
| * GeneralizedTime: VALUE will be a null terminated string in the | |
| * same format used to set the value. | |
| * | |
| * OCTET STRING: VALUE will contain the octet string and LEN will be | |
| * the number of octets. | |
| * | |
| * GeneralString: VALUE will contain the generalstring and LEN will | |
| * be the number of octets. | |
| * | |
| * BIT STRING: VALUE will contain the bit string organized by bytes | |
| * and LEN will be the number of bits. | |
| * | |
| * CHOICE: If NAME indicates a choice type, VALUE will specify the | |
| * alternative selected. | |
| * | |
| * ANY: If NAME indicates an any type, VALUE will indicate the DER | |
| * encoding of the structure actually used. | |
| * | |
| * Returns: %ASN1_SUCCESS if value is returned, | |
| * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, | |
| * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element | |
| * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough | |
| * to store the result, and in this case @len will contain the number of | |
| * bytes needed. On the occasion that the stored data are of zero-length | |
| * this function may return %ASN1_SUCCESS even if the provided @len is zero. | |
| **/ | |
| int | |
| asn1_read_value (asn1_node_const root, const char *name, void *ivalue, | |
| int *len) | |
| { | |
| return asn1_read_value_type (root, name, ivalue, len, NULL); | |
| } | |
| /** | |
| * asn1_read_value_type: | |
| * @root: pointer to a structure. | |
| * @name: the name of the element inside a structure that you want to read. | |
| * @ivalue: vector that will contain the element's content, must be a | |
| * pointer to memory cells already allocated (may be %NULL). | |
| * @len: number of bytes of *value: value[0]..value[len-1]. Initially | |
| * holds the sizeof value. | |
| * @etype: The type of the value read (ASN1_ETYPE) | |
| * | |
| * Returns the type and value of one element inside a structure. | |
| * If an element is OPTIONAL and this returns | |
| * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present | |
| * in the der encoding that created the structure. The first element | |
| * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and | |
| * so on. If the @root provided is a node to specific sequence element, | |
| * then the keyword "?CURRENT" is also acceptable and indicates the | |
| * current sequence element of this node. | |
| * | |
| * Note that there can be valid values with length zero. In these case | |
| * this function will succeed and @len will be zero. | |
| * | |
| * | |
| * INTEGER: VALUE will contain a two's complement form integer. | |
| * | |
| * integer=-1 -> value[0]=0xFF , len=1. | |
| * integer=1 -> value[0]=0x01 , len=1. | |
| * | |
| * ENUMERATED: As INTEGER (but only with not negative numbers). | |
| * | |
| * BOOLEAN: VALUE will be the null terminated string "TRUE" or | |
| * "FALSE" and LEN=5 or LEN=6. | |
| * | |
| * OBJECT IDENTIFIER: VALUE will be a null terminated string with | |
| * each number separated by a dot (i.e. "1.2.3.543.1"). | |
| * | |
| * LEN = strlen(VALUE)+1 | |
| * | |
| * UTCTime: VALUE will be a null terminated string in one of these | |
| * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'". | |
| * LEN=strlen(VALUE)+1. | |
| * | |
| * GeneralizedTime: VALUE will be a null terminated string in the | |
| * same format used to set the value. | |
| * | |
| * OCTET STRING: VALUE will contain the octet string and LEN will be | |
| * the number of octets. | |
| * | |
| * GeneralString: VALUE will contain the generalstring and LEN will | |
| * be the number of octets. | |
| * | |
| * BIT STRING: VALUE will contain the bit string organized by bytes | |
| * and LEN will be the number of bits. | |
| * | |
| * CHOICE: If NAME indicates a choice type, VALUE will specify the | |
| * alternative selected. | |
| * | |
| * ANY: If NAME indicates an any type, VALUE will indicate the DER | |
| * encoding of the structure actually used. | |
| * | |
| * Returns: %ASN1_SUCCESS if value is returned, | |
| * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, | |
| * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element | |
| * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough | |
| * to store the result, and in this case @len will contain the number of | |
| * bytes needed. On the occasion that the stored data are of zero-length | |
| * this function may return %ASN1_SUCCESS even if the provided @len is zero. | |
| **/ | |
| int | |
| asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue, | |
| int *len, unsigned int *etype) | |
| { | |
| asn1_node_const node, p, p2; | |
| int len2, len3, result; | |
| int value_size = *len; | |
| unsigned char *value = ivalue; | |
| unsigned type; | |
| node = asn1_find_node (root, name); | |
| if (node == NULL) | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| type = type_field (node->type); | |
| if ((type != ASN1_ETYPE_NULL) && | |
| (type != ASN1_ETYPE_CHOICE) && | |
| !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) && | |
| (node->value == NULL)) | |
| return ASN1_VALUE_NOT_FOUND; | |
| if (etype) | |
| *etype = type; | |
| switch (type) | |
| { | |
| case ASN1_ETYPE_NULL: | |
| PUT_STR_VALUE (value, value_size, "NULL"); | |
| break; | |
| case ASN1_ETYPE_BOOLEAN: | |
| if ((node->type & CONST_DEFAULT) && (node->value == NULL)) | |
| { | |
| p = node->down; | |
| while (type_field (p->type) != ASN1_ETYPE_DEFAULT) | |
| p = p->right; | |
| if (p->type & CONST_TRUE) | |
| { | |
| PUT_STR_VALUE (value, value_size, "TRUE"); | |
| } | |
| else | |
| { | |
| PUT_STR_VALUE (value, value_size, "FALSE"); | |
| } | |
| } | |
| else if (node->value[0] == 'T') | |
| { | |
| PUT_STR_VALUE (value, value_size, "TRUE"); | |
| } | |
| else | |
| { | |
| PUT_STR_VALUE (value, value_size, "FALSE"); | |
| } | |
| break; | |
| case ASN1_ETYPE_INTEGER: | |
| case ASN1_ETYPE_ENUMERATED: | |
| if ((node->type & CONST_DEFAULT) && (node->value == NULL)) | |
| { | |
| p = node->down; | |
| while (type_field (p->type) != ASN1_ETYPE_DEFAULT) | |
| p = p->right; | |
| if ((c_isdigit (p->value[0])) || (p->value[0] == '-') | |
| || (p->value[0] == '+')) | |
| { | |
| result = _asn1_convert_integer | |
| (p->value, value, value_size, len); | |
| if (result != ASN1_SUCCESS) | |
| return result; | |
| } | |
| else | |
| { /* is an identifier like v1 */ | |
| p2 = node->down; | |
| while (p2) | |
| { | |
| if (type_field (p2->type) == ASN1_ETYPE_CONSTANT) | |
| { | |
| if (!_asn1_strcmp (p2->name, p->value)) | |
| { | |
| result = _asn1_convert_integer | |
| (p2->value, value, value_size, len); | |
| if (result != ASN1_SUCCESS) | |
| return result; | |
| break; | |
| } | |
| } | |
| p2 = p2->right; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| len2 = -1; | |
| result = asn1_get_octet_der | |
| (node->value, node->value_len, &len2, value, value_size, len); | |
| if (result != ASN1_SUCCESS) | |
| return result; | |
| } | |
| break; | |
| case ASN1_ETYPE_OBJECT_ID: | |
| if (node->type & CONST_ASSIGN) | |
| { | |
| *len = 0; | |
| if (value) | |
| value[0] = 0; | |
| p = node->down; | |
| while (p) | |
| { | |
| if (type_field (p->type) == ASN1_ETYPE_CONSTANT) | |
| { | |
| ADD_STR_VALUE (value, value_size, p->value); | |
| if (p->right) | |
| { | |
| ADD_STR_VALUE (value, value_size, "."); | |
| } | |
| } | |
| p = p->right; | |
| } | |
| (*len)++; | |
| } | |
| else if ((node->type & CONST_DEFAULT) && (node->value == NULL)) | |
| { | |
| p = node->down; | |
| while (type_field (p->type) != ASN1_ETYPE_DEFAULT) | |
| p = p->right; | |
| PUT_STR_VALUE (value, value_size, p->value); | |
| } | |
| else | |
| { | |
| PUT_STR_VALUE (value, value_size, node->value); | |
| } | |
| break; | |
| case ASN1_ETYPE_GENERALIZED_TIME: | |
| case ASN1_ETYPE_UTC_TIME: | |
| PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len); | |
| break; | |
| case ASN1_ETYPE_OCTET_STRING: | |
| 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_BMP_STRING: | |
| case ASN1_ETYPE_UTF8_STRING: | |
| case ASN1_ETYPE_VISIBLE_STRING: | |
| len2 = -1; | |
| result = asn1_get_octet_der | |
| (node->value, node->value_len, &len2, value, value_size, len); | |
| if (result != ASN1_SUCCESS) | |
| return result; | |
| break; | |
| case ASN1_ETYPE_BIT_STRING: | |
| len2 = -1; | |
| result = asn1_get_bit_der | |
| (node->value, node->value_len, &len2, value, value_size, len); | |
| if (result != ASN1_SUCCESS) | |
| return result; | |
| break; | |
| case ASN1_ETYPE_CHOICE: | |
| PUT_STR_VALUE (value, value_size, node->down->name); | |
| break; | |
| case ASN1_ETYPE_ANY: | |
| len3 = -1; | |
| len2 = asn1_get_length_der (node->value, node->value_len, &len3); | |
| if (len2 < 0) | |
| return ASN1_DER_ERROR; | |
| PUT_VALUE (value, value_size, node->value + len3, len2); | |
| break; | |
| default: | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| break; | |
| } | |
| return ASN1_SUCCESS; | |
| } | |
| /** | |
| * asn1_read_tag: | |
| * @root: pointer to a structure | |
| * @name: the name of the element inside a structure. | |
| * @tagValue: variable that will contain the TAG value. | |
| * @classValue: variable that will specify the TAG type. | |
| * | |
| * Returns the TAG and the CLASS of one element inside a structure. | |
| * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION, | |
| * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or | |
| * %ASN1_CLASS_CONTEXT_SPECIFIC. | |
| * | |
| * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if | |
| * @name is not a valid element. | |
| **/ | |
| int | |
| asn1_read_tag (asn1_node_const root, const char *name, int *tagValue, | |
| int *classValue) | |
| { | |
| asn1_node node, p, pTag; | |
| node = asn1_find_node (root, name); | |
| if (node == NULL) | |
| return ASN1_ELEMENT_NOT_FOUND; | |
| p = node->down; | |
| /* pTag will points to the IMPLICIT TAG */ | |
| pTag = NULL; | |
| if (node->type & CONST_TAG) | |
| { | |
| while (p) | |
| { | |
| if (type_field (p->type) == ASN1_ETYPE_TAG) | |
| { | |
| if ((p->type & CONST_IMPLICIT) && (pTag == NULL)) | |
| pTag = p; | |
| else if (p->type & CONST_EXPLICIT) | |
| pTag = NULL; | |
| } | |
| p = p->right; | |
| } | |
| } | |
| if (pTag) | |
| { | |
| *tagValue = _asn1_strtoul (pTag->value, NULL, 10); | |
| if (pTag->type & CONST_APPLICATION) | |
| *classValue = ASN1_CLASS_APPLICATION; | |
| else if (pTag->type & CONST_UNIVERSAL) | |
| *classValue = ASN1_CLASS_UNIVERSAL; | |
| else if (pTag->type & CONST_PRIVATE) | |
| *classValue = ASN1_CLASS_PRIVATE; | |
| else | |
| *classValue = ASN1_CLASS_CONTEXT_SPECIFIC; | |
| } | |
| else | |
| { | |
| unsigned type = type_field (node->type); | |
| *classValue = ASN1_CLASS_UNIVERSAL; | |
| switch (type) | |
| { | |
| CASE_HANDLED_ETYPES: | |
| *tagValue = _asn1_tags[type].tag; | |
| break; | |
| case ASN1_ETYPE_TAG: | |
| case ASN1_ETYPE_CHOICE: | |
| case ASN1_ETYPE_ANY: | |
| *tagValue = -1; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| return ASN1_SUCCESS; | |
| } | |
| /** | |
| * asn1_read_node_value: | |
| * @node: pointer to a node. | |
| * @data: a point to a asn1_data_node_st | |
| * | |
| * Returns the value a data node inside a asn1_node structure. | |
| * The data returned should be handled as constant values. | |
| * | |
| * Returns: %ASN1_SUCCESS if the node exists. | |
| **/ | |
| int | |
| asn1_read_node_value (asn1_node_const node, asn1_data_node_st *data) | |
| { | |
| data->name = node->name; | |
| data->value = node->value; | |
| data->value_len = node->value_len; | |
| data->type = type_field (node->type); | |
| return ASN1_SUCCESS; | |
| } |