diff --git a/lib/asn1/asn1_print.1 b/lib/asn1/asn1_print.1 index ca10e7ecb..93a29310c 100644 --- a/lib/asn1/asn1_print.1 +++ b/lib/asn1/asn1_print.1 @@ -52,6 +52,10 @@ .Fl Fl list-types .Xc .Oc +.Oo Fl A \*(Ba Xo +.Fl Fl try-all-types +.Xc +.Oc .Oo Fl l v \*(Ba Xo .Fl Fl version .Xc @@ -60,26 +64,31 @@ .Fl Fl help .Xc .Oc -.Op Ar FILE Op Ar TypeName +.Op Ar FILE Op Ar TypeName... .Ek .Sh DESCRIPTION .Nm Dumps ASN.1 DER-encoded values. -If a +If one or more .Ar TypeName -is given, then +arguments are given, then .Nm will print the value in a JSON-like format using its knowledge of -the ASN.1 module defining that type. -If a -.Ar TypeName -is given, it must be the name of an ASN.1 type exported by an -ASN.1 module that is compiled into +the ASN.1 modules defining those types, stopping at the first type +for which it can successfully decode the value. +If +.Ar TypeNames +are given, they must be the names of ASN.1 types exported by an +ASN.1 modules that are compiled into .Nm . Use the .Fl Fl list-types option to list ASN.1 types known to .Nm . +Use the +.Fl Fl try-all-types +option to attempt decoding as all ASN.1 types known to +.Nm . .Pp Options supported: .Bl -tag -width Ds diff --git a/lib/asn1/asn1_print.c b/lib/asn1/asn1_print.c index 99ebe3ba2..f0d3c3a15 100644 --- a/lib/asn1/asn1_print.c +++ b/lib/asn1/asn1_print.c @@ -55,6 +55,7 @@ #include "rfc4108_asn1.h" #include "x690sample_asn1.h" +static int try_all_flag = 0; static int indent_flag = 1; static int inner_flag = 0; @@ -347,66 +348,86 @@ type_cmp(const void *va, const void *vb) } static int -doit(const char *filename, const char *typename) +dotype(unsigned char *buf, size_t len, char **argv) { - int fd = open(filename, O_RDONLY); - struct stat sb; - unsigned char *buf; - size_t len; - int ret; + struct types *sorted_types = emalloc(sizeof(types)); + const char *typename; + size_t matches = 0; + size_t sz; + size_t i = 0; + char *s; + void *v; + int ret = 0; - if(fd < 0) - err(1, "opening %s for read", filename); - if (fstat (fd, &sb) < 0) - err(1, "stat %s", filename); - len = sb.st_size; - buf = emalloc(len); - if (read(fd, buf, len) != len) - errx(1, "read failed"); - close(fd); - if (typename) { - struct types *sorted_types = emalloc(sizeof(types)); - size_t right = sizeof(types)/sizeof(types[0]) - 1; - size_t left = 0; - size_t mid; - size_t sz; - char *s; - void *v; - int c = -1; + memcpy(sorted_types, types, sizeof(types)); + qsort(sorted_types, + sizeof(types)/sizeof(types[0]), + sizeof(types[0]), + type_cmp); - memcpy(sorted_types, types, sizeof(types)); - qsort(sorted_types, - sizeof(types)/sizeof(types[0]), - sizeof(types[0]), - type_cmp); + while ((try_all_flag && i < sizeof(types)/sizeof(types[0])) || + (typename = (argv++)[0])) { - while (left <= right) { - mid = (left + right) >> 1; - c = strcmp(sorted_types[mid].name, typename); - if (c < 0) - left = mid + 1; - else if (c > 0) - right = mid - 1; - else - break; + if (try_all_flag) { + typename = sorted_types[i].name; + } else { + size_t right = sizeof(types)/sizeof(types[0]) - 1; + size_t left = 0; + size_t mid; + int c = -1; + + while (left <= right) { + mid = (left + right) >> 1; + c = strcmp(sorted_types[mid].name, typename); + if (c < 0) + left = mid + 1; + else if (c > 0) + right = mid - 1; + else + break; + } + if (c != 0) + errx(1, "Type %s not found", typename); + i = mid; } - if (c != 0) - errx(1, "Type %s not found", typename); - v = ecalloc(1, sorted_types[mid].sz); - ret = sorted_types[mid].decode(buf, len, v, &sz); + v = ecalloc(1, sorted_types[i].sz); + ret = sorted_types[i].decode(buf, len, v, &sz); if (ret == 0) { - s = sorted_types[mid].print(v, + if (sz == len) + fprintf(stderr, "Match: %s\n", typename); + else + fprintf(stderr, "Prefix match: %s\n", typename); + s = sorted_types[i].print(v, indent_flag ? ASN1_PRINT_INDENT : 0); - sorted_types[mid].release(v); + sorted_types[i].release(v); if (!s) ret = errno; } if (ret == 0) { fprintf(stdout, "%s\n", s); + + matches++; + i++; + if (try_all_flag) + continue; free(buf); free(s); exit(0); } + + if (argv[0]) + continue; + + if (try_all_flag) { + i++; + if (i < sizeof(types)/sizeof(types[0])) + continue; + if (matches) + break; + errx(1, "No type matched the input value"); + } + + /* XXX Use com_err */ switch (ret) { case ASN1_BAD_TIMEFORMAT: errx(1, "Could not decode and print data as type %s: " @@ -466,9 +487,36 @@ doit(const char *filename, const char *typename) default: err(1, "Could not decode and print data as type %s", typename); } - } - ret = loop(buf, len, 0); + free(buf); + free(s); + return 0; +} + +static int +doit(char **argv) +{ + int fd = open(argv[0], O_RDONLY); + struct stat sb; + unsigned char *buf; + size_t len; + int ret; + + if(fd < 0) + err(1, "opening %s for read", argv[0]); + if (fstat (fd, &sb) < 0) + err(1, "stat %s", argv[0]); + len = sb.st_size; + buf = emalloc(len); + if (read(fd, buf, len) != len) + errx(1, "read failed"); + close(fd); + + argv++; + if (argv[0] || try_all_flag) + ret = dotype(buf, len, argv); + else + ret = loop(buf, len, 0); free(buf); return ret; } @@ -484,6 +532,8 @@ struct getargs args[] = { "\ttry to parse inner structures of OCTET STRING", NULL }, { "list-types", 'l', arg_flag, &list_types_flag, "\tlist ASN.1 types known to this program", NULL }, + { "try-all-types", 'A', arg_flag, &try_all_flag, + "\ttry all known types", NULL }, { "version", 'v', arg_flag, &version_flag, NULL, NULL }, { "help", 'h', arg_flag, &help_flag, NULL, NULL } }; @@ -492,7 +542,7 @@ int num_args = sizeof(args) / sizeof(args[0]); static void usage(int code) { - arg_printusage(args, num_args, NULL, "dump-file [TypeName]"); + arg_printusage(args, num_args, NULL, "dump-file [TypeName [TypeName ...]]"); exit(code); } @@ -523,7 +573,7 @@ main(int argc, char **argv) printf("%s\n", types[i].name); exit(0); } - if (argc != 1 && argc != 2) + if (argc < 1) usage(1); - return doit(argv[0], argv[1]); + return doit(argv); }