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