[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.8

1.8     ! jsing       1: /* $OpenBSD: asn1pars.c,v 1.7 2017/01/20 08:57:11 deraadt 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:
                    129: static struct option asn1pars_options[] = {
                    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:
                    250:        if (single_execution) {
1.7       deraadt   251:                if (pledge("stdio cpath wpath rpath", NULL) == -1) {
1.5       doug      252:                        perror("pledge");
1.6       doug      253:                        exit(1);
                    254:                }
1.5       doug      255:        }
1.1       jsing     256:
1.3       doug      257:        memset(&asn1pars_config, 0, sizeof(asn1pars_config));
1.1       jsing     258:
1.3       doug      259:        asn1pars_config.informat = FORMAT_PEM;
                    260:        if ((asn1pars_config.osk = sk_OPENSSL_STRING_new_null()) == NULL) {
1.1       jsing     261:                BIO_printf(bio_err, "Memory allocation failure\n");
                    262:                goto end;
                    263:        }
                    264:
1.3       doug      265:        if (options_parse(argc, argv, asn1pars_options, NULL, NULL) != 0) {
                    266:                asn1pars_usage();
                    267:                return (1);
1.1       jsing     268:        }
                    269:
                    270:        in = BIO_new(BIO_s_file());
                    271:        out = BIO_new(BIO_s_file());
                    272:        if ((in == NULL) || (out == NULL)) {
                    273:                ERR_print_errors(bio_err);
                    274:                goto end;
                    275:        }
                    276:        BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
                    277:
1.3       doug      278:        if (asn1pars_config.oidfile != NULL) {
                    279:                if (BIO_read_filename(in, asn1pars_config.oidfile) <= 0) {
                    280:                        BIO_printf(bio_err, "problems opening %s\n",
                    281:                            asn1pars_config.oidfile);
1.1       jsing     282:                        ERR_print_errors(bio_err);
                    283:                        goto end;
                    284:                }
                    285:                OBJ_create_objects(in);
                    286:        }
1.3       doug      287:        if (asn1pars_config.infile == NULL)
1.1       jsing     288:                BIO_set_fp(in, stdin, BIO_NOCLOSE);
                    289:        else {
1.3       doug      290:                if (BIO_read_filename(in, asn1pars_config.infile) <= 0) {
                    291:                        perror(asn1pars_config.infile);
1.1       jsing     292:                        goto end;
                    293:                }
                    294:        }
                    295:
1.3       doug      296:        if (asn1pars_config.derfile) {
                    297:                if (!(derout = BIO_new_file(asn1pars_config.derfile, "wb"))) {
                    298:                        BIO_printf(bio_err, "problems opening %s\n",
                    299:                            asn1pars_config.derfile);
1.1       jsing     300:                        ERR_print_errors(bio_err);
                    301:                        goto end;
                    302:                }
                    303:        }
                    304:        if ((buf = BUF_MEM_new()) == NULL)
                    305:                goto end;
                    306:        if (!BUF_MEM_grow(buf, BUFSIZ * 8))
                    307:                goto end;       /* Pre-allocate :-) */
                    308:
1.3       doug      309:        if (asn1pars_config.genstr || asn1pars_config.genconf) {
                    310:                num = do_generate(bio_err, asn1pars_config.genstr,
                    311:                    asn1pars_config.genconf, buf);
1.1       jsing     312:                if (num < 0) {
                    313:                        ERR_print_errors(bio_err);
                    314:                        goto end;
                    315:                }
                    316:        } else {
                    317:
1.3       doug      318:                if (asn1pars_config.informat == FORMAT_PEM) {
1.1       jsing     319:                        BIO *tmp;
                    320:
                    321:                        if ((b64 = BIO_new(BIO_f_base64())) == NULL)
                    322:                                goto end;
                    323:                        BIO_push(b64, in);
                    324:                        tmp = in;
                    325:                        in = b64;
                    326:                        b64 = tmp;
                    327:                }
                    328:                num = 0;
                    329:                for (;;) {
                    330:                        if (!BUF_MEM_grow(buf, (int) num + BUFSIZ))
                    331:                                goto end;
                    332:                        i = BIO_read(in, &(buf->data[num]), BUFSIZ);
                    333:                        if (i <= 0)
                    334:                                break;
                    335:                        num += i;
                    336:                }
                    337:        }
                    338:        str = buf->data;
                    339:
                    340:        /* If any structs to parse go through in sequence */
                    341:
1.3       doug      342:        if (sk_OPENSSL_STRING_num(asn1pars_config.osk)) {
1.1       jsing     343:                tmpbuf = (unsigned char *) str;
                    344:                tmplen = num;
1.3       doug      345:                for (i = 0; i < sk_OPENSSL_STRING_num(asn1pars_config.osk);
                    346:                     i++) {
1.1       jsing     347:                        ASN1_TYPE *atmp;
                    348:                        int typ;
1.3       doug      349:                        j = strtonum(
                    350:                            sk_OPENSSL_STRING_value(asn1pars_config.osk, i),
1.1       jsing     351:                            1, INT_MAX, &errstr);
                    352:                        if (errstr) {
                    353:                                BIO_printf(bio_err,
                    354:                                    "'%s' is an invalid number: %s\n",
1.3       doug      355:                                    sk_OPENSSL_STRING_value(asn1pars_config.osk,
                    356:                                    i), errstr);
1.1       jsing     357:                                continue;
                    358:                        }
                    359:                        tmpbuf += j;
                    360:                        tmplen -= j;
                    361:                        atmp = at;
                    362:                        ctmpbuf = tmpbuf;
                    363:                        at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen);
                    364:                        ASN1_TYPE_free(atmp);
                    365:                        if (!at) {
                    366:                                BIO_printf(bio_err, "Error parsing structure\n");
                    367:                                ERR_print_errors(bio_err);
                    368:                                goto end;
                    369:                        }
                    370:                        typ = ASN1_TYPE_get(at);
                    371:                        if ((typ == V_ASN1_OBJECT) ||
                    372:                            (typ == V_ASN1_NULL)) {
                    373:                                BIO_printf(bio_err, "Can't parse %s type\n",
                    374:                                    typ == V_ASN1_NULL ? "NULL" : "OBJECT");
                    375:                                ERR_print_errors(bio_err);
                    376:                                goto end;
                    377:                        }
                    378:                        /* hmm... this is a little evil but it works */
                    379:                        tmpbuf = at->value.asn1_string->data;
                    380:                        tmplen = at->value.asn1_string->length;
                    381:                }
                    382:                str = (char *) tmpbuf;
                    383:                num = tmplen;
                    384:        }
