Fixed printing.
[silc.git] / apps / asn1utils / asn1dump.c
1 /*
2
3   asn1dump.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2007 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21
22 SilcBool hexdump = FALSE;
23 SilcBool dec_base64 = FALSE;
24
25 const char *asn1_tag_name(SilcAsn1Tag tag)
26 {
27   switch (tag) {
28   case SILC_ASN1_TAG_CHOICE:
29     return "choice";
30   case SILC_ASN1_TAG_ANY:
31     return "any";
32   case SILC_ASN1_TAG_ANY_PRIMITIVE:
33     return "any primitive";
34   case SILC_ASN1_TAG_SEQUENCE_OF:
35     return "sequence of";
36   case SILC_ASN1_TAG_SEQUENCE:
37     return "sequence";
38   case SILC_ASN1_TAG_SET:
39     return "set";
40   case SILC_ASN1_TAG_INTEGER:
41     return "integer";
42   case SILC_ASN1_TAG_SHORT_INTEGER:
43     return "short integer";
44   case SILC_ASN1_TAG_OID:
45     return "oid";
46   case SILC_ASN1_TAG_BOOLEAN:
47     return "boolean";
48   case SILC_ASN1_TAG_OCTET_STRING:
49     return "octet-string";
50   case SILC_ASN1_TAG_BIT_STRING:
51     return "bit-string";
52   case SILC_ASN1_TAG_NULL:
53     return "null";
54   case SILC_ASN1_TAG_ENUM:
55     return "enum";
56   case SILC_ASN1_TAG_UTC_TIME:
57     return "utc-time";
58   case SILC_ASN1_TAG_GENERALIZED_TIME:
59     return "generalized-time";
60   case SILC_ASN1_TAG_UTF8_STRING:
61     return "utf8-string";
62   case SILC_ASN1_TAG_NUMERIC_STRING:
63     return "numeric-string";
64   case SILC_ASN1_TAG_PRINTABLE_STRING:
65     return "printable-string";
66   case SILC_ASN1_TAG_IA5_STRING:
67     return "ia5-string";
68   case SILC_ASN1_TAG_VISIBLE_STRING:
69     return "visible-string";
70   case SILC_ASN1_TAG_UNIVERSAL_STRING:
71     return "universal-string";
72   case SILC_ASN1_TAG_UNRESTRICTED_STRING:
73     return "unrestricted-string";
74   case SILC_ASN1_TAG_BMP_STRING:
75     return "bmp-string";
76   case SILC_ASN1_TAG_ODE:
77     return "ode";
78   case SILC_ASN1_TAG_ETI:
79     return "eti";
80   case SILC_ASN1_TAG_REAL:
81     return "real";
82   case SILC_ASN1_TAG_EMBEDDED:
83     return "embedded";
84   case SILC_ASN1_TAG_ROI:
85     return "roi";
86   case SILC_ASN1_TAG_TELETEX_STRING:
87     return "teletex-string";
88   case SILC_ASN1_TAG_VIDEOTEX_STRING:
89     return "videotex-string";
90   case SILC_ASN1_TAG_GRAPHIC_STRING:
91     return "graphic-string";
92   case SILC_ASN1_TAG_GENERAL_STRING:
93     return "general-string";
94   default:
95     break;
96   }
97   return "unknown";
98 }
99
100 int asn1_dump(SilcAsn1 asn1, SilcBuffer src)
101 {
102   SilcBool ret = FALSE;
103   SilcBerEncoding renc;
104   SilcUInt32 rtag;
105   const unsigned char *rdata;
106   SilcUInt32 rdata_len, len = 0;
107   SilcBool rindef;
108   char indent[256];
109   int depth = 0;
110
111   SILC_LOG_DEBUG(("Dumping ASN.1"));
112   memset(indent, 0, sizeof(indent));
113
114   while (silc_buffer_len(src)) {
115     /* Decode the BER block */
116     ret = silc_ber_decode(src, NULL, &renc, &rtag, &rdata,
117                           &rdata_len, &rindef, &len);
118     if (!ret) {
119       fprintf(stderr, "Error: Cannot parse BER block, malformed ASN.1 data");
120       return -1;
121     }
122
123     memset(indent, 32, depth);
124
125     fprintf(stdout, "%04d: %s[%s] [%d]", depth, indent,
126             asn1_tag_name(rtag), (int)rtag);
127
128     if (rtag != SILC_ASN1_TAG_SEQUENCE) {
129       if (hexdump) {
130         fprintf(stdout, " [length %lu]\n", rdata_len);
131         silc_hexdump(rdata, rdata_len, stdout);
132       } else {
133         fprintf(stdout, "\n");
134       }
135     } else {
136       fprintf(stdout, "\n");
137     }
138
139     if (rtag == SILC_ASN1_TAG_SEQUENCE && depth < sizeof(indent))
140       depth++;
141
142     if (renc == SILC_BER_ENC_PRIMITIVE)
143       len = len + rdata_len;
144     else
145       len = len;
146
147     if (len)
148       silc_buffer_pull(src, len);
149   }
150
151   return 0;
152 }
153
154 void usage(void)
155 {
156     fprintf(stdout, ""
157 "Usage: asn1dump [OPTIONS] FILE\n"
158 "\n"
159 "Operation modes:\n"
160 "  -h          Print this help, then exit\n"
161 "  -x          HEX dump ASN.1 data\n"
162 "  -b          Decode Base64 encoding\n"
163 "\n"
164             );
165 }
166
167 int main(int argc, char **argv)
168 {
169   int opt, ret, i;
170   SilcAsn1 asn1;
171   SilcBufferStruct buf;
172   unsigned char *data, *tmp;
173   SilcUInt32 data_len;
174
175   if (argc < 2) {
176     usage();
177     return 1;
178   }
179
180   i = 1;
181   while ((opt = getopt(argc, argv, "hxb")) != EOF) {
182     switch (opt) {
183     case 'h':
184       usage();
185       return 1;
186       break;
187
188     case 'x':
189       hexdump = TRUE;
190       i++;
191       break;
192
193     case 'b':
194       dec_base64 = TRUE;
195       i++;
196       break;
197
198     default:
199       usage();
200       return 1;
201     }
202   }
203
204   data = tmp = silc_file_readfile(argv[i], &data_len, NULL);
205   if (!data) {
206     fprintf(stderr, "Error: Cannot read file '%s': %s", argv[i],
207             strerror(errno));
208     return 1;
209   }
210
211   if (dec_base64) {
212     data = silc_base64_decode(NULL, data, data_len, &data_len);
213     if (!data) {
214       fprintf(stderr, "Error: Cannot decode Base64 encoding\n");
215       return 1;
216     }
217     silc_free(tmp);
218   }
219
220   silc_buffer_set(&buf, data, data_len);
221
222   asn1 = silc_asn1_alloc(NULL);
223
224   ret = asn1_dump(asn1, &buf);
225
226   silc_asn1_free(asn1);
227   silc_free(data);
228
229   return ret;
230 }