Convert asn1pars.c to the new option handling.
authordoug <doug@openbsd.org>
Thu, 8 Jan 2015 11:00:12 +0000 (11:00 +0000)
committerdoug <doug@openbsd.org>
Thu, 8 Jan 2015 11:00:12 +0000 (11:00 +0000)
Also, removed a few useless if null checks.

input from bcook@
input + ok jsing@

usr.bin/openssl/asn1pars.c

index e6d5339..62af4f1 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: asn1pars.c,v 1.2 2014/08/28 14:23:52 jsing Exp $ */
+/* $OpenBSD: asn1pars.c,v 1.3 2015/01/08 11:00:12 doug Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
 #include <openssl/pem.h>
 #include <openssl/x509.h>
 
-/* -inform arg - input format - default PEM (DER or PEM)
- * -in arg     - input file - default stdin
- * -i          - indent the details by depth
- * -offset     - where in the file to start
- * -length     - how many bytes to use
- * -oid file   - extra oid description file
- */
+static struct {
+       char *derfile;
+       int dump;
+       char *genconf;
+       char *genstr;
+       int indent;
+       char *infile;
+       int informat;
+       unsigned int length;
+       int noout;
+       int offset;
+       char *oidfile;
+       STACK_OF(OPENSSL_STRING) *osk;
+} asn1pars_config;
+
+static int
+asn1pars_opt_dlimit(char *arg)
+{
+       const char *errstr;
+
+       asn1pars_config.dump = strtonum(arg, 1, INT_MAX, &errstr);
+       if (errstr) {
+               fprintf(stderr, "-dlimit must be from 1 to INT_MAX: %s\n",
+                   errstr);
+               return (-1);
+       }
+       return (0);
+}
+
+static int
+asn1pars_opt_length(char *arg)
+{
+       const char *errstr;
+
+       asn1pars_config.length = strtonum(arg, 1, UINT_MAX, &errstr);
+       if (errstr) {
+               fprintf(stderr, "-length must be from 1 to UINT_MAX: %s\n",
+                   errstr);
+               return (-1);
+       }
+       return (0);
+}
+
+static int
+asn1pars_opt_strparse(char *arg)
+{
+       if (sk_OPENSSL_STRING_push(asn1pars_config.osk, arg) == 0) {
+               fprintf(stderr, "-strparse cannot add argument\n");
+               return (-1);
+       }
+       return (0);
+}
 
