From 7eb760ed9083d5af0b8cd14bd2f26b88691be9ae Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 30 May 2014 13:50:48 +0200 Subject: simplified and optimized asn1_der_decoding_startEnd(). The second pass decoding is now avoided as the start and end values are cached during decoding. --- lib/decoding.c | 402 +++++---------------------------------------------------- lib/int.h | 2 + 2 files changed, 32 insertions(+), 372 deletions(-) (limited to 'lib') 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 -- cgit v1.2.3