Hi!
First we would like to thank all developers, contributors and maintainers of libtasn1 for providing a wonderful library, which, in turn, provides possibilities to deal with DER-encoded data and ASN.1 descriptions in runtime, without need to recompile the entire applications when some definitions change. However, we discovered, that some capabilities were absent from the library, one of which being the ability to process memory-cached ASN.1 descriptions. So, in order to accomplish this, we modified libtasn a bit. The patch is attached. Also, we got used to call asn1_get_length_der on a part of DER-encoded piece of data in order to acquire the size of entire piece. But, starting from commit 3873c6a49122e3f15901646e072938557acd3f8e (" Added overflow detection that does not depend on specific compiler, and asn1_get_der_length() verifies the length of the input data in small numbers as well.") this is no longer possible. So, the question is as follows: is there a way to achieve the same result now?

--
Sincerely yours,
Yuri V. Snegirev
Compass Plus Ltd




>From 5e9cf4df6e5f8c98b621c4e1a862ccb8e1e28e14 Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Mon, 18 Jun 2012 18:35:11 +0600
Subject: [PATCH 1/5] Implemented parsing ASN.1 descriptions from string

---
 lib/ASN1.y     |  131 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 lib/libtasn1.h |    4 ++
 2 files changed, 128 insertions(+), 7 deletions(-)

diff --git a/lib/ASN1.y b/lib/ASN1.y
index 80a68cc..de83979 100644
--- a/lib/ASN1.y
+++ b/lib/ASN1.y
@@ -46,9 +46,35 @@ static char lastToken[ASN1_MAX_NAME_SIZE+1];	/* last token find in the file
 extern char _asn1_identifierMissing[];
 static const char *fileName;		/* file to parse */
 
+
+enum _Mode 
+{
+    MODE_FILE,
+    MODE_BUF
+};
+
+struct _InputHandler
+{
+    int (*get) (void *From);
+    int (*unget) (int c, void *From);
+    const char *buf;
+    unsigned long pos;
+    unsigned long capacity;
+    enum _Mode mode;
+};
+typedef struct _InputHandler InputHandler;
+static InputHandler handler;
+
+static int get(void);
+static int unget(int c);
+
+static int str_get(void);
+static int str_unget(int c);
+
 static int _asn1_yyerror (const char *);
 static int _asn1_yylex(void);
 
+
 %}
 
 /* Prefix symbols and functions with _asn1_ */
