From 1213efef01cd0e58dff341e126b1af180cc27a1e Mon Sep 17 00:00:00 2001
From: Mike Gorse <mgorse@alum.wpi.edu>
Date: Thu, 11 Apr 2019 11:14:58 -0500
Subject: [PATCH] _asn1_expand_object_id: Limit recursion

Resolves #4

Signed-off-by: Mike Gorse <mgorse@suse.com>
Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
---
 lib/ASN1.c       |  8 +++++++-
 lib/ASN1.y       |  5 ++++-
 lib/errors.c     |  1 +
 lib/libtasn1.h   |  1 +
 lib/parser_aux.c | 31 ++++++++++++++++++++++++++++---
 lib/parser_aux.h |  1 +
 lib/structure.c  |  2 +-
 7 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/lib/ASN1.c b/lib/ASN1.c
index 586dcca..47074f0 100644
--- a/lib/ASN1.c
+++ b/lib/ASN1.c
@@ -2811,7 +2811,12 @@ asn1_parser2tree (const char *file, asn1_node * definitions,
               /* Convert into DER coding the value assign to INTEGER constants */
               _asn1_change_integer_value (p_tree);
               /* Expand the IDs of OBJECT IDENTIFIER constants */
-              _asn1_expand_object_id (p_tree);
+              result_parse = _asn1_expand_object_id (p_tree);
+              if (result_parse != ASN1_SUCCESS)
+                {
+                  _asn1_delete_list_and_nodes ();
+                  goto error;
+	        }
 
               *definitions = p_tree;
             }
@@ -2824,6 +2829,7 @@ asn1_parser2tree (const char *file, asn1_node * definitions,
         _asn1_delete_list_and_nodes ();
     }
 
+ error:
   _asn1_create_errorDescription (result_parse, error_desc);
 
   return result_parse;
diff --git a/lib/ASN1.y b/lib/ASN1.y
index 534a9f1..0b81b5b 100644
--- a/lib/ASN1.y
+++ b/lib/ASN1.y
@@ -701,7 +701,9 @@ asn1_parser2tree (const char *file, asn1_node * definitions,
               /* Convert into DER coding the value assign to INTEGER constants */
               _asn1_change_integer_value (p_tree);
               /* Expand the IDs of OBJECT IDENTIFIER constants */
-              _asn1_expand_object_id (p_tree);
+              result_parse = _asn1_expand_object_id (p_tree);
+              if (result_parse != ASN1_SUCCESS)
+                goto error;
 
               *definitions = p_tree;
             }
@@ -714,6 +716,7 @@ asn1_parser2tree (const char *file, asn1_node * definitions,
         _asn1_delete_list_and_nodes ();
     }
 
+ error:
   _asn1_create_errorDescription (result_parse, error_desc);
 
   return result_parse;
diff --git a/lib/errors.c b/lib/errors.c
index fef45ae..cee74da 100644
--- a/lib/errors.c
+++ b/lib/errors.c
@@ -53,6 +53,7 @@ static const libtasn1_error_entry error_algorithms[] = {
   LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR),
   LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY),
   LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR),
+  LIBTASN1_ERROR_ENTRY (ASN1_RECURSION),
   {0, 0}
 };
 
diff --git a/lib/libtasn1.h b/lib/libtasn1.h
index ea26b78..8c757d6 100644
--- a/lib/libtasn1.h
+++ b/lib/libtasn1.h
@@ -79,6 +79,7 @@ extern "C"
 #define ASN1_ARRAY_ERROR		16
 #define ASN1_ELEMENT_NOT_EMPTY		17
 #define ASN1_TIME_ENCODING_ERROR	18
+#define ASN1_RECURSION			19
 
   /*************************************/
   /* Constants used in asn1_visit_tree */
diff --git a/lib/parser_aux.c b/lib/parser_aux.c
index 7d7ccf3..e5fecbd 100644
--- a/lib/parser_aux.c
+++ b/lib/parser_aux.c
@@ -517,6 +517,23 @@ _asn1_find_up (asn1_node node)
 }
 
 /******************************************************************/
+/* Function : _asn1_delete_node_from_list                         */
+/* Description: deletes the list element given                    */
+/******************************************************************/
+static void
+_asn1_delete_node_from_list (asn1_node node)
+{
+  list_type *p = firstElement;
+
+  while (p)
+    {
+      if (p->node == node)
+        p->node = NULL;
+      p = p->next;
+    }
+}
+
+/******************************************************************/
 /* Function : _asn1_delete_list                                   */
 /* Description: deletes the list elements (not the elements       */
 /*  pointed by them).                                             */
@@ -667,15 +684,15 @@ _asn1_change_integer_value (asn1_node node)
 /* Parameters:                                                    */
 /*   node: root of an ASN1 element.                               */
 /* Return:                                                        */
-/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                       */
-/*   otherwise ASN1_SUCCESS                                             */
+/*   ASN1_ELEMENT_NOT_FOUND if NODE is NULL,                      */
+/*   otherwise ASN1_SUCCESS                                       */
 /******************************************************************/
 int
 _asn1_expand_object_id (asn1_node node)
 {
   asn1_node p, p2, p3, p4, p5;
   char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1];
-  int move, tlen;
+  int move, tlen, tries;
 
   if (node == NULL)
     return ASN1_ELEMENT_NOT_FOUND;
@@ -684,6 +701,7 @@ _asn1_expand_object_id (asn1_node node)
 
   p = node;
   move = DOWN;
+  tries = 0;
 
   while (!((p == node) && (move == UP)))
     {
@@ -707,6 +725,7 @@ _asn1_expand_object_id (asn1_node node)
 			  || !(p3->type & CONST_ASSIGN))
 			return ASN1_ELEMENT_NOT_FOUND;
 		      _asn1_set_down (p, p2->right);
+		      _asn1_delete_node_from_list(p2);
 		      _asn1_remove_node (p2, 0);
 		      p2 = p;
 		      p4 = p3->down;
@@ -738,6 +757,11 @@ _asn1_expand_object_id (asn1_node node)
 			  p4 = p4->right;
 			}
 		      move = DOWN;
+
+		      tries++;
+                      if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION)
+                        return ASN1_RECURSION;
+
 		      continue;
 		    }
 		}
@@ -747,6 +771,7 @@ _asn1_expand_object_id (asn1_node node)
       else
 	move = RIGHT;
 
+      tries = 0;
       if (move == DOWN)
 	{
 	  if (p->down)
diff --git a/lib/parser_aux.h b/lib/parser_aux.h
index 9f91833..bb05ae8 100644
--- a/lib/parser_aux.h
+++ b/lib/parser_aux.h
@@ -60,6 +60,7 @@ asn1_node _asn1_find_up (asn1_node node);
 
 int _asn1_change_integer_value (asn1_node node);
 
+#define EXPAND_OBJECT_ID_MAX_RECURSION 16
 int _asn1_expand_object_id (asn1_node node);
 
 int _asn1_type_set_config (asn1_node node);
diff --git a/lib/structure.c b/lib/structure.c
index 01715b1..f6a93fa 100644
--- a/lib/structure.c
+++ b/lib/structure.c
@@ -245,7 +245,7 @@ asn1_array2tree (const asn1_static_node * array, asn1_node * definitions,
       if (result == ASN1_SUCCESS)
 	{
 	  _asn1_change_integer_value (*definitions);
-	  _asn1_expand_object_id (*definitions);
+	  result = _asn1_expand_object_id (*definitions);
 	}
     }
   else
-- 
1.8.3.1