1.3       doug      385:        if (asn1pars_config.offset >= num) {
1.1       jsing     386:                BIO_printf(bio_err, "Error: offset too large\n");
                    387:                goto end;
                    388:        }
1.3       doug      389:        num -= asn1pars_config.offset;
1.1       jsing     390:
1.3       doug      391:        if ((asn1pars_config.length == 0) ||
                    392:            ((long)asn1pars_config.length > num))
                    393:                asn1pars_config.length = (unsigned int) num;
1.1       jsing     394:        if (derout) {
1.3       doug      395:                if (BIO_write(derout, str + asn1pars_config.offset,
                    396:                    asn1pars_config.length) != (int)asn1pars_config.length) {
1.1       jsing     397:                        BIO_printf(bio_err, "Error writing output\n");
                    398:                        ERR_print_errors(bio_err);
                    399:                        goto end;
                    400:                }
                    401:        }
1.3       doug      402:        if (!asn1pars_config.noout &&
                    403:            !ASN1_parse_dump(out,
                    404:            (unsigned char *)&(str[asn1pars_config.offset]),
                    405:            asn1pars_config.length, asn1pars_config.indent,
                    406:            asn1pars_config.dump)) {
1.1       jsing     407:                ERR_print_errors(bio_err);
                    408:                goto end;
                    409:        }
                    410:        ret = 0;
                    411: end:
                    412:        BIO_free(derout);
1.3       doug      413:        BIO_free(in);
                    414:        BIO_free_all(out);
                    415:        BIO_free(b64);
1.1       jsing     416:        if (ret != 0)
                    417:                ERR_print_errors(bio_err);
1.3       doug      418:        BUF_MEM_free(buf);
1.8     ! jsing     419:        ASN1_TYPE_free(at);
1.3       doug      420:        sk_OPENSSL_STRING_free(asn1pars_config.osk);
1.1       jsing     421:        OBJ_cleanup();
                    422:
                    423:        return (ret);
                    424: }
                    425:
                    426: static int
                    427: do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf)
                    428: {
                    429:        CONF *cnf = NULL;
                    430:        int len;
                    431:        long errline;
                    432:        unsigned char *p;
                    433:        ASN1_TYPE *atyp = NULL;
                    434:
                    435:        if (genconf) {
                    436:                cnf = NCONF_new(NULL);
                    437:                if (!NCONF_load(cnf, genconf, &errline))
                    438:                        goto conferr;
                    439:                if (!genstr)
                    440:                        genstr = NCONF_get_string(cnf, "default", "asn1");
                    441:                if (!genstr) {
                    442:                        BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf);
                    443:                        goto err;
                    444:                }
                    445:        }
                    446:        atyp = ASN1_generate_nconf(genstr, cnf);
                    447:        NCONF_free(cnf);
                    448:        cnf = NULL;
                    449:
                    450:        if (!atyp)
                    451:                return -1;
                    452:
                    453:        len = i2d_ASN1_TYPE(atyp, NULL);
                    454:        if (len <= 0)
                    455:                goto err;
                    456:
                    457:        if (!BUF_MEM_grow(buf, len))
                    458:                goto err;
                    459:
                    460:        p = (unsigned char *) buf->data;
                    461:
                    462:        i2d_ASN1_TYPE(atyp, &p);
                    463:
                    464:        ASN1_TYPE_free(atyp);
                    465:        return len;
                    466:
                    467: conferr:
                    468:
                    469:        if (errline > 0)
                    470:                BIO_printf(bio, "Error on line %ld of config file '%s'\n",
                    471:                    errline, genconf);
                    472:        else
                    473:                BIO_printf(bio, "Error loading config file '%s'\n", genconf);
                    474:
                    475: err:
                    476:        NCONF_free(cnf);
                    477:        ASN1_TYPE_free(atyp);
                    478:
                    479:        return -1;
                    480:
                    481: }