summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2014-05-30 13:50:48 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2014-05-30 15:21:25 +0200
commit7eb760ed9083d5af0b8cd14bd2f26b88691be9ae (patch)
tree14e39ba0594aae296082490ffc8c364f0033bbce
parentd14caccbe1f54c42437b41e5a1863339f5987fc6 (diff)
downloadlibtasn1-7eb760ed9083d5af0b8cd14bd2f26b88691be9ae.tar.gz
libtasn1-7eb760ed9083d5af0b8cd14bd2f26b88691be9ae.tar.bz2
libtasn1-7eb760ed9083d5af0b8cd14bd2f26b88691be9ae.zip
simplified and optimized asn1_der_decoding_startEnd().
The second pass decoding is now avoided as the start and end values are cached during decoding.
-rw-r--r--lib/decoding.c402
-rw-r--r--lib/int.h2
2 files changed, 32 insertions, 372 deletions
diff --git a/lib/decoding.c b/lib/decoding.c
index 47af7cd..510bb67 100644
--- a/lib/decoding.c
+++ b/lib/decoding.c
@@ -900,7 +900,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
int counter, len2, len3, len4, move, ris, tlen;
unsigned char class;
unsigned long tag;
- int indefinite, result;
+ int indefinite, result, total_len = ider_len;
const unsigned char *der = ider;
node = *element;
@@ -978,6 +978,10 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
}
}
+ /* the position in the DER structure this starts */
+ p->start = counter;
+ p->end = total_len;
+
if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
{
p2 = _asn1_find_up (p);
@@ -1037,6 +1041,8 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
}
else if (type_field (p->type) != ASN1_ETYPE_CHOICE)
p = p->down;
+
+ p->start = counter;
}
if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
@@ -1433,6 +1439,11 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
}
}
+ if (p)
+ {
+ p->end = counter - 1;
+ }
+
if (p == node && move != DOWN)
break;
@@ -1535,12 +1546,8 @@ int
asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len,
const char *name_element, int *start, int *end)
{
- asn1_node node, node_to_find, p, p2;
- int counter, len2, len3, len4, move, ris;
- unsigned char class;
- unsigned long tag;
- int indefinite, result = ASN1_DER_ERROR;
- const unsigned char *der = ider;
+ asn1_node node, node_to_find;
+ int result = ASN1_DER_ERROR;
node = element;
@@ -1552,377 +1559,28 @@ asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len,
if (node_to_find == NULL)
return ASN1_ELEMENT_NOT_FOUND;
- if (node_to_find == node)
- {
- *start = 0;
- *end = ider_len - 1;
- return ASN1_SUCCESS;
- }
+ *start = node_to_find->start;
+ *end = node_to_find->end;
- if (node->type & CONST_OPTION)
- return ASN1_GENERIC_ERROR;
-
- counter = 0;
- move = DOWN;
- p = node;
- while (1)
+ if (*start == 0 && *end == 0)
{
- if (p == NULL)
- return ASN1_DER_ERROR;
-
- ris = ASN1_SUCCESS;
-
- if (move != UP)
- {
- if (p->type & CONST_SET)
- {
- p2 = _asn1_find_up (p);
- if (p2 == NULL)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- len2 = p2->tmp_ival;
- if (len2 == -1)
- {
- if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1])
- {
- p = p2;
- move = UP;
- counter += 2;
- DECR_LEN(ider_len, 2);
- continue;
- }
- }
- else if (counter == len2)
- {
- p = p2;
- move = UP;
- continue;
- }
- else if (counter > len2)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- p2 = p2->down;
-
- while (p2)
- {
- if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED))
- { /* CONTROLLARE */
- ris =
- extract_tag_der_recursive (p2, der + counter,
- ider_len, &len2);
- if (ris == ASN1_SUCCESS)
- {
- p2->type &= ~CONST_NOT_USED;
- p = p2;
- break;
- }
- }
- p2 = p2->right;
- }
- if (p2 == NULL)
- {
- warn();
- return ASN1_DER_ERROR;
- }
- }
-
- if (p == node_to_find)
- *start = counter;
-
- if (type_field (p->type) == ASN1_ETYPE_CHOICE)
- {
- p = p->down;
- if (p == NULL)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- ris =
- _asn1_extract_tag_der (p, der + counter, ider_len,
- &len2);
- if (p == node_to_find)
- *start = counter;
- }
-
- if (ris == ASN1_SUCCESS)
- ris =
- _asn1_extract_tag_der (p, der + counter, ider_len, &len2);
- if (ris != ASN1_SUCCESS)
- {
- if (p->type & CONST_OPTION)
- {
- p->type |= CONST_NOT_USED;
- move = RIGHT;
- }
- else if (p->type & CONST_DEFAULT)
- {
- move = RIGHT;
- }
- else
- {
- warn();
- return ASN1_TAG_ERROR;
- }
- }
- else
- {
- DECR_LEN(ider_len, len2);
- counter += len2;
- }
- }
-
- if (ris == ASN1_SUCCESS)
- {
- switch (type_field (p->type))
- {
- case ASN1_ETYPE_NULL:
- DECR_LEN(ider_len, 1);
-
- if (der[counter])
- {
- warn();
- return ASN1_DER_ERROR;
- }
- counter++;
- move = RIGHT;
- break;
- case ASN1_ETYPE_BOOLEAN:
- DECR_LEN(ider_len, 2);
-
- if (der[counter] != 1)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- counter += 2;
- move = RIGHT;
- break;
- case ASN1_ETYPE_OCTET_STRING:
- ris = _asn1_get_octet_string (NULL, der + counter, ider_len, &len3);
- if (ris != ASN1_SUCCESS)
- {
- warn();
- return ris;
- }
- DECR_LEN(ider_len, len3);
- counter += len3;
- move = RIGHT;
- break;
- case ASN1_ETYPE_UTC_TIME:
- case ASN1_ETYPE_GENERALIZED_TIME:
- case ASN1_ETYPE_OBJECT_ID:
- case ASN1_ETYPE_INTEGER:
- case ASN1_ETYPE_ENUMERATED:
- 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:
- case ASN1_ETYPE_BIT_STRING:
- len2 =
- asn1_get_length_der (der + counter, ider_len, &len3);
- if (len2 < 0)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- DECR_LEN(ider_len, len3 + len2);
- counter += len3 + len2;
- move = RIGHT;
- break;
- case ASN1_ETYPE_SEQUENCE:
- case ASN1_ETYPE_SET:
- if (move != UP)
- {
- len3 =
- asn1_get_length_der (der + counter, ider_len, &len2);
- if (len3 < -1)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- DECR_LEN(ider_len, len2);
- counter += len2;
-
- if (len3 == 0)
- move = RIGHT;
- else
- move = DOWN;
- }
- else
- {
- if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) /* indefinite length method */
- {
- counter += 2;
- DECR_LEN(ider_len, 2);
- }
- move = RIGHT;
- }
- break;
- case ASN1_ETYPE_SEQUENCE_OF:
- case ASN1_ETYPE_SET_OF:
- if (move != UP)
- {
- len3 =
- asn1_get_length_der (der + counter, ider_len, &len2);
- if (len3 < -1)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- DECR_LEN(ider_len, len2);
- counter += len2;
-
- if (len3 == -1)
- {
- if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1])
- {
- DECR_LEN(ider_len, 2);
- counter += 2;
- }
- }
-
- if (len3)
- {
- p2 = p->down;
- while ((type_field (p2->type) == ASN1_ETYPE_TAG) ||
- (type_field (p2->type) == ASN1_ETYPE_SIZE))
- p2 = p2->right;
- p = p2;
- }
- }
- else
- {
- if (HAVE_TWO(ider_len) && !der[counter] && !der[counter + 1]) /* indefinite length method */
- {
- DECR_LEN(ider_len, 2);
- counter += 2;
- }
- }
- move = RIGHT;
- break;
- case ASN1_ETYPE_ANY:
- if (asn1_get_tag_der
- (der + counter, ider_len, &class, &len2,
- &tag) != ASN1_SUCCESS)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- DECR_LEN(ider_len, len2);
-
- len4 =
- asn1_get_length_der (der + counter + len2,
- ider_len, &len3);
- if (len4 < -1)
- {
- warn();
- return ASN1_DER_ERROR;
- }
-
- if (len4 != -1)
- {
- DECR_LEN(ider_len, len3 + len4);
- counter += len2 + len3 + len4;
- }
- else
- { /* indefinite length */
- /* Check indefinite lenth method in an EXPLICIT TAG */
- ider_len += len2; /* undo DECR_LEN */
-
- if (counter == 0)
- {
- result = ASN1_DER_ERROR;
- warn();
- goto cleanup;
- }
-
- if ((p->type & CONST_TAG) && (der[counter - 1] == 0x80))
- indefinite = 1;
- else
- indefinite = 0;
-
- ris =
- _asn1_get_indefinite_length_string (der + counter, ider_len, &len2);
- if (ris != ASN1_SUCCESS)
- {
- warn();
- return ris;
- }
- counter += len2;
- DECR_LEN(ider_len, len2);
-
- /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
- an indefinite length method. */
- if (indefinite)
- {
- DECR_LEN(ider_len, 2);
-
- if (!der[counter] && !der[counter + 1])
- counter += 2;
- else
- {
- warn();
- return ASN1_DER_ERROR;
- }
- }
- }
- move = RIGHT;
- break;
- default:
- move = (move == UP) ? RIGHT : DOWN;
- break;
- }
- }
+ /* it seems asn1_der_decoding() wasn't called before. Do it now */
+ result = asn1_der_decoding (&node, ider, ider_len, NULL);
+ if (result != ASN1_SUCCESS)
+ {
+ warn();
+ return result;
+ }
- if ((p == node_to_find) && (move == RIGHT))
- {
- *end = counter - 1;
- return ASN1_SUCCESS;
- }
+ node_to_find = asn1_find_node (node, name_element);
+ if (node_to_find == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
- if (p == node && move != DOWN)
- break;
-
- if (move == DOWN)
- {
- if (p->down)
- p = p->down;
- else
- move = RIGHT;
- }
- if ((move == RIGHT) && !(p->type & CONST_SET))
- {
- if (p->right)
- p = p->right;
- else
- move = UP;
- }
- if (move == UP)
- p = _asn1_find_up (p);
+ *start = node_to_find->start;
+ *end = node_to_find->end;
}
- warn();
- return ASN1_ELEMENT_NOT_FOUND;
-
-cleanup:
- return result;
+ return ASN1_SUCCESS;
}
/**
diff --git a/lib/int.h b/lib/int.h
index ab35e5b..82d0d3f 100644
--- a/lib/int.h
+++ b/lib/int.h
@@ -59,6 +59,8 @@ struct asn1_node_st
/* values used during decoding/coding */
int tmp_ival;
+ unsigned start; /* the start of the DER sequence - if decoded */
+ unsigned end; /* the end of the DER sequence - if decoded */
};
typedef struct tag_and_class_st