-int asn1parse_main(int, char **);
+static struct option asn1pars_options[] = {
+       {
+               .name = "dump",
+               .desc = "Dump unknown data in hex form",
+               .type = OPTION_VALUE,
+               .value = -1,
+               .opt.value = &asn1pars_config.dump,
+       },
+       {
+               .name = "dlimit",
+               .argname = "num",
+               .desc = "Dump the first num bytes of unknown data in hex form",
+               .type = OPTION_ARG_FUNC,
+               .opt.argfunc = asn1pars_opt_dlimit,
+       },
+       {
+               .name = "genconf",
+               .argname = "file",
+               .desc = "File to generate ASN.1 structure from",
+               .type = OPTION_ARG,
+               .opt.arg = &asn1pars_config.genconf,
+       },
+       {
+               .name = "genstr",
+               .argname = "string",
+               .desc = "String to generate ASN.1 structure from",
+               .type = OPTION_ARG,
+               .opt.arg = &asn1pars_config.genstr,
+       },
+       {
+               .name = "i",
+               .desc = "Indent output according to depth of structures",
+               .type = OPTION_FLAG,
+               .opt.flag = &asn1pars_config.indent,
+       },
+       {
+               .name = "in",
+               .argname = "file",
+               .desc = "The input file (default stdin)",
+               .type = OPTION_ARG,
+               .opt.arg = &asn1pars_config.infile,
+       },
+       {
+               .name = "inform",
+               .argname = "fmt",
+               .desc = "Input format (DER, TXT or PEM (default))",
+               .type = OPTION_ARG_FORMAT,
+               .opt.value = &asn1pars_config.informat,
+       },
+       {
+               .name = "length",
+               .argname = "num",
+               .desc = "Number of bytes to parse (default until EOF)",
+               .type = OPTION_ARG_FUNC,
+               .opt.argfunc = asn1pars_opt_length,
+       },
+       {
+               .name = "noout",
+               .desc = "Do not produce any output",
+               .type = OPTION_FLAG,
+               .opt.flag = &asn1pars_config.noout,
+       },
+       {
+               .name = "offset",
+               .argname = "num",
+               .desc = "Offset to begin parsing",
+               .type = OPTION_ARG_INT,
+               .opt.value = &asn1pars_config.offset,
+       },
+       {
+               .name = "oid",
+               .argname = "file",
+               .desc = "File containing additional object identifiers (OIDs)",
+               .type = OPTION_ARG,
+               .opt.arg = &asn1pars_config.oidfile,
+       },
+       {
+               .name = "out",
+               .argname = "file",
+               .desc = "Output file in DER format",
+               .type = OPTION_ARG,
+               .opt.arg = &asn1pars_config.derfile,
+       },
+       {
+               .name = "strparse",
+               .argname = "offset",
+               .desc = "Parse the content octets of ASN.1 object starting at"
+               " offset",
+               .type = OPTION_ARG_FUNC,
+               .opt.argfunc = asn1pars_opt_strparse,
+       },
+       { NULL },
+};
+
+static void
+asn1pars_usage()
+{
+       fprintf(stderr,
+           "usage: asn1parse [-i] [-dlimit num] [-dump] [-genconf file] "
+           "[-genstr string]\n"
+           "    [-in file] [-inform fmt] [-length num] [-noout] [-offset num] "
+           "[-oid file]\n"
+           "    [-out file] [-strparse offset]\n\n");
+       options_usage(asn1pars_options);
+}
 
