recover_pk.py: replace secp192r1 by prime192v1
[RRG-proxmark3.git] / client / src / crypto / asn1dump.c
blob32dc8f0511da2df21beda788adff068f03fa93d7
1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
16 // asn.1 dumping
17 //-----------------------------------------------------------------------------
19 #include "asn1dump.h"
21 #include "commonutil.h" // ARRAYLEN
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <jansson.h>
28 #include <mbedtls/asn1.h>
29 #include "mbedtls/bignum.h" // big num
30 #include <mbedtls/oid.h>
31 #include "emv/emv_tags.h"
32 #include "emv/emvjson.h"
33 #include "util.h"
34 #include "proxmark3.h"
35 #include "fileutils.h"
36 #include "pm3_cmd.h"
38 enum asn1_tag_t {
39 ASN1_TAG_GENERIC,
40 ASN1_TAG_BOOLEAN,
41 ASN1_TAG_INTEGER,
42 ASN1_TAG_STRING,
43 ASN1_TAG_OCTET_STRING,
44 ASN1_TAG_UTC_TIME,
45 ASN1_TAG_STR_TIME,
46 ASN1_TAG_OBJECT_ID,
47 ASN1_TAG_HEX,
48 ASN1_TAG_BIT_STRING,
51 struct asn1_tag {
52 tlv_tag_t tag;
53 const char *name;
54 enum asn1_tag_t type;
55 // const void *data;
58 static const struct asn1_tag asn1_tags[] = {
59 // internal
60 { 0x00, "elem", ASN1_TAG_GENERIC }, // PRIMITIVE
61 { 0x20, "CONSTRUCTED", ASN1_TAG_GENERIC }, // CONSTRUCTED, the sequence has multiple elements
62 { 0x80, "CONTEXT SPECIFIC", ASN1_TAG_GENERIC },
64 // ASN.1
65 { 0x01, "BOOLEAN", ASN1_TAG_BOOLEAN },
66 { 0x02, "INTEGER", ASN1_TAG_INTEGER },
67 { 0x03, "BIT STRING", ASN1_TAG_BIT_STRING },
68 { 0x04, "OCTET STRING", ASN1_TAG_OCTET_STRING },
69 { 0x05, "NULL", ASN1_TAG_GENERIC },
70 { 0x06, "OBJECT IDENTIFIER", ASN1_TAG_OBJECT_ID },
71 { 0x07, "OBJECT DESCRIPTOR", ASN1_TAG_GENERIC },
72 { 0x08, "EXTERNAL", ASN1_TAG_GENERIC },
73 { 0x09, "REAL", ASN1_TAG_GENERIC },
74 { 0x0A, "ENUMERATED", ASN1_TAG_GENERIC },
75 { 0x0B, "EMBEDDED_PDV", ASN1_TAG_GENERIC },
76 { 0x0C, "UTF8String", ASN1_TAG_STRING },
77 { 0x10, "SEQUENCE", ASN1_TAG_GENERIC },
78 { 0x11, "SET", ASN1_TAG_GENERIC },
79 { 0x12, "NumericString", ASN1_TAG_STRING },
80 { 0x13, "PrintableString", ASN1_TAG_STRING },
81 { 0x14, "T61String", ASN1_TAG_GENERIC },
82 { 0x15, "VideotexString", ASN1_TAG_GENERIC },
83 { 0x16, "IA5String", ASN1_TAG_GENERIC },
84 { 0x17, "UTCTime", ASN1_TAG_UTC_TIME },
85 { 0x18, "GeneralizedTime", ASN1_TAG_STR_TIME },
86 { 0x19, "GraphicString", ASN1_TAG_GENERIC },
87 { 0x1A, "VisibleString", ASN1_TAG_STRING },
88 { 0x1B, "GeneralString", ASN1_TAG_STRING },
89 { 0x1C, "UniversalString", ASN1_TAG_STRING },
90 { 0x1E, "BMPString", ASN1_TAG_GENERIC },
91 { 0x30, "SEQUENCE", ASN1_TAG_GENERIC },
92 { 0x31, "SET", ASN1_TAG_GENERIC },
93 { 0xa0, "[0]", ASN1_TAG_GENERIC },
94 { 0xa1, "[1]", ASN1_TAG_GENERIC },
95 { 0xa2, "[2]", ASN1_TAG_GENERIC },
96 { 0xa3, "[3]", ASN1_TAG_GENERIC },
97 { 0xa4, "[4]", ASN1_TAG_GENERIC },
98 { 0xa5, "[5]", ASN1_TAG_GENERIC },
101 static int asn1_sort_tag(tlv_tag_t tag) {
102 return (int)(tag >= 0x100 ? tag : tag << 8);
105 static int asn1_tlv_compare(const void *a, const void *b) {
106 const struct tlv *tlv = a;
107 const struct asn1_tag *tag = b;
109 return asn1_sort_tag(tlv->tag) - (asn1_sort_tag(tag->tag));
112 static const struct asn1_tag *asn1_get_tag(const struct tlv *tlv) {
113 struct asn1_tag *tag = bsearch(tlv, asn1_tags, ARRAYLEN(asn1_tags), sizeof(asn1_tags[0]), asn1_tlv_compare);
114 return tag ? tag : &asn1_tags[0];
117 static void asn1_tag_dump_str_time(const struct tlv *tlv, const struct asn1_tag *tag, int level, bool longyear, bool *needdump) {
118 int len = tlv->len;
119 *needdump = false;
121 int startidx = longyear ? 4 : 2;
123 if (len > 4) {
124 PrintAndLogEx(NORMAL, " value: '" NOLF);
125 while (true) {
127 // year
128 if (longyear == false) {
129 int short_year = (tlv->value[0] - '0') * 10 + (tlv->value[1] - '0');
130 if (short_year >= 0 && short_year <= 99) {
131 if (short_year > 50) {
132 PrintAndLogEx(NORMAL, "19" NOLF);
133 } else {
134 PrintAndLogEx(NORMAL, "20" NOLF);
139 PrintAndLogEx(NORMAL, "%.*s-" NOLF, startidx, tlv->value);
140 if (len < startidx + 2)
141 break;
143 // month
144 PrintAndLogEx(NORMAL, "%.*s-" NOLF, 2, tlv->value + startidx);
145 if (len < startidx + 4)
146 break;
148 // day
149 PrintAndLogEx(NORMAL, "%.*s " NOLF, 2, tlv->value + startidx + 2);
150 if (len < startidx + 6)
151 break;
153 // hour
154 PrintAndLogEx(NORMAL, "%.*s:" NOLF, 2, tlv->value + startidx + 4);
155 if (len < startidx + 8)
156 break;
158 // min
159 PrintAndLogEx(NORMAL, "%.*s:" NOLF, 2, tlv->value + startidx + 6);
160 if (len < startidx + 10)
161 break;
163 // sec
164 PrintAndLogEx(NORMAL, "%.*s" NOLF, 2, tlv->value + startidx + 8);
165 if (len < startidx + 12)
166 break;
168 // time zone
169 PrintAndLogEx(NORMAL, " zone: UTC %.*s" NOLF, len - startidx - 10, tlv->value + startidx + 10);
170 break;
172 PrintAndLogEx(NORMAL, "'");
173 } else {
174 PrintAndLogEx(NORMAL, "");
175 *needdump = true;
179 static void asn1_tag_dump_string(const struct tlv *tlv, const struct asn1_tag *tag, int level) {
180 PrintAndLogEx(NORMAL, " value: '" _GREEN_("%.*s") "' hex: '%s'", (int)tlv->len, tlv->value, sprint_hex(tlv->value, tlv->len));
183 static void asn1_tag_dump_bitstring(const struct tlv *tlv, const struct asn1_tag *tag, int level) {
185 size_t len = tlv->len;
186 size_t n = (len * 8);
187 bool skip = false;
189 if (tlv->value[0] == 0) {
190 n -= 8;
191 len--;
192 skip = true;
195 uint8_t *d = calloc(n, sizeof(uint8_t));
196 if (d == NULL) {
197 return;
200 if (skip)
201 bytes_to_bytebits(tlv->value + 1, len, d);
202 else
203 bytes_to_bytebits(tlv->value, len, d);
205 level++;
206 PrintAndLogEx(NORMAL, " (%zu bit)", n);
207 PrintAndLogEx(INFO, "%*s" NOLF, 1 + (level * 4), "");
209 for (int i = 0; i < n; i++) {
211 char c = d[i];
212 if (c < 2) {
213 c += '0';
214 } else {
215 goto out;
218 PrintAndLogEx(NORMAL, "%c" NOLF, c);
220 if (((i + 1) % 64) == 0) {
221 PrintAndLogEx(NORMAL, "");
222 PrintAndLogEx(INFO, "%*s" NOLF, 1 + (level * 4), "");
226 out:
227 free(d);
228 PrintAndLogEx(NORMAL, "");
231 static void asn1_tag_dump_hex(const struct tlv *tlv, const struct asn1_tag *tag, int level) {
232 PrintAndLogEx(NORMAL, " value: '%s'", sprint_hex_inrow(tlv->value, tlv->len));
235 static void asn1_tag_dump_octet_string(const struct tlv *tlv, const struct asn1_tag *tag, int level) {
237 for (size_t i = 0; i < tlv->len; i++) {
238 if (!isspace(tlv->value[i]) && !isprint(tlv->value[i])) {
239 *needdump = true;
240 break;
244 PrintAndLogEx(NORMAL, " " NOLF);
245 asn1_tag_dump_string(tlv, tag, level);
248 static void asn1_tag_dump_boolean(const struct tlv *tlv, const struct asn1_tag *tag, int level) {
249 PrintAndLogEx(NORMAL, "%*s" NOLF, (level * 4), " ");
250 if (tlv->len > 0) {
251 PrintAndLogEx(NORMAL, " value: %s", tlv->value[0] ? "true" : "false");
252 } else {
253 PrintAndLogEx(NORMAL, "n/a");
257 static void asn1_tag_dump_integer(const struct tlv *tlv, const struct asn1_tag *tag, int level) {
259 size_t n = (tlv->len * 2);
260 char *hex = calloc(n + 1, sizeof(uint8_t));
261 if (hex == NULL) {
262 return;
265 hex_to_buffer((uint8_t *)hex, tlv->value, tlv->len, tlv->len, 0, 0, false);
267 // results for MPI actions
268 bool ret = false;
270 // container of big number
271 mbedtls_mpi N;
272 mbedtls_mpi_init(&N);
274 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&N, 16, hex));
276 char s[600] = {0};
277 size_t slen = 0;
278 MBEDTLS_MPI_CHK(mbedtls_mpi_write_string(&N, 10, s, sizeof(s), &slen));
279 if (slen > 0) {
280 PrintAndLogEx(NORMAL, "%*s value: %s", (level), "", s);
283 cleanup:
284 mbedtls_mpi_free(&N);
285 free(hex);
288 static char *asn1_oid_description(const char *oid, bool with_group_desc) {
289 json_error_t error;
290 json_t *root = NULL;
291 static char res[300];
292 memset(res, 0x00, sizeof(res));
294 char *path;
295 if (searchFile(&path, RESOURCES_SUBDIR, "oids", ".json", false) != PM3_SUCCESS) {
296 return NULL;
299 // load `oids.json`
300 root = json_load_file(path, 0, &error);
301 free(path);
303 if (!root || !json_is_object(root)) {
304 goto error;
307 json_t *elm = json_object_get(root, oid);
308 if (!elm) {
309 goto error;
312 if (JsonLoadStr(elm, "$.d", res))
313 goto error;
315 char strext[300] = {0};
316 if (!JsonLoadStr(elm, "$.c", strext)) {
317 strcat(res, " (");
318 strcat(res, strext);
319 strcat(res, ")");
322 json_decref(root);
323 return res;
325 error:
326 if (root)
327 json_decref(root);
328 return NULL;
331 static void asn1_tag_dump_object_id(const struct tlv *tlv, const struct asn1_tag *tag, int level) {
333 mbedtls_asn1_buf asn1_buf;
334 asn1_buf.len = tlv->len;
335 asn1_buf.p = (uint8_t *)tlv->value;
336 char pstr[300];
337 mbedtls_oid_get_numeric_string(pstr, sizeof(pstr), &asn1_buf);
339 PrintAndLogEx(NORMAL, "%*s %s" NOLF, (level), " ", pstr);
341 char *jsondesc = asn1_oid_description(pstr, true);
342 if (jsondesc) {
343 PrintAndLogEx(NORMAL, " - %s" NOLF, jsondesc);
344 } else {
345 const char *ppstr = NULL;
346 mbedtls_oid_get_attr_short_name(&asn1_buf, &ppstr);
347 if (ppstr && str_nlen(ppstr, 1)) {
348 PrintAndLogEx(NORMAL, " (%s)", ppstr);
349 return;
351 mbedtls_oid_get_sig_alg_desc(&asn1_buf, &ppstr);
352 if (ppstr && str_nlen(ppstr, 1)) {
353 PrintAndLogEx(NORMAL, " (%s)", ppstr);
354 return;
356 mbedtls_oid_get_extended_key_usage(&asn1_buf, &ppstr);
357 if (ppstr && str_nlen(ppstr, 1)) {
358 PrintAndLogEx(NORMAL, " (%s)", ppstr);
359 return;
362 PrintAndLogEx(NORMAL, "");
365 bool asn1_tag_dump(const struct tlv *tlv, int level, bool *candump) {
366 if (tlv == NULL) {
367 PrintAndLogEx(FAILED, "NULL\n");
368 return false;
371 const struct asn1_tag *tag = asn1_get_tag(tlv);
374 if ((tlv->tag & 0x20) == 0x20 ) {
375 } else if ((tlv->tag & 0x80) == 0x80 ) {
376 } else {
380 PrintAndLogEx(INFO,
381 "%*s-- %02X [%02zX] '"_YELLOW_("%s") "'" NOLF
382 , (level * 4)
383 , " "
384 , tlv->tag
385 , tlv->len
386 , tag->name
389 switch (tag->type) {
390 case ASN1_TAG_GENERIC:
391 PrintAndLogEx(NORMAL, "");
392 // maybe print number of elements?
393 break;
394 case ASN1_TAG_STRING:
395 asn1_tag_dump_string(tlv, tag, level);
396 *candump = false;
397 break;
398 case ASN1_TAG_OCTET_STRING:
399 asn1_tag_dump_octet_string(tlv, tag, level);
400 *candump = false;
401 break;
402 case ASN1_TAG_BOOLEAN:
403 asn1_tag_dump_boolean(tlv, tag, level);
404 *candump = false;
405 break;
406 case ASN1_TAG_INTEGER:
407 asn1_tag_dump_integer(tlv, tag, level);
408 *candump = false;
409 break;
410 case ASN1_TAG_UTC_TIME:
411 asn1_tag_dump_str_time(tlv, tag, level, false, candump);
412 break;
413 case ASN1_TAG_STR_TIME:
414 asn1_tag_dump_str_time(tlv, tag, level, true, candump);
415 break;
416 case ASN1_TAG_OBJECT_ID:
417 asn1_tag_dump_object_id(tlv, tag, level);
418 *candump = false;
419 break;
420 case ASN1_TAG_HEX:
421 asn1_tag_dump_hex(tlv, tag, level);
422 *candump = false;
423 break;
424 case ASN1_TAG_BIT_STRING:
425 asn1_tag_dump_bitstring(tlv, tag, level);
426 *candump = false;
427 break;
430 return true;