asn1pars.c revision 296465
1163899Smjacob/* apps/asn1pars.c */ 2163899Smjacob/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3167403Smjacob * All rights reserved. 4167403Smjacob * 5167403Smjacob * This package is an SSL implementation written 6167403Smjacob * by Eric Young (eay@cryptsoft.com). 7167403Smjacob * The implementation was written so as to conform with Netscapes SSL. 8167403Smjacob * 9167403Smjacob * This library is free for commercial and non-commercial use as long as 10167403Smjacob * the following conditions are aheared to. The following conditions 11167403Smjacob * apply to all code found in this distribution, be it the RC4, RSA, 12167403Smjacob * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13167403Smjacob * included with this distribution is covered by the same copyright terms 14167403Smjacob * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15167403Smjacob * 16167403Smjacob * Copyright remains Eric Young's, and as such any Copyright notices in 17167403Smjacob * the code are not to be removed. 18167403Smjacob * If this package is used in a product, Eric Young should be given attribution 19167403Smjacob * as the author of the parts of the library used. 20167403Smjacob * This can be in the form of a textual message at program startup or 21167403Smjacob * in documentation (online or textual) provided with the package. 22167403Smjacob * 23167403Smjacob * Redistribution and use in source and binary forms, with or without 24167403Smjacob * modification, are permitted provided that the following conditions 25167403Smjacob * are met: 26167403Smjacob * 1. Redistributions of source code must retain the copyright 27163899Smjacob * notice, this list of conditions and the following disclaimer. 28163899Smjacob * 2. Redistributions in binary form must reproduce the above copyright 29163899Smjacob * notice, this list of conditions and the following disclaimer in the 30163899Smjacob * documentation and/or other materials provided with the distribution. 31163899Smjacob * 3. All advertising materials mentioning features or use of this software 32163899Smjacob * must display the following acknowledgement: 33163899Smjacob * "This product includes cryptographic software written by 34163899Smjacob * Eric Young (eay@cryptsoft.com)" 35163899Smjacob * The word 'cryptographic' can be left out if the rouines from the library 36163899Smjacob * being used are not cryptographic related :-). 37163899Smjacob * 4. If you include any Windows specific code (or a derivative thereof) from 38163899Smjacob * the apps directory (application code) you must include an acknowledgement: 39163899Smjacob * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40163899Smjacob * 41163899Smjacob * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42163899Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43163899Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44163899Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45163899Smjacob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46163899Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47163899Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48163899Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49163899Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50163899Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51163899Smjacob * SUCH DAMAGE. 52163899Smjacob * 53163899Smjacob * The licence and distribution terms for any publically available version or 54163899Smjacob * derivative of this code cannot be changed. i.e. this code cannot simply be 55163899Smjacob * copied and put under another distribution licence 56163899Smjacob * [including the GNU Public Licence.] 57163899Smjacob */ 58163899Smjacob 59163899Smjacob/* 60163899Smjacob * A nice addition from Dr Stephen Henson <steve@openssl.org> to add the 61163899Smjacob * -strparse option which parses nested binary structures 62163899Smjacob */ 63163899Smjacob 64163899Smjacob#include <stdio.h> 65163899Smjacob#include <stdlib.h> 66163899Smjacob#include <string.h> 67163899Smjacob#include "apps.h" 68163899Smjacob#include <openssl/err.h> 69163899Smjacob#include <openssl/evp.h> 70163899Smjacob#include <openssl/x509.h> 71163899Smjacob#include <openssl/pem.h> 72163899Smjacob 73163899Smjacob/*- 74163899Smjacob * -inform arg - input format - default PEM (DER or PEM) 75163899Smjacob * -in arg - input file - default stdin 76163899Smjacob * -i - indent the details by depth 77163899Smjacob * -offset - where in the file to start 78163899Smjacob * -length - how many bytes to use 79163899Smjacob * -oid file - extra oid description file 80163899Smjacob */ 81163899Smjacob 82163899Smjacob#undef PROG 83163899Smjacob#define PROG asn1parse_main 84163899Smjacob 85163899Smjacobint MAIN(int, char **); 86163899Smjacob 87163899Smjacobstatic int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf); 88163899Smjacob 89163899Smjacobint MAIN(int argc, char **argv) 90163899Smjacob{ 91163899Smjacob int i, badops = 0, offset = 0, ret = 1, j; 92163899Smjacob unsigned int length = 0; 93163899Smjacob long num, tmplen; 94163899Smjacob BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL; 95163899Smjacob int informat, indent = 0, noout = 0, dump = 0; 96163899Smjacob char *infile = NULL, *str = NULL, *prog, *oidfile = NULL, *derfile = NULL; 97163899Smjacob char *genstr = NULL, *genconf = NULL; 98163899Smjacob unsigned char *tmpbuf; 99163899Smjacob const unsigned char *ctmpbuf; 100163899Smjacob BUF_MEM *buf = NULL; 101163899Smjacob STACK *osk = NULL; 102163899Smjacob ASN1_TYPE *at = NULL; 103163899Smjacob 104163899Smjacob informat = FORMAT_PEM; 105163899Smjacob 106163899Smjacob apps_startup(); 107163899Smjacob 108163899Smjacob if (bio_err == NULL) 109163899Smjacob if ((bio_err = BIO_new(BIO_s_file())) != NULL) 110163899Smjacob BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT); 111163899Smjacob 112163899Smjacob if (!load_config(bio_err, NULL)) 113163899Smjacob goto end; 114163899Smjacob 115163899Smjacob prog = argv[0]; 116163899Smjacob argc--; 117163899Smjacob argv++; 118163899Smjacob if ((osk = sk_new_null()) == NULL) { 119163899Smjacob BIO_printf(bio_err, "Memory allocation failure\n"); 120163899Smjacob goto end; 121163899Smjacob } 122163899Smjacob while (argc >= 1) { 123163899Smjacob if (strcmp(*argv, "-inform") == 0) { 124163899Smjacob if (--argc < 1) 125163899Smjacob goto bad; 126163899Smjacob informat = str2fmt(*(++argv)); 127163899Smjacob } else if (strcmp(*argv, "-in") == 0) { 128163899Smjacob if (--argc < 1) 129163899Smjacob goto bad; 130164272Smjacob infile = *(++argv); 131163899Smjacob } else if (strcmp(*argv, "-out") == 0) { 132163899Smjacob if (--argc < 1) 133163899Smjacob goto bad; 134163899Smjacob derfile = *(++argv); 135163899Smjacob } else if (strcmp(*argv, "-i") == 0) { 136163899Smjacob indent = 1; 137163899Smjacob } else if (strcmp(*argv, "-noout") == 0) 138163899Smjacob noout = 1; 139164272Smjacob else if (strcmp(*argv, "-oid") == 0) { 140164272Smjacob if (--argc < 1) 141164272Smjacob goto bad; 142164272Smjacob oidfile = *(++argv); 143164272Smjacob } else if (strcmp(*argv, "-offset") == 0) { 144163899Smjacob if (--argc < 1) 145164272Smjacob goto bad; 146164272Smjacob offset = atoi(*(++argv)); 147164272Smjacob } else if (strcmp(*argv, "-length") == 0) { 148164272Smjacob if (--argc < 1) 149164272Smjacob goto bad; 150164272Smjacob length = atoi(*(++argv)); 151164272Smjacob if (length == 0) 152164272Smjacob goto bad; 153163899Smjacob } else if (strcmp(*argv, "-dump") == 0) { 154163899Smjacob dump = -1; 155163899Smjacob } else if (strcmp(*argv, "-dlimit") == 0) { 156163899Smjacob if (--argc < 1) 157163899Smjacob goto bad; 158163899Smjacob dump = atoi(*(++argv)); 159163899Smjacob if (dump <= 0) 160163899Smjacob goto bad; 161163899Smjacob } else if (strcmp(*argv, "-strparse") == 0) { 162163899Smjacob if (--argc < 1) 163163899Smjacob goto bad; 164163899Smjacob sk_push(osk, *(++argv)); 165163899Smjacob } else if (strcmp(*argv, "-genstr") == 0) { 166163899Smjacob if (--argc < 1) 167163899Smjacob goto bad; 168163899Smjacob genstr = *(++argv); 169163899Smjacob } else if (strcmp(*argv, "-genconf") == 0) { 170163899Smjacob if (--argc < 1) 171163899Smjacob goto bad; 172163899Smjacob genconf = *(++argv); 173163899Smjacob } else { 174163899Smjacob BIO_printf(bio_err, "unknown option %s\n", *argv); 175163899Smjacob badops = 1; 176163899Smjacob break; 177163899Smjacob } 178163899Smjacob argc--; 179163899Smjacob argv++; 180163899Smjacob } 181163899Smjacob 182163899Smjacob if (badops) { 183163899Smjacob bad: 184163899Smjacob BIO_printf(bio_err, "%s [options] <infile\n", prog); 185163899Smjacob BIO_printf(bio_err, "where options are\n"); 186163899Smjacob BIO_printf(bio_err, " -inform arg input format - one of DER PEM\n"); 187163899Smjacob BIO_printf(bio_err, " -in arg input file\n"); 188163899Smjacob BIO_printf(bio_err, 189163899Smjacob " -out arg output file (output format is always DER\n"); 190163899Smjacob BIO_printf(bio_err, " -noout arg don't produce any output\n"); 191163899Smjacob BIO_printf(bio_err, " -offset arg offset into file\n"); 192163899Smjacob BIO_printf(bio_err, " -length arg length of section in file\n"); 193163899Smjacob BIO_printf(bio_err, " -i indent entries\n"); 194163899Smjacob BIO_printf(bio_err, " -dump dump unknown data in hex form\n"); 195163899Smjacob BIO_printf(bio_err, 196163899Smjacob " -dlimit arg dump the first arg bytes of unknown data in hex form\n"); 197163899Smjacob BIO_printf(bio_err, " -oid file file of extra oid definitions\n"); 198163899Smjacob BIO_printf(bio_err, " -strparse offset\n"); 199163899Smjacob BIO_printf(bio_err, 200163899Smjacob " a series of these can be used to 'dig' into multiple\n"); 201163899Smjacob BIO_printf(bio_err, " ASN1 blob wrappings\n"); 202163899Smjacob BIO_printf(bio_err, 203163899Smjacob " -genstr str string to generate ASN1 structure from\n"); 204163899Smjacob BIO_printf(bio_err, 205163899Smjacob " -genconf file file to generate ASN1 structure from\n"); 206163899Smjacob goto end; 207163899Smjacob } 208163899Smjacob 209163899Smjacob ERR_load_crypto_strings(); 210163899Smjacob 211163899Smjacob 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_num(osk)) { 292 tmpbuf = (unsigned char *)str; 293 tmplen = num; 294 for (i = 0; i < sk_num(osk); i++) { 295 ASN1_TYPE *atmp; 296 int typ; 297 j = atoi(sk_value(osk, i)); 298 if (j == 0) { 299 BIO_printf(bio_err, "'%s' is an invalid number\n", 300 sk_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_BOOLEAN) 317 || (typ == V_ASN1_NULL)) { 318 BIO_printf(bio_err, "Can't parse %s type\n", ASN1_tag2str(typ)); 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_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; 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