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