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

1.3     ! doug        1: /* $OpenBSD: asn1pars.c,v 1.2 2014/08/28 14:23:52 jsing 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"
                     69:
                     70: #include <openssl/err.h>
                     71: #include <openssl/evp.h>
                     72: #include <openssl/pem.h>
                     73: #include <openssl/x509.h>
                     74:
1.3     ! doug       75: static struct {
        !            76:        char *derfile;
        !            77:        int dump;
        !            78:        char *genconf;
        !            79:        char *genstr;
        !            80:        int indent;
        !            81:        char *infile;
        !            82:        int informat;
        !            83:        unsigned int length;
        !            84:        int noout;
        !            85:        int offset;
        !            86:        char *oidfile;
        !            87:        STACK_OF(OPENSSL_STRING) *osk;
        !            88: } asn1pars_config;
        !            89:
        !            90: static int
        !            91: asn1pars_opt_dlimit(char *arg)
        !            92: {
        !            93:        const char *errstr;
        !            94:
        !            95:        asn1pars_config.dump = strtonum(arg, 1, INT_MAX, &errstr);
        !            96:        if (errstr) {
        !            97:                fprintf(stderr, "-dlimit must be from 1 to INT_MAX: %s\n",
        !            98:                    errstr);
        !            99:                return (-1);
        !           100:        }
        !           101:        return (0);
        !           102: }
        !           103:
        !           104: static int
        !           105: asn1pars_opt_length(char *arg)
        !           106: {
        !           107:        const char *errstr;
        !           108:
        !           109:        asn1pars_config.length = strtonum(arg, 1, UINT_MAX, &errstr);
        !           110:        if (errstr) {
        !           111:                fprintf(stderr, "-length must be from 1 to UINT_MAX: %s\n",
        !           112:                    errstr);
        !           113:                return (-1);
        !           114:        }
        !           115:        return (0);
        !           116: }
        !           117:
        !           118: static int
        !           119: asn1pars_opt_strparse(char *arg)
        !           120: {
        !           121:        if (sk_OPENSSL_STRING_push(asn1pars_config.osk, arg) == 0) {
        !           122:                fprintf(stderr, "-strparse cannot add argument\n");
        !           123:                return (-1);
        !           124:        }
        !           125:        return (0);
        !           126: }
        !           127:
        !           128: static struct option asn1pars_options[] = {
        !           129:        {
        !           130:                .name = "dump",
        !           131:                .desc = "Dump unknown data in hex form",
        !           132:                .type = OPTION_VALUE,
        !           133:                .value = -1,
        !           134:                .opt.value = &asn1pars_config.dump,
        !           135:        },
        !           136:        {
        !           137:                .name = "dlimit",
        !           138:                .argname = "num",
        !           139:                .desc = "Dump the first num bytes of unknown data in hex form",
        !           140:                .type = OPTION_ARG_FUNC,
        !           141:                .opt.argfunc = asn1pars_opt_dlimit,
        !           142:        },
        !           143:        {
        !           144:                .name = "genconf",
        !           145:                .argname = "file",
        !           146:                .desc = "File to generate ASN.1 structure from",
        !           147:                .type = OPTION_ARG,
        !           148:                .opt.arg = &asn1pars_config.genconf,
        !           149:        },
        !           150:        {
        !           151:                .name = "genstr",
        !           152:                .argname = "string",
        !           153:                .desc = "String to generate ASN.1 structure from",
        !           154:                .type = OPTION_ARG,
        !           155:                .opt.arg = &asn1pars_config.genstr,
        !           156:        },
        !           157:        {
        !           158:                .name = "i",
        !           159:                .desc = "Indent output according to depth of structures",
        !           160:                .type = OPTION_FLAG,
        !           161:                .opt.flag = &asn1pars_config.indent,
        !           162:        },
        !           163:        {
        !           164:                .name = "in",
        !           165:                .argname = "file",
        !           166:                .desc = "The input file (default stdin)",
        !           167:                .type = OPTION_ARG,
        !           168:                .opt.arg = &asn1pars_config.infile,
        !           169:        },
        !           170:        {
        !           171:                .name = "inform",
        !           172:                .argname = "fmt",
        !           173:                .desc = "Input format (DER, TXT or PEM (default))",
        !           174:                .type = OPTION_ARG_FORMAT,
        !           175:                .opt.value = &asn1pars_config.informat,
        !           176:        },
        !           177:        {
        !           178:                .name = "length",
        !           179:                .argname = "num",
        !           180:                .desc = "Number of bytes to parse (default until EOF)",
        !           181:                .type = OPTION_ARG_FUNC,
        !           182:                .opt.argfunc = asn1pars_opt_length,
        !           183:        },
        !           184:        {
        !           185:                .name = "noout",
        !           186:                .desc = "Do not produce any output",
        !           187:                .type = OPTION_FLAG,
        !           188:                .opt.flag = &asn1pars_config.noout,
        !           189:        },
        !           190:        {
        !           191:                .name = "offset",
        !           192:                .argname = "num",
        !           193:                .desc = "Offset to begin parsing",
        !           194:                .type = OPTION_ARG_INT,
        !           195:                .opt.value = &asn1pars_config.offset,
        !           196:        },
        !           197:        {
        !           198:                .name = "oid",
        !           199:                .argname = "file",
        !           200:                .desc = "File containing additional object identifiers (OIDs)",
        !           201:                .type = OPTION_ARG,
        !           202:                .opt.arg = &asn1pars_config.oidfile,
        !           203:        },
        !           204:        {
        !           205:                .name = "out",
        !           206:                .argname = "file",
        !           207:                .desc = "Output file in DER format",
        !           208:                .type = OPTION_ARG,
        !           209:                .opt.arg = &asn1pars_config.derfile,
        !           210:        },
        !           211:        {
        !           212:                .name = "strparse",
        !           213:                .argname = "offset",
        !           214:                .desc = "Parse the content octets of ASN.1 object starting at"
        !           215:                " offset",
        !           216:                .type = OPTION_ARG_FUNC,
        !           217:                .opt.argfunc = asn1pars_opt_strparse,
        !           218:        },
        !           219:        { NULL },
        !           220: };
1.1       jsing     221:
1.3     ! doug      222: static void
        !           223: asn1pars_usage()
        !           224: {
        !           225:        fprintf(stderr,
        !           226:            "usage: asn1parse [-i] [-dlimit num] [-dump] [-genconf file] "
        !           227:            "[-genstr string]\n"
        !           228:            "    [-in file] [-inform fmt] [-length num] [-noout] [-offset num] "
        !           229:            "[-oid file]\n"
        !           230:            "    [-out file] [-strparse offset]\n\n");
        !           231:        options_usage(asn1pars_options);
        !           232: }
1.1       jsing     233:
1.3     ! doug      234: static int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf);
1.1       jsing     235:
                    236: int
                    237: asn1parse_main(int argc, char **argv)
                    238: {
1.3     ! doug      239:        int i, j, ret = 1;
1.1       jsing     240:        long num, tmplen;
                    241:        BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL;
1.3     ! doug      242:        char *str = NULL;
1.1       jsing     243:        const char *errstr = NULL;
                    244:        unsigned char *tmpbuf;
                    245:        const unsigned char *ctmpbuf;
                    246:        BUF_MEM *buf = NULL;
                    247:        ASN1_TYPE *at = NULL;
                    248:
1.3     ! doug      249:        memset(&asn1pars_config, 0, sizeof(asn1pars_config));
1.1       jsing     250:
1.3     ! doug      251:        asn1pars_config.informat = FORMAT_PEM;
        !           252:        if ((asn1pars_config.osk = sk_OPENSSL_STRING_new_null()) == NULL) {
1.1       jsing     253:                BIO_printf(bio_err, "Memory allocation failure\n");
                    254:                goto end;
                    255:        }
                    256:
1.3     ! doug      257:        if (options_parse(argc, argv, asn1pars_options, NULL, NULL) != 0) {
        !           258:                asn1pars_usage();
        !           259:                return (1);
1.1       jsing     260:        }
                    261:
                    262:        in = BIO_new(BIO_s_file());
                    263:        out = BIO_new(BIO_s_file());
                    264:        if ((in == NULL) || (out == NULL)) {
                    265:                ERR_print_errors(bio_err);
                    266:                goto end;
                    267:        }
                    268:        BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
                    269:
1.3     ! doug      270:        if (asn1pars_config.oidfile != NULL) {
        !           271:                if (BIO_read_filename(in, asn1pars_config.oidfile) <= 0) {
        !           272:                        BIO_printf(bio_err, "problems opening %s\n",
        !           273:                            asn1pars_config.oidfile);
1.1       jsing     274:                        ERR_print_errors(bio_err);
                    275:                        goto end;
                    276:                }
                    277:                OBJ_create_objects(in);
                    278:        }
1.3     ! doug      279:        if (asn1pars_config.infile == NULL)
1.1       jsing     280:                BIO_set_fp(in, stdin, BIO_NOCLOSE);
                    281:        else {
1.3     ! doug      282:                if (BIO_read_filename(in, asn1pars_config.infile) <= 0) {
        !           283:                        perror(asn1pars_config.infile);
1.1       jsing     284:                        goto end;
                    285:                }
                    286:        }
                    287:
1.3     ! doug      288:        if (asn1pars_config.derfile) {
        !           289:                if (!(derout = BIO_new_file(asn1pars_config.derfile, "wb"))) {
        !           290:                        BIO_printf(bio_err, "problems opening %s\n",
        !           291:                            asn1pars_config.derfile);
1.1       jsing     292:                        ERR_print_errors(bio_err);
                    293:                        goto end;
                    294:                }
                    295:        }
                    296:        if ((buf = BUF_MEM_new()) == NULL)
                    297:                goto end;
                    298:        if (!BUF_MEM_grow(buf, BUFSIZ * 8))
                    299:                goto end;       /* Pre-allocate :-) */
                    300:
