diff options
Diffstat (limited to 'lib/minitasn1/element.c')
-rw-r--r-- | lib/minitasn1/element.c | 1111 |
1 files changed, 1111 insertions, 0 deletions
diff --git a/lib/minitasn1/element.c b/lib/minitasn1/element.c new file mode 100644 index 0000000..550fdb2 --- /dev/null +++ b/lib/minitasn1/element.c @@ -0,0 +1,1111 @@ +/* + * 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 + */ + +/*****************************************************/ +/* 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" + +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 convertion from a null */ +/* terminated string to an integer is made with */ +/* the 'strtol' function. */ +/* Parameters: */ +/* value: null terminated string to convert. */ +/* value_out: convertion 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; +} + +/* 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; + + 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; + } + + if (p->name[0] == 0) + _asn1_str_cpy (temp, sizeof (temp), "?1"); + else + { + n = strtol (p->name + 1, NULL, 0); + n++; + temp[0] = '?'; + _asn1_ltostr (n, temp + 1); + } + _asn1_set_name (p2, temp); + /* p2->type |= CONST_OPTION; */ + + 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]. Initialy + * 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]. Initialy + * 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; +} |