summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@crystal.(none)>2008-11-02 14:40:41 +0200
committerNikos Mavrogiannopoulos <nmav@crystal.(none)>2008-11-03 21:49:50 +0200
commit47a0c91a38c458653be1645ff162c53253cbeadd (patch)
tree49b54e24bee2e3384041e527713c9f79ff3ce7fa
parentdf34fbdecce86c00f6287c5f3002078529dcc07e (diff)
downloadgnutls-47a0c91a38c458653be1645ff162c53253cbeadd.tar.gz
* added BER octet string decoder from libtasn1.
* added the tree generation optimizations.
-rw-r--r--lib/minitasn1/decoding.c193
-rw-r--r--lib/minitasn1/element.c45
-rw-r--r--lib/minitasn1/libtasn1.h5
-rw-r--r--lib/minitasn1/parser_aux.c120
-rw-r--r--lib/minitasn1/parser_aux.h10
5 files changed, 233 insertions, 140 deletions
diff --git a/lib/minitasn1/decoding.c b/lib/minitasn1/decoding.c
index c1de9e6773..51ecc01cea 100644
--- a/lib/minitasn1/decoding.c
+++ b/lib/minitasn1/decoding.c
@@ -33,8 +33,10 @@
#include "structure.h"
#include "element.h"
+static asn1_retCode
+_asn1_get_indefinite_length_string (const unsigned char *der, int *len);
-void
+static void
_asn1_error_description_tag_error (node_asn * node, char *ErrorDescription)
{
@@ -101,8 +103,6 @@ asn1_get_length_der (const unsigned char *der, int der_len, int *len)
}
-
-
/**
* asn1_get_tag_der:
* @der: DER data to decode.
@@ -121,7 +121,7 @@ asn1_get_tag_der (const unsigned char *der, int der_len,
{
int punt, ris;
- if (der == NULL || der_len <= 0 || len == NULL)
+ if (der == NULL || der_len < 2 || len == NULL)
return ASN1_DER_ERROR;
*cls = der[0] & 0xE0;
@@ -160,8 +160,36 @@ asn1_get_tag_der (const unsigned char *der, int der_len,
return ASN1_SUCCESS;
}
-
-
+/**
+ * asn1_get_length_ber:
+ * @ber: BER data to decode.
+ * @ber_len: Length of BER data to decode.
+ * @len: Output variable containing the length of the BER length field.
+ *
+ * Extract a length field from BER data.
+ *
+ * Return value: Return the decoded length value, or negative value
+ * when the value was too big. The difference with asn1_get_length_der()
+ * is that it will return length even if the value has indefinite encoding.
+ *
+ **/
+long
+asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len)
+{
+ int ret;
+ long err;
+
+ ret = asn1_get_length_der( ber, ber_len, len);
+ if (ret == -1)
+ { /* indefinite length method */
+ ret = ber_len;
+ err = _asn1_get_indefinite_length_string (ber+1, &ret);
+ if (err != ASN1_SUCCESS)
+ return -3;
+ }
+
+ return ret;
+}
/**
* asn1_get_octet_der:
@@ -268,9 +296,6 @@ _asn1_get_objectid_der (const unsigned char *der, int der_len, int *ret_len,
*ret_len = len + len_len;
}
-
-
-
/**
* asn1_get_bit_der:
* @der: DER data to decode containing the BIT SEQUENCE.
@@ -349,15 +374,21 @@ _asn1_extract_tag_der (node_asn * node, const unsigned char *der, int der_len,
(der + counter, der_len - counter, &class, &len2,
&tag) != ASN1_SUCCESS)
return ASN1_DER_ERROR;
+
if (counter + len2 > der_len)
return ASN1_DER_ERROR;
counter += len2;
+
len3 =
- asn1_get_length_der (der + counter, der_len - counter,
+ asn1_get_length_ber (der + counter, der_len - counter,
&len2);
if (len3 < 0)
return ASN1_DER_ERROR;
+
counter += len2;
+ if (counter > der_len)
+ return ASN1_DER_ERROR;
+
if (!is_tag_implicit)
{
if ((class != (class2 | ASN1_CLASS_STRUCTURED)) ||
@@ -369,7 +400,6 @@ _asn1_extract_tag_der (node_asn * node, const unsigned char *der, int der_len,
if ((class != class_implicit) || (tag != tag_implicit))
return ASN1_TAG_ERROR;
}
-
is_tag_implicit = 0;
}
else
@@ -425,6 +455,7 @@ _asn1_extract_tag_der (node_asn * node, const unsigned char *der, int der_len,
(der + counter, der_len - counter, &class, &len2,
&tag) != ASN1_SUCCESS)
return ASN1_DER_ERROR;
+
if (counter + len2 > der_len)
return ASN1_DER_ERROR;
@@ -565,12 +596,52 @@ _asn1_delete_not_used (node_asn * node)
return ASN1_SUCCESS;
}
+asn1_retCode _asn1_extract_der_octet(node_asn * node, const unsigned char *der, int der_len)
+{
+int len2, len3;
+int counter2, counter_end;
+
+ len2 = asn1_get_length_der (der, der_len, &len3);
+ if (len2 < -1)
+ return ASN1_DER_ERROR;
+
+ counter2 = len3 + 1;
+
+ if (len2 == -1)
+ counter_end = der_len - 2;
+ else
+ counter_end = der_len;
+
+ while (counter2 < counter_end)
+ {
+ len2 = asn1_get_length_der (der + counter2, der_len - counter2, &len3);
+
+ if (len2 < -1)
+ return ASN1_DER_ERROR;
+
+ if (len2 > 0)
+ {
+ _asn1_append_value( node, der + counter2 + len3, len2);
+ }
+ else
+ { /* indefinite */
+
+ len2 = _asn1_extract_der_octet( node, der+counter2+len3, der_len-counter2-len3);
+ if (len2 < 0)
+ return len2;
+ }
+
+ counter2 += len2 + len3 + 1;
+ }
+
+ return ASN1_SUCCESS;
+}
+
asn1_retCode
_asn1_get_octet_string (const unsigned char *der, node_asn * node, int *len)
{
- int len2, len3, counter, counter2, counter_end, tot_len, indefinite;
- unsigned char *temp, *temp2;
+ int len2, len3, counter, tot_len, indefinite;
counter = 0;
@@ -617,43 +688,20 @@ _asn1_get_octet_string (const unsigned char *der, node_asn * node, int *len)
/* copy */
if (node)
{
- asn1_length_der (tot_len, NULL, &len2);
- temp = _asn1_malloc (len2 + tot_len);
- if (temp == NULL)
- {
- return ASN1_MEM_ALLOC_ERROR;
- }
+ unsigned char temp[DER_LEN];
+ int ret;
+
+ len2 = sizeof(temp);
asn1_length_der (tot_len, temp, &len2);
- tot_len += len2;
- temp2 = temp + len2;
- len2 = asn1_get_length_der (der, *len, &len3);
- if (len2 < -1)
- return ASN1_DER_ERROR;
- counter2 = len3 + 1;
-
- if (indefinite == -1)
- counter_end = counter - 2;
- else
- counter_end = counter;
+ _asn1_set_value (node, temp, len2);
- while (counter2 < counter_end)
- {
- len2 =
- asn1_get_length_der (der + counter2, *len - counter, &len3);
- if (len2 < -1)
- return ASN1_DER_ERROR;
+ tot_len += len2;
- /* FIXME: to be checked. Is this ok? Has the
- * size been checked before?
- */
- memcpy (temp2, der + counter2 + len3, len2);
- temp2 += len2;
- counter2 += len2 + len3 + 1;
- }
+ ret = _asn1_extract_der_octet(node, der, *len);
+ if (ret!=ASN1_SUCCESS)
+ return ret;
- _asn1_set_value (node, temp, tot_len);
- _asn1_free (temp);
}
}
else
@@ -673,8 +721,7 @@ _asn1_get_octet_string (const unsigned char *der, node_asn * node, int *len)
}
-
-asn1_retCode
+static asn1_retCode
_asn1_get_indefinite_length_string (const unsigned char *der, int *len)
{
int len2, len3, counter, indefinite;
@@ -756,7 +803,7 @@ asn1_der_decoding (ASN1_TYPE * element, const void *ider, int len,
node_asn *node, *p, *p2, *p3;
char temp[128];
int counter, len2, len3, len4, move, ris, tlen;
- unsigned char class, *temp2;
+ unsigned char class;
unsigned long tag;
int indefinite, result;
const unsigned char *der = ider;
@@ -1192,17 +1239,7 @@ asn1_der_decoding (ASN1_TYPE * element, const void *ider, int len,
if (len4 != -1)
{
len2 += len4;
- asn1_length_der (len2 + len3, NULL, &len4);
- temp2 = (unsigned char *) _asn1_malloc (len2 + len3 + len4);
- if (temp2 == NULL)
- {
- asn1_delete_structure (element);
- return ASN1_MEM_ALLOC_ERROR;
- }
-
- asn1_octet_der (der + counter, len2 + len3, temp2, &len4);
- _asn1_set_value (p, temp2, len4);
- _asn1_free (temp2);
+ _asn1_set_value_octet (p, der+counter, len2+len3);
counter += len2 + len3;
}
else
@@ -1221,17 +1258,8 @@ asn1_der_decoding (ASN1_TYPE * element, const void *ider, int len,
asn1_delete_structure (element);
return ris;
}
- asn1_length_der (len2, NULL, &len4);
- temp2 = (unsigned char *) _asn1_malloc (len2 + len4);
- if (temp2 == NULL)
- {
- asn1_delete_structure (element);
- return ASN1_MEM_ALLOC_ERROR;
- }
- asn1_octet_der (der + counter, len2, temp2, &len4);
- _asn1_set_value (p, temp2, len4);
- _asn1_free (temp2);
+ _asn1_set_value_octet (p, der+counter, len2);
counter += len2;
/* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
@@ -1877,19 +1905,8 @@ asn1_der_decoding_element (ASN1_TYPE * structure, const char *elementName,
len2 += len4;
if (state == FOUND)
{
- asn1_length_der (len2 + len3, NULL, &len4);
- temp2 =
- (unsigned char *) _asn1_malloc (len2 + len3 + len4);
- if (temp2 == NULL)
- {
- asn1_delete_structure (structure);
- return ASN1_MEM_ALLOC_ERROR;
- }
-
- asn1_octet_der (der + counter, len2 + len3, temp2,
- &len4);
- _asn1_set_value (p, temp2, len4);
- _asn1_free (temp2);
+ _asn1_set_value_octet (p, der+counter, len2+len3);
+ temp2 = NULL;
if (p == nodeFound)
state = EXIT;
@@ -1915,17 +1932,7 @@ asn1_der_decoding_element (ASN1_TYPE * structure, const char *elementName,
if (state == FOUND)
{
- asn1_length_der (len2, NULL, &len4);
- temp2 = (unsigned char *) _asn1_malloc (len2 + len4);
- if (temp2 == NULL)
- {
- asn1_delete_structure (structure);
- return ASN1_MEM_ALLOC_ERROR;
- }
-
- asn1_octet_der (der + counter, len2, temp2, &len4);
- _asn1_set_value (p, temp2, len4);
- _asn1_free (temp2);
+ _asn1_set_value_octet (p, der+counter, len2);
if (p == nodeFound)
state = EXIT;
diff --git a/lib/minitasn1/element.c b/lib/minitasn1/element.c
index 703276c809..25ecd5af3f 100644
--- a/lib/minitasn1/element.c
+++ b/lib/minitasn1/element.c
@@ -417,19 +417,7 @@ asn1_write_value (ASN1_TYPE node_root, const char *name,
(!negative && (value_temp[k] & 0x80)))
k--;
- asn1_length_der (len - k, NULL, &len2);
- temp = (unsigned char *) _asn1_malloc (len - k + len2);
- if (temp == NULL)
- {
- _asn1_free (value_temp);
- return ASN1_MEM_ALLOC_ERROR;
- }
-
- asn1_octet_der (value_temp + k, len - k, temp, &len2);
- _asn1_set_value (node, temp, len2);
-
- _asn1_free (temp);
-
+ _asn1_set_value_octet (node, value_temp+k, len-k);
if (node->type & CONST_DEFAULT)
{
@@ -569,26 +557,12 @@ asn1_write_value (ASN1_TYPE node_root, const char *name,
case TYPE_OCTET_STRING:
if (len == 0)
len = strlen (value);
- asn1_length_der (len, NULL, &len2);
- temp = (unsigned char *) _asn1_malloc (len + len2);
- if (temp == NULL)
- return ASN1_MEM_ALLOC_ERROR;
-
- asn1_octet_der (value, len, temp, &len2);
- _asn1_set_value (node, temp, len2);
- _asn1_free (temp);
+ _asn1_set_value_octet (node, value, len);
break;
case TYPE_GENERALSTRING:
if (len == 0)
len = strlen (value);
- asn1_length_der (len, NULL, &len2);
- temp = (unsigned char *) _asn1_malloc (len + len2);
- if (temp == NULL)
- return ASN1_MEM_ALLOC_ERROR;
-
- asn1_octet_der (value, len, temp, &len2);
- _asn1_set_value (node, temp, len2);
- _asn1_free (temp);
+ _asn1_set_value_octet (node, value, len);
break;
case TYPE_BIT_STRING:
if (len == 0)
@@ -599,8 +573,8 @@ asn1_write_value (ASN1_TYPE node_root, const char *name,
return ASN1_MEM_ALLOC_ERROR;
asn1_bit_der (value, len, temp, &len2);
- _asn1_set_value (node, temp, len2);
- _asn1_free (temp);
+ _asn1_set_value_m (node, temp, len2);
+ temp = NULL;
break;
case TYPE_CHOICE:
p = node->down;
@@ -627,14 +601,7 @@ asn1_write_value (ASN1_TYPE node_root, const char *name,
return ASN1_ELEMENT_NOT_FOUND;
break;
case TYPE_ANY:
- asn1_length_der (len, NULL, &len2);
- temp = (unsigned char *) _asn1_malloc (len + len2);
- if (temp == NULL)
- return ASN1_MEM_ALLOC_ERROR;
-
- asn1_octet_der (value, len, temp, &len2);
- _asn1_set_value (node, temp, len2);
- _asn1_free (temp);
+ _asn1_set_value_octet (node, value, len);
break;
case TYPE_SEQUENCE_OF:
case TYPE_SET_OF:
diff --git a/lib/minitasn1/libtasn1.h b/lib/minitasn1/libtasn1.h
index d7d4f70a7c..efcee0e1bc 100644
--- a/lib/minitasn1/libtasn1.h
+++ b/lib/minitasn1/libtasn1.h
@@ -105,11 +105,14 @@ extern "C"
/* that represent an ASN.1 DEFINITION. */
/******************************************************/
+#define SMALL_VALUE_SIZE 16
+
struct node_asn_struct
{
char *name; /* Node name */
unsigned int type; /* Node type */
unsigned char *value; /* Node value */
+ unsigned char small_value[SMALL_VALUE_SIZE]; /* if value is less than that store it here */
int value_len;
struct node_asn_struct *down; /* Pointer to the son node */
struct node_asn_struct *right; /* Pointer to the brother node */
@@ -228,6 +231,8 @@ extern "C"
signed long asn1_get_length_der (const unsigned char *der, int der_len,
int *len);
+ long asn1_get_length_ber (const unsigned char *ber, int ber_len,
+ int *len);
void asn1_length_der (unsigned long int len, unsigned char *ans,
int *ans_len);
diff --git a/lib/minitasn1/parser_aux.c b/lib/minitasn1/parser_aux.c
index 51169b14b4..43522dace6 100644
--- a/lib/minitasn1/parser_aux.c
+++ b/lib/minitasn1/parser_aux.c
@@ -199,23 +199,27 @@ asn1_find_node (ASN1_TYPE pointer, const char *name)
/* Return: pointer to the NODE_ASN element. */
/******************************************************************/
node_asn *
-_asn1_set_value (node_asn * node, const void *_value, unsigned int len)
+_asn1_set_value (node_asn * node, const void *value, unsigned int len)
{
- const unsigned char *value = _value;
-
if (node == NULL)
return node;
if (node->value)
{
- _asn1_free (node->value);
+ if (node->value != node->small_value) _asn1_free (node->value);
node->value = NULL;
node->value_len = 0;
}
+
if (!len)
return node;
- node->value = (unsigned char *) _asn1_malloc (len);
- if (node->value == NULL)
- return NULL;
+
+ if (len < sizeof(node->small_value)) {
+ node->value = node->small_value;
+ } else {
+ node->value = _asn1_malloc (len);
+ if (node->value == NULL)
+ return NULL;
+ }
node->value_len = len;
memcpy (node->value, value, len);
@@ -223,6 +227,106 @@ _asn1_set_value (node_asn * node, const void *_value, unsigned int len)
}
/******************************************************************/
+/* Function : _asn1_set_value_octet */
+/* Description: sets the field VALUE in a NODE_ASN element. The */
+/* previous value (if exist) will be lost. The value */
+/* given is stored as an octet string. */
+/* Parameters: */
+/* node: element pointer. */
+/* value: pointer to the value that you want to set. */
+/* len: character number of value. */
+/* Return: pointer to the NODE_ASN element. */
+/******************************************************************/
+node_asn *
+_asn1_set_value_octet (node_asn * node, const void *value, unsigned int len)
+{
+int len2;
+void* temp;
+
+ if (node == NULL)
+ return node;
+
+ asn1_length_der (len, NULL, &len2);
+ temp = (unsigned char *) _asn1_malloc (len + len2);
+ if (temp == NULL)
+ return NULL;
+
+ asn1_octet_der (value, len, temp, &len2);
+ return _asn1_set_value_m (node, temp, len2);
+}
+
+/* the same as _asn1_set_value except that it sets an already malloc'ed
+ * value.
+ */
+node_asn *
+_asn1_set_value_m (node_asn * node, void *value, unsigned int len)
+{
+ if (node == NULL)
+ return node;
+
+ if (node->value)
+ {
+ if (node->value != node->small_value) _asn1_free (node->value);
+ node->value = NULL;
+ node->value_len = 0;
+ }
+
+ if (!len)
+ return node;
+
+ node->value = value;
+ node->value_len = len;
+
+ return node;
+}
+
+/******************************************************************/
+/* Function : _asn1_append_value */
+/* Description: appends to the field VALUE in a NODE_ASN element. */
+/* */
+/* Parameters: */
+/* node: element pointer. */
+/* value: pointer to the value that you want to be appended. */
+/* len: character number of value. */
+/* Return: pointer to the NODE_ASN element. */
+/******************************************************************/
+node_asn *
+_asn1_append_value (node_asn * node, const void *value, unsigned int len)
+{
+ if (node == NULL)
+ return node;
+ if (node->value != NULL && node->value != node->small_value) /* value is allocated */
+ {
+ int prev_len = node->value_len;
+ node->value_len+=len;
+ node->value = _asn1_realloc( node->value, node->value_len);
+ if (node->value == NULL) {
+ node->value_len = 0;
+ return NULL;
+ }
+ memcpy( &node->value[prev_len], value, len);
+
+ return node;
+ }
+ else if (node->value == node->small_value) /* value is in node */
+ {
+ int prev_len = node->value_len;
+ node->value_len+=len;
+ node->value = _asn1_malloc( node->value_len);
+ if (node->value == NULL) {
+ node->value_len = 0;
+ return NULL;
+ }
+ memcpy( node->value, node->small_value, prev_len);
+ memcpy( &node->value[prev_len], value, len);
+
+ return node;
+ }
+ else /* node->value == NULL */
+ return _asn1_set_value(node, value, len);
+}
+
+/******************************************************************/
/* Function : _asn1_set_name */
/* Description: sets the field NAME in a NODE_ASN element. The */
/* previous value (if exist) will be lost */
@@ -401,7 +505,7 @@ _asn1_remove_node (node_asn * node)
if (node->name != NULL)
_asn1_free (node->name);
- if (node->value != NULL)
+ if (node->value != NULL && node->value != node->small_value)
_asn1_free (node->value);
_asn1_free (node);
}
diff --git a/lib/minitasn1/parser_aux.h b/lib/minitasn1/parser_aux.h
index 3055510cbe..6e18bb69c2 100644
--- a/lib/minitasn1/parser_aux.h
+++ b/lib/minitasn1/parser_aux.h
@@ -2,6 +2,7 @@
#ifndef _PARSER_AUX_H
#define _PARSER_AUX_H
+#define DER_LEN 16
/***************************************/
/* Functions used by ASN.1 parser */
@@ -13,6 +14,15 @@ node_asn *
_asn1_set_value(node_asn *node,const void *value,unsigned int len);
node_asn *
+_asn1_set_value_m(node_asn *node,void *value,unsigned int len);
+
+node_asn *
+_asn1_set_value_octet(node_asn *node,const void *value,unsigned int len);
+
+node_asn *
+_asn1_append_value(node_asn *node,const void *value,unsigned int len);
+
+node_asn *
_asn1_set_name(node_asn *node,const char *name);
node_asn *