libisdn
|
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