[BACK]Return to asn1pars.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / openssl

Annotation of src/usr.bin/openssl/asn1pars.c, Revision 1.12

1.12    ! joshua      1: /* $OpenBSD: asn1pars.c,v 1.11 2022/01/12 22:55:51 tb Exp $ */
1.1       jsing       2: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
                      3:  * All rights reserved.
                      4:  *
                      5:  * This package is an SSL implementation written
                      6:  * by Eric Young (eay@cryptsoft.com).
                      7:  * The implementation was written so as to conform with Netscapes SSL.
                      8:  *
                      9:  * This library is free for commercial and non-commercial use as long as
                     10:  * the following conditions are aheared to.  The following conditions
                     11:  * apply to all code found in this distribution, be it the RC4, RSA,
                     12:  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
                     13:  * included with this distribution is covered by the same copyright terms
                     14:  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
                     15:  *
                     16:  * Copyright remains Eric Young's, and as such any Copyright notices in
                     17:  * the code are not to be removed.
                     18:  * If this package is used in a product, Eric Young should be given attribution
                     19:  * as the author of the parts of the library used.
                     20:  * This can be in the form of a textual message at program startup or
                     21:  * in documentation (online or textual) provided with the package.
                     22:  *
                     23:  * Redistribution and use in source and binary forms, with or without
                     24:  * modification, are permitted provided that the following conditions
                     25:  * are met:
                     26:  * 1. Redistributions of source code must retain the copyright
                     27:  *    notice, this list of conditions and the following disclaimer.
                     28:  * 2. Redistributions in binary form must reproduce the above copyright
                     29:  *    notice, this list of conditions and the following disclaimer in the
                     30:  *    documentation and/or other materials provided with the distribution.
                     31:  * 3. All advertising materials mentioning features or use of this software
                     32:  *    must display the following acknowledgement:
                     33:  *    "This product includes cryptographic software written by
                     34:  *     Eric Young (eay@cryptsoft.com)"
                     35:  *    The word 'cryptographic' can be left out if the rouines from the library
                     36:  *    being used are not cryptographic related :-).
                     37:  * 4. If you include any Windows specific code (or a derivative thereof) from
                     38:  *    the apps directory (application code) you must include an acknowledgement:
                     39:  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
                     40:  *
                     41:  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
                     42:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     43:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     44:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     45:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     46:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     47:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     48:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     49:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     50:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     51:  * SUCH DAMAGE.
                     52:  *
                     53:  * The licence and distribution terms for any publically available version or
                     54:  * derivative of this code cannot be changed.  i.e. this code cannot simply be
                     55:  * copied and put under another distribution licence
                     56:  * [including the GNU Public Licence.]
                     57:  */
                     58:
                     59: /* A nice addition from Dr Stephen Henson <steve@openssl.org> to
                     60:  * add the -strparse option which parses nested binary structures
                     61:  */
                     62:
                     63: #include <stdio.h>
                     64: #include <stdlib.h>
                     65: #include <limits.h>
                     66: #include <string.h>
                     67:
                     68: #include "apps.h"
1.4       deraadt    69: #include "progs.h"
1.1       jsing      70:
                     71: #include <openssl/err.h>
                     72: #include <openssl/evp.h>
                     73: #include <openssl/pem.h>
                     74: #include <openssl/x509.h>
                     75:
1.3       doug       76: static struct {
                     77:        char *derfile;
                     78:        int dump;
                     79:        char *genconf;
                     80:        char *genstr;
                     81:        int indent;
                     82:        char *infile;
                     83:        int informat;
                     84:        unsigned int length;
                     85:        int noout;
                     86:        int offset;
                     87:        char *oidfile;
                     88:        STACK_OF(OPENSSL_STRING) *osk;
                     89: } asn1pars_config;
                     90:
                     91: static int
                     92: asn1pars_opt_dlimit(char *arg)
                     93: {
                     94:        const char *errstr;
                     95:
                     96:        asn1pars_config.dump = strtonum(arg, 1, INT_MAX, &errstr);
                     97:        if (errstr) {
                     98:                fprintf(stderr, "-dlimit must be from 1 to INT_MAX: %s\n",
                     99:                    errstr);
                    100:                return (-1);
                    101:        }
                    102:        return (0);
                    103: }
                    104:
                    105: static int
                    106: asn1pars_opt_length(char *arg)
                    107: {
                    108:        const char *errstr;
                    109:
                    110:        asn1pars_config.length = strtonum(arg, 1, UINT_MAX, &errstr);
                    111:        if (errstr) {
                    112:                fprintf(stderr, "-length must be from 1 to UINT_MAX: %s\n",
                    113:                    errstr);
                    114:                return (-1);
                    115:        }
                    116:        return (0);
                    117: }
                    118:
                    119: static int
                    120: asn1pars_opt_strparse(char *arg)
                    121: {
                    122:        if (sk_OPENSSL_STRING_push(asn1pars_config.osk, arg) == 0) {
                    123:                fprintf(stderr, "-strparse cannot add argument\n");
                    124:                return (-1);
                    125:        }
                    126:        return (0);
                    127: }
                    128:
1.10      guenther  129: static const struct option asn1pars_options[] = {
1.3       doug      130:        {
                    131:                .name = "dump",
                    132:                .desc = "Dump unknown data in hex form",
                    133:                .type = OPTION_VALUE,
                    134:                .value = -1,
                    135:                .opt.value = &asn1pars_config.dump,
                    136:        },
                    137:        {
                    138:                .name = "dlimit",
                    139:                .argname = "num",
                    140:                .desc = "Dump the first num bytes of unknown data in hex form",
                    141:                .type = OPTION_ARG_FUNC,
                    142:                .opt.argfunc = asn1pars_opt_dlimit,
                    143:        },
                    144:        {
                    145:                .name = "genconf",
                    146:                .argname = "file",
                    147:                .desc = "File to generate ASN.1 structure from",
                    148:                .type = OPTION_ARG,
                    149:                .opt.arg = &asn1pars_config.genconf,
                    150:        },
                    151:        {
                    152:                .name = "genstr",
                    153:                .argname = "string",
                    154:                .desc = "String to generate ASN.1 structure from",
                    155:                .type = OPTION_ARG,
                    156:                .opt.arg = &asn1pars_config.genstr,
                    157:        },
                    158:        {
                    159:                .name = "i",
                    160:                .desc = "Indent output according to depth of structures",
                    161:                .type = OPTION_FLAG,
                    162:                .opt.flag = &asn1pars_config.indent,
                    163:        },
                    164:        {
                    165:                .name = "in",
                    166:                .argname = "file",
                    167:                .desc = "The input file (default stdin)",
                    168:                .type = OPTION_ARG,
                    169:                .opt.arg = &asn1pars_config.infile,
                    170:        },
                    171:        {
                    172:                .name = "inform",
                    173:                .argname = "fmt",
                    174:                .desc = "Input format (DER, TXT or PEM (default))",
                    175:                .type = OPTION_ARG_FORMAT,
                    176:                .opt.value = &asn1pars_config.informat,
                    177:        },
                    178:        {
                    179:                .name = "length",
                    180:                .argname = "num",
                    181:                .desc = "Number of bytes to parse (default until EOF)",
                    182:                .type = OPTION_ARG_FUNC,
                    183:                .opt.argfunc = asn1pars_opt_length,
                    184:        },
                    185:        {
                    186:                .name = "noout",
                    187:                .desc = "Do not produce any output",
                    188:                .type = OPTION_FLAG,
                    189:                .opt.flag = &asn1pars_config.noout,
                    190:        },
                    191:        {
                    192:                .name = "offset",
                    193:                .argname = "num",
                    194:                .desc = "Offset to begin parsing",
                    195:                .type = OPTION_ARG_INT,
                    196:                .opt.value = &asn1pars_config.offset,
                    197:        },
                    198:        {
                    199:                .name = "oid",
                    200:                .argname = "file",
                    201:                .desc = "File containing additional object identifiers (OIDs)",
                    202:                .type = OPTION_ARG,
                    203:                .opt.arg = &asn1pars_config.oidfile,
                    204:        },
                    205:        {
                    206:                .name = "out",
                    207:                .argname = "file",
                    208:                .desc = "Output file in DER format",
                    209:                .type = OPTION_ARG,
                    210:                .opt.arg = &asn1pars_config.derfile,
                    211:        },
                    212:        {
                    213:                .name = "strparse",
                    214:                .argname = "offset",
                    215:                .desc = "Parse the content octets of ASN.1 object starting at"
                    216:                " offset",
                    217:                .type = OPTION_ARG_FUNC,
                    218:                .opt.argfunc = asn1pars_opt_strparse,
                    219:        },
                    220:        { NULL },
                    221: };
