simplified and optimized asn1_der_decoding_startEnd().
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Fri, 30 May 2014 11:50:48 +0000 (13:50 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Fri, 30 May 2014 13:21:25 +0000 (15:21 +0200)
The second pass decoding is now avoided as the start and end
values are cached during decoding.

lib/decoding.c
lib/int.h

index 47af7cd..510bb67 100644 (file)
@@ -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;
 }
 
 /**
index ab35e5b..82d0d3f 100644 (file)
--- 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