>From 5e9cf4df6e5f8c98b621c4e1a862ccb8e1e28e14 Mon Sep 17 00:00:00 2001 From: ysnegirev 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 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 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 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 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 #include "libtasn1.h" +#include + 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