1.1       jsing     222:
1.3       doug      223: static void
                    224: asn1pars_usage()
                    225: {
                    226:        fprintf(stderr,
                    227:            "usage: asn1parse [-i] [-dlimit num] [-dump] [-genconf file] "
                    228:            "[-genstr string]\n"
                    229:            "    [-in file] [-inform fmt] [-length num] [-noout] [-offset num] "
                    230:            "[-oid file]\n"
                    231:            "    [-out file] [-strparse offset]\n\n");
                    232:        options_usage(asn1pars_options);
                    233: }
1.1       jsing     234:
1.3       doug      235: static int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf);
1.1       jsing     236:
                    237: int
                    238: asn1parse_main(int argc, char **argv)
                    239: {
1.3       doug      240:        int i, j, ret = 1;
1.1       jsing     241:        long num, tmplen;
                    242:        BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL;
1.3       doug      243:        char *str = NULL;
1.1       jsing     244:        const char *errstr = NULL;
                    245:        unsigned char *tmpbuf;
                    246:        const unsigned char *ctmpbuf;
                    247:        BUF_MEM *buf = NULL;
                    248:        ASN1_TYPE *at = NULL;
1.5       doug      249:
1.12    ! joshua    250:        if (pledge("stdio cpath wpath rpath", NULL) == -1) {
        !           251:                perror("pledge");
        !           252:                exit(1);
1.5       doug      253:        }
1.1       jsing     254:
1.3       doug      255:        memset(&asn1pars_config, 0, sizeof(asn1pars_config));
1.1       jsing     256:
1.3       doug      257:        asn1pars_config.informat = FORMAT_PEM;
                    258:        if ((asn1pars_config.osk = sk_OPENSSL_STRING_new_null()) == NULL) {
1.1       jsing     259:                BIO_printf(bio_err, "Memory allocation failure\n");
                    260:                goto end;
                    261:        }
                    262:
1.3       doug      263:        if (options_parse(argc, argv, asn1pars_options, NULL, NULL) != 0) {
                    264:                asn1pars_usage();
                    265:                return (1);
1.1       jsing     266:        }
                    267:
                    268:        in = BIO_new(BIO_s_file());
                    269:        out = BIO_new(BIO_s_file());
                    270:        if ((in == NULL) || (out == NULL)) {
                    271:                ERR_print_errors(bio_err);
                    272:                goto end;
                    273:        }
                    274:        BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
                    275:
1.3       doug      276:        if (asn1pars_config.oidfile != NULL) {
                    277:                if (BIO_read_filename(in, asn1pars_config.oidfile) <= 0) {
                    278:                        BIO_printf(bio_err, "problems opening %s\n",
                    279:                            asn1pars_config.oidfile);
1.1       jsing     280:                        ERR_print_errors(bio_err);
                    281:                        goto end;
                    282:                }
                    283:                OBJ_create_objects(in);
                    284:        }
1.3       doug      285:        if (asn1pars_config.infile == NULL)
1.1       jsing     286:                BIO_set_fp(in, stdin, BIO_NOCLOSE);
                    287:        else {
1.3       doug      288:                if (BIO_read_filename(in, asn1pars_config.infile) <= 0) {
                    289:                        perror(asn1pars_config.infile);
1.1       jsing     290:                        goto end;
                    291:                }
                    292:        }
                    293:
1.3       doug      294:        if (asn1pars_config.derfile) {
                    295:                if (!(derout = BIO_new_file(asn1pars_config.derfile, "wb"))) {
                    296:                        BIO_printf(bio_err, "problems opening %s\n",
                    297:                            asn1pars_config.derfile);
1.1       jsing     298:                        ERR_print_errors(bio_err);
                    299:                        goto end;
                    300:                }
                    301:        }
                    302:        if ((buf = BUF_MEM_new()) == NULL)
                    303:                goto end;
                    304:        if (!BUF_MEM_grow(buf, BUFSIZ * 8))
                    305:                goto end;       /* Pre-allocate :-) */
                    306:
1.3       doug      307:        if (asn1pars_config.genstr || asn1pars_config.genconf) {
                    308:                num = do_generate(bio_err, asn1pars_config.genstr,
                    309:                    asn1pars_config.genconf, buf);
1.1       jsing     310:                if (num < 0) {
                    311:                        ERR_print_errors(bio_err);
                    312:                        goto end;
                    313:                }
                    314:        } else {
                    315:
1.3       doug      316:                if (asn1pars_config.informat == FORMAT_PEM) {
1.1       jsing     317:                        BIO *tmp;
                    318:
                    319:                        if ((b64 = BIO_new(BIO_f_base64())) == NULL)
                    320:                                goto end;
                    321:                        BIO_push(b64, in);
                    322:                        tmp = in;
                    323:                        in = b64;
                    324:                        b64 = tmp;
                    325:                }
                    326:                num = 0;
                    327:                for (;;) {
                    328:                        if (!BUF_MEM_grow(buf, (int) num + BUFSIZ))
                    329:                                goto end;
                    330:                        i = BIO_read(in, &(buf->data[num]), BUFSIZ);
                    331:                        if (i <= 0)
                    332:                                break;
                    333:                        num += i;
                    334:                }
                    335:        }
                    336:        str = buf->data;
                    337:
                    338:        /* If any structs to parse go through in sequence */
                    339:
1.3       doug      340:        if (sk_OPENSSL_STRING_num(asn1pars_config.osk)) {
1.1       jsing     341:                tmpbuf = (unsigned char *) str;
                    342:                tmplen = num;
1.3       doug      343:                for (i = 0; i < sk_OPENSSL_STRING_num(asn1pars_config.osk);
                    344:                     i++) {
1.1       jsing     345:                        ASN1_TYPE *atmp;
                    346:                        int typ;
1.3       doug      347:                        j = strtonum(
                    348:                            sk_OPENSSL_STRING_value(asn1pars_config.osk, i),
1.1       jsing     349:                            1, INT_MAX, &errstr);
                    350:                        if (errstr) {
                    351:                                BIO_printf(bio_err,
                    352:                                    "'%s' is an invalid number: %s\n",
1.3       doug      353:                                    sk_OPENSSL_STRING_value(asn1pars_config.osk,
                    354:                                    i), errstr);
1.1       jsing     355:                                continue;
                    356:                        }
                    357:                        tmpbuf += j;
                    358:                        tmplen -= j;
                    359:                        atmp = at;
                    360:                        ctmpbuf = tmpbuf;
                    361:                        at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen);
                    362:                        ASN1_TYPE_free(atmp);
                    363:                        if (!at) {
                    364:                                BIO_printf(bio_err, "Error parsing structure\n");
                    365:                                ERR_print_errors(bio_err);
                    366:                                goto end;
                    367:                        }
                    368:                        typ = ASN1_TYPE_get(at);
                    369:                        if ((typ == V_ASN1_OBJECT) ||
                    370:                            (typ == V_ASN1_NULL)) {
                    371:                                BIO_printf(bio_err, "Can't parse %s type\n",
                    372:                                    typ == V_ASN1_NULL ? "NULL" : "OBJECT");
                    373:                                ERR_print_errors(bio_err);
                    374:                                goto end;
                    375:                        }
                    376:                        /* hmm... this is a little evil but it works */
                    377:                        tmpbuf = at->value.asn1_string->data;
                    378:                        tmplen = at->value.asn1_string->length;
                    379:                }
                    380:                str = (char *) tmpbuf;
                    381:                num = tmplen;
                    382:        }
