155714Skris/* apps/asn1pars.c */ 255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 355714Skris * All rights reserved. 455714Skris * 555714Skris * This package is an SSL implementation written 655714Skris * by Eric Young (eay@cryptsoft.com). 755714Skris * The implementation was written so as to conform with Netscapes SSL. 8296465Sdelphij * 955714Skris * This library is free for commercial and non-commercial use as long as 1055714Skris * the following conditions are aheared to. The following conditions 1155714Skris * apply to all code found in this distribution, be it the RC4, RSA, 1255714Skris * lhash, DES, etc., code; not just the SSL code. The SSL documentation 1355714Skris * included with this distribution is covered by the same copyright terms 1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15296465Sdelphij * 1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in 1755714Skris * the code are not to be removed. 1855714Skris * If this package is used in a product, Eric Young should be given attribution 1955714Skris * as the author of the parts of the library used. 2055714Skris * This can be in the form of a textual message at program startup or 2155714Skris * in documentation (online or textual) provided with the package. 22296465Sdelphij * 2355714Skris * Redistribution and use in source and binary forms, with or without 2455714Skris * modification, are permitted provided that the following conditions 2555714Skris * are met: 2655714Skris * 1. Redistributions of source code must retain the copyright 2755714Skris * notice, this list of conditions and the following disclaimer. 2855714Skris * 2. Redistributions in binary form must reproduce the above copyright 2955714Skris * notice, this list of conditions and the following disclaimer in the 3055714Skris * documentation and/or other materials provided with the distribution. 3155714Skris * 3. All advertising materials mentioning features or use of this software 3255714Skris * must display the following acknowledgement: 3355714Skris * "This product includes cryptographic software written by 3455714Skris * Eric Young (eay@cryptsoft.com)" 3555714Skris * The word 'cryptographic' can be left out if the rouines from the library 3655714Skris * being used are not cryptographic related :-). 37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from 3855714Skris * the apps directory (application code) you must include an acknowledgement: 3955714Skris * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40296465Sdelphij * 4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4455714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5155714Skris * SUCH DAMAGE. 52296465Sdelphij * 5355714Skris * The licence and distribution terms for any publically available version or 5455714Skris * derivative of this code cannot be changed. i.e. this code cannot simply be 5555714Skris * copied and put under another distribution licence 5655714Skris * [including the GNU Public Licence.] 5755714Skris */ 5855714Skris 59296465Sdelphij/* 60296465Sdelphij * A nice addition from Dr Stephen Henson <steve@openssl.org> to add the 61296465Sdelphij * -strparse option which parses nested binary structures 6255714Skris */ 6355714Skris 6455714Skris#include <stdio.h> 6555714Skris#include <stdlib.h> 6655714Skris#include <string.h> 6755714Skris#include "apps.h" 6855714Skris#include <openssl/err.h> 6955714Skris#include <openssl/evp.h> 7055714Skris#include <openssl/x509.h> 7155714Skris#include <openssl/pem.h> 7255714Skris 73296465Sdelphij/*- 74296465Sdelphij * -inform arg - input format - default PEM (DER or PEM) 75296465Sdelphij * -in arg - input file - default stdin 76296465Sdelphij * -i - indent the details by depth 77296465Sdelphij * -offset - where in the file to start 78296465Sdelphij * -length - how many bytes to use 79296465Sdelphij * -oid file - extra oid description file 8055714Skris */ 8155714Skris 8255714Skris#undef PROG 83296465Sdelphij#define PROG asn1parse_main 8455714Skris 8559191Skrisint MAIN(int, char **); 8659191Skris 87160814Ssimonstatic int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf); 88160814Ssimon 8955714Skrisint MAIN(int argc, char **argv) 90296465Sdelphij{ 91296465Sdelphij int i, badops = 0, offset = 0, ret = 1, j; 92296465Sdelphij unsigned int length = 0; 93296465Sdelphij long num, tmplen; 94296465Sdelphij BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL; 95296465Sdelphij int informat, indent = 0, noout = 0, dump = 0; 96296465Sdelphij char *infile = NULL, *str = NULL, *prog, *oidfile = NULL, *derfile = NULL; 97296465Sdelphij char *genstr = NULL, *genconf = NULL; 98296465Sdelphij unsigned char *tmpbuf; 99296465Sdelphij const unsigned char *ctmpbuf; 100296465Sdelphij BUF_MEM *buf = NULL; 101296465Sdelphij STACK *osk = NULL; 102296465Sdelphij ASN1_TYPE *at = NULL; 10355714Skris 104296465Sdelphij informat = FORMAT_PEM; 10555714Skris 106296465Sdelphij apps_startup(); 10755714Skris 108296465Sdelphij if (bio_err == NULL) 109296465Sdelphij if ((bio_err = BIO_new(BIO_s_file())) != NULL) 110296465Sdelphij BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); 11155714Skris 112296465Sdelphij if (!load_config(bio_err, NULL)) 113296465Sdelphij goto end; 114109998Smarkm 115296465Sdelphij prog = argv[0]; 116296465Sdelphij argc--; 117296465Sdelphij argv++; 118296465Sdelphij if ((osk = sk_new_null()) == NULL) { 119296465Sdelphij BIO_printf(bio_err, "Memory allocation failure\n"); 120296465Sdelphij goto end; 121296465Sdelphij } 122296465Sdelphij while (argc >= 1) { 123296465Sdelphij if (strcmp(*argv, "-inform") == 0) { 124296465Sdelphij if (--argc < 1) 125296465Sdelphij goto bad; 126296465Sdelphij informat = str2fmt(*(++argv)); 127296465Sdelphij } else if (strcmp(*argv, "-in") == 0) { 128296465Sdelphij if (--argc < 1) 129296465Sdelphij goto bad; 130296465Sdelphij infile = *(++argv); 131296465Sdelphij } else if (strcmp(*argv, "-out") == 0) { 132296465Sdelphij if (--argc < 1) 133296465Sdelphij goto bad; 134296465Sdelphij derfile = *(++argv); 135296465Sdelphij } else if (strcmp(*argv, "-i") == 0) { 136296465Sdelphij indent = 1; 137296465Sdelphij } else if (strcmp(*argv, "-noout") == 0) 138296465Sdelphij noout = 1; 139296465Sdelphij else if (strcmp(*argv, "-oid") == 0) { 140296465Sdelphij if (--argc < 1) 141296465Sdelphij goto bad; 142296465Sdelphij oidfile = *(++argv); 143296465Sdelphij } else if (strcmp(*argv, "-offset") == 0) { 144296465Sdelphij if (--argc < 1) 145296465Sdelphij goto bad; 146296465Sdelphij offset = atoi(*(++argv)); 147296465Sdelphij } else if (strcmp(*argv, "-length") == 0) { 148296465Sdelphij if (--argc < 1) 149296465Sdelphij goto bad; 150296465Sdelphij length = atoi(*(++argv)); 151296465Sdelphij if (length == 0) 152296465Sdelphij goto bad; 153296465Sdelphij } else if (strcmp(*argv, "-dump") == 0) { 154296465Sdelphij dump = -1; 155296465Sdelphij } else if (strcmp(*argv, "-dlimit") == 0) { 156296465Sdelphij if (--argc < 1) 157296465Sdelphij goto bad; 158296465Sdelphij dump = atoi(*(++argv)); 159296465Sdelphij if (dump <= 0) 160296465Sdelphij goto bad; 161296465Sdelphij } else if (strcmp(*argv, "-strparse") == 0) { 162296465Sdelphij if (--argc < 1) 163296465Sdelphij goto bad; 164296465Sdelphij sk_push(osk, *(++argv)); 165296465Sdelphij } else if (strcmp(*argv, "-genstr") == 0) { 166296465Sdelphij if (--argc < 1) 167296465Sdelphij goto bad; 168296465Sdelphij genstr = *(++argv); 169296465Sdelphij } else if (strcmp(*argv, "-genconf") == 0) { 170296465Sdelphij if (--argc < 1) 171296465Sdelphij goto bad; 172296465Sdelphij genconf = *(++argv); 173296465Sdelphij } else { 174296465Sdelphij BIO_printf(bio_err, "unknown option %s\n", *argv); 175296465Sdelphij badops = 1; 176296465Sdelphij break; 177296465Sdelphij } 178296465Sdelphij argc--; 179296465Sdelphij argv++; 180296465Sdelphij } 18155714Skris 182296465Sdelphij if (badops) { 183296465Sdelphij bad: 184296465Sdelphij BIO_printf(bio_err, "%s [options] <infile\n", prog); 185296465Sdelphij BIO_printf(bio_err, "where options are\n"); 186296465Sdelphij BIO_printf(bio_err, " -inform arg input format - one of DER PEM\n"); 187296465Sdelphij BIO_printf(bio_err, " -in arg input file\n"); 188296465Sdelphij BIO_printf(bio_err, 189296465Sdelphij " -out arg output file (output format is always DER\n"); 190296465Sdelphij BIO_printf(bio_err, " -noout arg don't produce any output\n"); 191296465Sdelphij BIO_printf(bio_err, " -offset arg offset into file\n"); 192296465Sdelphij BIO_printf(bio_err, " -length arg length of section in file\n"); 193296465Sdelphij BIO_printf(bio_err, " -i indent entries\n"); 194296465Sdelphij BIO_printf(bio_err, " -dump dump unknown data in hex form\n"); 195296465Sdelphij BIO_printf(bio_err, 196296465Sdelphij " -dlimit arg dump the first arg bytes of unknown data in hex form\n"); 197296465Sdelphij BIO_printf(bio_err, " -oid file file of extra oid definitions\n"); 198296465Sdelphij BIO_printf(bio_err, " -strparse offset\n"); 199296465Sdelphij BIO_printf(bio_err, 200296465Sdelphij " a series of these can be used to 'dig' into multiple\n"); 201296465Sdelphij BIO_printf(bio_err, " ASN1 blob wrappings\n"); 202296465Sdelphij BIO_printf(bio_err, 203296465Sdelphij " -genstr str string to generate ASN1 structure from\n"); 204296465Sdelphij BIO_printf(bio_err, 205296465Sdelphij " -genconf file file to generate ASN1 structure from\n"); 206296465Sdelphij goto end; 207296465Sdelphij } 20855714Skris 209296465Sdelphij ERR_load_crypto_strings(); 21055714Skris 211296465Sdelphij in = BIO_new(BIO_s_file()); 212296465Sdelphij out = BIO_new(BIO_s_file()); 213296465Sdelphij if ((in == NULL) || (out == NULL)) { 214296465Sdelphij ERR_print_errors(bio_err); 215296465Sdelphij goto end; 216296465Sdelphij } 217296465Sdelphij BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); 218109998Smarkm#ifdef OPENSSL_SYS_VMS 219296465Sdelphij { 220296465Sdelphij BIO *tmpbio = BIO_new(BIO_f_linebuffer()); 221296465Sdelphij out = BIO_push(tmpbio, out); 222296465Sdelphij } 22368651Skris#endif 22455714Skris 225296465Sdelphij if (oidfile != NULL) { 226296465Sdelphij if (BIO_read_filename(in, oidfile) <= 0) { 227296465Sdelphij BIO_printf(bio_err, "problems opening %s\n", oidfile); 228296465Sdelphij ERR_print_errors(bio_err); 229296465Sdelphij goto end; 230296465Sdelphij } 231296465Sdelphij OBJ_create_objects(in); 232296465Sdelphij } 23355714Skris 234296465Sdelphij if (infile == NULL) 235296465Sdelphij BIO_set_fp(in, stdin, BIO_NOCLOSE); 236296465Sdelphij else { 237296465Sdelphij if (BIO_read_filename(in, infile) <= 0) { 238296465Sdelphij perror(infile); 239296465Sdelphij goto end; 240296465Sdelphij } 241296465Sdelphij } 24255714Skris 243296465Sdelphij if (derfile) { 244296465Sdelphij if (!(derout = BIO_new_file(derfile, "wb"))) { 245296465Sdelphij BIO_printf(bio_err, "problems opening %s\n", derfile); 246296465Sdelphij ERR_print_errors(bio_err); 247296465Sdelphij goto end; 248296465Sdelphij } 249296465Sdelphij } 25055714Skris 251296465Sdelphij if ((buf = BUF_MEM_new()) == NULL) 252296465Sdelphij goto end; 253296465Sdelphij if (!BUF_MEM_grow(buf, BUFSIZ * 8)) 254296465Sdelphij goto end; /* Pre-allocate :-) */ 25555714Skris 256296465Sdelphij if (genstr || genconf) { 257296465Sdelphij num = do_generate(bio_err, genstr, genconf, buf); 258296465Sdelphij if (num < 0) { 259296465Sdelphij ERR_print_errors(bio_err); 260296465Sdelphij goto end; 261296465Sdelphij } 262296465Sdelphij } 26355714Skris 264296465Sdelphij else { 265160814Ssimon 266296465Sdelphij if (informat == FORMAT_PEM) { 267296465Sdelphij BIO *tmp; 268160814Ssimon 269296465Sdelphij if ((b64 = BIO_new(BIO_f_base64())) == NULL) 270296465Sdelphij goto end; 271296465Sdelphij BIO_push(b64, in); 272296465Sdelphij tmp = in; 273296465Sdelphij in = b64; 274296465Sdelphij b64 = tmp; 275296465Sdelphij } 276160814Ssimon 277296465Sdelphij num = 0; 278296465Sdelphij for (;;) { 279296465Sdelphij if (!BUF_MEM_grow(buf, (int)num + BUFSIZ)) 280296465Sdelphij goto end; 281296465Sdelphij i = BIO_read(in, &(buf->data[num]), BUFSIZ); 282296465Sdelphij if (i <= 0) 283296465Sdelphij break; 284296465Sdelphij num += i; 285296465Sdelphij } 286296465Sdelphij } 287296465Sdelphij str = buf->data; 28855714Skris 289296465Sdelphij /* If any structs to parse go through in sequence */ 29055714Skris 291296465Sdelphij if (sk_num(osk)) { 292296465Sdelphij tmpbuf = (unsigned char *)str; 293296465Sdelphij tmplen = num; 294296465Sdelphij for (i = 0; i < sk_num(osk); i++) { 295296465Sdelphij ASN1_TYPE *atmp; 296296465Sdelphij int typ; 297296465Sdelphij j = atoi(sk_value(osk, i)); 298296465Sdelphij if (j == 0) { 299296465Sdelphij BIO_printf(bio_err, "'%s' is an invalid number\n", 300296465Sdelphij sk_value(osk, i)); 301296465Sdelphij continue; 302296465Sdelphij } 303296465Sdelphij tmpbuf += j; 304296465Sdelphij tmplen -= j; 305296465Sdelphij atmp = at; 306296465Sdelphij ctmpbuf = tmpbuf; 307296465Sdelphij at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen); 308296465Sdelphij ASN1_TYPE_free(atmp); 309296465Sdelphij if (!at) { 310296465Sdelphij BIO_printf(bio_err, "Error parsing structure\n"); 311296465Sdelphij ERR_print_errors(bio_err); 312296465Sdelphij goto end; 313296465Sdelphij } 314296465Sdelphij typ = ASN1_TYPE_get(at); 315296465Sdelphij if ((typ == V_ASN1_OBJECT) 316296465Sdelphij || (typ == V_ASN1_BOOLEAN) 317296465Sdelphij || (typ == V_ASN1_NULL)) { 318296465Sdelphij BIO_printf(bio_err, "Can't parse %s type\n", ASN1_tag2str(typ)); 319296465Sdelphij ERR_print_errors(bio_err); 320296465Sdelphij goto end; 321296465Sdelphij } 322296465Sdelphij /* hmm... this is a little evil but it works */ 323296465Sdelphij tmpbuf = at->value.asn1_string->data; 324296465Sdelphij tmplen = at->value.asn1_string->length; 325296465Sdelphij } 326296465Sdelphij str = (char *)tmpbuf; 327296465Sdelphij num = tmplen; 328296465Sdelphij } 32955714Skris 330296465Sdelphij if (offset >= num) { 331296465Sdelphij BIO_printf(bio_err, "Error: offset too large\n"); 332296465Sdelphij goto end; 333296465Sdelphij } 334127128Snectar 335296465Sdelphij num -= offset; 336127128Snectar 337296465Sdelphij if ((length == 0) || ((long)length > num)) 338296465Sdelphij length = (unsigned int)num; 339296465Sdelphij if (derout) { 340296465Sdelphij if (BIO_write(derout, str + offset, length) != (int)length) { 341296465Sdelphij BIO_printf(bio_err, "Error writing output\n"); 342296465Sdelphij ERR_print_errors(bio_err); 343296465Sdelphij goto end; 344296465Sdelphij } 345296465Sdelphij } 346296465Sdelphij if (!noout && 347296465Sdelphij !ASN1_parse_dump(out, (unsigned char *)&(str[offset]), length, 348296465Sdelphij indent, dump)) { 349296465Sdelphij ERR_print_errors(bio_err); 350296465Sdelphij goto end; 351296465Sdelphij } 352296465Sdelphij ret = 0; 353296465Sdelphij end: 354296465Sdelphij BIO_free(derout); 355296465Sdelphij if (in != NULL) 356296465Sdelphij BIO_free(in); 357296465Sdelphij if (out != NULL) 358296465Sdelphij BIO_free_all(out); 359296465Sdelphij if (b64 != NULL) 360296465Sdelphij BIO_free(b64); 361296465Sdelphij if (ret != 0) 362296465Sdelphij ERR_print_errors(bio_err); 363296465Sdelphij if (buf != NULL) 364296465Sdelphij BUF_MEM_free(buf); 365296465Sdelphij if (at != NULL) 366296465Sdelphij ASN1_TYPE_free(at); 367296465Sdelphij if (osk != NULL) 368296465Sdelphij sk_free(osk); 369296465Sdelphij OBJ_cleanup(); 370296465Sdelphij apps_shutdown(); 371296465Sdelphij OPENSSL_EXIT(ret); 372296465Sdelphij} 37355714Skris 374160814Ssimonstatic int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf) 375296465Sdelphij{ 376296465Sdelphij CONF *cnf = NULL; 377296465Sdelphij int len; 378296465Sdelphij long errline; 379296465Sdelphij unsigned char *p; 380296465Sdelphij ASN1_TYPE *atyp = NULL; 381160814Ssimon 382296465Sdelphij if (genconf) { 383296465Sdelphij cnf = NCONF_new(NULL); 384296465Sdelphij if (!NCONF_load(cnf, genconf, &errline)) 385296465Sdelphij goto conferr; 386296465Sdelphij if (!genstr) 387296465Sdelphij genstr = NCONF_get_string(cnf, "default", "asn1"); 388296465Sdelphij if (!genstr) { 389296465Sdelphij BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf); 390296465Sdelphij goto err; 391296465Sdelphij } 392296465Sdelphij } 393160814Ssimon 394296465Sdelphij atyp = ASN1_generate_nconf(genstr, cnf); 395296465Sdelphij NCONF_free(cnf); 396296465Sdelphij cnf = NULL; 397160814Ssimon 398296465Sdelphij if (!atyp) 399296465Sdelphij return -1; 400160814Ssimon 401296465Sdelphij len = i2d_ASN1_TYPE(atyp, NULL); 402160814Ssimon 403296465Sdelphij if (len <= 0) 404296465Sdelphij goto err; 405160814Ssimon 406296465Sdelphij if (!BUF_MEM_grow(buf, len)) 407296465Sdelphij goto err; 408160814Ssimon 409296465Sdelphij p = (unsigned char *)buf->data; 410160814Ssimon 411296465Sdelphij i2d_ASN1_TYPE(atyp, &p); 412160814Ssimon 413296465Sdelphij ASN1_TYPE_free(atyp); 414296465Sdelphij return len; 415160814Ssimon 416296465Sdelphij conferr: 417160814Ssimon 418296465Sdelphij if (errline > 0) 419296465Sdelphij BIO_printf(bio, "Error on line %ld of config file '%s'\n", 420296465Sdelphij errline, genconf); 421296465Sdelphij else 422296465Sdelphij BIO_printf(bio, "Error loading config file '%s'\n", genconf); 423160814Ssimon 424296465Sdelphij err: 425296465Sdelphij NCONF_free(cnf); 426296465Sdelphij ASN1_TYPE_free(atyp); 427160814Ssimon 428296465Sdelphij return -1; 429160814Ssimon 430296465Sdelphij} 431