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. 8296341Sdelphij * 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). 15296341Sdelphij * 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. 22296341Sdelphij * 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 :-). 37296341Sdelphij * 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)" 40296341Sdelphij * 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. 52296341Sdelphij * 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 59296341Sdelphij/* 60296341Sdelphij * A nice addition from Dr Stephen Henson <steve@openssl.org> to add the 61296341Sdelphij * -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 73296341Sdelphij/*- 74296341Sdelphij * -inform arg - input format - default PEM (DER or PEM) 75296341Sdelphij * -in arg - input file - default stdin 76296341Sdelphij * -i - indent the details by depth 77296341Sdelphij * -offset - where in the file to start 78296341Sdelphij * -length - how many bytes to use 79296341Sdelphij * -oid file - extra oid description file 8055714Skris */ 8155714Skris 8255714Skris#undef PROG 83296341Sdelphij#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) 90296341Sdelphij{ 91296341Sdelphij int i, badops = 0, offset = 0, ret = 1, j; 92296341Sdelphij unsigned int length = 0; 93296341Sdelphij long num, tmplen; 94296341Sdelphij BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL; 95296341Sdelphij int informat, indent = 0, noout = 0, dump = 0; 96296341Sdelphij char *infile = NULL, *str = NULL, *prog, *oidfile = NULL, *derfile = NULL; 97296341Sdelphij char *genstr = NULL, *genconf = NULL; 98296341Sdelphij unsigned char *tmpbuf; 99296341Sdelphij const unsigned char *ctmpbuf; 100296341Sdelphij BUF_MEM *buf = NULL; 101296341Sdelphij STACK_OF(OPENSSL_STRING) *osk = NULL; 102296341Sdelphij ASN1_TYPE *at = NULL; 10355714Skris 104296341Sdelphij informat = FORMAT_PEM; 10555714Skris 106296341Sdelphij apps_startup(); 10755714Skris 108296341Sdelphij if (bio_err == NULL) 109296341Sdelphij if ((bio_err = BIO_new(BIO_s_file())) != NULL) 110296341Sdelphij BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); 11155714Skris 112296341Sdelphij if (!load_config(bio_err, NULL)) 113296341Sdelphij goto end; 114109998Smarkm 115296341Sdelphij prog = argv[0]; 116296341Sdelphij argc--; 117296341Sdelphij argv++; 118296341Sdelphij if ((osk = sk_OPENSSL_STRING_new_null()) == NULL) { 119296341Sdelphij BIO_printf(bio_err, "Memory allocation failure\n"); 120296341Sdelphij goto end; 121296341Sdelphij } 122296341Sdelphij while (argc >= 1) { 123296341Sdelphij if (strcmp(*argv, "-inform") == 0) { 124296341Sdelphij if (--argc < 1) 125296341Sdelphij goto bad; 126296341Sdelphij informat = str2fmt(*(++argv)); 127296341Sdelphij } else if (strcmp(*argv, "-in") == 0) { 128296341Sdelphij if (--argc < 1) 129296341Sdelphij goto bad; 130296341Sdelphij infile = *(++argv); 131296341Sdelphij } else if (strcmp(*argv, "-out") == 0) { 132296341Sdelphij if (--argc < 1) 133296341Sdelphij goto bad; 134296341Sdelphij derfile = *(++argv); 135296341Sdelphij } else if (strcmp(*argv, "-i") == 0) { 136296341Sdelphij indent = 1; 137296341Sdelphij } else if (strcmp(*argv, "-noout") == 0) 138296341Sdelphij noout = 1; 139296341Sdelphij else if (strcmp(*argv, "-oid") == 0) { 140296341Sdelphij if (--argc < 1) 141296341Sdelphij goto bad; 142296341Sdelphij oidfile = *(++argv); 143296341Sdelphij } else if (strcmp(*argv, "-offset") == 0) { 144296341Sdelphij if (--argc < 1) 145296341Sdelphij goto bad; 146296341Sdelphij offset = atoi(*(++argv)); 147296341Sdelphij } else if (strcmp(*argv, "-length") == 0) { 148296341Sdelphij if (--argc < 1) 149296341Sdelphij goto bad; 150296341Sdelphij length = atoi(*(++argv)); 151296341Sdelphij if (length == 0) 152296341Sdelphij goto bad; 153296341Sdelphij } else if (strcmp(*argv, "-dump") == 0) { 154296341Sdelphij dump = -1; 155296341Sdelphij } else if (strcmp(*argv, "-dlimit") == 0) { 156296341Sdelphij if (--argc < 1) 157296341Sdelphij goto bad; 158296341Sdelphij dump = atoi(*(++argv)); 159296341Sdelphij if (dump <= 0) 160296341Sdelphij goto bad; 161296341Sdelphij } else if (strcmp(*argv, "-strparse") == 0) { 162296341Sdelphij if (--argc < 1) 163296341Sdelphij goto bad; 164296341Sdelphij sk_OPENSSL_STRING_push(osk, *(++argv)); 165296341Sdelphij } else if (strcmp(*argv, "-genstr") == 0) { 166296341Sdelphij if (--argc < 1) 167296341Sdelphij goto bad; 168296341Sdelphij genstr = *(++argv); 169296341Sdelphij } else if (strcmp(*argv, "-genconf") == 0) { 170296341Sdelphij if (--argc < 1) 171296341Sdelphij goto bad; 172296341Sdelphij genconf = *(++argv); 173296341Sdelphij } else { 174296341Sdelphij BIO_printf(bio_err, "unknown option %s\n", *argv); 175296341Sdelphij badops = 1; 176296341Sdelphij break; 177296341Sdelphij } 178296341Sdelphij argc--; 179296341Sdelphij argv++; 180296341Sdelphij } 18155714Skris 182296341Sdelphij if (badops) { 183296341Sdelphij bad: 184296341Sdelphij BIO_printf(bio_err, "%s [options] <infile\n", prog); 185296341Sdelphij BIO_printf(bio_err, "where options are\n"); 186296341Sdelphij BIO_printf(bio_err, " -inform arg input format - one of DER PEM\n"); 187296341Sdelphij BIO_printf(bio_err, " -in arg input file\n"); 188296341Sdelphij BIO_printf(bio_err, 189296341Sdelphij " -out arg output file (output format is always DER\n"); 190296341Sdelphij BIO_printf(bio_err, " -noout arg don't produce any output\n"); 191296341Sdelphij BIO_printf(bio_err, " -offset arg offset into file\n"); 192296341Sdelphij BIO_printf(bio_err, " -length arg length of section in file\n"); 193296341Sdelphij BIO_printf(bio_err, " -i indent entries\n"); 194296341Sdelphij BIO_printf(bio_err, " -dump dump unknown data in hex form\n"); 195296341Sdelphij BIO_printf(bio_err, 196296341Sdelphij " -dlimit arg dump the first arg bytes of unknown data in hex form\n"); 197296341Sdelphij BIO_printf(bio_err, " -oid file file of extra oid definitions\n"); 198296341Sdelphij BIO_printf(bio_err, " -strparse offset\n"); 199296341Sdelphij BIO_printf(bio_err, 200296341Sdelphij " a series of these can be used to 'dig' into multiple\n"); 201296341Sdelphij BIO_printf(bio_err, " ASN1 blob wrappings\n"); 202296341Sdelphij BIO_printf(bio_err, 203296341Sdelphij " -genstr str string to generate ASN1 structure from\n"); 204296341Sdelphij BIO_printf(bio_err, 205296341Sdelphij " -genconf file file to generate ASN1 structure from\n"); 206296341Sdelphij goto end; 207296341Sdelphij } 20855714Skris 209296341Sdelphij ERR_load_crypto_strings(); 21055714Skris 211296341Sdelphij in = BIO_new(BIO_s_file()); 212296341Sdelphij out = BIO_new(BIO_s_file()); 213296341Sdelphij if ((in == NULL) || (out == NULL)) { 214296341Sdelphij ERR_print_errors(bio_err); 215296341Sdelphij goto end; 216296341Sdelphij } 217296341Sdelphij BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); 218109998Smarkm#ifdef OPENSSL_SYS_VMS 219296341Sdelphij { 220296341Sdelphij BIO *tmpbio = BIO_new(BIO_f_linebuffer()); 221296341Sdelphij out = BIO_push(tmpbio, out); 222296341Sdelphij } 22368651Skris#endif 22455714Skris 225296341Sdelphij if (oidfile != NULL) { 226296341Sdelphij if (BIO_read_filename(in, oidfile) <= 0) { 227296341Sdelphij BIO_printf(bio_err, "problems opening %s\n", oidfile); 228296341Sdelphij ERR_print_errors(bio_err); 229296341Sdelphij goto end; 230296341Sdelphij } 231296341Sdelphij OBJ_create_objects(in); 232296341Sdelphij } 23355714Skris 234296341Sdelphij if (infile == NULL) 235296341Sdelphij BIO_set_fp(in, stdin, BIO_NOCLOSE); 236296341Sdelphij else { 237296341Sdelphij if (BIO_read_filename(in, infile) <= 0) { 238296341Sdelphij perror(infile); 239296341Sdelphij goto end; 240296341Sdelphij } 241296341Sdelphij } 24255714Skris 243296341Sdelphij if (derfile) { 244296341Sdelphij if (!(derout = BIO_new_file(derfile, "wb"))) { 245296341Sdelphij BIO_printf(bio_err, "problems opening %s\n", derfile); 246296341Sdelphij ERR_print_errors(bio_err); 247296341Sdelphij goto end; 248296341Sdelphij } 249296341Sdelphij } 25055714Skris 251296341Sdelphij if ((buf = BUF_MEM_new()) == NULL) 252296341Sdelphij goto end; 253296341Sdelphij if (!BUF_MEM_grow(buf, BUFSIZ * 8)) 254296341Sdelphij goto end; /* Pre-allocate :-) */ 25555714Skris 256296341Sdelphij if (genstr || genconf) { 257296341Sdelphij num = do_generate(bio_err, genstr, genconf, buf); 258296341Sdelphij if (num < 0) { 259296341Sdelphij ERR_print_errors(bio_err); 260296341Sdelphij goto end; 261296341Sdelphij } 262296341Sdelphij } 26355714Skris 264296341Sdelphij else { 265160814Ssimon 266296341Sdelphij if (informat == FORMAT_PEM) { 267296341Sdelphij BIO *tmp; 268160814Ssimon 269296341Sdelphij if ((b64 = BIO_new(BIO_f_base64())) == NULL) 270296341Sdelphij goto end; 271296341Sdelphij BIO_push(b64, in); 272296341Sdelphij tmp = in; 273296341Sdelphij in = b64; 274296341Sdelphij b64 = tmp; 275296341Sdelphij } 276160814Ssimon 277296341Sdelphij num = 0; 278296341Sdelphij for (;;) { 279296341Sdelphij if (!BUF_MEM_grow(buf, (int)num + BUFSIZ)) 280296341Sdelphij goto end; 281296341Sdelphij i = BIO_read(in, &(buf->data[num]), BUFSIZ); 282296341Sdelphij if (i <= 0) 283296341Sdelphij break; 284296341Sdelphij num += i; 285296341Sdelphij } 286296341Sdelphij } 287296341Sdelphij str = buf->data; 28855714Skris 289296341Sdelphij /* If any structs to parse go through in sequence */ 29055714Skris 291296341Sdelphij if (sk_OPENSSL_STRING_num(osk)) { 292296341Sdelphij tmpbuf = (unsigned char *)str; 293296341Sdelphij tmplen = num; 294296341Sdelphij for (i = 0; i < sk_OPENSSL_STRING_num(osk); i++) { 295296341Sdelphij ASN1_TYPE *atmp; 296296341Sdelphij int typ; 297296341Sdelphij j = atoi(sk_OPENSSL_STRING_value(osk, i)); 298296341Sdelphij if (j == 0) { 299296341Sdelphij BIO_printf(bio_err, "'%s' is an invalid number\n", 300296341Sdelphij sk_OPENSSL_STRING_value(osk, i)); 301296341Sdelphij continue; 302296341Sdelphij } 303296341Sdelphij tmpbuf += j; 304296341Sdelphij tmplen -= j; 305296341Sdelphij atmp = at; 306296341Sdelphij ctmpbuf = tmpbuf; 307296341Sdelphij at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen); 308296341Sdelphij ASN1_TYPE_free(atmp); 309296341Sdelphij if (!at) { 310296341Sdelphij BIO_printf(bio_err, "Error parsing structure\n"); 311296341Sdelphij ERR_print_errors(bio_err); 312296341Sdelphij goto end; 313296341Sdelphij } 314296341Sdelphij typ = ASN1_TYPE_get(at); 315296341Sdelphij if ((typ == V_ASN1_OBJECT) 316296341Sdelphij || (typ == V_ASN1_NULL)) { 317296341Sdelphij BIO_printf(bio_err, "Can't parse %s type\n", 318296341Sdelphij typ == V_ASN1_NULL ? "NULL" : "OBJECT"); 319296341Sdelphij ERR_print_errors(bio_err); 320296341Sdelphij goto end; 321296341Sdelphij } 322296341Sdelphij /* hmm... this is a little evil but it works */ 323296341Sdelphij tmpbuf = at->value.asn1_string->data; 324296341Sdelphij tmplen = at->value.asn1_string->length; 325296341Sdelphij } 326296341Sdelphij str = (char *)tmpbuf; 327296341Sdelphij num = tmplen; 328296341Sdelphij } 32955714Skris 330296341Sdelphij if (offset >= num) { 331296341Sdelphij BIO_printf(bio_err, "Error: offset too large\n"); 332296341Sdelphij goto end; 333296341Sdelphij } 334127128Snectar 335296341Sdelphij num -= offset; 336127128Snectar 337296341Sdelphij if ((length == 0) || ((long)length > num)) 338296341Sdelphij length = (unsigned int)num; 339296341Sdelphij if (derout) { 340296341Sdelphij if (BIO_write(derout, str + offset, length) != (int)length) { 341296341Sdelphij BIO_printf(bio_err, "Error writing output\n"); 342296341Sdelphij ERR_print_errors(bio_err); 343296341Sdelphij goto end; 344296341Sdelphij } 345296341Sdelphij } 346296341Sdelphij if (!noout && 347296341Sdelphij !ASN1_parse_dump(out, (unsigned char *)&(str[offset]), length, 348296341Sdelphij indent, dump)) { 349296341Sdelphij ERR_print_errors(bio_err); 350296341Sdelphij goto end; 351296341Sdelphij } 352296341Sdelphij ret = 0; 353296341Sdelphij end: 354296341Sdelphij BIO_free(derout); 355296341Sdelphij if (in != NULL) 356296341Sdelphij BIO_free(in); 357296341Sdelphij if (out != NULL) 358296341Sdelphij BIO_free_all(out); 359296341Sdelphij if (b64 != NULL) 360296341Sdelphij BIO_free(b64); 361296341Sdelphij if (ret != 0) 362296341Sdelphij ERR_print_errors(bio_err); 363296341Sdelphij if (buf != NULL) 364296341Sdelphij BUF_MEM_free(buf); 365296341Sdelphij if (at != NULL) 366296341Sdelphij ASN1_TYPE_free(at); 367296341Sdelphij if (osk != NULL) 368296341Sdelphij sk_OPENSSL_STRING_free(osk); 369296341Sdelphij OBJ_cleanup(); 370296341Sdelphij apps_shutdown(); 371296341Sdelphij OPENSSL_EXIT(ret); 372296341Sdelphij} 37355714Skris 374160814Ssimonstatic int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf) 375296341Sdelphij{ 376296341Sdelphij CONF *cnf = NULL; 377296341Sdelphij int len; 378296341Sdelphij long errline = 0; 379296341Sdelphij unsigned char *p; 380296341Sdelphij ASN1_TYPE *atyp = NULL; 381160814Ssimon 382296341Sdelphij if (genconf) { 383296341Sdelphij cnf = NCONF_new(NULL); 384296341Sdelphij if (!NCONF_load(cnf, genconf, &errline)) 385296341Sdelphij goto conferr; 386296341Sdelphij if (!genstr) 387296341Sdelphij genstr = NCONF_get_string(cnf, "default", "asn1"); 388296341Sdelphij if (!genstr) { 389296341Sdelphij BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf); 390296341Sdelphij goto err; 391296341Sdelphij } 392296341Sdelphij } 393160814Ssimon 394296341Sdelphij atyp = ASN1_generate_nconf(genstr, cnf); 395296341Sdelphij NCONF_free(cnf); 396296341Sdelphij cnf = NULL; 397160814Ssimon 398296341Sdelphij if (!atyp) 399296341Sdelphij return -1; 400160814Ssimon 401296341Sdelphij len = i2d_ASN1_TYPE(atyp, NULL); 402160814Ssimon 403296341Sdelphij if (len <= 0) 404296341Sdelphij goto err; 405160814Ssimon 406296341Sdelphij if (!BUF_MEM_grow(buf, len)) 407296341Sdelphij goto err; 408160814Ssimon 409296341Sdelphij p = (unsigned char *)buf->data; 410160814Ssimon 411296341Sdelphij i2d_ASN1_TYPE(atyp, &p); 412160814Ssimon 413296341Sdelphij ASN1_TYPE_free(atyp); 414296341Sdelphij return len; 415160814Ssimon 416296341Sdelphij conferr: 417160814Ssimon 418296341Sdelphij if (errline > 0) 419296341Sdelphij BIO_printf(bio, "Error on line %ld of config file '%s'\n", 420296341Sdelphij errline, genconf); 421296341Sdelphij else 422296341Sdelphij BIO_printf(bio, "Error loading config file '%s'\n", genconf); 423160814Ssimon 424296341Sdelphij err: 425296341Sdelphij NCONF_free(cnf); 426296341Sdelphij ASN1_TYPE_free(atyp); 427160814Ssimon 428296341Sdelphij return -1; 429160814Ssimon 430296341Sdelphij} 431