1.3       doug      383:        if (asn1pars_config.offset >= num) {
1.1       jsing     384:                BIO_printf(bio_err, "Error: offset too large\n");
                    385:                goto end;
                    386:        }
1.3       doug      387:        num -= asn1pars_config.offset;
1.1       jsing     388:
1.3       doug      389:        if ((asn1pars_config.length == 0) ||
                    390:            ((long)asn1pars_config.length > num))
                    391:                asn1pars_config.length = (unsigned int) num;
1.1       jsing     392:        if (derout) {
1.3       doug      393:                if (BIO_write(derout, str + asn1pars_config.offset,
                    394:                    asn1pars_config.length) != (int)asn1pars_config.length) {
1.1       jsing     395:                        BIO_printf(bio_err, "Error writing output\n");
                    396:                        ERR_print_errors(bio_err);
                    397:                        goto end;
                    398:                }
                    399:        }
1.3       doug      400:        if (!asn1pars_config.noout &&
                    401:            !ASN1_parse_dump(out,
                    402:            (unsigned char *)&(str[asn1pars_config.offset]),
                    403:            asn1pars_config.length, asn1pars_config.indent,
                    404:            asn1pars_config.dump)) {
1.1       jsing     405:                ERR_print_errors(bio_err);
                    406:                goto end;
                    407:        }
                    408:        ret = 0;
