Annotation of src/usr.bin/openssl/asn1pars.c, Revision 1.1
1.1 ! jsing 1: /* $OpenBSD: asn1pars.c,v 1.27 2014/07/14 00:35:10 deraadt Exp $ */
! 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:
! 75: /* -inform arg - input format - default PEM (DER or PEM)
! 76: * -in arg - input file - default stdin
! 77: * -i - indent the details by depth
! 78: * -offset - where in the file to start
! 79: * -length - how many bytes to use
! 80: * -oid file - extra oid description file
! 81: */
! 82:
! 83: int asn1parse_main(int, char **);
! 84:
! 85: static int do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf);
! 86:
! 87: int
! 88: asn1parse_main(int argc, char **argv)
! 89: {
! 90: int i, badops = 0, offset = 0, ret = 1, j;
! 91: unsigned int length = 0;
! 92: long num, tmplen;
! 93: BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL;
! 94: int informat, indent = 0, noout = 0, dump = 0;
! 95: char *infile = NULL, *str = NULL, *prog, *oidfile = NULL, *derfile = NULL;
! 96: char *genstr = NULL, *genconf = NULL;
! 97: const char *errstr = NULL;
! 98: unsigned char *tmpbuf;
! 99: const unsigned char *ctmpbuf;
! 100: BUF_MEM *buf = NULL;
! 101: STACK_OF(OPENSSL_STRING) * osk = NULL;
! 102: ASN1_TYPE *at = NULL;
! 103:
! 104: informat = FORMAT_PEM;
! 105:
! 106: prog = argv[0];
! 107: argc--;
! 108: argv++;
! 109: if ((osk = sk_OPENSSL_STRING_new_null()) == NULL) {
! 110: BIO_printf(bio_err, "Memory allocation failure\n");
! 111: goto end;
! 112: }
! 113: while (argc >= 1) {
! 114: if (strcmp(*argv, "-inform") == 0) {
! 115: if (--argc < 1)
! 116: goto bad;
! 117: informat = str2fmt(*(++argv));
! 118: } else if (strcmp(*argv, "-in") == 0) {
! 119: if (--argc < 1)
! 120: goto bad;
! 121: infile = *(++argv);
! 122: } else if (strcmp(*argv, "-out") == 0) {
! 123: if (--argc < 1)
! 124: goto bad;
! 125: derfile = *(++argv);
! 126: } else if (strcmp(*argv, "-i") == 0) {
! 127: indent = 1;
! 128: } else if (strcmp(*argv, "-noout") == 0)
! 129: noout = 1;
! 130: else if (strcmp(*argv, "-oid") == 0) {
! 131: if (--argc < 1)
! 132: goto bad;
! 133: oidfile = *(++argv);
! 134: } else if (strcmp(*argv, "-offset") == 0) {
! 135: if (--argc < 1)
! 136: goto bad;
! 137: offset = strtonum(*(++argv), 0, INT_MAX, &errstr);
! 138: if (errstr)
! 139: goto bad;
! 140: } else if (strcmp(*argv, "-length") == 0) {
! 141: if (--argc < 1)
! 142: goto bad;
! 143: length = strtonum(*(++argv), 1, UINT_MAX, &errstr);
! 144: if (errstr)
! 145: goto bad;
! 146: } else if (strcmp(*argv, "-dump") == 0) {
! 147: dump = -1;
! 148: } else if (strcmp(*argv, "-dlimit") == 0) {
! 149: if (--argc < 1)
! 150: goto bad;
! 151: dump = strtonum(*(++argv), 1, INT_MAX, &errstr);
! 152: if (errstr)
! 153: goto bad;
! 154: } else if (strcmp(*argv, "-strparse") == 0) {
! 155: if (--argc < 1)
! 156: goto bad;
! 157: sk_OPENSSL_STRING_push(osk, *(++argv));
! 158: } else if (strcmp(*argv, "-genstr") == 0) {
! 159: if (--argc < 1)
! 160: goto bad;
! 161: genstr = *(++argv);
! 162: } else if (strcmp(*argv, "-genconf") == 0) {
! 163: if (--argc < 1)
! 164: goto bad;
! 165: genconf = *(++argv);
! 166: } else {
! 167: BIO_printf(bio_err, "unknown option %s\n", *argv);
! 168: badops = 1;
! 169: break;
! 170: }
! 171: argc--;
! 172: argv++;
! 173: }
! 174:
! 175: if (badops) {
! 176: bad:
! 177: BIO_printf(bio_err, "%s [options] <infile\n", prog);
! 178: BIO_printf(bio_err, "where options are\n");
! 179: BIO_printf(bio_err, " -inform arg input format - one of DER PEM\n");
! 180: BIO_printf(bio_err, " -in arg input file\n");
! 181: BIO_printf(bio_err, " -out arg output file (output format is always DER\n");
! 182: BIO_printf(bio_err, " -noout arg don't produce any output\n");
! 183: BIO_printf(bio_err, " -offset arg offset into file\n");
! 184: BIO_printf(bio_err, " -length arg length of section in file\n");
! 185: BIO_printf(bio_err, " -i indent entries\n");
! 186: BIO_printf(bio_err, " -dump dump unknown data in hex form\n");
! 187: BIO_printf(bio_err, " -dlimit arg dump the first arg bytes of unknown data in hex form\n");
! 188: BIO_printf(bio_err, " -oid file file of extra oid definitions\n");
! 189: BIO_printf(bio_err, " -strparse offset\n");
! 190: BIO_printf(bio_err, " a series of these can be used to 'dig' into multiple\n");
! 191: BIO_printf(bio_err, " ASN1 blob wrappings\n");
! 192: BIO_printf(bio_err, " -genstr str string to generate ASN1 structure from\n");
! 193: BIO_printf(bio_err, " -genconf file file to generate ASN1 structure from\n");
! 194: goto end;
! 195: }
! 196: ERR_load_crypto_strings();
! 197:
! 198: in = BIO_new(BIO_s_file());
! 199: out = BIO_new(BIO_s_file());
! 200: if ((in == NULL) || (out == NULL)) {
! 201: ERR_print_errors(bio_err);
! 202: goto end;
! 203: }
! 204: BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
! 205:
! 206: if (oidfile != NULL) {
! 207: if (BIO_read_filename(in, oidfile) <= 0) {
! 208: BIO_printf(bio_err, "problems opening %s\n", oidfile);
! 209: ERR_print_errors(bio_err);
! 210: goto end;
! 211: }
! 212: OBJ_create_objects(in);
! 213: }
! 214: if (infile == NULL)
! 215: BIO_set_fp(in, stdin, BIO_NOCLOSE);
! 216: else {
! 217: if (BIO_read_filename(in, infile) <= 0) {
! 218: perror(infile);
! 219: goto end;
! 220: }
! 221: }
! 222:
! 223: if (derfile) {
! 224: if (!(derout = BIO_new_file(derfile, "wb"))) {
! 225: BIO_printf(bio_err, "problems opening %s\n", derfile);
! 226: ERR_print_errors(bio_err);
! 227: goto end;
! 228: }
! 229: }
! 230: if ((buf = BUF_MEM_new()) == NULL)
! 231: goto end;
! 232: if (!BUF_MEM_grow(buf, BUFSIZ * 8))
! 233: goto end; /* Pre-allocate :-) */
! 234:
! 235: if (genstr || genconf) {
! 236: num = do_generate(bio_err, genstr, genconf, buf);
! 237: if (num < 0) {
! 238: ERR_print_errors(bio_err);
! 239: goto end;
! 240: }
! 241: } else {
! 242:
! 243: if (informat == FORMAT_PEM) {
! 244: BIO *tmp;
! 245:
! 246: if ((b64 = BIO_new(BIO_f_base64())) == NULL)
! 247: goto end;
! 248: BIO_push(b64, in);
! 249: tmp = in;
! 250: in = b64;
! 251: b64 = tmp;
! 252: }
! 253: num = 0;
! 254: for (;;) {
! 255: if (!BUF_MEM_grow(buf, (int) num + BUFSIZ))
! 256: goto end;
! 257: i = BIO_read(in, &(buf->data[num]), BUFSIZ);
! 258: if (i <= 0)
! 259: break;
! 260: num += i;
! 261: }
! 262: }
! 263: str = buf->data;
! 264:
! 265: /* If any structs to parse go through in sequence */
! 266:
! 267: if (sk_OPENSSL_STRING_num(osk)) {
! 268: tmpbuf = (unsigned char *) str;
! 269: tmplen = num;
! 270: for (i = 0; i < sk_OPENSSL_STRING_num(osk); i++) {
! 271: ASN1_TYPE *atmp;
! 272: int typ;
! 273: j = strtonum(sk_OPENSSL_STRING_value(osk, i),
! 274: 1, INT_MAX, &errstr);
! 275: if (errstr) {
! 276: BIO_printf(bio_err,
! 277: "'%s' is an invalid number: %s\n",
! 278: sk_OPENSSL_STRING_value(osk, i), errstr);
! 279: continue;
! 280: }
! 281: tmpbuf += j;
! 282: tmplen -= j;
! 283: atmp = at;
! 284: ctmpbuf = tmpbuf;
! 285: at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen);
! 286: ASN1_TYPE_free(atmp);
! 287: if (!at) {
! 288: BIO_printf(bio_err, "Error parsing structure\n");
! 289: ERR_print_errors(bio_err);
! 290: goto end;
! 291: }
! 292: typ = ASN1_TYPE_get(at);
! 293: if ((typ == V_ASN1_OBJECT) ||
! 294: (typ == V_ASN1_NULL)) {
! 295: BIO_printf(bio_err, "Can't parse %s type\n",
! 296: typ == V_ASN1_NULL ? "NULL" : "OBJECT");
! 297: ERR_print_errors(bio_err);
! 298: goto end;
! 299: }
! 300: /* hmm... this is a little evil but it works */
! 301: tmpbuf = at->value.asn1_string->data;
! 302: tmplen = at->value.asn1_string->length;
! 303: }
! 304: str = (char *) tmpbuf;
! 305: num = tmplen;
! 306: }
! 307: if (offset >= num) {
! 308: BIO_printf(bio_err, "Error: offset too large\n");
! 309: goto end;
! 310: }
! 311: num -= offset;
! 312:
! 313: if ((length == 0) || ((long) length > num))
! 314: length = (unsigned int) num;
! 315: if (derout) {
! 316: if (BIO_write(derout, str + offset, length) != (int) length) {
! 317: BIO_printf(bio_err, "Error writing output\n");
! 318: ERR_print_errors(bio_err);
! 319: goto end;
! 320: }
! 321: }
! 322: if (!noout &&
! 323: !ASN1_parse_dump(out, (unsigned char *) &(str[offset]), length,
! 324: indent, dump)) {
! 325: ERR_print_errors(bio_err);
! 326: goto end;
! 327: }
! 328: ret = 0;
! 329: end:
! 330: BIO_free(derout);
! 331: if (in != NULL)
! 332: BIO_free(in);
! 333: if (out != NULL)
! 334: BIO_free_all(out);
! 335: if (b64 != NULL)
! 336: BIO_free(b64);
! 337: if (ret != 0)
! 338: ERR_print_errors(bio_err);
! 339: if (buf != NULL)
! 340: BUF_MEM_free(buf);
! 341: if (at != NULL)
! 342: ASN1_TYPE_free(at);
! 343: if (osk != NULL)
! 344: sk_OPENSSL_STRING_free(osk);
! 345: OBJ_cleanup();
! 346:
! 347: return (ret);
! 348: }
! 349:
! 350: static int
! 351: do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf)
! 352: {
! 353: CONF *cnf = NULL;
! 354: int len;
! 355: long errline;
! 356: unsigned char *p;
! 357: ASN1_TYPE *atyp = NULL;
! 358:
! 359: if (genconf) {
! 360: cnf = NCONF_new(NULL);
! 361: if (!NCONF_load(cnf, genconf, &errline))
! 362: goto conferr;
! 363: if (!genstr)
! 364: genstr = NCONF_get_string(cnf, "default", "asn1");
! 365: if (!genstr) {
! 366: BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf);
! 367: goto err;
! 368: }
! 369: }
! 370: atyp = ASN1_generate_nconf(genstr, cnf);
! 371: NCONF_free(cnf);
! 372: cnf = NULL;
! 373:
! 374: if (!atyp)
! 375: return -1;
! 376:
! 377: len = i2d_ASN1_TYPE(atyp, NULL);
! 378:
! 379: if (len <= 0)
! 380: goto err;
! 381:
! 382: if (!BUF_MEM_grow(buf, len))
! 383: goto err;
! 384:
! 385: p = (unsigned char *) buf->data;
! 386:
! 387: i2d_ASN1_TYPE(atyp, &p);
! 388:
! 389: ASN1_TYPE_free(atyp);
! 390: return len;
! 391:
! 392: conferr:
! 393:
! 394: if (errline > 0)
! 395: BIO_printf(bio, "Error on line %ld of config file '%s'\n",
! 396: errline, genconf);
! 397: else
! 398: BIO_printf(bio, "Error loading config file '%s'\n", genconf);
! 399:
! 400: err:
! 401: NCONF_free(cnf);
! 402: ASN1_TYPE_free(atyp);
! 403:
! 404: return -1;
! 405:
! 406: }