@@ -422,7 +448,7 @@ static const int key_word_token[] = {
 /*    Token identifier or ASCII code or 0(zero: End Of File) */
 /*************************************************************/
 static int
-_asn1_yylex()
+_asn1_yylex(void)
 {
   int c,counter=0,k,lastc;
   char string[ASN1_MAX_NAME_SIZE+1]; /* will contain the next token */
@@ -430,7 +456,7 @@ _asn1_yylex()
 
   while(1)
     {
-    while((c=fgetc(file_asn1))==' ' || c=='\t' || c=='\n')
+    while((c=get())==' ' || c=='\t' || c=='\n')
       if(c=='\n') lineNumber++;
 
     if(c==EOF){
@@ -445,8 +471,8 @@ _asn1_yylex()
       return c;
     }
     if(c=='-'){  /* Maybe the first '-' of a comment */
-      if((c=fgetc(file_asn1))!='-'){
-	ungetc(c,file_asn1);
+      if((c=get())!='-'){
+	unget(c);
 	lastToken[0]='-';lastToken[1]=0;
 	return '-';
       }
@@ -454,7 +480,7 @@ _asn1_yylex()
 	lastc=0;
 	counter=0;
 	/* A comment finishes at the next double hypen or the end of line */
-	while((c=fgetc(file_asn1))!=EOF && c!='\n' &&
+	while((c=get())!=EOF && c!='\n' &&
 	      (lastc!='-' || (lastc=='-' && c!='-')))
 	  lastc=c;
 	if(c==EOF){
@@ -469,7 +495,7 @@ _asn1_yylex()
     }
     string[counter++]=c;
     /* Till the end of the token */
-    while(!((c=fgetc(file_asn1))==EOF || c==' '|| c=='\t' || c=='\n' ||
+    while(!((c=get())==EOF || c==' '|| c=='\t' || c=='\n' ||
 	     c=='(' || c==')' || c=='[' || c==']' ||
 	     c=='{' || c=='}' || c==',' || c=='.'))
       {
@@ -479,7 +505,7 @@ _asn1_yylex()
 	}
 	string[counter++]=c;
       }
-    ungetc(c,file_asn1);
+    unget(c);
     string[counter]=0;
     strcpy(lastToken,string);
 
@@ -596,6 +622,9 @@ asn1_parser2tree(const char *file_name, ASN1_TYPE *definitions,
   }
   else{
     result_parse=ASN1_SUCCESS;
+    /*handler.get = getc;
+    handler.unget = ungetc;*/
+    handler.mode = MODE_FILE;
 
     lineNumber=1;
     yyparse();
@@ -676,6 +705,7 @@ int asn1_parser2array(const char *inputFileName,const char *outputFileName,
     result_parse=ASN1_FILE_NOT_FOUND;
   else{
     result_parse=ASN1_SUCCESS;
+    handler.mode = MODE_FILE;
 
     lineNumber=1;
     yyparse();
@@ -777,3 +807,90 @@ static int _asn1_yyerror (const char *s)
 
   return 0;
 }
+
+static int str_get(void)
+{
+    int ret = EOF;
+    if(handler.pos < handler.capacity)
+        ret = (int)handler.buf[handler.pos++];
+    return ret;
+}
+
+static int str_unget(int c)
+{
+    handler.pos--;
+    return c;
+}
+
+static int get(void)
+{
+    switch (handler.mode) {
+        case MODE_FILE:
+            return getc(file_asn1);
+        case MODE_BUF:
+        default:
+            return str_get();
+    }
+}
+
+static int unget(int c)
+{
+    switch (handler.mode) {
+        case MODE_FILE:
+            return ungetc(c, file_asn1);
+        case MODE_BUF:
+        default:
+            return str_unget(c);
+    }
+}
+
+asn1_retCode
+asn1_parser_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription)
+{
+    p_tree=ASN1_TYPE_EMPTY;
+    
+    if(*definitions != ASN1_TYPE_EMPTY)
+      return ASN1_ELEMENT_NOT_EMPTY;
+    
+    result_parse = ASN1_SUCCESS;
+    handler.buf = buf;
+    handler.capacity = capacity;
+    /*bufPos = 0;*/
+    handler.pos = 0;
+
+
+    handler.mode = MODE_BUF;
+
+    lineNumber = 1;
+    yyparse();
+
+    if(result_parse==ASN1_SUCCESS){ /* syntax OK */
+      /* set IMPLICIT or EXPLICIT property */
+      _asn1_set_default_tag(p_tree);
+      /* set CONST_SET and CONST_NOT_USED */
+      _asn1_type_set_config(p_tree);
+      /* check the identifier definitions */
+      result_parse=_asn1_check_identifier(p_tree);
+      if(result_parse==ASN1_SUCCESS){ /* all identifier defined */
+	        /* Delete the list and keep the ASN1 structure */
+	        _asn1_delete_list();
+	        /* 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);
+
+	        *definitions=p_tree;
+      }
+      else /* some identifiers not defined */
+	/* Delete the list and the ASN1 structure */
+	_asn1_delete_list_and_nodes();
+    }
+    else  /* syntax error */
+      /* Delete the list and the ASN1 structure */
+      _asn1_delete_list_and_nodes();
+
+  if (errorDescription!=NULL)
+	_asn1_create_errorDescription(result_parse,errorDescription);
+
+  return result_parse;
+}
diff --git a/lib/libtasn1.h b/lib/libtasn1.h
index 784a67e..b46b382 100644
--- a/lib/libtasn1.h
+++ b/lib/libtasn1.h
@@ -171,6 +171,10 @@ extern "C"
     asn1_array2tree (const ASN1_ARRAY_TYPE * array,
 		     ASN1_TYPE * definitions, char *errorDescription);
 
+  
+  extern ASN1_API asn1_retCode
+      asn1_parser_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription);
+
   extern ASN1_API void
     asn1_print_structure (FILE * out, ASN1_TYPE structure,
 			  const char *name, int mode);
-- 
1.7.0.4


>From ef602dc08b78a2285b0904ee335fbb0323a2462a Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Mon, 18 Jun 2012 18:39:31 +0600
Subject: [PATCH 2/5] Forgot to add exports in previous commit

---
 lib/libtasn1.map |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/lib/libtasn1.map b/lib/libtasn1.map
index 1906cd5..2c9dc88 100644
--- a/lib/libtasn1.map
+++ b/lib/libtasn1.map
@@ -18,6 +18,7 @@
 LIBTASN1_0_3
 {
   global:
+    asn1_parser_from_buf;
     asn1_array2tree;
     asn1_bit_der;
     asn1_check_version;
-- 
1.7.0.4


>From b5da0c108e1124fac554022a1aa06ea8c1d4d943 Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Tue, 19 Jun 2012 10:15:17 +0600
Subject: [PATCH 3/5] Changed function name a bit and slightly adopted documentation from asn1_parser2tree

---
 lib/ASN1.y       |   21 ++++++++++++++++++++-
 lib/libtasn1.h   |    2 +-
 lib/libtasn1.map |    2 +-
 3 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/lib/ASN1.y b/lib/ASN1.y
index de83979..b932ad9 100644
--- a/lib/ASN1.y
+++ b/lib/ASN1.y
@@ -844,8 +844,27 @@ static int unget(int c)
     }
 }
 
+/**
+ * asn1_tree_from_buf:
+ * @buf: Char array, containing ASN.1 description
+ * @capacity: Array length
+ * @definitions: return the pointer to the structure created from
+ *   buffer contents ASN.1 declarations.
+ * @errorDescription : return the error description or an empty
+ *   string if success.
+ *
+ * Parse ASN.1 definitions, contained in buffer, in order to create
+ * structures, necessary for managing those definitions. Does exactly what
+ * asn1_parser2tree does with the file.
+ *
+ * Returns: %ASN1_SUCCESS if the file buffer has correct syntax and every
+ *   identifier is known, %ASN1_ELEMENT_NOT_EMPTY if @definitions not
+ *   %ASN1_TYPE_EMPTY, %ASN1_SYNTAX_ERROR if the syntax is not
+ *   correct, %ASN1_IDENTIFIER_NOT_FOUND if buffer contains an
+ *   identifier that is not defined.
+ **/
 asn1_retCode
-asn1_parser_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription)
+asn1_tree_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription)
 {
     p_tree=ASN1_TYPE_EMPTY;
     
diff --git a/lib/libtasn1.h b/lib/libtasn1.h
index b46b382..91f26ac 100644
--- a/lib/libtasn1.h
+++ b/lib/libtasn1.h
@@ -173,7 +173,7 @@ extern "C"
 
   
   extern ASN1_API asn1_retCode
-      asn1_parser_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription);
+      asn1_tree_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription);
 
   extern ASN1_API void
     asn1_print_structure (FILE * out, ASN1_TYPE structure,
diff --git a/lib/libtasn1.map b/lib/libtasn1.map
index 2c9dc88..abb16d1 100644
--- a/lib/libtasn1.map
+++ b/lib/libtasn1.map
@@ -18,7 +18,7 @@
 LIBTASN1_0_3
 {
   global:
-    asn1_parser_from_buf;
+    asn1_tree_from_buf;
     asn1_array2tree;
     asn1_bit_der;
     asn1_check_version;
-- 
1.7.0.4


>From 30b12a75d3fc1d408033b7a8dab445d373eca08f Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Tue, 19 Jun 2012 10:19:00 +0600
Subject: [PATCH 4/5] Removed unnecessary comments and reformated code a bit

---
 lib/ASN1.y |   10 +++-------
 1 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/lib/ASN1.y b/lib/ASN1.y
index b932ad9..2a816f2 100644
--- a/lib/ASN1.y
+++ b/lib/ASN1.y
@@ -55,8 +55,6 @@ enum _Mode
 
 struct _InputHandler
 {
-    int (*get) (void *From);
-    int (*unget) (int c, void *From);
     const char *buf;
     unsigned long pos;
     unsigned long capacity;
@@ -622,8 +620,7 @@ asn1_parser2tree(const char *file_name, ASN1_TYPE *definitions,
   }
   else{
     result_parse=ASN1_SUCCESS;
-    /*handler.get = getc;
-    handler.unget = ungetc;*/
+    
     handler.mode = MODE_FILE;
 
     lineNumber=1;
@@ -705,6 +702,7 @@ int asn1_parser2array(const char *inputFileName,const char *outputFileName,
     result_parse=ASN1_FILE_NOT_FOUND;
   else{
     result_parse=ASN1_SUCCESS;
+    
     handler.mode = MODE_FILE;
 
     lineNumber=1;
@@ -874,10 +872,7 @@ asn1_tree_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitio
     result_parse = ASN1_SUCCESS;
     handler.buf = buf;
     handler.capacity = capacity;
-    /*bufPos = 0;*/
     handler.pos = 0;
-
-
     handler.mode = MODE_BUF;
 
     lineNumber = 1;
@@ -913,3 +908,4 @@ asn1_tree_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitio
 
   return result_parse;
 }
+
-- 
1.7.0.4


>From dfb7d3d70ac92ef8226a981bc93e80085b0f6f0c Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Tue, 19 Jun 2012 17:35:19 +0600
Subject: [PATCH 5/5] Added asn1_tree_from_buf test to Test_parser.c

---
 tests/Test_parser.c |  181 +++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 147 insertions(+), 34 deletions(-)

diff --git a/tests/Test_parser.c b/tests/Test_parser.c
index 76daf09..923f10e 100644
--- a/tests/Test_parser.c
+++ b/tests/Test_parser.c
@@ -30,6 +30,8 @@
 #include <stdlib.h>
 #include "libtasn1.h"
 
+#include <sys/stat.h>
+
 typedef struct
 {
   int lineNumber;
@@ -106,6 +108,26 @@ test_type test_array[] = {
   {0}
 };
 
+typedef struct {
+    char *buf;
+    size_t buf_size; /* current size */
+    size_t capacity; /* maximum size */
+} buffer_ctx;
+
+static int
+resize_buffer(buffer_ctx *ctx, size_t new_capacity)
+{
+    int ret = 0;
+    if(!ctx)
+        ret = -1;
+    else if(ctx->capacity < new_capacity) {
+        ctx->capacity = ctx->buf_size = new_capacity;
+        if(!(ctx->buf = realloc(ctx->buf, ctx->capacity * sizeof(char))))
+            ret = -2;
+    }
+    return ret;
+}
+
 static int
 readLine (FILE * file, char *line)
 {
@@ -145,6 +167,46 @@ createFile (int lineNumber, const char *line)
   fclose (fileIn);
 }
 
+static int
+bufferize_file(const char *fname, buffer_ctx *ctx)
+{
+#define CLEANUP(CODE) {\
+    ret = CODE;        \
+    goto cleanup;      \
+}
+
+    int ret = 0;
+    FILE *in = fopen(fname, "r");
+    
+    if(!in) 
+        return -1;
+    
+    struct stat st;
+    if(fstat(fileno(in), &st) < 0) {
+        printf("stat failed\n");
+        fclose(in);
+        perror("stat");
+        CLEANUP(-2);
+    }
+    memset(ctx->buf, 0, ctx->capacity);
+    if(ctx->capacity < st.st_size) {
+        if( (ret=resize_buffer(ctx, st.st_size)) < 0) {
+            CLEANUP(-3);
+        }
+    }
+    ctx->buf_size = st.st_size;
+    
+    if(fread((void*)ctx->buf, sizeof(char), st.st_size / sizeof(char), in) < st.st_size) {
+        printf("Read error occured\n");
+        CLEANUP(-4);
+    }
+
+cleanup:
+    if(in)
+        fclose(in);
+
+    return ret;
+}
 
 int
 main (int argc, char *argv[])
@@ -180,40 +242,91 @@ main (int argc, char *argv[])
   /* Clear the definitions structures */
   asn1_delete_structure (&definitions);
 
-
-  test = test_array;
-
-  while (test->lineNumber != 0)
-    {
-      testCounter++;
-
-      createFile (test->lineNumber, test->line);
-
-      result =
-	asn1_parser2tree (fileErroredName, &definitions, errorDescription);
-      asn1_delete_structure (&definitions);
-
-      if ((result != test->errorNumber) ||
-	  (strcmp (errorDescription, test->errorDescription)))
-	{
-	  errorCounter++;
-	  printf ("ERROR N. %d:\n", errorCounter);
-	  printf ("  Line %d - %s\n", test->lineNumber, test->line);
-	  printf ("  Error expected: %s - %s\n",
-		  asn1_strerror (test->errorNumber), test->errorDescription);
-	  printf ("  Error detected: %s - %s\n\n", asn1_strerror (result),
-		  errorDescription);
-	}
-
-      test++;
-    }
-
-
-  printf ("Total tests : %d\n", testCounter);
-  printf ("Total errors: %d\n", errorCounter);
-
-  if (errorCounter > 0)
-    return 1;
+  {
+      test = test_array;
+      testCounter = errorCounter = 0;
+
+      while (test->lineNumber != 0)
+        {
+          testCounter++;
+
+          createFile (test->lineNumber, test->line);
+
+          result =
+        asn1_parser2tree (fileErroredName, &definitions, errorDescription);
+          asn1_delete_structure (&definitions);
+
+          if ((result != test->errorNumber) ||
+          (strcmp (errorDescription, test->errorDescription)))
+        {
+          errorCounter++;
+          printf ("ERROR N. %d:\n", errorCounter);
+          printf ("  Line %d - %s\n", test->lineNumber, test->line);
+          printf ("  Error expected: %s - %s\n",
+              asn1_strerror (test->errorNumber), test->errorDescription);
+          printf ("  Error detected: %s - %s\n\n", asn1_strerror (result),
+              errorDescription);
+        }
+
+          test++;
+        }
+
+      printf ("Parsing files:\n");
+      printf ("  Total tests : %d\n", testCounter);
+      printf ("  Total errors: %d\n", errorCounter);
+
+      if (errorCounter > 0)
+        return 1;
+  }
+    
+  /* Now do the same, but dealing with memory buffered ANS.1 
+   * descriptions */
+  {
+      printf("------------------------------\n");
+      test = test_array;
+      testCounter = errorCounter = 0;
+      buffer_ctx ctx;
+      ctx.capacity = ctx.buf_size = 200;
+      if(!(ctx.buf = calloc(ctx.capacity, sizeof(char)))) {
+          printf("Buffer allocation failed\n");
+          exit(-1);
+      }
+      int res = 0;
+
+      while (test->lineNumber != 0) {
+          testCounter++;
+
+          createFile (test->lineNumber, test->line);
+          
+          if( (res = bufferize_file(fileErroredName, &ctx)) < 0) {
+              printf("Failed to bufferize %s contents with code: %d\n", fileErroredName, res);
+              exit(res);
+          }
+
+          result = asn1_tree_from_buf(ctx.buf, ctx.buf_size, &definitions, errorDescription);
+          asn1_delete_structure (&definitions);
+
+          if ((result != test->errorNumber) || 
+                  (strcmp (errorDescription, test->errorDescription))) {
+              errorCounter++;
+              printf ("ERROR N. %d:\n", errorCounter);
+              printf ("  Line %d - %s\n", test->lineNumber, test->line);
+              printf ("  Error expected: %s - %s\n",
+                  asn1_strerror (test->errorNumber), test->errorDescription);
+              printf ("  Error detected: %s - %s\n\n", asn1_strerror (result),
+                  errorDescription);
+          }
+          
+          test++;
+      }
+      
+      printf ("Parsing strings:\n");
+      printf ("  Total tests : %d\n", testCounter);
+      printf ("  Total errors: %d\n", errorCounter);
+
+      if (errorCounter > 0)
+        return 1;
+  }
 
   exit (0);
 }
-- 
1.7.0.4




Reply via email to