Fido U2F complete (#716)
[proxmark3-svn] / client / crypto / asn1dump.c
1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
3 //
4 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
5 // at your option, any later version. See the LICENSE.txt file for the text of
6 // the license.
7 //-----------------------------------------------------------------------------
8 // asn.1 dumping
9 //-----------------------------------------------------------------------------
10
11 #include "asn1dump.h"
12 #include <ctype.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <stdio.h>
16 #include <jansson.h>
17 #include <mbedtls/asn1.h>
18 #include <mbedtls/oid.h>
19 #include "emv/emv_tags.h"
20 #include "emv/dump.h"
21 #include "emv/emvjson.h"
22 #include "util.h"
23 #include "proxmark3.h"
24
25 #define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");}
26
27 enum asn1_tag_t {
28 ASN1_TAG_GENERIC,
29 ASN1_TAG_BOOLEAN,
30 ASN1_TAG_INTEGER,
31 ASN1_TAG_STRING,
32 ASN1_TAG_OCTET_STRING,
33 ASN1_TAG_UTC_TIME,
34 ASN1_TAG_STR_TIME,
35 ASN1_TAG_OBJECT_ID,
36 };
37
38 struct asn1_tag {
39 tlv_tag_t tag;
40 char *name;
41 enum asn1_tag_t type;
42 const void *data;
43 };
44
45 static const struct asn1_tag asn1_tags[] = {
46 // internal
47 { 0x00 , "Unknown ???" },
48
49 // ASN.1
50 { 0x01, "BOOLEAN", ASN1_TAG_BOOLEAN },
51 { 0x02, "INTEGER", ASN1_TAG_INTEGER },
52 { 0x03, "BIT STRING" },
53 { 0x04, "OCTET STRING", ASN1_TAG_OCTET_STRING},
54 { 0x05, "NULL" },
55 { 0x06, "OBJECT IDENTIFIER", ASN1_TAG_OBJECT_ID },
56 { 0x07, "OBJECT DESCRIPTOR" },
57 { 0x08, "EXTERNAL" },
58 { 0x09, "REAL" },
59 { 0x0A, "ENUMERATED" },
60 { 0x0B, "EMBEDDED_PDV" },
61 { 0x0C, "UTF8String", ASN1_TAG_STRING },
62 { 0x10, "SEQUENCE" },
63 { 0x11, "SET" },
64 { 0x12, "NumericString", ASN1_TAG_STRING },
65 { 0x13, "PrintableString", ASN1_TAG_STRING },
66 { 0x14, "T61String" },
67 { 0x15, "VideotexString" },
68 { 0x16, "IA5String" },
69 { 0x17, "UTCTime", ASN1_TAG_UTC_TIME },
70 { 0x18, "GeneralizedTime", ASN1_TAG_STR_TIME },
71 { 0x19, "GraphicString" },
72 { 0x1A, "VisibleString", ASN1_TAG_STRING },
73 { 0x1B, "GeneralString", ASN1_TAG_STRING },
74 { 0x1C, "UniversalString", ASN1_TAG_STRING },
75 { 0x1E, "BMPString" },
76 { 0x30, "SEQUENCE" },
77 { 0x31, "SET" },
78 { 0xa0, "[0]" },
79 { 0xa1, "[1]" },
80 { 0xa2, "[2]" },
81 { 0xa3, "[3]" },
82 { 0xa4, "[4]" },
83 { 0xa5, "[5]" },
84 };
85
86 static int asn1_sort_tag(tlv_tag_t tag) {
87 return (int)(tag >= 0x100 ? tag : tag << 8);
88 }
89
90 static int asn1_tlv_compare(const void *a, const void *b) {
91 const struct tlv *tlv = a;
92 const struct asn1_tag *tag = b;
93
94 return asn1_sort_tag(tlv->tag) - (asn1_sort_tag(tag->tag));
95 }
96
97 static const struct asn1_tag *asn1_get_tag(const struct tlv *tlv) {
98 struct asn1_tag *tag = bsearch(tlv, asn1_tags, sizeof(asn1_tags) / sizeof(asn1_tags[0]),
99 sizeof(asn1_tags[0]), asn1_tlv_compare);
100
101 return tag ? tag : &asn1_tags[0];
102 }
103
104 static void asn1_tag_dump_str_time(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level, bool longyear, bool *needdump){
105 int len = tlv->len;
106 *needdump = false;
107
108 int startindx = longyear ? 4 : 2;
109
110 if (len > 4) {
111 fprintf(f, "\tvalue: '");
112 while (true) {
113 // year
114 if (!longyear)
115 fprintf(f, "20");
116 fwrite(tlv->value, 1, longyear ? 4 : 2, f);
117 fprintf(f, "-");
118 if (len < startindx + 2)
119 break;
120 // month
121 fwrite(&tlv->value[startindx], 1, 2, f);
122 fprintf(f, "-");
123 if (len < startindx + 4)
124 break;
125 // day
126 fwrite(&tlv->value[startindx + 2], 1, 2, f);
127 fprintf(f, " ");
128 if (len < startindx + 6)
129 break;
130 // hour
131 fwrite(&tlv->value[startindx + 4], 1, 2, f);
132 fprintf(f, ":");
133 if (len < startindx + 8)
134 break;
135 // min
136 fwrite(&tlv->value[startindx + 6], 1, 2, f);
137 fprintf(f, ":");
138 if (len < startindx + 10)
139 break;
140 // sec
141 fwrite(&tlv->value[startindx + 8], 1, 2, f);
142 if (len < startindx + 11)
143 break;
144 // time zone
145 fprintf(f, " zone: %.*s", len - 10 - (longyear ? 4 : 2), &tlv->value[startindx + 10]);
146
147 break;
148 }
149 fprintf(f, "'\n");
150 } else {
151 fprintf(f, "\n");
152 *needdump = true;
153 }
154 }
155
156 static void asn1_tag_dump_string(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level){
157 fprintf(f, "\tvalue: '");
158 fwrite(tlv->value, 1, tlv->len, f);
159 fprintf(f, "'\n");
160 }
161
162 static void asn1_tag_dump_octet_string(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level, bool *needdump){
163 *needdump = false;
164 for (int i = 0; i < tlv->len; i++)
165 if (!isspace(tlv->value[i]) && !isprint(tlv->value[i])){
166 *needdump = true;
167 break;
168 }
169
170 if (*needdump) {
171 fprintf(f, "'\n");
172 } else {
173 fprintf(f, "\t\t");
174 asn1_tag_dump_string(tlv, tag, f, level);
175 }
176 }
177
178 static unsigned long asn1_value_integer(const struct tlv *tlv, unsigned start, unsigned end) {
179 unsigned long ret = 0;
180 int i;
181
182 if (end > tlv->len * 2)
183 return ret;
184 if (start >= end)
185 return ret;
186
187 if (start & 1) {
188 ret += tlv->value[start/2] & 0xf;
189 i = start + 1;
190 } else
191 i = start;
192
193 for (; i < end - 1; i += 2) {
194 ret *= 10;
195 ret += tlv->value[i/2] >> 4;
196 ret *= 10;
197 ret += tlv->value[i/2] & 0xf;
198 }
199
200 if (end & 1) {
201 ret *= 10;
202 ret += tlv->value[end/2] >> 4;
203 }
204
205 return ret;
206 }
207
208 static void asn1_tag_dump_boolean(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) {
209 PRINT_INDENT(level);
210 if (tlv->len > 0) {
211 fprintf(f, "\tvalue: %s\n", tlv->value[0]?"true":"false");
212 } else {
213 fprintf(f, "n/a\n");
214 }
215 }
216
217 static void asn1_tag_dump_integer(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) {
218 PRINT_INDENT(level);
219 if (tlv->len == 4) {
220 int32_t val = 0;
221 for (int i = 0; i < tlv->len; i++)
222 val = (val << 8) + tlv->value[i];
223 fprintf(f, "\tvalue4b: %d\n", val);
224 return;
225 }
226 fprintf(f, "\tvalue: %lu\n", asn1_value_integer(tlv, 0, tlv->len * 2));
227 }
228
229 static char *asn1_oid_description(const char *oid, bool with_group_desc) {
230 json_error_t error;
231 json_t *root = NULL;
232 char fname[300] = {0};
233 static char res[300];
234 memset(res, 0x00, sizeof(res));
235
236 strcpy(fname, get_my_executable_directory());
237 strcat(fname, "crypto/oids.json");
238 if (access(fname, F_OK) < 0) {
239 strcpy(fname, get_my_executable_directory());
240 strcat(fname, "oids.json");
241 if (access(fname, F_OK) < 0) {
242 goto error; // file not found
243 }
244 }
245
246 // load `oids.json`
247 root = json_load_file(fname, 0, &error);
248
249 if (!root || !json_is_object(root)) {
250 goto error;
251 }
252
253 json_t *elm = json_object_get(root, oid);
254 if (!elm) {
255 goto error;
256 }
257
258 if (JsonLoadStr(elm, "$.d", res))
259 goto error;
260
261 char strext[300] = {0};
262 if (!JsonLoadStr(elm, "$.c", strext)) {
263 strcat(res, " (");
264 strcat(res, strext);
265 strcat(res, ")");
266 }
267
268 json_decref(root);
269 return res;
270
271 error:
272 if (root)
273 json_decref(root);
274 return NULL;
275 }
276
277 static void asn1_tag_dump_object_id(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) {
278 PRINT_INDENT(level);
279 mbedtls_asn1_buf asn1_buf;
280 asn1_buf.len = tlv->len;
281 asn1_buf.p = (uint8_t *)tlv->value;
282 char pstr[300];
283 mbedtls_oid_get_numeric_string(pstr, sizeof(pstr), &asn1_buf);
284 fprintf(f, " %s", pstr);
285
286 char *jsondesc = asn1_oid_description(pstr, true);
287 if (jsondesc) {
288 fprintf(f, " - %s", jsondesc);
289 } else {
290 const char *ppstr;
291 mbedtls_oid_get_attr_short_name(&asn1_buf, &ppstr);
292 if (ppstr && strnlen(ppstr, 1)) {
293 fprintf(f, " (%s)\n", ppstr);
294 return;
295 }
296 mbedtls_oid_get_sig_alg_desc(&asn1_buf, &ppstr);
297 if (ppstr && strnlen(ppstr, 1)) {
298 fprintf(f, " (%s)\n", ppstr);
299 return;
300 }
301 mbedtls_oid_get_extended_key_usage(&asn1_buf, &ppstr);
302 if (ppstr && strnlen(ppstr, 1)) {
303 fprintf(f, " (%s)\n", ppstr);
304 return;
305 }
306 }
307 fprintf(f, "\n");
308 }
309
310 bool asn1_tag_dump(const struct tlv *tlv, FILE *f, int level, bool *candump) {
311 if (!tlv) {
312 fprintf(f, "NULL\n");
313 return false;
314 }
315
316 const struct asn1_tag *tag = asn1_get_tag(tlv);
317
318 PRINT_INDENT(level);
319 fprintf(f, "--%2hx[%02zx] '%s':", tlv->tag, tlv->len, tag->name);
320
321 switch (tag->type) {
322 case ASN1_TAG_GENERIC:
323 fprintf(f, "\n");
324 break;
325 case ASN1_TAG_STRING:
326 asn1_tag_dump_string(tlv, tag, f, level);
327 *candump = false;
328 break;
329 case ASN1_TAG_OCTET_STRING:
330 asn1_tag_dump_octet_string(tlv, tag, f, level, candump);
331 break;
332 case ASN1_TAG_BOOLEAN:
333 asn1_tag_dump_boolean(tlv, tag, f, level);
334 *candump = false;
335 break;
336 case ASN1_TAG_INTEGER:
337 asn1_tag_dump_integer(tlv, tag, f, level);
338 *candump = false;
339 break;
340 case ASN1_TAG_UTC_TIME:
341 asn1_tag_dump_str_time(tlv, tag, f, level, false, candump);
342 break;
343 case ASN1_TAG_STR_TIME:
344 asn1_tag_dump_str_time(tlv, tag, f, level, true, candump);
345 break;
346 case ASN1_TAG_OBJECT_ID:
347 asn1_tag_dump_object_id(tlv, tag, f, level);
348 *candump = false;
349 break;
350 };
351
352 return true;
353 }
Impressum, Datenschutz