asn1pars.c 13 KB

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