diff options
-rw-r--r-- | src/usr.bin/openssl/asn1pars.c | 343 |
1 files changed, 206 insertions, 137 deletions
diff --git a/src/usr.bin/openssl/asn1pars.c b/src/usr.bin/openssl/asn1pars.c index e6d5339f66..62af4f164e 100644 --- a/src/usr.bin/openssl/asn1pars.c +++ b/src/usr.bin/openssl/asn1pars.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: asn1pars.c,v 1.2 2014/08/28 14:23:52 jsing Exp $ */ | 1 | /* $OpenBSD: asn1pars.c,v 1.3 2015/01/08 11:00:12 doug Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -72,126 +72,191 @@ | |||
72 | #include <openssl/pem.h> | 72 | #include <openssl/pem.h> |
73 | #include <openssl/x509.h> | 73 | #include <openssl/x509.h> |
74 | 74 | ||
75 | /* -inform arg - input format - default PEM (DER or PEM) | 75 | static struct { |
76 | * -in arg - input file - default stdin | 76 | char *derfile; |
77 | * -i - indent the details by depth | 77 | int dump; |
78 | * -offset - where in the file to start | 78 | char *genconf; |
79 | * -length - how many bytes to use | 79 | char *genstr; |
80 | * -oid file - extra oid description file | 80 | int indent; |
81 | */ | 81 | char *infile; |
82 | int informat; | ||
83 | unsigned int length; | ||
84 | int noout; | ||
85 | int offset; | ||
86 | char *oidfile; | ||
87 | STACK_OF(OPENSSL_STRING) *osk; | ||
88 | } asn1pars_config; | ||
89 | |||
90 | static int | ||
91 | asn1pars_opt_dlimit(char *arg) | ||
92 | { | ||
93 | const char *errstr; | ||
94 | |||
95 | asn1pars_config.dump = strtonum(arg, 1, INT_MAX, &errstr); | ||
96 | if (errstr) { | ||
97 | fprintf(stderr, "-dlimit must be from 1 to INT_MAX: %s\n", | ||
98 | errstr); | ||
99 | return (-1); | ||
100 | } | ||
101 | return (0); | ||
102 | } | ||
103 | |||
104 | static int | ||
105 | asn1pars_opt_length(char *arg) | ||
106 | { | ||
107 | const char *errstr; | ||
108 | |||
109 | asn1pars_config.length = strtonum(arg, 1, UINT_MAX, &errstr); | ||
110 | if (errstr) { | ||
111 | fprintf(stderr, "-length must be from 1 to UINT_MAX: %s\n", | ||
112 | errstr); | ||
113 | return (-1); | ||
114 | } | ||
115 | return (0); | ||
116 | } | ||
117 | |||
118 | static int | ||
119 | asn1pars_opt_strparse(char *arg) | ||
120 | { | ||
121 | if (sk_OPENSSL_STRING_push(asn1pars_config.osk, arg) == 0) { | ||
122 | fprintf(stderr, "-strparse cannot add argument\n"); | ||
123 | return (-1); | ||
124 | } | ||
125 | return (0); | ||
126 | } | ||
82 | 127 | ||
83 | int asn1parse_main(int, char **); | 128 | static struct option asn1pars_options[] = { |
129 | { | ||
130 | .name = "dump", | ||
131 | .desc = "Dump unknown data in hex form", | ||
132 | .type = OPTION_VALUE, | ||
133 | .value = -1, | ||
134 | .opt.value = &asn1pars_config.dump, | ||
135 | }, | ||
136 | { | ||
137 | .name = "dlimit", | ||
138 | .argname = "num", | ||
139 | .desc = "Dump the first num bytes of unknown data in hex form", | ||
140 | .type = OPTION_ARG_FUNC, | ||
141 | .opt.argfunc = asn1pars_opt_dlimit, | ||
142 | }, | ||
143 | { | ||
144 | .name = "genconf", | ||
145 | .argname = "file", | ||
146 | .desc = "File to generate ASN.1 structure from", | ||
147 | .type = OPTION_ARG, | ||
148 | .opt.arg = &asn1pars_config.genconf, | ||
149 | }, | ||
150 | { | ||
151 | .name = "genstr", | ||
152 | .argname = "string", | ||
153 | .desc = "String to generate ASN.1 structure from", | ||
154 | .type = OPTION_ARG, | ||
155 | .opt.arg = &asn1pars_config.genstr, | ||
156 | }, | ||
157 | { | ||
158 | .name = "i", | ||
159 | .desc = "Indent output according to depth of structures", | ||
160 | .type = OPTION_FLAG, | ||
161 | .opt.flag = &asn1pars_config.indent, | ||
162 | }, | ||
163 | { | ||
164 | .name = "in", | ||
165 | .argname = "file", | ||
166 | .desc = "The input file (default stdin)", | ||
167 | .type = OPTION_ARG, | ||
168 | .opt.arg = &asn1pars_config.infile, | ||
169 | }, | ||
170 | { | ||
171 | .name = "inform", | ||
172 | .argname = "fmt", | ||
173 | .desc = "Input format (DER, TXT or PEM (default))", | ||
174 | .type = OPTION_ARG_FORMAT, | ||
175 | .opt.value = &asn1pars_config.informat, | ||
176 | }, | ||
177 | { | ||
178 | .name = "length", | ||
179 | .argname = "num", | ||
180 | .desc = "Number of bytes to parse (default until EOF)", | ||
181 | .type = OPTION_ARG_FUNC, | ||
182 | .opt.argfunc = asn1pars_opt_length, | ||
183 | }, | ||
184 | { | ||
185 | .name = "noout", | ||
186 | .desc = "Do not produce any output", | ||
187 | .type = OPTION_FLAG, | ||
188 | .opt.flag = &asn1pars_config.noout, | ||
189 | }, | ||
190 | { | ||
191 | .name = "offset", | ||
192 | .argname = "num", | ||
193 | .desc = "Offset to begin parsing", | ||
194 | .type = OPTION_ARG_INT, | ||
195 | .opt.value = &asn1pars_config.offset, | ||
196 | }, | ||
197 | { | ||
198 | .name = "oid", | ||
199 | .argname = "file", | ||
200 | .desc = "File containing additional object identifiers (OIDs)", | ||
201 | .type = OPTION_ARG, | ||
202 | .opt.arg = &asn1pars_config.oidfile, | ||
203 | }, | ||
204 | { | ||
205 | .name = "out", | ||
206 | .argname = "file", | ||
207 | .desc = "Output file in DER format", | ||
208 | .type = OPTION_ARG, | ||
209 | .opt.arg = &asn1pars_config.derfile, | ||
210 | }, | ||
211 | { | ||
212 | .name = "strparse", | ||
213 | .argname = "offset", | ||
214 | .desc = "Parse the content octets of ASN.1 object starting at" | ||
215 | " offset", | ||
216 | .type = OPTION_ARG_FUNC, | ||
217 | .opt.argfunc = asn1pars_opt_strparse, | ||
218 | }, | ||
219 | { NULL }, | ||
220 | }; | ||
221 | |||
222 | static void | ||
223 | asn1pars_usage() | ||
224 | { | ||
225 | fprintf(stderr, | ||
226 | "usage: asn1parse [-i] [-dlimit num] [-dump] [-genconf file] " | ||
227 | "[-genstr string]\n" | ||
228 | " [-in file] [-inform fmt] [-length num] [-noout] [-offset num] " | ||
229 | "[-oid file]\n" | ||
230 | " [-out file] [-strparse offset]\n\n"); | ||
231 | options_usage(asn1pars_options); | ||
232 | } | ||
84 | 233 | ||
85 | static int do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf); | 234 | static int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf); |
86 | 235 | ||
87 | int | 236 | int |
88 | asn1parse_main(int argc, char **argv) | 237 | asn1parse_main(int argc, char **argv) |
89 | { | 238 | { |
90 | int i, badops = 0, offset = 0, ret = 1, j; | 239 | int i, j, ret = 1; |
91 | unsigned int length = 0; | ||
92 | long num, tmplen; | 240 | long num, tmplen; |
93 | BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL; | 241 | BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL; |
94 | int informat, indent = 0, noout = 0, dump = 0; | 242 | char *str = NULL; |
95 | char *infile = NULL, *str = NULL, *prog, *oidfile = NULL, *derfile = NULL; | ||
96 | char *genstr = NULL, *genconf = NULL; | ||
97 | const char *errstr = NULL; | 243 | const char *errstr = NULL; |
98 | unsigned char *tmpbuf; | 244 | unsigned char *tmpbuf; |
99 | const unsigned char *ctmpbuf; | 245 | const unsigned char *ctmpbuf; |
100 | BUF_MEM *buf = NULL; | 246 | BUF_MEM *buf = NULL; |
101 | STACK_OF(OPENSSL_STRING) * osk = NULL; | ||
102 | ASN1_TYPE *at = NULL; | 247 | ASN1_TYPE *at = NULL; |
103 | 248 | ||
104 | informat = FORMAT_PEM; | 249 | memset(&asn1pars_config, 0, sizeof(asn1pars_config)); |
105 | 250 | ||
106 | prog = argv[0]; | 251 | asn1pars_config.informat = FORMAT_PEM; |
107 | argc--; | 252 | if ((asn1pars_config.osk = sk_OPENSSL_STRING_new_null()) == NULL) { |
108 | argv++; | ||
109 | if ((osk = sk_OPENSSL_STRING_new_null()) == NULL) { | ||
110 | BIO_printf(bio_err, "Memory allocation failure\n"); | 253 | BIO_printf(bio_err, "Memory allocation failure\n"); |
111 | goto end; | 254 | goto end; |
112 | } | 255 | } |
113 | while (argc >= 1) { | ||
114 | if (strcmp(*argv, "-inform") == 0) { | ||
115 | if (--argc < 1) | ||
116 | goto bad; | ||
117 | informat = str2fmt(*(++argv)); | ||
118 | } else if (strcmp(*argv, "-in") == 0) { | ||
119 | if (--argc < 1) | ||
120 | goto bad; | ||
121 | infile = *(++argv); | ||
122 | } else if (strcmp(*argv, "-out") == 0) { | ||
123 | if (--argc < 1) | ||
124 | goto bad; | ||
125 | derfile = *(++argv); | ||
126 | } else if (strcmp(*argv, "-i") == 0) { | ||
127 | indent = 1; | ||
128 | } else if (strcmp(*argv, "-noout") == 0) | ||
129 | noout = 1; | ||
130 | else if (strcmp(*argv, "-oid") == 0) { | ||
131 | if (--argc < 1) | ||
132 | goto bad; | ||
133 | oidfile = *(++argv); | ||
134 | } else if (strcmp(*argv, "-offset") == 0) { | ||
135 | if (--argc < 1) | ||
136 | goto bad; | ||
137 | offset = strtonum(*(++argv), 0, INT_MAX, &errstr); | ||
138 | if (errstr) | ||
139 | goto bad; | ||
140 | } else if (strcmp(*argv, "-length") == 0) { | ||
141 | if (--argc < 1) | ||
142 | goto bad; | ||
143 | length = strtonum(*(++argv), 1, UINT_MAX, &errstr); | ||
144 | if (errstr) | ||
145 | goto bad; | ||
146 | } else if (strcmp(*argv, "-dump") == 0) { | ||
147 | dump = -1; | ||
148 | } else if (strcmp(*argv, "-dlimit") == 0) { | ||
149 | if (--argc < 1) | ||
150 | goto bad; | ||
151 | dump = strtonum(*(++argv), 1, INT_MAX, &errstr); | ||
152 | if (errstr) | ||
153 | goto bad; | ||
154 | } else if (strcmp(*argv, "-strparse") == 0) { | ||
155 | if (--argc < 1) | ||
156 | goto bad; | ||
157 | sk_OPENSSL_STRING_push(osk, *(++argv)); | ||
158 | } else if (strcmp(*argv, "-genstr") == 0) { | ||
159 | if (--argc < 1) | ||
160 | goto bad; | ||
161 | genstr = *(++argv); | ||
162 | } else if (strcmp(*argv, "-genconf") == 0) { | ||
163 | if (--argc < 1) | ||
164 | goto bad; | ||
165 | genconf = *(++argv); | ||
166 | } else { | ||
167 | BIO_printf(bio_err, "unknown option %s\n", *argv); | ||
168 | badops = 1; | ||
169 | break; | ||
170 | } | ||
171 | argc--; | ||
172 | argv++; | ||
173 | } | ||
174 | 256 | ||
175 | if (badops) { | 257 | if (options_parse(argc, argv, asn1pars_options, NULL, NULL) != 0) { |
176 | bad: | 258 | asn1pars_usage(); |
177 | BIO_printf(bio_err, "%s [options] <infile\n", prog); | 259 | return (1); |
178 | BIO_printf(bio_err, "where options are\n"); | ||
179 | BIO_printf(bio_err, " -inform arg input format - one of DER PEM\n"); | ||
180 | BIO_printf(bio_err, " -in arg input file\n"); | ||
181 | BIO_printf(bio_err, " -out arg output file (output format is always DER\n"); | ||
182 | BIO_printf(bio_err, " -noout arg don't produce any output\n"); | ||
183 | BIO_printf(bio_err, " -offset arg offset into file\n"); | ||
184 | BIO_printf(bio_err, " -length arg length of section in file\n"); | ||
185 | BIO_printf(bio_err, " -i indent entries\n"); | ||
186 | BIO_printf(bio_err, " -dump dump unknown data in hex form\n"); | ||
187 | BIO_printf(bio_err, " -dlimit arg dump the first arg bytes of unknown data in hex form\n"); | ||
188 | BIO_printf(bio_err, " -oid file file of extra oid definitions\n"); | ||
189 | BIO_printf(bio_err, " -strparse offset\n"); | ||
190 | BIO_printf(bio_err, " a series of these can be used to 'dig' into multiple\n"); | ||
191 | BIO_printf(bio_err, " ASN1 blob wrappings\n"); | ||
192 | BIO_printf(bio_err, " -genstr str string to generate ASN1 structure from\n"); | ||
193 | BIO_printf(bio_err, " -genconf file file to generate ASN1 structure from\n"); | ||
194 | goto end; | ||
195 | } | 260 | } |
196 | 261 | ||
197 | in = BIO_new(BIO_s_file()); | 262 | in = BIO_new(BIO_s_file()); |
@@ -202,26 +267,28 @@ bad: | |||
202 | } | 267 | } |
203 | BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); | 268 | BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); |
204 | 269 | ||
205 | if (oidfile != NULL) { | 270 | if (asn1pars_config.oidfile != NULL) { |
206 | if (BIO_read_filename(in, oidfile) <= 0) { | 271 | if (BIO_read_filename(in, asn1pars_config.oidfile) <= 0) { |
207 | BIO_printf(bio_err, "problems opening %s\n", oidfile); | 272 | BIO_printf(bio_err, "problems opening %s\n", |
273 | asn1pars_config.oidfile); | ||
208 | ERR_print_errors(bio_err); | 274 | ERR_print_errors(bio_err); |
209 | goto end; | 275 | goto end; |
210 | } | 276 | } |
211 | OBJ_create_objects(in); | 277 | OBJ_create_objects(in); |
212 | } | 278 | } |
213 | if (infile == NULL) | 279 | if (asn1pars_config.infile == NULL) |
214 | BIO_set_fp(in, stdin, BIO_NOCLOSE); | 280 | BIO_set_fp(in, stdin, BIO_NOCLOSE); |
215 | else { | 281 | else { |
216 | if (BIO_read_filename(in, infile) <= 0) { | 282 | if (BIO_read_filename(in, asn1pars_config.infile) <= 0) { |
217 | perror(infile); | 283 | perror(asn1pars_config.infile); |
218 | goto end; | 284 | goto end; |
219 | } | 285 | } |
220 | } | 286 | } |
221 | 287 | ||
222 | if (derfile) { | 288 | if (asn1pars_config.derfile) { |
223 | if (!(derout = BIO_new_file(derfile, "wb"))) { | 289 | if (!(derout = BIO_new_file(asn1pars_config.derfile, "wb"))) { |
224 | BIO_printf(bio_err, "problems opening %s\n", derfile); | 290 | BIO_printf(bio_err, "problems opening %s\n", |
291 | asn1pars_config.derfile); | ||
225 | ERR_print_errors(bio_err); | 292 | ERR_print_errors(bio_err); |
226 | goto end; | 293 | goto end; |
227 | } | 294 | } |
@@ -231,15 +298,16 @@ bad: | |||
231 | if (!BUF_MEM_grow(buf, BUFSIZ * 8)) | 298 | if (!BUF_MEM_grow(buf, BUFSIZ * 8)) |
232 | goto end; /* Pre-allocate :-) */ | 299 | goto end; /* Pre-allocate :-) */ |
233 | 300 | ||
234 | if (genstr || genconf) { | 301 | if (asn1pars_config.genstr || asn1pars_config.genconf) { |
235 | num = do_generate(bio_err, genstr, genconf, buf); | 302 | num = do_generate(bio_err, asn1pars_config.genstr, |
303 | asn1pars_config.genconf, buf); | ||
236 | if (num < 0) { | 304 | if (num < 0) { |
237 | ERR_print_errors(bio_err); | 305 | ERR_print_errors(bio_err); |
238 | goto end; | 306 | goto end; |
239 | } | 307 | } |
240 | } else { | 308 | } else { |
241 | 309 | ||
242 | if (informat == FORMAT_PEM) { | 310 | if (asn1pars_config.informat == FORMAT_PEM) { |
243 | BIO *tmp; | 311 | BIO *tmp; |
244 | 312 | ||
245 | if ((b64 = BIO_new(BIO_f_base64())) == NULL) | 313 | if ((b64 = BIO_new(BIO_f_base64())) == NULL) |
@@ -263,18 +331,21 @@ bad: | |||
263 | 331 | ||
264 | /* If any structs to parse go through in sequence */ | 332 | /* If any structs to parse go through in sequence */ |
265 | 333 | ||
266 | if (sk_OPENSSL_STRING_num(osk)) { | 334 | if (sk_OPENSSL_STRING_num(asn1pars_config.osk)) { |
267 | tmpbuf = (unsigned char *) str; | 335 | tmpbuf = (unsigned char *) str; |
268 | tmplen = num; | 336 | tmplen = num; |
269 | for (i = 0; i < sk_OPENSSL_STRING_num(osk); i++) { | 337 | for (i = 0; i < sk_OPENSSL_STRING_num(asn1pars_config.osk); |
338 | i++) { | ||
270 | ASN1_TYPE *atmp; | 339 | ASN1_TYPE *atmp; |
271 | int typ; | 340 | int typ; |
272 | j = strtonum(sk_OPENSSL_STRING_value(osk, i), | 341 | j = strtonum( |
342 | sk_OPENSSL_STRING_value(asn1pars_config.osk, i), | ||
273 | 1, INT_MAX, &errstr); | 343 | 1, INT_MAX, &errstr); |
274 | if (errstr) { | 344 | if (errstr) { |
275 | BIO_printf(bio_err, | 345 | BIO_printf(bio_err, |
276 | "'%s' is an invalid number: %s\n", | 346 | "'%s' is an invalid number: %s\n", |
277 | sk_OPENSSL_STRING_value(osk, i), errstr); | 347 | sk_OPENSSL_STRING_value(asn1pars_config.osk, |
348 | i), errstr); | ||
278 | continue; | 349 | continue; |
279 | } | 350 | } |
280 | tmpbuf += j; | 351 | tmpbuf += j; |
@@ -303,44 +374,43 @@ bad: | |||
303 | str = (char *) tmpbuf; | 374 | str = (char *) tmpbuf; |
304 | num = tmplen; | 375 | num = tmplen; |
305 | } | 376 | } |
306 | if (offset >= num) { | 377 | if (asn1pars_config.offset >= num) { |
307 | BIO_printf(bio_err, "Error: offset too large\n"); | 378 | BIO_printf(bio_err, "Error: offset too large\n"); |
308 | goto end; | 379 | goto end; |
309 | } | 380 | } |
310 | num -= offset; | 381 | num -= asn1pars_config.offset; |
311 | 382 | ||
312 | if ((length == 0) || ((long) length > num)) | 383 | if ((asn1pars_config.length == 0) || |
313 | length = (unsigned int) num; | 384 | ((long)asn1pars_config.length > num)) |
385 | asn1pars_config.length = (unsigned int) num; | ||
314 | if (derout) { | 386 | if (derout) { |
315 | if (BIO_write(derout, str + offset, length) != (int) length) { | 387 | if (BIO_write(derout, str + asn1pars_config.offset, |
388 | asn1pars_config.length) != (int)asn1pars_config.length) { | ||
316 | BIO_printf(bio_err, "Error writing output\n"); | 389 | BIO_printf(bio_err, "Error writing output\n"); |
317 | ERR_print_errors(bio_err); | 390 | ERR_print_errors(bio_err); |
318 | goto end; | 391 | goto end; |
319 | } | 392 | } |
320 | } | 393 | } |
321 | if (!noout && | 394 | if (!asn1pars_config.noout && |
322 | !ASN1_parse_dump(out, (unsigned char *) &(str[offset]), length, | 395 | !ASN1_parse_dump(out, |
323 | indent, dump)) { | 396 | (unsigned char *)&(str[asn1pars_config.offset]), |
397 | asn1pars_config.length, asn1pars_config.indent, | ||
398 | asn1pars_config.dump)) { | ||
324 | ERR_print_errors(bio_err); | 399 | ERR_print_errors(bio_err); |
325 | goto end; | 400 | goto end; |
326 | } | 401 | } |
327 | ret = 0; | 402 | ret = 0; |
328 | end: | 403 | end: |
329 | BIO_free(derout); | 404 | BIO_free(derout); |
330 | if (in != NULL) | 405 | BIO_free(in); |
331 | BIO_free(in); | 406 | BIO_free_all(out); |
332 | if (out != NULL) | 407 | BIO_free(b64); |
333 | BIO_free_all(out); | ||
334 | if (b64 != NULL) | ||
335 | BIO_free(b64); | ||
336 | if (ret != 0) | 408 | if (ret != 0) |
337 | ERR_print_errors(bio_err); | 409 | ERR_print_errors(bio_err); |
338 | if (buf != NULL) | 410 | BUF_MEM_free(buf); |
339 | BUF_MEM_free(buf); | ||
340 | if (at != NULL) | 411 | if (at != NULL) |
341 | ASN1_TYPE_free(at); | 412 | ASN1_TYPE_free(at); |
342 | if (osk != NULL) | 413 | sk_OPENSSL_STRING_free(asn1pars_config.osk); |
343 | sk_OPENSSL_STRING_free(osk); | ||
344 | OBJ_cleanup(); | 414 | OBJ_cleanup(); |
345 | 415 | ||
346 | return (ret); | 416 | return (ret); |
@@ -374,7 +444,6 @@ do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf) | |||
374 | return -1; | 444 | return -1; |
375 | 445 | ||
376 | len = i2d_ASN1_TYPE(atyp, NULL); | 446 | len = i2d_ASN1_TYPE(atyp, NULL); |
377 | |||
378 | if (len <= 0) | 447 | if (len <= 0) |
379 | goto err; | 448 | goto err; |
380 | 449 | ||