-static int do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf);
+static int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf);
 
 int
 asn1parse_main(int argc, char **argv)
 {
-       int i, badops = 0, offset = 0, ret = 1, j;
-       unsigned int length = 0;
+       int i, j, ret = 1;
        long num, tmplen;
        BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL;
-       int informat, indent = 0, noout = 0, dump = 0;
-       char *infile = NULL, *str = NULL, *prog, *oidfile = NULL, *derfile = NULL;
-       char *genstr = NULL, *genconf = NULL;
+       char *str = NULL;
        const char *errstr = NULL;
        unsigned char *tmpbuf;
        const unsigned char *ctmpbuf;
        BUF_MEM *buf = NULL;
-       STACK_OF(OPENSSL_STRING) * osk = NULL;
        ASN1_TYPE *at = NULL;
 
-       informat = FORMAT_PEM;
+       memset(&asn1pars_config, 0, sizeof(asn1pars_config));
 
-       prog = argv[0];
-       argc--;
-       argv++;
-       if ((osk = sk_OPENSSL_STRING_new_null()) == NULL) {
+       asn1pars_config.informat = FORMAT_PEM;
+       if ((asn1pars_config.osk = sk_OPENSSL_STRING_new_null()) == NULL) {
                BIO_printf(bio_err, "Memory allocation failure\n");
                goto end;
        }
-       while (argc >= 1) {
-               if (strcmp(*argv, "-inform") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       informat = str2fmt(*(++argv));
-               } else if (strcmp(*argv, "-in") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       infile = *(++argv);
-               } else if (strcmp(*argv, "-out") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       derfile = *(++argv);
-               } else if (strcmp(*argv, "-i") == 0) {
-                       indent = 1;
-               } else if (strcmp(*argv, "-noout") == 0)
-                       noout = 1;
-               else if (strcmp(*argv, "-oid") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       oidfile = *(++argv);
-               } else if (strcmp(*argv, "-offset") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       offset = strtonum(*(++argv), 0, INT_MAX, &errstr);
-                       if (errstr)
-                               goto bad;
-               } else if (strcmp(*argv, "-length") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       length = strtonum(*(++argv), 1, UINT_MAX, &errstr);
-                       if (errstr)
-                               goto bad;
-               } else if (strcmp(*argv, "-dump") == 0) {
-                       dump = -1;
-               } else if (strcmp(*argv, "-dlimit") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       dump = strtonum(*(++argv), 1, INT_MAX, &errstr);
-                       if (errstr)
-                               goto bad;
-               } else if (strcmp(*argv, "-strparse") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       sk_OPENSSL_STRING_push(osk, *(++argv));
-               } else if (strcmp(*argv, "-genstr") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       genstr = *(++argv);
-               } else if (strcmp(*argv, "-genconf") == 0) {
-                       if (--argc < 1)
-                               goto bad;
-                       genconf = *(++argv);
-               } else {
-                       BIO_printf(bio_err, "unknown option %s\n", *argv);
-                       badops = 1;
-                       break;
-               }
-               argc--;
-               argv++;
-       }
 
-       if (badops) {
-bad:
-               BIO_printf(bio_err, "%s [options] <infile\n", prog);
-               BIO_printf(bio_err, "where options are\n");
-               BIO_printf(bio_err, " -inform arg   input format - one of DER PEM\n");
-               BIO_printf(bio_err, " -in arg       input file\n");
-               BIO_printf(bio_err, " -out arg      output file (output format is always DER\n");
-               BIO_printf(bio_err, " -noout arg    don't produce any output\n");
-               BIO_printf(bio_err, " -offset arg   offset into file\n");
-               BIO_printf(bio_err, " -length arg   length of section in file\n");
-               BIO_printf(bio_err, " -i            indent entries\n");
-               BIO_printf(bio_err, " -dump         dump unknown data in hex form\n");
-               BIO_printf(bio_err, " -dlimit arg   dump the first arg bytes of unknown data in hex form\n");
-               BIO_printf(bio_err, " -oid file     file of extra oid definitions\n");
-               BIO_printf(bio_err, " -strparse offset\n");
-               BIO_printf(bio_err, "               a series of these can be used to 'dig' into multiple\n");
-               BIO_printf(bio_err, "               ASN1 blob wrappings\n");
-               BIO_printf(bio_err, " -genstr str   string to generate ASN1 structure from\n");
-               BIO_printf(bio_err, " -genconf file file to generate ASN1 structure from\n");
-               goto end;
+       if (options_parse(argc, argv, asn1pars_options, NULL, NULL) != 0) {
+               asn1pars_usage();
+               return (1);
        }
 
        in = BIO_new(BIO_s_file());
@@ -202,26 +267,28 @@ bad:
        }
        BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
 
-       if (oidfile != NULL) {
-               if (BIO_read_filename(in, oidfile) <= 0) {
-                       BIO_printf(bio_err, "problems opening %s\n", oidfile);
+       if (asn1pars_config.oidfile != NULL) {
+               if (BIO_read_filename(in, asn1pars_config.oidfile) <= 0) {
+                       BIO_printf(bio_err, "problems opening %s\n",
+                           asn1pars_config.oidfile);
                        ERR_print_errors(bio_err);
                        goto end;
                }
                OBJ_create_objects(in);
        }
-       if (infile == NULL)
+       if (asn1pars_config.infile == NULL)
                BIO_set_fp(in, stdin, BIO_NOCLOSE);
        else {
-               if (BIO_read_filename(in, infile) <= 0) {
-                       perror(infile);
+               if (BIO_read_filename(in, asn1pars_config.infile) <= 0) {
+                       perror(asn1pars_config.infile);
                        goto end;
                }
        }
 
-       if (derfile) {
-               if (!(derout = BIO_new_file(derfile, "wb"))) {
-                       BIO_printf(bio_err, "problems opening %s\n", derfile);
+       if (asn1pars_config.derfile) {
+               if (!(derout = BIO_new_file(asn1pars_config.derfile, "wb"))) {
+                       BIO_printf(bio_err, "problems opening %s\n",
+                           asn1pars_config.derfile);
                        ERR_print_errors(bio_err);
                        goto end;
                }
@@ -231,15 +298,16 @@ bad:
        if (!BUF_MEM_grow(buf, BUFSIZ * 8))
                goto end;       /* Pre-allocate :-) */
 
-       if (genstr || genconf) {
-               num = do_generate(bio_err, genstr, genconf, buf);
+       if (asn1pars_config.genstr || asn1pars_config.genconf) {
+               num = do_generate(bio_err, asn1pars_config.genstr,
+                   asn1pars_config.genconf, buf);
                if (num < 0) {
                        ERR_print_errors(bio_err);
                        goto end;
                }
        } else {
 
-               if (informat == FORMAT_PEM) {
+               if (asn1pars_config.informat == FORMAT_PEM) {
                        BIO *tmp;
 
                        if ((b64 = BIO_new(BIO_f_base64())) == NULL)
@@ -263,18 +331,21 @@ bad:
 
        /* If any structs to parse go through in sequence */
 
-       if (sk_OPENSSL_STRING_num(osk)) {
+       if (sk_OPENSSL_STRING_num(asn1pars_config.osk)) {
                tmpbuf = (unsigned char *) str;
                tmplen = num;
-               for (i = 0; i < sk_OPENSSL_STRING_num(osk); i++) {
+               for (i = 0; i < sk_OPENSSL_STRING_num(asn1pars_config.osk);
+                    i++) {
                        ASN1_TYPE *atmp;
                        int typ;
-                       j = strtonum(sk_OPENSSL_STRING_value(osk, i),
+                       j = strtonum(
+                           sk_OPENSSL_STRING_value(asn1pars_config.osk, i),
                            1, INT_MAX, &errstr);
                        if (errstr) {
                                BIO_printf(bio_err,
                                    "'%s' is an invalid number: %s\n",
-                                   sk_OPENSSL_STRING_value(osk, i), errstr);
+                                   sk_OPENSSL_STRING_value(asn1pars_config.osk,
+                                   i), errstr);
                                continue;
                        }
                        tmpbuf += j;
@@ -303,44 +374,43 @@ bad:
                str = (char *) tmpbuf;
                num = tmplen;
        }
-       if (offset >= num) {
+       if (asn1pars_config.offset >= num) {
                BIO_printf(bio_err, "Error: offset too large\n");
                goto end;
        }
-       num -= offset;
+       num -= asn1pars_config.offset;
 
-       if ((length == 0) || ((long) length > num))
-               length = (unsigned int) num;
+       if ((asn1pars_config.length == 0) ||
+           ((long)asn1pars_config.length > num))
+               asn1pars_config.length = (unsigned int) num;
        if (derout) {
-               if (BIO_write(derout, str + offset, length) != (int) length) {
+               if (BIO_write(derout, str + asn1pars_config.offset,
+                   asn1pars_config.length) != (int)asn1pars_config.length) {
                        BIO_printf(bio_err, "Error writing output\n");
                        ERR_print_errors(bio_err);
                        goto end;
                }
        }
-       if (!noout &&
-           !ASN1_parse_dump(out, (unsigned char *) &(str[offset]), length,
-               indent, dump)) {
+       if (!asn1pars_config.noout &&
+           !ASN1_parse_dump(out,
+           (unsigned char *)&(str[asn1pars_config.offset]),
+           asn1pars_config.length, asn1pars_config.indent,
+           asn1pars_config.dump)) {
                ERR_print_errors(bio_err);
                goto end;
        }
        ret = 0;
 end:
        BIO_free(derout);
-       if (in != NULL)
-               BIO_free(in);
-       if (out != NULL)
-               BIO_free_all(out);
-       if (b64 != NULL)
-               BIO_free(b64);
+       BIO_free(in);
+       BIO_free_all(out);
+       BIO_free(b64);
        if (ret != 0)
                ERR_print_errors(bio_err);
-       if (buf != NULL)
-               BUF_MEM_free(buf);
+       BUF_MEM_free(buf);
        if (at != NULL)
                ASN1_TYPE_free(at);
-       if (osk != NULL)
-               sk_OPENSSL_STRING_free(osk);
+       sk_OPENSSL_STRING_free(asn1pars_config.osk);
        OBJ_cleanup();
 
        return (ret);
@@ -374,7 +444,6 @@ do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf)
                return -1;
 
        len = i2d_ASN1_TYPE(atyp, NULL);
-
        if (len <= 0)
                goto err;