1.9       jsing     409:  end:
1.1       jsing     410:        BIO_free(derout);
1.3       doug      411:        BIO_free(in);
                    412:        BIO_free_all(out);
                    413:        BIO_free(b64);
1.1       jsing     414:        if (ret != 0)
                    415:                ERR_print_errors(bio_err);
1.3       doug      416:        BUF_MEM_free(buf);
1.8       jsing     417:        ASN1_TYPE_free(at);
1.3       doug      418:        sk_OPENSSL_STRING_free(asn1pars_config.osk);
1.1       jsing     419:        OBJ_cleanup();
                    420:
                    421:        return (ret);
                    422: }
                    423:
                    424: static int
1.11      tb        425: do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf)
1.1       jsing     426: {
                    427:        CONF *cnf = NULL;
                    428:        int len;
                    429:        long errline;
                    430:        unsigned char *p;
                    431:        ASN1_TYPE *atyp = NULL;
                    432:
                    433:        if (genconf) {
                    434:                cnf = NCONF_new(NULL);
                    435:                if (!NCONF_load(cnf, genconf, &errline))
                    436:                        goto conferr;
                    437:                if (!genstr)
                    438:                        genstr = NCONF_get_string(cnf, "default", "asn1");
                    439:                if (!genstr) {
                    440:                        BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf);
                    441:                        goto err;
                    442:                }
                    443:        }
                    444:        atyp = ASN1_generate_nconf(genstr, cnf);
                    445:        NCONF_free(cnf);
                    446:        cnf = NULL;
                    447:
                    448:        if (!atyp)
                    449:                return -1;
                    450:
                    451:        len = i2d_ASN1_TYPE(atyp, NULL);
                    452:        if (len <= 0)
                    453:                goto err;
                    454:
                    455:        if (!BUF_MEM_grow(buf, len))
                    456:                goto err;
                    457:
                    458:        p = (unsigned char *) buf->data;
                    459:
                    460:        i2d_ASN1_TYPE(atyp, &p);
                    461:
                    462:        ASN1_TYPE_free(atyp);
                    463:        return len;
                    464:
1.9       jsing     465:  conferr:
1.1       jsing     466:
                    467:        if (errline > 0)
                    468:                BIO_printf(bio, "Error on line %ld of config file '%s'\n",
                    469:                    errline, genconf);
                    470:        else
                    471:                BIO_printf(bio, "Error loading config file '%s'\n", genconf);
                    472:
1.9       jsing     473:  err:
1.1       jsing     474:        NCONF_free(cnf);
                    475:        ASN1_TYPE_free(atyp);
                    476:
                    477:        return -1;
                    478:
                    479: }