155714Skris/* apps/asn1pars.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8296465Sdelphij *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15296465Sdelphij *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22296465Sdelphij *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40296465Sdelphij *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52296465Sdelphij *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
59296465Sdelphij/*
60296465Sdelphij * A nice addition from Dr Stephen Henson <steve@openssl.org> to add the
61296465Sdelphij * -strparse option which parses nested binary structures
6255714Skris */
6355714Skris
6455714Skris#include <stdio.h>
6555714Skris#include <stdlib.h>
6655714Skris#include <string.h>
6755714Skris#include "apps.h"
6855714Skris#include <openssl/err.h>
6955714Skris#include <openssl/evp.h>
7055714Skris#include <openssl/x509.h>
7155714Skris#include <openssl/pem.h>
7255714Skris
73296465Sdelphij/*-
74296465Sdelphij * -inform arg  - input format - default PEM (DER or PEM)
75296465Sdelphij * -in arg      - input file - default stdin
76296465Sdelphij * -i           - indent the details by depth
77296465Sdelphij * -offset      - where in the file to start
78296465Sdelphij * -length      - how many bytes to use
79296465Sdelphij * -oid file    - extra oid description file
8055714Skris */
8155714Skris
8255714Skris#undef PROG
83296465Sdelphij#define PROG    asn1parse_main
8455714Skris
8559191Skrisint MAIN(int, char **);
8659191Skris
87160814Ssimonstatic int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf);
88160814Ssimon
8955714Skrisint MAIN(int argc, char **argv)
90296465Sdelphij{
91296465Sdelphij    int i, badops = 0, offset = 0, ret = 1, j;
92296465Sdelphij    unsigned int length = 0;
93296465Sdelphij    long num, tmplen;
94296465Sdelphij    BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL;
95296465Sdelphij    int informat, indent = 0, noout = 0, dump = 0;
96296465Sdelphij    char *infile = NULL, *str = NULL, *prog, *oidfile = NULL, *derfile = NULL;
97296465Sdelphij    char *genstr = NULL, *genconf = NULL;
98296465Sdelphij    unsigned char *tmpbuf;
99296465Sdelphij    const unsigned char *ctmpbuf;
100296465Sdelphij    BUF_MEM *buf = NULL;
101296465Sdelphij    STACK *osk = NULL;
102296465Sdelphij    ASN1_TYPE *at = NULL;
10355714Skris
104296465Sdelphij    informat = FORMAT_PEM;
10555714Skris
106296465Sdelphij    apps_startup();
10755714Skris
108296465Sdelphij    if (bio_err == NULL)
109296465Sdelphij        if ((bio_err = BIO_new(BIO_s_file())) != NULL)
110296465Sdelphij            BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
11155714Skris
112296465Sdelphij    if (!load_config(bio_err, NULL))
113296465Sdelphij        goto end;
114109998Smarkm
115296465Sdelphij    prog = argv[0];
116296465Sdelphij    argc--;
117296465Sdelphij    argv++;
118296465Sdelphij    if ((osk = sk_new_null()) == NULL) {
119296465Sdelphij        BIO_printf(bio_err, "Memory allocation failure\n");
120296465Sdelphij        goto end;
121296465Sdelphij    }
122296465Sdelphij    while (argc >= 1) {
123296465Sdelphij        if (strcmp(*argv, "-inform") == 0) {
124296465Sdelphij            if (--argc < 1)
125296465Sdelphij                goto bad;
126296465Sdelphij            informat = str2fmt(*(++argv));
127296465Sdelphij        } else if (strcmp(*argv, "-in") == 0) {
128296465Sdelphij            if (--argc < 1)
129296465Sdelphij                goto bad;
130296465Sdelphij            infile = *(++argv);
131296465Sdelphij        } else if (strcmp(*argv, "-out") == 0) {
132296465Sdelphij            if (--argc < 1)
133296465Sdelphij                goto bad;
134296465Sdelphij            derfile = *(++argv);
135296465Sdelphij        } else if (strcmp(*argv, "-i") == 0) {
136296465Sdelphij            indent = 1;
137296465Sdelphij        } else if (strcmp(*argv, "-noout") == 0)
138296465Sdelphij            noout = 1;
139296465Sdelphij        else if (strcmp(*argv, "-oid") == 0) {
140296465Sdelphij            if (--argc < 1)
141296465Sdelphij                goto bad;
142296465Sdelphij            oidfile = *(++argv);
143296465Sdelphij        } else if (strcmp(*argv, "-offset") == 0) {
144296465Sdelphij            if (--argc < 1)
145296465Sdelphij                goto bad;
146296465Sdelphij            offset = atoi(*(++argv));
147296465Sdelphij        } else if (strcmp(*argv, "-length") == 0) {
148296465Sdelphij            if (--argc < 1)
149296465Sdelphij                goto bad;
150296465Sdelphij            length = atoi(*(++argv));
151296465Sdelphij            if (length == 0)
152296465Sdelphij                goto bad;
153296465Sdelphij        } else if (strcmp(*argv, "-dump") == 0) {
154296465Sdelphij            dump = -1;
155296465Sdelphij        } else if (strcmp(*argv, "-dlimit") == 0) {
156296465Sdelphij            if (--argc < 1)
157296465Sdelphij                goto bad;
158296465Sdelphij            dump = atoi(*(++argv));
159296465Sdelphij            if (dump <= 0)
160296465Sdelphij                goto bad;
161296465Sdelphij        } else if (strcmp(*argv, "-strparse") == 0) {
162296465Sdelphij            if (--argc < 1)
163296465Sdelphij                goto bad;
164296465Sdelphij            sk_push(osk, *(++argv));
165296465Sdelphij        } else if (strcmp(*argv, "-genstr") == 0) {
166296465Sdelphij            if (--argc < 1)
167296465Sdelphij                goto bad;
168296465Sdelphij            genstr = *(++argv);
169296465Sdelphij        } else if (strcmp(*argv, "-genconf") == 0) {
170296465Sdelphij            if (--argc < 1)
171296465Sdelphij                goto bad;
172296465Sdelphij            genconf = *(++argv);
173296465Sdelphij        } else {
174296465Sdelphij            BIO_printf(bio_err, "unknown option %s\n", *argv);
175296465Sdelphij            badops = 1;
176296465Sdelphij            break;
177296465Sdelphij        }
178296465Sdelphij        argc--;
179296465Sdelphij        argv++;
180296465Sdelphij    }
18155714Skris
182296465Sdelphij    if (badops) {
183296465Sdelphij bad:
184296465Sdelphij        BIO_printf(bio_err, "%s [options] <infile\n", prog);
185296465Sdelphij        BIO_printf(bio_err, "where options are\n");
186296465Sdelphij        BIO_printf(bio_err, " -inform arg   input format - one of DER PEM\n");
187296465Sdelphij        BIO_printf(bio_err, " -in arg       input file\n");
188296465Sdelphij        BIO_printf(bio_err,
189296465Sdelphij                   " -out arg      output file (output format is always DER\n");
190296465Sdelphij        BIO_printf(bio_err, " -noout arg    don't produce any output\n");
191296465Sdelphij        BIO_printf(bio_err, " -offset arg   offset into file\n");
192296465Sdelphij        BIO_printf(bio_err, " -length arg   length of section in file\n");
193296465Sdelphij        BIO_printf(bio_err, " -i            indent entries\n");
194296465Sdelphij        BIO_printf(bio_err, " -dump         dump unknown data in hex form\n");
195296465Sdelphij        BIO_printf(bio_err,
196296465Sdelphij                   " -dlimit arg   dump the first arg bytes of unknown data in hex form\n");
197296465Sdelphij        BIO_printf(bio_err, " -oid file     file of extra oid definitions\n");
198296465Sdelphij        BIO_printf(bio_err, " -strparse offset\n");
199296465Sdelphij        BIO_printf(bio_err,
200296465Sdelphij                   "               a series of these can be used to 'dig' into multiple\n");
201296465Sdelphij        BIO_printf(bio_err, "               ASN1 blob wrappings\n");
202296465Sdelphij        BIO_printf(bio_err,
203296465Sdelphij                   " -genstr str   string to generate ASN1 structure from\n");
204296465Sdelphij        BIO_printf(bio_err,
205296465Sdelphij                   " -genconf file file to generate ASN1 structure from\n");
206296465Sdelphij        goto end;
207296465Sdelphij    }
20855714Skris
209296465Sdelphij    ERR_load_crypto_strings();
21055714Skris
211296465Sdelphij    in = BIO_new(BIO_s_file());
212296465Sdelphij    out = BIO_new(BIO_s_file());
213296465Sdelphij    if ((in == NULL) || (out == NULL)) {
214296465Sdelphij        ERR_print_errors(bio_err);
215296465Sdelphij        goto end;
216296465Sdelphij    }
217296465Sdelphij    BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
218109998Smarkm#ifdef OPENSSL_SYS_VMS
219296465Sdelphij    {
220296465Sdelphij        BIO *tmpbio = BIO_new(BIO_f_linebuffer());
221296465Sdelphij        out = BIO_push(tmpbio, out);
222296465Sdelphij    }
22368651Skris#endif
22455714Skris
225296465Sdelphij    if (oidfile != NULL) {
226296465Sdelphij        if (BIO_read_filename(in, oidfile) <= 0) {
227296465Sdelphij            BIO_printf(bio_err, "problems opening %s\n", oidfile);
228296465Sdelphij            ERR_print_errors(bio_err);
229296465Sdelphij            goto end;
230296465Sdelphij        }
231296465Sdelphij        OBJ_create_objects(in);
232296465Sdelphij    }
23355714Skris
234296465Sdelphij    if (infile == NULL)
235296465Sdelphij        BIO_set_fp(in, stdin, BIO_NOCLOSE);
236296465Sdelphij    else {
237296465Sdelphij        if (BIO_read_filename(in, infile) <= 0) {
238296465Sdelphij            perror(infile);
239296465Sdelphij            goto end;
240296465Sdelphij        }
241296465Sdelphij    }
24255714Skris
243296465Sdelphij    if (derfile) {
244296465Sdelphij        if (!(derout = BIO_new_file(derfile, "wb"))) {
245296465Sdelphij            BIO_printf(bio_err, "problems opening %s\n", derfile);
246296465Sdelphij            ERR_print_errors(bio_err);
247296465Sdelphij            goto end;
248296465Sdelphij        }
249296465Sdelphij    }
25055714Skris
251296465Sdelphij    if ((buf = BUF_MEM_new()) == NULL)
252296465Sdelphij        goto end;
253296465Sdelphij    if (!BUF_MEM_grow(buf, BUFSIZ * 8))
254296465Sdelphij        goto end;               /* Pre-allocate :-) */
25555714Skris
256296465Sdelphij    if (genstr || genconf) {
257296465Sdelphij        num = do_generate(bio_err, genstr, genconf, buf);
258296465Sdelphij        if (num < 0) {
259296465Sdelphij            ERR_print_errors(bio_err);
260296465Sdelphij            goto end;
261296465Sdelphij        }
262296465Sdelphij    }
26355714Skris
264296465Sdelphij    else {
265160814Ssimon
266296465Sdelphij        if (informat == FORMAT_PEM) {
267296465Sdelphij            BIO *tmp;
268160814Ssimon
269296465Sdelphij            if ((b64 = BIO_new(BIO_f_base64())) == NULL)
270296465Sdelphij                goto end;
271296465Sdelphij            BIO_push(b64, in);
272296465Sdelphij            tmp = in;
273296465Sdelphij            in = b64;
274296465Sdelphij            b64 = tmp;
275296465Sdelphij        }
276160814Ssimon
277296465Sdelphij        num = 0;
278296465Sdelphij        for (;;) {
279296465Sdelphij            if (!BUF_MEM_grow(buf, (int)num + BUFSIZ))
280296465Sdelphij                goto end;
281296465Sdelphij            i = BIO_read(in, &(buf->data[num]), BUFSIZ);
282296465Sdelphij            if (i <= 0)
283296465Sdelphij                break;
284296465Sdelphij            num += i;
285296465Sdelphij        }
286296465Sdelphij    }
287296465Sdelphij    str = buf->data;
28855714Skris
289296465Sdelphij    /* If any structs to parse go through in sequence */
29055714Skris
291296465Sdelphij    if (sk_num(osk)) {
292296465Sdelphij        tmpbuf = (unsigned char *)str;
293296465Sdelphij        tmplen = num;
294296465Sdelphij        for (i = 0; i < sk_num(osk); i++) {
295296465Sdelphij            ASN1_TYPE *atmp;
296296465Sdelphij            int typ;
297296465Sdelphij            j = atoi(sk_value(osk, i));
298296465Sdelphij            if (j == 0) {
299296465Sdelphij                BIO_printf(bio_err, "'%s' is an invalid number\n",
300296465Sdelphij                           sk_value(osk, i));
301296465Sdelphij                continue;
302296465Sdelphij            }
303296465Sdelphij            tmpbuf += j;
304296465Sdelphij            tmplen -= j;
305296465Sdelphij            atmp = at;
306296465Sdelphij            ctmpbuf = tmpbuf;
307296465Sdelphij            at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen);
308296465Sdelphij            ASN1_TYPE_free(atmp);
309296465Sdelphij            if (!at) {
310296465Sdelphij                BIO_printf(bio_err, "Error parsing structure\n");
311296465Sdelphij                ERR_print_errors(bio_err);
312296465Sdelphij                goto end;
313296465Sdelphij            }
314296465Sdelphij            typ = ASN1_TYPE_get(at);
315296465Sdelphij            if ((typ == V_ASN1_OBJECT)
316296465Sdelphij                || (typ == V_ASN1_BOOLEAN)
317296465Sdelphij                || (typ == V_ASN1_NULL)) {
318296465Sdelphij                BIO_printf(bio_err, "Can't parse %s type\n", ASN1_tag2str(typ));
319296465Sdelphij                ERR_print_errors(bio_err);
320296465Sdelphij                goto end;
321296465Sdelphij            }
322296465Sdelphij            /* hmm... this is a little evil but it works */
323296465Sdelphij            tmpbuf = at->value.asn1_string->data;
324296465Sdelphij            tmplen = at->value.asn1_string->length;
325296465Sdelphij        }
326296465Sdelphij        str = (char *)tmpbuf;
327296465Sdelphij        num = tmplen;
328296465Sdelphij    }
32955714Skris
330296465Sdelphij    if (offset >= num) {
331296465Sdelphij        BIO_printf(bio_err, "Error: offset too large\n");
332296465Sdelphij        goto end;
333296465Sdelphij    }
334127128Snectar
335296465Sdelphij    num -= offset;
336127128Snectar
337296465Sdelphij    if ((length == 0) || ((long)length > num))
338296465Sdelphij        length = (unsigned int)num;
339296465Sdelphij    if (derout) {
340296465Sdelphij        if (BIO_write(derout, str + offset, length) != (int)length) {
341296465Sdelphij            BIO_printf(bio_err, "Error writing output\n");
342296465Sdelphij            ERR_print_errors(bio_err);
343296465Sdelphij            goto end;
344296465Sdelphij        }
345296465Sdelphij    }
346296465Sdelphij    if (!noout &&
347296465Sdelphij        !ASN1_parse_dump(out, (unsigned char *)&(str[offset]), length,
348296465Sdelphij                         indent, dump)) {
349296465Sdelphij        ERR_print_errors(bio_err);
350296465Sdelphij        goto end;
351296465Sdelphij    }
352296465Sdelphij    ret = 0;
353296465Sdelphij end:
354296465Sdelphij    BIO_free(derout);
355296465Sdelphij    if (in != NULL)
356296465Sdelphij        BIO_free(in);
357296465Sdelphij    if (out != NULL)
358296465Sdelphij        BIO_free_all(out);
359296465Sdelphij    if (b64 != NULL)
360296465Sdelphij        BIO_free(b64);
361296465Sdelphij    if (ret != 0)
362296465Sdelphij        ERR_print_errors(bio_err);
363296465Sdelphij    if (buf != NULL)
364296465Sdelphij        BUF_MEM_free(buf);
365296465Sdelphij    if (at != NULL)
366296465Sdelphij        ASN1_TYPE_free(at);
367296465Sdelphij    if (osk != NULL)
368296465Sdelphij        sk_free(osk);
369296465Sdelphij    OBJ_cleanup();
370296465Sdelphij    apps_shutdown();
371296465Sdelphij    OPENSSL_EXIT(ret);
372296465Sdelphij}
37355714Skris
374160814Ssimonstatic int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf)
375296465Sdelphij{
376296465Sdelphij    CONF *cnf = NULL;
377296465Sdelphij    int len;
378296465Sdelphij    long errline;
379296465Sdelphij    unsigned char *p;
380296465Sdelphij    ASN1_TYPE *atyp = NULL;
381160814Ssimon
382296465Sdelphij    if (genconf) {
383296465Sdelphij        cnf = NCONF_new(NULL);
384296465Sdelphij        if (!NCONF_load(cnf, genconf, &errline))
385296465Sdelphij            goto conferr;
386296465Sdelphij        if (!genstr)
387296465Sdelphij            genstr = NCONF_get_string(cnf, "default", "asn1");
388296465Sdelphij        if (!genstr) {
389296465Sdelphij            BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf);
390296465Sdelphij            goto err;
391296465Sdelphij        }
392296465Sdelphij    }
393160814Ssimon
394296465Sdelphij    atyp = ASN1_generate_nconf(genstr, cnf);
395296465Sdelphij    NCONF_free(cnf);
396296465Sdelphij    cnf = NULL;
397160814Ssimon
398296465Sdelphij    if (!atyp)
399296465Sdelphij        return -1;
400160814Ssimon
401296465Sdelphij    len = i2d_ASN1_TYPE(atyp, NULL);
402160814Ssimon
403296465Sdelphij    if (len <= 0)
404296465Sdelphij        goto err;
405160814Ssimon
406296465Sdelphij    if (!BUF_MEM_grow(buf, len))
407296465Sdelphij        goto err;
408160814Ssimon
409296465Sdelphij    p = (unsigned char *)buf->data;
410160814Ssimon
411296465Sdelphij    i2d_ASN1_TYPE(atyp, &p);
412160814Ssimon
413296465Sdelphij    ASN1_TYPE_free(atyp);
414296465Sdelphij    return len;
415160814Ssimon
416296465Sdelphij conferr:
417160814Ssimon
418296465Sdelphij    if (errline > 0)
419296465Sdelphij        BIO_printf(bio, "Error on line %ld of config file '%s'\n",
420296465Sdelphij                   errline, genconf);
421296465Sdelphij    else
422296465Sdelphij        BIO_printf(bio, "Error loading config file '%s'\n", genconf);
423160814Ssimon
424296465Sdelphij err:
425296465Sdelphij    NCONF_free(cnf);
426296465Sdelphij    ASN1_TYPE_free(atyp);
427160814Ssimon
428296465Sdelphij    return -1;
429160814Ssimon
430296465Sdelphij}
431