155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2005 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
755682Smarkm *
8233294Sstas * Redistribution and use in source and binary forms, with or without
9233294Sstas * modification, are permitted provided that the following conditions
10233294Sstas * are met:
1155682Smarkm *
12233294Sstas * 1. Redistributions of source code must retain the above copyright
13233294Sstas *    notice, this list of conditions and the following disclaimer.
1455682Smarkm *
15233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
16233294Sstas *    notice, this list of conditions and the following disclaimer in the
17233294Sstas *    documentation and/or other materials provided with the distribution.
1855682Smarkm *
19233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
20233294Sstas *    may be used to endorse or promote products derived from this software
21233294Sstas *    without specific prior written permission.
22233294Sstas *
23233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33233294Sstas * SUCH DAMAGE.
3455682Smarkm */
3555682Smarkm
3655682Smarkm#include "der_locl.h"
37102644Snectar#include <com_err.h>
3855682Smarkm#include <sys/types.h>
3955682Smarkm#include <sys/stat.h>
4055682Smarkm#include <getarg.h>
4155682Smarkm#include <err.h>
42178825Sdfr#include <der.h>
4355682Smarkm
44178825Sdfrstatic int indent_flag = 1;
45233294Sstasstatic int inner_flag = 0;
4655682Smarkm
47178825Sdfrstatic unsigned long indefinite_form_loop;
48178825Sdfrstatic unsigned long indefinite_form_loop_max = 10000;
4955682Smarkm
50178825Sdfrstatic size_t
5155682Smarkmloop (unsigned char *buf, size_t len, int indent)
5255682Smarkm{
53178825Sdfr    unsigned char *start_buf = buf;
54178825Sdfr
5555682Smarkm    while (len > 0) {
5655682Smarkm	int ret;
5755682Smarkm	Der_class class;
5855682Smarkm	Der_type type;
59178825Sdfr	unsigned int tag;
6055682Smarkm	size_t sz;
6155682Smarkm	size_t length;
62178825Sdfr	size_t loop_length = 0;
63178825Sdfr	int end_tag = 0;
64178825Sdfr	const char *tagname;
6555682Smarkm
6655682Smarkm	ret = der_get_tag (buf, len, &class, &type, &tag, &sz);
6755682Smarkm	if (ret)
68102644Snectar	    errx (1, "der_get_tag: %s", error_message (ret));
6972445Sassar	if (sz > len)
7072445Sassar	    errx (1, "unreasonable length (%u) > %u",
7172445Sassar		  (unsigned)sz, (unsigned)len);
7255682Smarkm	buf += sz;
7355682Smarkm	len -= sz;
74178825Sdfr	if (indent_flag) {
75178825Sdfr	    int i;
76178825Sdfr	    for (i = 0; i < indent; ++i)
77178825Sdfr		printf (" ");
78178825Sdfr	}
79178825Sdfr	printf ("%s %s ", der_get_class_name(class), der_get_type_name(type));
80178825Sdfr	tagname = der_get_tag_name(tag);
81178825Sdfr	if (class == ASN1_C_UNIV && tagname != NULL)
82178825Sdfr	    printf ("%s = ", tagname);
8355682Smarkm	else
8455682Smarkm	    printf ("tag %d = ", tag);
8555682Smarkm	ret = der_get_length (buf, len, &length, &sz);
8655682Smarkm	if (ret)
87102644Snectar	    errx (1, "der_get_tag: %s", error_message (ret));
88178825Sdfr	if (sz > len)
89178825Sdfr	    errx (1, "unreasonable tag length (%u) > %u",
90178825Sdfr		  (unsigned)sz, (unsigned)len);
9155682Smarkm	buf += sz;
9255682Smarkm	len -= sz;
93178825Sdfr	if (length == ASN1_INDEFINITE) {
94178825Sdfr	    if ((class == ASN1_C_UNIV && type == PRIM && tag == UT_OctetString) ||
95178825Sdfr		(class == ASN1_C_CONTEXT && type == CONS) ||
96178825Sdfr		(class == ASN1_C_UNIV && type == CONS && tag == UT_Sequence) ||
97178825Sdfr		(class == ASN1_C_UNIV && type == CONS && tag == UT_Set)) {
98178825Sdfr		printf("*INDEFINITE FORM*");
99178825Sdfr	    } else {
100178825Sdfr		fflush(stdout);
101178825Sdfr		errx(1, "indef form used on unsupported object");
102178825Sdfr	    }
103178825Sdfr	    end_tag = 1;
104178825Sdfr	    if (indefinite_form_loop > indefinite_form_loop_max)
105178825Sdfr		errx(1, "indefinite form used recursively more then %lu "
106178825Sdfr		     "times, aborting", indefinite_form_loop_max);
107178825Sdfr	    indefinite_form_loop++;
108178825Sdfr	    length = len;
109178825Sdfr	} else if (length > len) {
110178825Sdfr	    printf("\n");
111178825Sdfr	    fflush(stdout);
112178825Sdfr	    errx (1, "unreasonable inner length (%u) > %u",
113178825Sdfr		  (unsigned)length, (unsigned)len);
114178825Sdfr	}
115178825Sdfr	if (class == ASN1_C_CONTEXT || class == ASN1_C_APPL) {
116178825Sdfr	    printf ("%lu bytes [%u]", (unsigned long)length, tag);
117178825Sdfr	    if (type == CONS) {
118178825Sdfr		printf("\n");
119178825Sdfr		loop_length = loop (buf, length, indent + 2);
120178825Sdfr	    } else {
121178825Sdfr		printf(" IMPLICIT content\n");
122178825Sdfr	    }
123178825Sdfr	} else if (class == ASN1_C_UNIV) {
12455682Smarkm	    switch (tag) {
125178825Sdfr	    case UT_EndOfContent:
126178825Sdfr		printf (" INDEFINITE length was %lu\n",
127178825Sdfr			(unsigned long)(buf - start_buf));
128178825Sdfr		break;
129178825Sdfr	    case UT_Set :
13055682Smarkm	    case UT_Sequence :
131178825Sdfr		printf ("%lu bytes {\n", (unsigned long)length);
132178825Sdfr		loop_length = loop (buf, length, indent + 2);
133178825Sdfr		if (indent_flag) {
134178825Sdfr		    int i;
135178825Sdfr		    for (i = 0; i < indent; ++i)
136178825Sdfr			printf (" ");
137178825Sdfr		    printf ("}\n");
138178825Sdfr		} else
139178825Sdfr		    printf ("} indent = %d\n", indent / 2);
14055682Smarkm		break;
14155682Smarkm	    case UT_Integer : {
14255682Smarkm		int val;
14355682Smarkm
144178825Sdfr		if (length <= sizeof(val)) {
145178825Sdfr		    ret = der_get_integer (buf, length, &val, NULL);
146178825Sdfr		    if (ret)
147178825Sdfr			errx (1, "der_get_integer: %s", error_message (ret));
148178825Sdfr		    printf ("integer %d\n", val);
149178825Sdfr		} else {
150178825Sdfr		    heim_integer vali;
151178825Sdfr		    char *p;
152178825Sdfr
153178825Sdfr		    ret = der_get_heim_integer(buf, length, &vali, NULL);
154178825Sdfr		    if (ret)
155233294Sstas			errx (1, "der_get_heim_integer: %s",
156178825Sdfr			      error_message (ret));
157178825Sdfr		    ret = der_print_hex_heim_integer(&vali, &p);
158178825Sdfr		    if (ret)
159233294Sstas			errx (1, "der_print_hex_heim_integer: %s",
160178825Sdfr			      error_message (ret));
161233294Sstas		    printf ("BIG NUM integer: length %lu %s\n",
162178825Sdfr			    (unsigned long)length, p);
163178825Sdfr		    free(p);
164178825Sdfr		}
16555682Smarkm		break;
16655682Smarkm	    }
16755682Smarkm	    case UT_OctetString : {
168178825Sdfr		heim_octet_string str;
169233294Sstas		size_t i;
17055682Smarkm
17155682Smarkm		ret = der_get_octet_string (buf, length, &str, NULL);
17255682Smarkm		if (ret)
173102644Snectar		    errx (1, "der_get_octet_string: %s", error_message (ret));
17490926Snectar		printf ("(length %lu), ", (unsigned long)length);
175233294Sstas
176233294Sstas		if (inner_flag) {
177233294Sstas		    Der_class class;
178233294Sstas		    Der_type type;
179233294Sstas		    unsigned int tag;
180233294Sstas
181233294Sstas		    ret = der_get_tag(str.data, str.length,
182233294Sstas				      &class, &type, &tag, &sz);
183233294Sstas		    if (ret || sz > str.length ||
184233294Sstas			type != CONS || tag != UT_Sequence)
185233294Sstas			goto just_an_octet_string;
186233294Sstas
187233294Sstas		    printf("{\n");
188233294Sstas		    loop (str.data, str.length, indent + 2);
189233294Sstas		    for (i = 0; i < indent; ++i)
190233294Sstas			printf (" ");
191233294Sstas		    printf ("}\n");
192233294Sstas
193233294Sstas		} else {
194233294Sstas		    unsigned char *uc;
195233294Sstas
196233294Sstas		just_an_octet_string:
197233294Sstas		    uc = (unsigned char *)str.data;
198233294Sstas		    for (i = 0; i < min(16,length); ++i)
199233294Sstas			printf ("%02x", uc[i]);
200233294Sstas		    printf ("\n");
201233294Sstas		}
20255682Smarkm		free (str.data);
20355682Smarkm		break;
20455682Smarkm	    }
205233294Sstas	    case UT_IA5String :
206233294Sstas	    case UT_PrintableString : {
207233294Sstas		heim_printable_string str;
208233294Sstas		unsigned char *s;
209233294Sstas		size_t n;
210233294Sstas
211233294Sstas		memset(&str, 0, sizeof(str));
212233294Sstas
213233294Sstas		ret = der_get_printable_string (buf, length, &str, NULL);
214233294Sstas		if (ret)
215233294Sstas		    errx (1, "der_get_general_string: %s",
216233294Sstas			  error_message (ret));
217233294Sstas		s = str.data;
218233294Sstas		printf("\"");
219233294Sstas		for (n = 0; n < str.length; n++) {
220233294Sstas		    if (isprint((int)s[n]))
221233294Sstas			printf ("%c", s[n]);
222233294Sstas		    else
223233294Sstas			printf ("#%02x", s[n]);
224233294Sstas		}
225233294Sstas		printf("\"\n");
226233294Sstas		der_free_printable_string(&str);
227233294Sstas		break;
228233294Sstas	    }
22955682Smarkm	    case UT_GeneralizedTime :
230178825Sdfr	    case UT_GeneralString :
231233294Sstas	    case UT_VisibleString :
232233294Sstas	    case UT_UTF8String : {
233178825Sdfr		heim_general_string str;
23455682Smarkm
23555682Smarkm		ret = der_get_general_string (buf, length, &str, NULL);
23655682Smarkm		if (ret)
23755682Smarkm		    errx (1, "der_get_general_string: %s",
238102644Snectar			  error_message (ret));
23955682Smarkm		printf ("\"%s\"\n", str);
24055682Smarkm		free (str);
24155682Smarkm		break;
24255682Smarkm	    }
243102644Snectar	    case UT_OID: {
244178825Sdfr		heim_oid o;
245178825Sdfr		char *p;
246102644Snectar
247102644Snectar		ret = der_get_oid(buf, length, &o, NULL);
248102644Snectar		if (ret)
249102644Snectar		    errx (1, "der_get_oid: %s", error_message (ret));
250178825Sdfr		ret = der_print_heim_oid(&o, '.', &p);
251178825Sdfr		der_free_oid(&o);
252178825Sdfr		if (ret)
253178825Sdfr		    errx (1, "der_print_heim_oid: %s", error_message (ret));
254178825Sdfr		printf("%s\n", p);
255178825Sdfr		free(p);
256178825Sdfr
257178825Sdfr		break;
258178825Sdfr	    }
259178825Sdfr	    case UT_Enumerated: {
260178825Sdfr		int num;
261178825Sdfr
262178825Sdfr		ret = der_get_integer (buf, length, &num, NULL);
263178825Sdfr		if (ret)
264178825Sdfr		    errx (1, "der_get_enum: %s", error_message (ret));
265233294Sstas
266178825Sdfr		printf("%u\n", num);
267102644Snectar		break;
268102644Snectar	    }
26955682Smarkm	    default :
27090926Snectar		printf ("%lu bytes\n", (unsigned long)length);
27155682Smarkm		break;
27255682Smarkm	    }
27355682Smarkm	}
274178825Sdfr	if (end_tag) {
275178825Sdfr	    if (loop_length == 0)
276233294Sstas		errx(1, "zero length INDEFINITE data ? indent = %d\n",
277178825Sdfr		     indent / 2);
278178825Sdfr	    if (loop_length < length)
279178825Sdfr		length = loop_length;
280178825Sdfr	    if (indefinite_form_loop == 0)
281178825Sdfr		errx(1, "internal error in indefinite form loop detection");
282178825Sdfr	    indefinite_form_loop--;
283178825Sdfr	} else if (loop_length)
284178825Sdfr	    errx(1, "internal error for INDEFINITE form");
28555682Smarkm	buf += length;
28655682Smarkm	len -= length;
28755682Smarkm    }
28855682Smarkm    return 0;
28955682Smarkm}
29055682Smarkm
29155682Smarkmstatic int
29255682Smarkmdoit (const char *filename)
29355682Smarkm{
29455682Smarkm    int fd = open (filename, O_RDONLY);
29555682Smarkm    struct stat sb;
29655682Smarkm    unsigned char *buf;
29755682Smarkm    size_t len;
29855682Smarkm    int ret;
29955682Smarkm
30055682Smarkm    if(fd < 0)
30155682Smarkm	err (1, "opening %s for read", filename);
30255682Smarkm    if (fstat (fd, &sb) < 0)
30355682Smarkm	err (1, "stat %s", filename);
30455682Smarkm    len = sb.st_size;
305178825Sdfr    buf = emalloc (len);
30655682Smarkm    if (read (fd, buf, len) != len)
30755682Smarkm	errx (1, "read failed");
30855682Smarkm    close (fd);
30955682Smarkm    ret = loop (buf, len, 0);
31055682Smarkm    free (buf);
311233294Sstas    return ret;
31255682Smarkm}
31355682Smarkm
31455682Smarkm
31555682Smarkmstatic int version_flag;
31655682Smarkmstatic int help_flag;
31755682Smarkmstruct getargs args[] = {
318178825Sdfr    { "indent", 0, arg_negative_flag, &indent_flag },
319233294Sstas    { "inner", 0, arg_flag, &inner_flag, "try to parse inner structures of OCTET STRING" },
32055682Smarkm    { "version", 0, arg_flag, &version_flag },
32155682Smarkm    { "help", 0, arg_flag, &help_flag }
32255682Smarkm};
32355682Smarkmint num_args = sizeof(args) / sizeof(args[0]);
32455682Smarkm
32555682Smarkmstatic void
32655682Smarkmusage(int code)
32755682Smarkm{
32855682Smarkm    arg_printusage(args, num_args, NULL, "dump-file");
32955682Smarkm    exit(code);
33055682Smarkm}
33155682Smarkm
33255682Smarkmint
33355682Smarkmmain(int argc, char **argv)
33455682Smarkm{
335178825Sdfr    int optidx = 0;
33655682Smarkm
33778527Sassar    setprogname (argv[0]);
338102644Snectar    initialize_asn1_error_table ();
339178825Sdfr    if(getarg(args, num_args, argc, argv, &optidx))
34055682Smarkm	usage(1);
34155682Smarkm    if(help_flag)
34255682Smarkm	usage(0);
34355682Smarkm    if(version_flag) {
34455682Smarkm	print_version(NULL);
34555682Smarkm	exit(0);
34655682Smarkm    }
347178825Sdfr    argv += optidx;
348178825Sdfr    argc -= optidx;
34955682Smarkm    if (argc != 1)
35055682Smarkm	usage (1);
35155682Smarkm    return doit (argv[0]);
35255682Smarkm}
353