libisdn
asn1.c
Go to the documentation of this file.
00001 /*
00002  * Experimental ASN.1 code
00003  *
00004  * Copyright (C) 2009 Stefan Knoblich <s.knoblich@axsentis.de>
00005  */
00006 /*
00007  * TODO:
00008  *      - Fix integer en-/decoding
00009  */
00010 #ifdef HAVE_CONFIG_H
00011 #include "config.h"
00012 #endif
00013 
00014 #include <stdio.h>
00015 #include <string.h>
00016 #include <stdlib.h>
00017 #include <stdint.h>
00018 #include <ctype.h>
00019 
00020 #include "asn1.h"
00021 #include "asn1_common.h"
00022 #include "asn1_log.h"
00023 #include "asn1_types.h"
00024 #include "asn1_list.h"
00025 
00026 /* codecs */
00027 #include "asn1_codec_ber.h"
00028 
00029 #define ASN1_CANARIES   1
00030 
00031 
00032 
00033 /*************************************************************************************************
00034  * Memory debugging
00035  *************************************************************************************************/
00036 
00037 #if __SIZEOF_LONG__ == 8
00038 #define ASN1_CANARY     { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef }
00039 #else
00040 #define ASN1_CANARY     { 0xde, 0xad, 0xbe, 0xef }
00041 #endif
00042 
00043 static const unsigned char asn1_canary[] = ASN1_CANARY;
00044 static unsigned long asn1_allocated_bytes = 0;
00045 static unsigned long asn1_freed_bytes = 0;
00046 
00047 void *_asn1_malloc(const long size)
00048 {
00049         char *ptr = NULL, *obj = NULL;
00050 #ifdef ASN1_CANARIES
00051         obj = ptr = malloc(size + (ARRAY_SIZE(asn1_canary) * 2) + sizeof(long));
00052         memcpy(obj, asn1_canary, ARRAY_SIZE(asn1_canary));
00053         obj += ARRAY_SIZE(asn1_canary);
00054         memcpy(obj, &size, sizeof(long));
00055         obj += sizeof(long);
00056         memcpy(obj + size, asn1_canary, ARRAY_SIZE(asn1_canary));
00057 #else
00058         obj = ptr = malloc(size);
00059 #endif
00060         if (obj)
00061                 asn1_allocated_bytes += size;
00062 
00063         asn1_debug("Allocated %ld bytes @%p->%p [total: %ld]\n", size, ptr, obj, asn1_allocated_bytes);
00064         return obj;
00065 }
00066 
00067 
00068 void ____asn1_ptr_check(const char *file, const int line, void *obj)
00069 {
00070 #ifdef ASN1_CANARIES
00071         char *ptr  =  (char *)obj - (ARRAY_SIZE(asn1_canary) + sizeof(long));
00072         long  size = *(long *)(ptr + ARRAY_SIZE(asn1_canary));  /* size of object */
00073         int dump = 0;
00074 
00075         /* check canary at beginning of object */
00076         if (memcmp(ptr, asn1_canary, ARRAY_SIZE(asn1_canary))) {
00077                 asn1_error("%s:%d - Pre-Canary error\n", file, line);
00078                 dump = 1;
00079         }
00080 
00081         /* check canary at end of object */
00082         if (memcmp((char *)obj + size, asn1_canary, ARRAY_SIZE(asn1_canary))) {
00083                 asn1_error("%s:%d - Post-Canary error\n", file, line);
00084                 dump = 1;
00085         }
00086 
00087         if (dump) {
00088                 struct asn1_object *elem = obj;
00089                 fprintf(stderr, "Element @%p, class %s (%d), type %s (%d)\n", elem,
00090                         asn1_class_name(asn1_get_class(elem)),
00091                         asn1_get_class(elem),
00092                         asn1_type_name(asn1_get_type(elem)),
00093                         asn1_get_type(elem)
00094                 );
00095                 abort();
00096         }
00097 #endif
00098 }
00099 
00100 void _asn1_free(void *obj)
00101 {
00102         asn1_debug("Freeing bytes @%p\n", obj);
00103 #ifdef ASN1_CANARIES
00104         {
00105                 char *ptr  =  (char *)obj - (ARRAY_SIZE(asn1_canary) + sizeof(long));
00106                 long  size = *(long *)(ptr + ARRAY_SIZE(asn1_canary));  /* size of object */
00107 
00108                 /* check canary at beginning of object */
00109                 if (memcmp(ptr, asn1_canary, ARRAY_SIZE(asn1_canary)))
00110                         asn1_error("Pre-Canary error\n");
00111 
00112                 /* check canary at end of object */
00113                 if (memcmp((char *)obj + size, asn1_canary, ARRAY_SIZE(asn1_canary)))
00114                         asn1_error("Post-Canary error\n");
00115 
00116                 asn1_freed_bytes += size;
00117                 asn1_debug("Freed %ld bytes @%p->%p [total: %ld]\n", size, ptr, obj, asn1_freed_bytes);
00118                 free(ptr);
00119         }
00120 #else
00121         free(obj);
00122 #endif
00123 }
00124 
00125 
00126 /*************************************************************************************************
00127  * Complex type manipulation
00128  *************************************************************************************************/
00129 
00133 int asn1_set_add(struct asn1_set *set, struct asn1_object *elem)
00134 {
00135         return 0;
00136 }
00137 
00138 
00139 
00140 /*************************************************************************************************
00141  * High-level functions
00142  *************************************************************************************************/
00143 
00144 static struct asn1_object *asn1_alloc(const struct asn1_header *hdr)
00145 {
00146         struct asn1_object *tmp = NULL;
00147         int    size = sizeof(struct asn1_object);
00148 
00149         if (hdr->asn_class == ASN1_CLASS_UNIVERSAL) {
00150                 switch (hdr->asn_type) {
00151                 case ASN1_TYPE_BOOLEAN:
00152                         size = sizeof(struct asn1_boolean);
00153                         break;
00154                 case ASN1_TYPE_INTEGER:
00155                         size = sizeof(struct asn1_integer);
00156                         break;
00157                 case ASN1_TYPE_REAL:
00158                         size = sizeof(struct asn1_real);
00159                         break;
00160                 case ASN1_TYPE_NUMERIC_STRING:
00161                 case ASN1_TYPE_OCTET_STRING:
00162                 case ASN1_TYPE_IA5_STRING:
00163                         size = sizeof(struct asn1_string) + hdr->size;
00164                         break;
00165                 case ASN1_TYPE_OID:
00166                         size = sizeof(struct asn1_oid);
00167                         break;
00168                 case ASN1_TYPE_SET:
00169                         size = sizeof(struct asn1_set);
00170                         break;
00171                 case ASN1_TYPE_ENUMERATED:
00172                         size = sizeof(struct asn1_enumerated);
00173                         break;
00174                 case ASN1_TYPE_SEQUENCE:
00175                         size = sizeof(struct asn1_sequence);
00176                         break;
00177                 default:
00178                         size += hdr->size;
00179                 }
00180                 asn1_trace("Allocating universal element: %d\n", size);
00181         }
00182         else if (hdr->asn_complex) {
00183                 size = sizeof(struct asn1_complex);
00184                 asn1_trace("Allocating complex element: %d bytes\n", size);
00185         }
00186         else {
00187                 /* just copy octets, treat as octet string */
00188                 size = sizeof(struct asn1_string) + hdr->size;
00189                 asn1_trace("Allocating custom element: %d\n", size);
00190         }
00191 
00192         tmp = asn1_malloc(size);
00193         if (tmp) {
00194                 memset(tmp, 0, size);
00195         }
00196         return (struct asn1_object *)tmp;
00197 }
00198 
00199 
00200 struct asn1_level_ref {
00201         int    offset;
00202         int    size;
00203         struct asn1_list *ptr;  /* children head of current level */
00204 };
00205 
00206 
00207 int asn1_encode(const struct asn1_tree *tree, char *output, int *size)
00208 {
00209         const struct asn1_codec *codec = NULL;
00210         struct asn1_level_ref level[ASN1_MAXDEPTH];
00211         struct asn1_header *hdr  = NULL;
00212         struct asn1_object *elem = NULL;
00213         struct asn1_list   *ptr  = NULL;
00214         struct asn1_buffer buf;
00215         int    depth = 0;
00216         int    res;
00217 
00218         if (!tree || !output || !size || *size <= 0)
00219                 return -1;
00220 
00221         if (!tree->codec)
00222                 return -1;
00223 
00224         codec = tree->codec;
00225 
00226         asn1_debug("ASN.1 %s Encoder start\n", codec->name);
00227 
00228         /* init buffer */
00229         memset(&buf, 0, sizeof(buf));
00230         buf.data   = (char *)output;
00231         buf.size   = *size;
00232         buf.offset = 0;
00233 
00234         /* root level */
00235         memset(level, 0, sizeof(level));
00236         level[0].ptr    = (struct asn1_list *)&tree->root;
00237         level[0].size   = 0;
00238         level[0].offset = 0;
00239 
00240         /*
00241          * Two-Step approach here, first round: Gather size information
00242          */
00243         ptr = asn1_get_first(&tree->root);
00244 
00245         while (ptr) {
00246                 elem = container_of(ptr, struct asn1_object, siblings);
00247                 hdr  = &elem->hdr;
00248 
00249                 __asn1_ptr_check(elem);
00250 
00251                 if (elem->hdr.asn_complex) {
00252                         if (depth == ASN1_MAXDEPTH) {
00253                                 /* already at max. level */
00254                                 asn1_error("--- Exceeding maximum depth %d\n", ASN1_MAXDEPTH);
00255                                 break;
00256                         }
00257 
00258                         /* go one level up */
00259                         depth++;
00260                         asn1_trace("^^^ Going one level up [%d -> %d]\n", depth - 1, depth);
00261 
00262                         ptr = asn1_get_first_child((struct asn1_complex *)elem);
00263                         if (!ptr) {
00264                                 asn1_error("No children!!!");
00265                                 break;
00266                         }
00267 
00268                         level[depth].size = 0;
00269                         continue;
00270                 }
00271 
00272                 asn1_trace("*** Current element [class:p/c:type %d:%d:%d], size %d @%p (last? %s, head? %s) ***\n", elem->hdr.asn_class, elem->hdr.asn_complex, elem->hdr.asn_type, elem->hdr.size, elem, asn1_is_last(ptr) ? "yes" : "no", asn1_is_head(ptr) ? "yes" : "no");
00273 
00274                 /* update size */
00275                 level[depth].size += hdr->size + codec->header_size(hdr);
00276 
00277                 /* go down? */
00278                 while (asn1_is_last(ptr) && depth > 0) {
00279                         ptr = asn1_get_parent(ptr);
00280 
00281                         /* update container size */
00282                         elem           = container_of(ptr, struct asn1_object, siblings);
00283                         elem->hdr.size = level[depth].size;
00284 
00285                         __asn1_ptr_check(elem);
00286 
00287                         /* update size to include container header and add to parent level */
00288                         level[depth].size     += codec->header_size(&elem->hdr);
00289                         level[depth - 1].size += level[depth].size;
00290 
00291                         depth--;
00292                         asn1_trace("vvv Going one level down [%d -> %d: %d octets]\n", depth + 1, depth, elem->hdr.size);
00293                 }
00294 
00295                 ptr = asn1_get_next(ptr);
00296                 if (ptr) {
00297                         elem = container_of(ptr, struct asn1_object, siblings);
00298                         __asn1_ptr_check(elem);
00299                         asn1_trace("*** Next element [class:p/c:type %d:%d:%d] @%p (last? %s, head? %s) ***\n", elem->hdr.asn_class, elem->hdr.asn_complex, elem->hdr.asn_type, elem, asn1_is_last(ptr) ? "yes" : "no", asn1_is_head(ptr) ? "yes" : "no");
00300                 }
00301         }
00302         asn1_trace("Overall (estimated) output size: %d octets\n", level[0].size);
00303 
00304         /*
00305          * Second round: Write values
00306          */
00307         ptr = asn1_get_first(&tree->root);
00308 
00309         while (ptr) {
00310                 elem = container_of(ptr, struct asn1_object, siblings);
00311                 hdr  = &elem->hdr;
00312 
00313                 __asn1_ptr_check(elem);
00314 
00315                 /* Encode header */
00316                 res = codec->encode_header(&buf, hdr);
00317                 if (res <= 0) {
00318                         asn1_debug("*** Error encoding header: %d\n", res);
00319                         break;
00320                 }
00321 
00322                 asn1_trace("Current buffer state, offset: %d\n", buf.offset);
00323 
00324                 /* Handle value */
00325                 if (hdr->asn_class == ASN1_CLASS_UNIVERSAL) {
00326                         switch (hdr->asn_type) {
00327                         case ASN1_TYPE_BOOLEAN:
00328                         case ASN1_TYPE_INTEGER:
00329                         case ASN1_TYPE_REAL:
00330                         case ASN1_TYPE_OID:
00331                         case ASN1_TYPE_ENUMERATED:
00332                         case ASN1_TYPE_NUMERIC_STRING:
00333                         case ASN1_TYPE_OCTET_STRING:
00334                         case ASN1_TYPE_UTF8_STRING:
00335                         case ASN1_TYPE_IA5_STRING:
00336                         case ASN1_TYPE_BIT_STRING:
00337                                 res = codec->encode_value(&buf, elem);
00338                                 break;
00339 
00340                         default:
00341                                 if (!hdr->asn_complex) {
00342                                         /* unhandled type */
00343                                         asn1_error("*** Unhandled type [class:p/c:type %d:%d:%d] (@%05d, size %d)\n", hdr->asn_class, hdr->asn_complex, hdr->asn_type, buf.offset, hdr->size);
00344                                         goto out;
00345                                 }
00346                                 break;
00347                         }
00348                 }
00349                 else if (hdr->asn_complex) {
00350                         asn1_trace(">>> Not reading data of non-universal class, complex type [tag: %d]\n", hdr->asn_type);
00351                 }
00352                 else {
00353                         asn1_trace(">>> Reading data of non-universal class, non-complex type [tag: %d]\n", hdr->asn_type);
00354                         res = codec->encode_value(&buf, elem);
00355                 }
00356 
00357                 /* ??? */
00358 
00359                 if (elem->hdr.asn_complex) {
00360                         if (depth == ASN1_MAXDEPTH) {
00361                                 /* already at max. level */
00362                                 asn1_error("--- Exceeding maximum depth %d\n", ASN1_MAXDEPTH);
00363                                 break;
00364                         }
00365 
00366                         /* go one level up */
00367                         depth++;
00368                         asn1_trace("^^^ Going one level up [%d -> %d]\n", depth - 1, depth);
00369 
00370                         ptr = asn1_get_first_child((struct asn1_complex *)elem);
00371                         if (!ptr) {
00372                                 asn1_trace("No children!!!\n");
00373                                 break;
00374                         }
00375                         continue;
00376                 }
00377 
00378                 /* go down? */
00379                 while (asn1_is_last(ptr) && depth > 0) {
00380                         ptr = asn1_get_parent(ptr);
00381                         depth--;
00382                         asn1_trace("vvv Going one level down [%d -> %d]\n", depth + 1, depth);
00383                 }
00384 
00385                 ptr = asn1_get_next(ptr);
00386 //              if (ptr) {
00387 //                      elem = container_of(ptr, struct asn1_object, siblings);
00388 //                      asn1_trace("*** Next element [class:p/c:type %d:%d:%d] @%p (last? %s, head? %s) ***\n", elem->hdr.asn_class, elem->hdr.asn_complex, elem->hdr.asn_type, elem, asn1_is_last(ptr) ? "yes" : "no", asn1_is_head(ptr) ? "yes" : "no");
00389 //              }
00390         }
00391 out:
00392         *size = buf.offset;
00393 
00394         asn1_debug("ASN.1 %s Encoder end\n", codec->name);
00395 
00396         return 0;
00397 }
00398 
00399 
00405 static int asn1_find_eoc(struct asn1_buffer *buf)
00406 {
00407         int x;
00408 
00409         for (x = buf->offset; x < buf->size - 1; x++) {
00410                 if (!buf->data[x] && !buf->data[x + 1]) {
00411                         return x;
00412                 }
00413         }
00414         return 0;
00415 }
00416 
00417 
00418 int asn1_decode(struct asn1_tree *tree, const char *input, const int size)
00419 {
00420         const struct asn1_codec *codec = NULL;
00421         struct asn1_level_ref level[ASN1_MAXDEPTH];
00422         struct asn1_buffer buf;
00423         int depth = 0;
00424         int res = 0;
00425 
00426         if (!tree || !input || size <= 0)
00427                 return -1;
00428 
00429         if (!tree->codec)
00430                 return -1;
00431 
00432         codec = tree->codec;
00433 
00434         asn1_debug("ASN.1 %s Decoder start\n", codec->name);
00435 
00436         memset(level, 0, sizeof(level));
00437         buf.data   = (char *)input;
00438         buf.size   = size;
00439         buf.offset = 0;
00440 
00441         /* root level */
00442         memset(&tree->root, 0, sizeof(struct asn1_list));
00443         ASN1_INIT_HEAD(&tree->root);
00444         level[0].ptr    = &tree->root;
00445         level[0].size   = size;
00446         level[0].offset = 0;
00447 
00448         while ((buf.size - buf.offset) >= ASN1_MINSIZE) {
00449                 struct asn1_header  hdr;
00450                 struct asn1_object *elem = NULL;
00451 #ifdef DEBUG
00452                 buf.max_depth = MAX(buf.max_depth, depth);
00453 #endif
00454                 res = codec->decode_header(&buf, &hdr);
00455                 if (res <= 0) {
00456                         asn1_error("*** Error decoding header: %d\n", res);
00457                         break;
00458                 }
00459                 asn1_trace("<<< New Element [class:p/c:type %d:%d:%d] (@%05d, size %d, res %d)\n", hdr.asn_class, hdr.asn_complex, hdr.asn_type, buf.offset, hdr.size, res);
00460 
00461                 if (hdr.size > (buf.size - buf.offset)) {
00462                         /* element larger than what is left in buffer */
00463                         asn1_error("*** Element larger than octets left in buffer (%d vs. %d)\n", hdr.size, (buf.size - buf.offset));
00464                         res = -1;
00465                         break;
00466                 }
00467 
00468                 /*
00469                  * Handle indefinite encoded values
00470                  */
00471                 if (hdr.size == 0) {
00472                         int eoc_offset;
00473 
00474                         asn1_trace("--- Indefinite element, scanning @%05d -> %05d octetes for EOC\n", buf.offset, buf.size);
00475 
00476                         if (!(eoc_offset = asn1_find_eoc(&buf))) {
00477                                 asn1_trace("*** EOC not found in buffer (size: %d)\n", buf.size);
00478                                 break;
00479                         }
00480 
00481                         asn1_trace("--- EOC found at offset @%05d octets\n", eoc_offset);
00482                         hdr.size = eoc_offset - buf.offset;     /* turn into definitve form */
00483                 }
00484 
00485                 /*
00486                  * TODO: Compare current element against definition in tree
00487                  */
00488 
00489                 /* Add new element, copy information */
00490                 elem = asn1_alloc(&hdr);
00491                 if (!elem) {
00492                         /* Failed to allocate */
00493                         asn1_error("Failed to allocate new element\n");
00494                         res = -1;
00495                         break;
00496                 }
00497 
00498                 /* copy meta information */
00499                 memcpy(elem, &hdr, sizeof(struct asn1_header));
00500 
00501                 __asn1_ptr_check(elem);
00502 
00503                 /* Handle value */
00504                 if (hdr.asn_class == ASN1_CLASS_UNIVERSAL) {
00505                         switch (hdr.asn_type) {
00506                         case ASN1_TYPE_BOOLEAN:
00507                         case ASN1_TYPE_INTEGER:
00508                         case ASN1_TYPE_REAL:
00509                         case ASN1_TYPE_OID:
00510                         case ASN1_TYPE_ENUMERATED:
00511                         case ASN1_TYPE_NUMERIC_STRING:
00512                         case ASN1_TYPE_OCTET_STRING:
00513                         case ASN1_TYPE_UTF8_STRING:
00514                         case ASN1_TYPE_IA5_STRING:
00515                         case ASN1_TYPE_BIT_STRING:
00516                                 res = codec->decode_value(&buf, elem);
00517                                 break;
00518                         default:
00519                                 if (!hdr.asn_complex) {
00520                                         /* unhandled type */
00521                                         asn1_error("*** Unhandled type [class:p/c:type %d:%d:%d] (@%05d, size %d)\n", hdr.asn_class, hdr.asn_complex, hdr.asn_type, buf.offset, hdr.size);
00522                                         res = -1;
00523                                         goto out;
00524                                 }
00525                                 break;
00526                         }
00527                 }
00528                 else if (hdr.asn_complex) {
00529                         asn1_trace(">>> Not reading data of non-universal class, complex type [tag: %d]\n", hdr.asn_type);
00530                 }
00531                 else {
00532                         asn1_trace(">>> Reading data of non-universal class, non-complex type [tag: %d]\n", hdr.asn_type);
00533                         res = codec->decode_value(&buf, elem);
00534                 }
00535 
00536                 __asn1_ptr_check(elem);
00537 
00538                 /* add to tree */
00539                 asn1_append(level[depth].ptr, &elem->siblings);
00540 
00541                 /* reset */
00542                 res = 0;
00543 #ifdef __BROKEN__
00544                 /*
00545                  * Handle EOC???
00546                  * (known broken)
00547                  */
00548                 if (asn1_eq_type(elem, ASN1_TYPE_EOC)) {
00549                         if (depth > 0) {
00550                                 /* go one level down */
00551                                 depth--;
00552                                 asn1_trace("vvv EOC @%05d, going one level down [%d -> %d]\n", buf.offset, depth + 1, depth);
00553                                 continue;
00554                         }
00555                         /* end of data */
00556                         asn1_trace("*** Got EOC @%05d\n", buf.offset);
00557                         break;
00558                 }
00559 #endif
00560                 /* REALLY go one level up for every complex type? */
00561                 if (hdr.asn_complex) {
00562                         struct asn1_complex *p = (struct asn1_complex *)elem;
00563                         ASN1_INIT_HEAD(&p->children);
00564 
00565                         __asn1_ptr_check(elem);
00566 
00567                         depth++;
00568                         level[depth].offset = buf.offset;
00569                         level[depth].size   = hdr.size;
00570                         level[depth].ptr    = &p->children;
00571 
00572                         asn1_trace("^^^ Going one level up [%d -> %d] [class:p/c:type %d:%d:%d '%s'] (@%05d, size %d)\n", depth - 1, depth, hdr.asn_class, hdr.asn_complex, hdr.asn_type, asn1_type_name(hdr.asn_type), buf.offset, hdr.size);
00573                         continue;                       /* start over at next level */
00574                 }
00575 
00576                 /* reached end of parent? */
00577                 while ((level[depth].offset + level[depth].size == buf.offset) && depth > 0) {
00578                         asn1_trace("vvv Going one level down [%d -> %d]\n", depth, depth - 1);
00579                         depth--;
00580                 }
00581         }
00582 out:
00583         asn1_debug("ASN.1 %s Decoder end\n", codec->name);
00584 
00585         if (depth > 0) {
00586                 /* aborted in the middle? */
00587                 asn1_error("Decoding aborted due to error\n");
00588                 return -1;
00589         }
00590 #ifdef DEBUG
00591         asn1_debug("Max depth: %d\n", buf.max_depth);
00592 #endif
00593         return res;
00594 }
00595 
00596 
00597 struct asn1_tree *asn1_create(void)
00598 {
00599         struct asn1_tree *tmp = NULL;
00600 
00601         tmp = calloc(1, sizeof(*tmp));
00602         if (!tmp)
00603                 return NULL;
00604 
00605         ASN1_INIT_HEAD(&tmp->root);
00606         asn1_set_codec_by_id(tmp, ASN1_CODEC_BER); /* default codec */
00607         return tmp;
00608 }
00609 
00610 
00611 int asn1_destroy(struct asn1_tree *tree)
00612 {
00613         struct asn1_list *ptr = NULL;
00614         int depth = 0;
00615 
00616         if (!tree)
00617                 return -1;
00618 
00619         ptr = asn1_get_first(&tree->root);
00620 
00621         /* free elements */
00622         while (ptr) {
00623                 struct asn1_object *elem = container_of(ptr, struct asn1_object, siblings);
00624                 struct asn1_list *next = NULL;
00625 
00626                 __asn1_ptr_check(elem);
00627 
00628                 if (elem->hdr.asn_complex) {
00629                         /* has children? go up */
00630                         if ((next = asn1_get_first_child((struct asn1_complex *)elem)) != NULL) {
00631                                 ptr = next;
00632                                 depth++;
00633                                 continue;
00634                         }
00635                 }
00636 
00637                 if ((next = asn1_get_next(ptr)) == NULL && depth > 0) {
00638                         /* no siblings? go down */
00639                         next = asn1_get_parent(ptr);
00640                         depth--;
00641                 }
00642 
00643                 /* remove current from list */
00644                 asn1_remove(ptr);
00645                 asn1_free(elem);
00646                 ptr = next;
00647         }
00648 
00649         free(tree);
00650         return 0;
00651 }
00652 
00653 
00654 int asn1_print(struct asn1_tree *tree, FILE *fp)
00655 {
00656         struct asn1_list   *ptr;
00657         struct asn1_object *elem;
00658         char   indent[ASN1_MAXDEPTH] = { 0 };
00659         int    depth = 0;
00660 
00661         if (!tree || !fp)
00662                 return -1;
00663 
00664         ptr = asn1_get_first(&tree->root);
00665 
00666         /* output header */
00667         fprintf(fp, "\n===================================== ASN.1 =====================================\n\n");
00668 
00669         /* traverse tree */
00670         while (ptr) {
00671                 elem = container_of(ptr, struct asn1_object, siblings);
00672 
00673                 __asn1_ptr_check(elem);
00674 
00675                 asn1_trace("%s<<< Element [class:p/c:type %d:%d:%d] @%p >>>\n", indent, elem->hdr.asn_class, elem->hdr.asn_complex, elem->hdr.asn_type, elem);
00676 
00677                 /* print value */
00678                 if (asn1_get_class(elem) == ASN1_CLASS_UNIVERSAL) {
00679                         switch (asn1_get_type(elem)) {
00680                         case ASN1_TYPE_BOOLEAN:
00681                                 {
00682                                         struct asn1_boolean *val = (struct asn1_boolean *)elem;
00683 
00684                                         fprintf(fp, "%sboolean:\t%s\n", indent, (val->value) ? "true" : "false");
00685                                 }
00686                                 break;
00687                         case ASN1_TYPE_INTEGER:
00688                                 {
00689                                         struct asn1_integer *val = (struct asn1_integer *)elem;
00690 
00691                                         fprintf(fp, "%sinteger:\t%d\n", indent, val->value);
00692                                 }
00693                                 break;
00694                         case ASN1_TYPE_ENUMERATED:
00695                                 {
00696                                         struct asn1_enumerated *val = (struct asn1_enumerated *)elem;
00697 
00698                                         fprintf(fp, "%senumerated:\t%d\n", indent, val->value);
00699                                 }
00700                                 break;
00701                         case ASN1_TYPE_OID:
00702                                 {
00703                                         struct asn1_oid *val = (struct asn1_oid *)elem;
00704                                         int    x;
00705 
00706                                         fprintf(fp, "%soid:\t\t", indent);
00707                                         for (x = 0; x < val->length; x++) {
00708                                                 fprintf(fp, "%u%c", val->value[x], ((x + 1) < val->length) ? '.' : '\0');
00709                                         }
00710                                         fprintf(fp, "\n");
00711                                 }
00712                                 break;
00713                         case ASN1_TYPE_BIT_STRING:
00714                                 {
00715                                         struct asn1_string *val = (struct asn1_string *)elem;
00716                                         int    x;
00717 
00718                                         fprintf(fp, "%sbit string:\t[", indent);
00719                                         for (x = 0; x < elem->hdr.size; x++) {
00720                                                 fprintf(fp, "%c", (val->value[x] ? '1' : '0'));
00721                                         }
00722                                         fprintf(fp, "]\n");
00723                                 }
00724                                 break;
00725                         case ASN1_TYPE_OCTET_STRING:
00726                                 {
00727                                         struct asn1_string *val = (struct asn1_string *)elem;
00728                                         int    x;
00729 
00730                                         fprintf(fp, "%soctet string:\t[", indent);
00731                                         for (x = 0; x < elem->hdr.size; x++) {
00732                                                 fprintf(fp, " %" HEX_INT8_FMT, val->value[x]);
00733                                         }
00734                                         fprintf(fp, "]\n");
00735                                 }
00736                                 break;
00737                         case ASN1_TYPE_NUMERIC_STRING:
00738                                 {
00739                                         struct asn1_string *val = (struct asn1_string *)elem;
00740                                         int    x;
00741 
00742                                         fprintf(fp, "%snumeric string:\t'", indent);
00743                                         for (x = 0; x < elem->hdr.size; x++) {
00744                                                 if (isdigit(val->value[x]))
00745                                                         fprintf(fp, "%c", val->value[x]);
00746                                                 else
00747                                                         fprintf(fp, " (!%" HEX_INT8_FMT ") ", val->value[x]);
00748                                         }
00749                                         fprintf(fp, "'\n");
00750                                 }
00751                                 break;
00752                         case ASN1_TYPE_IA5_STRING:
00753                                 {
00754                                         struct asn1_string *val = (struct asn1_string *)elem;
00755                                         int    x;
00756 
00757                                         fprintf(fp, "%sIA5 string:\t'", indent);
00758                                         for (x = 0; x < elem->hdr.size; x++) {
00759                                                 if (isprint(val->value[x]))
00760                                                         fprintf(fp, "%c", val->value[x]);
00761                                                 else
00762                                                         fprintf(fp, " ");
00763                                         }
00764                                         fprintf(fp, "'\n");
00765                                 }
00766                                 break;
00767                         case ASN1_TYPE_UTF8_STRING:
00768                                 {
00769                                         struct asn1_string *val = (struct asn1_string *)elem;
00770                                         int    x;
00771 
00772                                         fprintf(fp, "%sUTF-8 string:\t'", indent);
00773                                         for (x = 0; x < elem->hdr.size; x++) {
00774                                                 if (isprint(val->value[x]))
00775                                                         fprintf(fp, "%c", val->value[x]);
00776                                                 else
00777                                                         fprintf(fp, " ");
00778                                         }
00779                                         fprintf(fp, "'\n");
00780                                 }
00781                                 break;
00782                         case ASN1_TYPE_SET:
00783                                 fprintf(fp, "%sset\n", indent);
00784                                 break;
00785                         case ASN1_TYPE_SEQUENCE:
00786                                 fprintf(fp, "%ssequence\n", indent);
00787                                 break;
00788                         case ASN1_TYPE_EOC:
00789                                 fprintf(fp, "%sEOC (%p, root %p)\n", indent, (void *)elem, (void *)&tree->root);
00790                                 break;
00791                         default:
00792                                 fprintf(fp, "%sunhandled type %s\n", indent, asn1_type_name(elem->hdr.asn_type));
00793                                 break;
00794                         }
00795                 } else {
00796                         fprintf(fp, "%s%s element, tag: %d", indent, asn1_class_name(elem->hdr.asn_class), elem->hdr.asn_type);
00797 
00798                         /* non-complex types (may) have data */
00799                         if (!elem->hdr.asn_complex && elem->hdr.size > 0) {
00800                                 struct asn1_string *val = (struct asn1_string *)elem;
00801                                 int    x;
00802 
00803                                 fprintf(fp, ", size: %d octets\n%s\t[", elem->hdr.size, indent);
00804                                 for (x = 0; x < elem->hdr.size; x++) {
00805                                         fprintf(fp, " %" HEX_INT8_FMT, val->value[x]);
00806                                 }
00807                                 fprintf(fp, " ]");
00808                         }
00809                         fprintf(fp, "\n");
00810                 }
00811 
00812                 if (elem->hdr.asn_complex) {
00813 
00814                         if (depth == ASN1_MAXDEPTH) {
00815                                 /* already at max. level */
00816                                 asn1_error("--- Exceeding maximum depth %d\n", ASN1_MAXDEPTH);
00817                                 break;
00818                         }
00819 
00820                         /* go one level up */
00821                         depth++;
00822 
00823                         asn1_trace("^^^ Going one level up [%d -> %d]\n", depth - 1, depth);
00824 
00825                         ptr = asn1_get_first_child((struct asn1_complex *)elem);
00826                         if (!ptr) {
00827                                 asn1_error("No children!!!");
00828                                 break;
00829                         }
00830                         fprintf(fp, "%s{\n", indent);
00831 
00832                         /* update indentation */
00833                         indent[depth - 1] = '\t';
00834                         indent[depth]     = '\0';
00835                         continue;
00836                 }
00837 
00838                 /* go down? */
00839                 while (asn1_is_last(ptr) && depth > 0) {
00840                         ptr  = asn1_get_parent(ptr);
00841                         depth--;
00842 
00843                         asn1_trace("vvv Going one level down [%d -> %d]\n", depth + 1, depth);
00844                         indent[depth] = '\0';
00845                         fprintf(fp, "%s}\n", indent);
00846                 }
00847 
00848                 ptr = asn1_get_next(ptr);
00849                 if (ptr) {
00850                         elem = container_of(ptr, struct asn1_object, siblings);
00851                         __asn1_ptr_check(elem);
00852                         asn1_trace("%s*** Next element [class:p/c:type %d:%d:%d] @%p (last? %s, head? %s) ***\n", indent, elem->hdr.asn_class, elem->hdr.asn_complex, elem->hdr.asn_type, elem, asn1_is_last(ptr) ? "yes" : "no", asn1_is_head(ptr) ? "yes" : "no");
00853                 }
00854         }
00855         fprintf(fp, "\n---------------------------------------------------------------------------------\n");
00856 
00857         return 0;
00858 }
00859 
00860 
00861 /****************************************************************************
00862  * Unit tests
00863  ****************************************************************************/
00864 #ifdef TEST
00865 #include <sys/time.h>
00866 #include <time.h>
00867 
00868 #ifdef PLATFORM_LINUX
00869 #define HAVE_CLOCK_GETTIME
00870 #endif
00871 
00872 #define ts_diff(a, b)   do { \
00873                 (a)->tv_sec  -= (b)->tv_sec;                            \
00874                 (a)->tv_nsec -= (b)->tv_nsec;                           \
00875                 if ((a)->tv_nsec < 0) {                                 \
00876                         (a)->tv_sec--;                                  \
00877                         (a)->tv_nsec = 1000000000 + (a)->tv_nsec;       \
00878                 }                                                       \
00879         } while(0);
00880 
00881 #define tv_diff(a, b)   do { \
00882                 (a)->tv_sec  -= (b)->tv_sec;                            \
00883                 (a)->tv_usec -= (b)->tv_usec;                           \
00884                 if ((a)->tv_usec < 0) {                                 \
00885                         (a)->tv_sec--;                                  \
00886                         (a)->tv_usec = 1000000 + (a)->tv_usec;          \
00887                 }                                                       \
00888         } while(0);
00889 
00890 #ifdef HAVE_CLOCK_GETTIME
00891 typedef struct timespec tsw_t;
00892 #define tsw_diff(a, b)  ts_diff(a, b)
00893 #define tsw_read(a)     clock_gettime((a), CLOCK_MONOTONIC)
00894 #define tsw_get_sec(a)  ((a)->tv_sec)
00895 #define tsw_get_nsec(a) ((a)->tv_nsec)
00896 #define tsw_get_usec(a) ((a)->tv_nsec / 1000)
00897 #else
00898 typedef struct timeval  tsw_t;
00899 #define tsw_diff(a, b)  tv_diff(a, b)
00900 #define tsw_read(a)     gettimeofday((a), NULL)
00901 #define tsw_get_sec(a)  ((a)->tv_sec)
00902 #define tsw_get_nsec(a) ((a)->tv_usec * 1000)
00903 #define tsw_get_usec(a) ((a)->tv_usec)
00904 #endif
00905 
00906 
00907 static void print_hex(const char *buf, const int size)
00908 {
00909         const static char htable[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
00910         int x;
00911 
00912         printf("------ dump (%d octets) ------\n[", size);
00913         for (x = 0; x < size; x++) {
00914                 printf(" %c%c", htable[(buf[x] >> 4) & 0x0f], htable[buf[x] & 0x0f]);
00915         }
00916         printf(" ]\n");
00917 }
00918 
00919 static int compare(const char *a, const int size_a, const char *b, const int size_b)
00920 {
00921         int i, count = 0;
00922 
00923         for (i = 0; i < MIN(size_a, size_b); i++)
00924                 if (a[i] != b[i]) count++;
00925 
00926         if (size_a != size_b)
00927                 count += MAX(size_a, size_b) - MIN(size_a, size_b);
00928 
00929         return count;
00930 }
00931 
00932 
00933 int main(void)
00934 {
00935         tsw_t tv_after, tv_before;
00936         struct asn1_tree decoded;
00937 #if 1
00938         /* */
00939         char inbuf[] = {
00940                 0xa1, 0x32, 0x02, 0x02, 0x02, 0xf5,
00941                 0x06, 0x06, 0x04, 0x00, 0x85, 0x69, 0x01, 0x03,
00942                 0x30, 0x24, 0xa1, 0x06, 0x80, 0x04, 0x31, 0x30, 0x30, 0x31,
00943                 0xa2, 0x03, 0x0a, 0x01, 0x01, 0xa3, 0x03, 0x02, 0x01, 0x00,
00944                 0xa4, 0x06, 0x80, 0x04, 0x31, 0x30, 0x30, 0x31, 0xa6, 0x08,
00945                 0x30, 0x06, 0x02, 0x01, 0x00, 0x0a, 0x01, 0x01
00946         };
00947 #elif 0
00948         /*  */
00949         char inbuf[] = {
00950                 0xa1, 0x1c, 0x02, 0x02, 0x88, 0x24, 0x02, 0x01, 0x0a, 0x30, 0x13, 0x0a, 0x01,
00951                 0x02, 0x0a, 0x01, 0x01, 0xa1, 0x0b, 0x0a, 0x01, 0x04, 0x12, 0x06, 0x31, 0x34,
00952                 0x30, 0x30, 0x38, 0x34
00953         };
00954 #else
00955         /* */
00956         char inbuf[] = {
00957                 0xa1, 0x27, 0x02, 0x02, 0x8b, 0x2d, 0x02, 0x01, 0x0c, 0x30, 0x1e, 0x0a, 0x01,
00958                 0x01, 0x0a, 0x01, 0x20, 0xa0, 0x16, 0xa0, 0x14, 0xa1, 0x0f, 0x0a, 0x01, 0x02,
00959                 0x12, 0x0a, 0x32, 0x32, 0x33, 0x38, 0x39, 0x32, 0x32, 0x37, 0x33, 0x33, 0x0a,
00960                 0x01, 0x01
00961         };
00962 #endif
00963         char outbuf[1024] = { 0 };
00964         int  size = sizeof(outbuf);
00965 
00966         if (asn1_init(&decoded) < 0) {
00967                 printf("error initializing empty ASN.1 tree structure\n");
00968                 return 1;
00969         }
00970 
00971         /*
00972          * Decode ASN.1
00973          */
00974         tsw_read(&tv_before);
00975 
00976         if (asn1_decode(&decoded, inbuf, sizeof(inbuf)) < 0) {
00977                 printf("error decoding ASN.1 data\n");
00978                 return 1;
00979         }
00980 
00981         tsw_read(&tv_after);
00982         tsw_diff(&tv_after, &tv_before);
00983 
00984         printf("Successfully decoded %d octets of ASN.1 BER data\n", (int)sizeof(inbuf));
00985 
00986         printf("ASN.1 decoder allocated %u bytes\n", asn1_allocated_bytes);
00987         printf("Duration %d seconds, %ld microseconds\n", (int)tsw_get_sec(&tv_after), tsw_get_usec(&tv_after));
00988 
00989         /*
00990          * Pretty-print
00991          */
00992         asn1_print(&decoded);
00993 
00994         /*
00995          * Encode ASN.1
00996          */
00997         tsw_read(&tv_before);
00998 
00999         asn1_encode(&decoded, outbuf, &size);
01000 
01001         tsw_read(&tv_after);
01002         tsw_diff(&tv_after, &tv_before);
01003 
01004         printf("Successfully encoded %d octets of ASN.1 BER data\n", size);
01005         print_hex(inbuf, sizeof(inbuf));
01006         print_hex(outbuf, size);
01007 
01008         printf("Compare: %d octets mismatch\n", compare(inbuf, sizeof(inbuf), outbuf, size));
01009         printf("Duration %d seconds, %ld microseconds\n", (int)tsw_get_sec(&tv_after), tsw_get_usec(&tv_after));
01010         return 0;
01011 }
01012 #endif