1.3     ! doug      301:        if (asn1pars_config.genstr || asn1pars_config.genconf) {
        !           302:                num = do_generate(bio_err, asn1pars_config.genstr,
        !           303:                    asn1pars_config.genconf, buf);
1.1       jsing     304:                if (num < 0) {
                    305:                        ERR_print_errors(bio_err);
                    306:                        goto end;
                    307:                }
                    308:        } else {
                    309:
1.3     ! doug      310:                if (asn1pars_config.informat == FORMAT_PEM) {
1.1       jsing     311:                        BIO *tmp;
                    312:
                    313:                        if ((b64 = BIO_new(BIO_f_base64())) == NULL)
                    314:                                goto end;
                    315:                        BIO_push(b64, in);
                    316:                        tmp = in;
                    317:                        in = b64;
                    318:                        b64 = tmp;
                    319:                }
                    320:                num = 0;
                    321:                for (;;) {
                    322:                        if (!BUF_MEM_grow(buf, (int) num + BUFSIZ))
                    323:                                goto end;
                    324:                        i = BIO_read(in, &(buf->data[num]), BUFSIZ);
                    325:                        if (i <= 0)
                    326:                                break;
                    327:                        num += i;
                    328:                }
                    329:        }
                    330:        str = buf->data;
                    331:
                    332:        /* If any structs to parse go through in sequence */
                    333:
1.3     ! doug      334:        if (sk_OPENSSL_STRING_num(asn1pars_config.osk)) {
1.1       jsing     335:                tmpbuf = (unsigned char *) str;
                    336:                tmplen = num;
1.3     ! doug      337:                for (i = 0; i < sk_OPENSSL_STRING_num(asn1pars_config.osk);
        !           338:                     i++) {
1.1       jsing     339:                        ASN1_TYPE *atmp;
                    340:                        int typ;
1.3     ! doug      341:                        j = strtonum(
        !           342:                            sk_OPENSSL_STRING_value(asn1pars_config.osk, i),
1.1       jsing     343:                            1, INT_MAX, &errstr);
                    344:                        if (errstr) {
                    345:                                BIO_printf(bio_err,
                    346:                                    "'%s' is an invalid number: %s\n",
1.3     ! doug      347:                                    sk_OPENSSL_STRING_value(asn1pars_config.osk,
        !           348:                                    i), errstr);
1.1       jsing     349:                                continue;
                    350:                        }
                    351:                        tmpbuf += j;
                    352:                        tmplen -= j;
                    353:                        atmp = at;
                    354:                        ctmpbuf = tmpbuf;
                    355:                        at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen);
                    356:                        ASN1_TYPE_free(atmp);
                    357:                        if (!at) {
                    358:                                BIO_printf(bio_err, "Error parsing structure\n");
                    359:                                ERR_print_errors(bio_err);
                    360:                                goto end;
                    361:                        }
                    362:                        typ = ASN1_TYPE_get(at);
                    363:                        if ((typ == V_ASN1_OBJECT) ||
                    364:                            (typ == V_ASN1_NULL)) {
                    365:                                BIO_printf(bio_err, "Can't parse %s type\n",
                    366:                                    typ == V_ASN1_NULL ? "NULL" : "OBJECT");
                    367:                                ERR_print_errors(bio_err);
                    368:                                goto end;
                    369:                        }
                    370:                        /* hmm... this is a little evil but it works */
                    371:                        tmpbuf = at->value.asn1_string->data;
                    372:                        tmplen = at->value.asn1_string->length;
                    373:                }
                    374:                str = (char *) tmpbuf;
                    375:                num = tmplen;
                    376:        }
