Added apps/asn1utils, asn1dump.
[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_END:
29     return "END";
30   case SILC_ASN1_TAG_OPTS:
31     return "";
32   case SILC_ASN1_TAG_CHOICE:
33     return "choice";
34   case SILC_ASN1_TAG_ANY:
35     return "any";
36   case SILC_ASN1_TAG_ANY_PRIMITIVE:
37     return "any primitive";
38   case SILC_ASN1_TAG_SEQUENCE_OF:
39     return "sequence of";
40   case SILC_ASN1_TAG_SEQUENCE:
41     return "sequence";
42   case SILC_ASN1_TAG_SET:
43     return "set";
44   case SILC_ASN1_TAG_INTEGER:
45     return "integer";
46   case SILC_ASN1_TAG_SHORT_INTEGER:
47     return "short integer";
48   case SILC_ASN1_TAG_OID:
49     return "oid";
50   case SILC_ASN1_TAG_BOOLEAN:
51     return "boolean";
52   case SILC_ASN1_TAG_OCTET_STRING:
53     return "octet-string";
54   case SILC_ASN1_TAG_BIT_STRING:
55     return "bit-string";
56   case SILC_ASN1_TAG_NULL:
57     return "null";
58   case SILC_ASN1_TAG_ENUM:
59     return "enum";
60   case SILC_ASN1_TAG_UTC_TIME:
61     return "utc-time";
62   case SILC_ASN1_TAG_GENERALIZED_TIME:
63     return "generalized-time";
64   case SILC_ASN1_TAG_UTF8_STRING:
65     return "utf8-string";
66   case SILC_ASN1_TAG_NUMERIC_STRING:
67     return "numeric-string";
68   case SILC_ASN1_TAG_PRINTABLE_STRING:
69     return "printable-string";
70   case SILC_ASN1_TAG_IA5_STRING:
71     return "ia5-string";
72   case SILC_ASN1_TAG_VISIBLE_STRING:
73     return "visible-string";
74   case SILC_ASN1_TAG_UNIVERSAL_STRING:
75     return "universal-string";
76   case SILC_ASN1_TAG_UNRESTRICTED_STRING:
77     return "unrestricted-string";
78   case SILC_ASN1_TAG_BMP_STRING:
79     return "bmp-string";
80   case SILC_ASN1_TAG_ODE:
81     return "ode";
82   case SILC_ASN1_TAG_ETI:
83     return "eti";
84   case SILC_ASN1_TAG_REAL:
85     return "real";
86   case SILC_ASN1_TAG_EMBEDDED:
87     return "embedded";
88   case SILC_ASN1_TAG_ROI:
89     return "roi";
90   case SILC_ASN1_TAG_TELETEX_STRING:
91     return "teletex-string";
92   case SILC_ASN1_TAG_VIDEOTEX_STRING:
93     return "videotex-string";
94   case SILC_ASN1_TAG_GRAPHIC_STRING:
95     return "graphic-string";
96   case SILC_ASN1_TAG_GENERAL_STRING:
97     return "general-string";
98   default:
99     break;
100   }
101   return "unknown";
102 }
103
104 int asn1_dump(SilcAsn1 asn1, SilcBuffer src)
105 {
106   SilcBool ret = FALSE;
107   SilcBerEncoding renc;
108   SilcUInt32 rtag;
109   const unsigned char *rdata;
110   SilcUInt32 rdata_len, len = 0;
111   SilcBool rindef;
112   char indent[64];
113   int depth = 0;
114
115   SILC_LOG_DEBUG(("Dumping ASN.1"));
116   memset(indent, 0, sizeof(indent));
117
118   while (silc_buffer_len(src)) {
119     /* Decode the BER block */
120     ret = silc_ber_decode(src, NULL, &renc, &rtag, &rdata,
121                           &rdata_len, &rindef, &len);
122     if (!ret) {
123       fprintf(stderr, "Error: Cannot parse BER block, malformed ASN.1 data");
124       return -1;
125     }
126
127     memset(indent, 32, depth);
128
129     fprintf(stdout, "%04d: %s[%s] [%d]", depth, indent,
130             asn1_tag_name(rtag), (int)rtag);
131
132     if (rtag != SILC_ASN1_TAG_SEQUENCE) {
133       if (hexdump) {
134         fprintf(stdout, " [length %lu]\n", rdata_len);
135         silc_hexdump(rdata, rdata_len, stdout);
136       } else {
137         fprintf(stdout, "\n");
138       }
139     } else {
140       fprintf(stdout, "\n");
141     }
142
143     if (rtag == SILC_ASN1_TAG_SEQUENCE && depth < sizeof(indent))
144       depth++;
145
146     if (renc == SILC_BER_ENC_PRIMITIVE)
147       len = len + rdata_len;
148     else
149       len = len;
150
151     if (len)
152       silc_buffer_pull(src, len);
153   }
154
155   return 0;
156 }
157
158 void usage(void)
159 {
160     fprintf(stdout, ""
161 "Usage: asn1dump [OPTIONS] FILE\n"
162 "\n"
163 "Operation modes:\n"
164 "  -h          Print this help, then exit\n"
165 "  -x          HEX dump ASN.1 data\n"
166 "  -b          Decode Base64 encoding\n"
167 "\n"
168             );
169 }
170
171 int main(int argc, char **argv)
172 {
173   int opt, ret, i;
174   SilcAsn1 asn1;
175   SilcBufferStruct buf;
176   unsigned char *data, *tmp;
177   SilcUInt32 data_len;
178
179   if (argc < 2) {
180     usage();
181     return 1;
182   }
183
184   i = 1;
185   while ((opt = getopt(argc, argv, "hxb")) != EOF) {
186     switch (opt) {
187     case 'h':
188       usage();
189       return 1;
190       break;
191
192     case 'x':
193       hexdump = TRUE;
194       i++;
195       break;
196
197     case 'b':
198       dec_base64 = TRUE;
199       i++;
200       break;
201
202     default:
203       usage();
204       return 1;
205     }
206   }
207
208   data = tmp = silc_file_readfile(argv[i], &data_len, NULL);
209   if (!data) {
210     fprintf(stderr, "Error: Cannot read file '%s': %s", argv[i],
211             strerror(errno));
212     return 1;
213   }
214
215   if (dec_base64) {
216     data = silc_base64_decode(NULL, data, data_len, &data_len);
217     if (!data) {
218       fprintf(stderr, "Error: Cannot decode Base64 encoding\n");
219       return 1;
220     }
221     silc_free(tmp);
222   }
223
224   silc_buffer_set(&buf, data, data_len);
225
226   asn1 = silc_asn1_alloc(NULL);
227
228   ret = asn1_dump(asn1, &buf);
229
230   silc_asn1_free(asn1);
231   silc_free(data);
232
233   return ret;
234 }