1.3     ! doug      377:        if (asn1pars_config.offset >= num) {
1.1       jsing     378:                BIO_printf(bio_err, "Error: offset too large\n");
                    379:                goto end;
                    380:        }
1.3     ! doug      381:        num -= asn1pars_config.offset;
1.1       jsing     382:
1.3     ! doug      383:        if ((asn1pars_config.length == 0) ||
        !           384:            ((long)asn1pars_config.length > num))
        !           385:                asn1pars_config.length = (unsigned int) num;
1.1       jsing     386:        if (derout) {
1.3     ! doug      387:                if (BIO_write(derout, str + asn1pars_config.offset,
        !           388:                    asn1pars_config.length) != (int)asn1pars_config.length) {
1.1       jsing     389:                        BIO_printf(bio_err, "Error writing output\n");
                    390:                        ERR_print_errors(bio_err);
                    391:                        goto end;
                    392:                }
                    393:        }
1.3     ! doug      394:        if (!asn1pars_config.noout &&
        !           395:            !ASN1_parse_dump(out,
        !           396:            (unsigned char *)&(str[asn1pars_config.offset]),
        !           397:            asn1pars_config.length, asn1pars_config.indent,
        !           398:            asn1pars_config.dump)) {
1.1       jsing     399:                ERR_print_errors(bio_err);
                    400:                goto end;
                    401:        }
                    402:        ret = 0;
                    403: end:
                    404:        BIO_free(derout);
1.3     ! doug      405:        BIO_free(in);
        !           406:        BIO_free_all(out);
        !           407:        BIO_free(b64);
1.1       jsing     408:        if (ret != 0)
                    409:                ERR_print_errors(bio_err);
1.3     ! doug      410:        BUF_MEM_free(buf);
1.1       jsing     411:        if (at != NULL)
                    412:                ASN1_TYPE_free(at);
1.3     ! doug      413:        sk_OPENSSL_STRING_free(asn1pars_config.osk);
1.1       jsing     414:        OBJ_cleanup();
                    415:
                    416:        return (ret);
                    417: }
                    418:
                    419: static int
                    420: do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf)
                    421: {
                    422:        CONF *cnf = NULL;
                    423:        int len;
                    424:        long errline;
                    425:        unsigned char *p;
                    426:        ASN1_TYPE *atyp = NULL;
                    427:
                    428:        if (genconf) {
                    429:                cnf = NCONF_new(NULL);
                    430:                if (!NCONF_load(cnf, genconf, &errline))
                    431:                        goto conferr;
                    432:                if (!genstr)
                    433:                        genstr = NCONF_get_string(cnf, "default", "asn1");
                    434:                if (!genstr) {
                    435:                        BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf);
                    436:                        goto err;
                    437:                }
                    438:        }
                    439:        atyp = ASN1_generate_nconf(genstr, cnf);
                    440:        NCONF_free(cnf);
                    441:        cnf = NULL;
                    442:
                    443:        if (!atyp)
                    444:                return -1;
                    445:
                    446:        len = i2d_ASN1_TYPE(atyp, NULL);
                    447:        if (len <= 0)
                    448:                goto err;
                    449:
                    450:        if (!BUF_MEM_grow(buf, len))
                    451:                goto err;
                    452:
                    453:        p = (unsigned char *) buf->data;
                    454:
                    455:        i2d_ASN1_TYPE(atyp, &p);
                    456:
                    457:        ASN1_TYPE_free(atyp);
                    458:        return len;
                    459:
                    460: conferr:
                    461:
                    462:        if (errline > 0)
                    463:                BIO_printf(bio, "Error on line %ld of config file '%s'\n",
                    464:                    errline, genconf);
                    465:        else
                    466:                BIO_printf(bio, "Error loading config file '%s'\n", genconf);
                    467:
                    468: err:
                    469:        NCONF_free(cnf);
                    470:        ASN1_TYPE_free(atyp);
                    471:
                    472:        return -1;
                    473:
                    474: }