1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2018 Merlok
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
7 //-----------------------------------------------------------------------------
9 //-----------------------------------------------------------------------------
10 #define _POSIX_C_SOURCE 200809L // need for strnlen()
13 #include "commonutil.h" // ARRAYLEN
20 #include <mbedtls/asn1.h>
21 #include <mbedtls/oid.h>
22 #include "emv/emv_tags.h"
23 #include "emv/emvjson.h"
25 #include "proxmark3.h"
26 #include "fileutils.h"
34 ASN1_TAG_OCTET_STRING
,
48 static const struct asn1_tag asn1_tags
[] = {
50 { 0x00, "elem", ASN1_TAG_GENERIC
}, // PRIMITIVE
51 { 0x20, "CONSTRUCTED", ASN1_TAG_GENERIC
}, // CONSTRUCTED, the sequence has multiple elements
52 { 0x80, "CONTEXT SPECIFIC", ASN1_TAG_GENERIC
},
55 { 0x01, "BOOLEAN", ASN1_TAG_BOOLEAN
},
56 { 0x02, "INTEGER", ASN1_TAG_INTEGER
},
57 { 0x03, "BIT STRING", ASN1_TAG_GENERIC
},
58 { 0x04, "OCTET STRING", ASN1_TAG_OCTET_STRING
},
59 { 0x05, "NULL", ASN1_TAG_GENERIC
},
60 { 0x06, "OBJECT IDENTIFIER", ASN1_TAG_OBJECT_ID
},
61 { 0x07, "OBJECT DESCRIPTOR", ASN1_TAG_GENERIC
},
62 { 0x08, "EXTERNAL", ASN1_TAG_GENERIC
},
63 { 0x09, "REAL", ASN1_TAG_GENERIC
},
64 { 0x0A, "ENUMERATED", ASN1_TAG_GENERIC
},
65 { 0x0B, "EMBEDDED_PDV", ASN1_TAG_GENERIC
},
66 { 0x0C, "UTF8String", ASN1_TAG_STRING
},
67 { 0x10, "SEQUENCE", ASN1_TAG_GENERIC
},
68 { 0x11, "SET", ASN1_TAG_GENERIC
},
69 { 0x12, "NumericString", ASN1_TAG_STRING
},
70 { 0x13, "PrintableString", ASN1_TAG_STRING
},
71 { 0x14, "T61String", ASN1_TAG_GENERIC
},
72 { 0x15, "VideotexString", ASN1_TAG_GENERIC
},
73 { 0x16, "IA5String", ASN1_TAG_GENERIC
},
74 { 0x17, "UTCTime", ASN1_TAG_UTC_TIME
},
75 { 0x18, "GeneralizedTime", ASN1_TAG_STR_TIME
},
76 { 0x19, "GraphicString", ASN1_TAG_GENERIC
},
77 { 0x1A, "VisibleString", ASN1_TAG_STRING
},
78 { 0x1B, "GeneralString", ASN1_TAG_STRING
},
79 { 0x1C, "UniversalString", ASN1_TAG_STRING
},
80 { 0x1E, "BMPString", ASN1_TAG_GENERIC
},
81 { 0x30, "SEQUENCE", ASN1_TAG_GENERIC
},
82 { 0x31, "SET", ASN1_TAG_GENERIC
},
83 { 0xa0, "[0]", ASN1_TAG_GENERIC
},
84 { 0xa1, "[1]", ASN1_TAG_GENERIC
},
85 { 0xa2, "[2]", ASN1_TAG_GENERIC
},
86 { 0xa3, "[3]", ASN1_TAG_GENERIC
},
87 { 0xa4, "[4]", ASN1_TAG_GENERIC
},
88 { 0xa5, "[5]", ASN1_TAG_GENERIC
},
92 static int asn1_sort_tag(tlv_tag_t tag
) {
93 return (int)(tag
>= 0x100 ? tag
: tag
<< 8);
96 static int asn1_tlv_compare(const void *a
, const void *b
) {
97 const struct tlv
*tlv
= a
;
98 const struct asn1_tag
*tag
= b
;
100 return asn1_sort_tag(tlv
->tag
) - (asn1_sort_tag(tag
->tag
));
103 static const struct asn1_tag
*asn1_get_tag(const struct tlv
*tlv
) {
104 struct asn1_tag
*tag
= bsearch(tlv
, asn1_tags
, ARRAYLEN(asn1_tags
),
105 sizeof(asn1_tags
[0]), asn1_tlv_compare
);
107 return tag
? tag
: &asn1_tags
[0];
110 static void asn1_tag_dump_str_time(const struct tlv
*tlv
, const struct asn1_tag
*tag
, int level
, bool longyear
, bool *needdump
) {
114 int startindx
= longyear
? 4 : 2;
117 PrintAndLogEx(NORMAL
, " value: '" NOLF
);
120 if (longyear
== false)
121 PrintAndLogEx(NORMAL
, "20" NOLF
);
123 PrintAndLogEx(NORMAL
, "%s-" NOLF
, sprint_hex(tlv
->value
, startindx
));
125 if (len
< startindx
+ 2)
129 PrintAndLogEx(NORMAL
, "%02x%02x-" NOLF
, tlv
->value
[startindx
], tlv
->value
[startindx
+ 1]);
130 if (len
< startindx
+ 4)
134 PrintAndLogEx(NORMAL
, "%02x%02x " NOLF
, tlv
->value
[startindx
+ 2], tlv
->value
[startindx
+ 3]);
135 if (len
< startindx
+ 6)
138 PrintAndLogEx(NORMAL
, "%02x%02x:" NOLF
, tlv
->value
[startindx
+ 4], tlv
->value
[startindx
+ 5]);
139 if (len
< startindx
+ 8)
142 PrintAndLogEx(NORMAL
, "%02x%02x:" NOLF
, tlv
->value
[startindx
+ 6], tlv
->value
[startindx
+ 7]);
143 if (len
< startindx
+ 10)
146 PrintAndLogEx(NORMAL
, "%02x%02x" NOLF
, tlv
->value
[startindx
+ 8], tlv
->value
[startindx
+ 9]);
147 if (len
< startindx
+ 11)
150 PrintAndLogEx(NORMAL
, " zone: %.*s" NOLF
, len
- 10 - (longyear
? 4 : 2), &tlv
->value
[startindx
+ 10]);
153 PrintAndLogEx(NORMAL
, "'");
155 PrintAndLogEx(NORMAL
, "");
160 static void asn1_tag_dump_string(const struct tlv
*tlv
, const struct asn1_tag
*tag
, int level
) {
161 PrintAndLogEx(NORMAL
, " value: '%s'", sprint_hex(tlv
->value
, tlv
->len
));
164 static void asn1_tag_dump_hex(const struct tlv
*tlv
, const struct asn1_tag
*tag
, int level
) {
165 PrintAndLogEx(NORMAL
, " value: '%s'", sprint_hex_inrow(tlv
->value
, tlv
->len
));
168 static void asn1_tag_dump_octet_string(const struct tlv
*tlv
, const struct asn1_tag
*tag
, int level
, bool *needdump
) {
170 for (size_t i
= 0; i
< tlv
->len
; i
++)
171 if (!isspace(tlv
->value
[i
]) && !isprint(tlv
->value
[i
])) {
177 PrintAndLogEx(NORMAL
, "");
179 PrintAndLogEx(NORMAL
, " " NOLF
);
180 asn1_tag_dump_string(tlv
, tag
, level
);
184 static unsigned long asn1_value_integer(const struct tlv
*tlv
, unsigned start
, unsigned end
) {
185 unsigned long ret
= 0;
188 if (end
> tlv
->len
* 2)
194 ret
+= tlv
->value
[start
/ 2] & 0xf;
199 for (; i
< end
- 1; i
+= 2) {
201 ret
+= tlv
->value
[i
/ 2] >> 4;
203 ret
+= tlv
->value
[i
/ 2] & 0xf;
208 ret
+= tlv
->value
[end
/ 2] >> 4;
214 static void asn1_tag_dump_boolean(const struct tlv
*tlv
, const struct asn1_tag
*tag
, int level
) {
215 PrintAndLogEx(NORMAL
, "%*s" NOLF
, (level
* 4), " ");
217 PrintAndLogEx(NORMAL
, " value: %s", tlv
->value
[0] ? "true" : "false");
219 PrintAndLogEx(NORMAL
, "n/a");
223 static void asn1_tag_dump_integer(const struct tlv
*tlv
, const struct asn1_tag
*tag
, int level
) {
224 PrintAndLogEx(NORMAL
, "%*s" NOLF
, (level
* 4), " ");
227 for (size_t i
= 0; i
< tlv
->len
; i
++) {
228 val
= (val
<< 8) + tlv
->value
[i
];
230 PrintAndLogEx(NORMAL
, " value4b: %d", val
);
233 PrintAndLogEx(NORMAL
, " value: %lu", asn1_value_integer(tlv
, 0, tlv
->len
* 2));
236 static char *asn1_oid_description(const char *oid
, bool with_group_desc
) {
239 static char res
[300];
240 memset(res
, 0x00, sizeof(res
));
243 if (searchFile(&path
, RESOURCES_SUBDIR
, "oids", ".json", false) != PM3_SUCCESS
) {
248 root
= json_load_file(path
, 0, &error
);
251 if (!root
|| !json_is_object(root
)) {
255 json_t
*elm
= json_object_get(root
, oid
);
260 if (JsonLoadStr(elm
, "$.d", res
))
263 char strext
[300] = {0};
264 if (!JsonLoadStr(elm
, "$.c", strext
)) {
279 static void asn1_tag_dump_object_id(const struct tlv
*tlv
, const struct asn1_tag
*tag
, int level
) {
281 mbedtls_asn1_buf asn1_buf
;
282 asn1_buf
.len
= tlv
->len
;
283 asn1_buf
.p
= (uint8_t *)tlv
->value
;
285 mbedtls_oid_get_numeric_string(pstr
, sizeof(pstr
), &asn1_buf
);
287 PrintAndLogEx(INFO
, "%*s %s" NOLF
, (level
* 4), " ", pstr
);
289 char *jsondesc
= asn1_oid_description(pstr
, true);
291 PrintAndLogEx(NORMAL
, " - %s" NOLF
, jsondesc
);
294 mbedtls_oid_get_attr_short_name(&asn1_buf
, &ppstr
);
295 if (ppstr
&& strnlen(ppstr
, 1)) {
296 PrintAndLogEx(NORMAL
, " (%s)", ppstr
);
299 mbedtls_oid_get_sig_alg_desc(&asn1_buf
, &ppstr
);
300 if (ppstr
&& strnlen(ppstr
, 1)) {
301 PrintAndLogEx(NORMAL
, " (%s)", ppstr
);
304 mbedtls_oid_get_extended_key_usage(&asn1_buf
, &ppstr
);
305 if (ppstr
&& strnlen(ppstr
, 1)) {
306 PrintAndLogEx(NORMAL
, " (%s)", ppstr
);
310 PrintAndLogEx(NORMAL
, "");
313 bool asn1_tag_dump(const struct tlv
*tlv
, int level
, bool *candump
) {
315 PrintAndLogEx(FAILED
, "NULL\n");
319 const struct asn1_tag
*tag
= asn1_get_tag(tlv
);
322 if ((tlv->tag & 0x20) == 0x20 ) {
323 } else if ((tlv->tag & 0x80) == 0x80 ) {
329 "%*s-- %2x [%02zx] '"_YELLOW_("%s") "'" NOLF
338 case ASN1_TAG_GENERIC
:
339 PrintAndLogEx(NORMAL
, "");
340 // maybe print number of elements?
342 case ASN1_TAG_STRING
:
343 asn1_tag_dump_string(tlv
, tag
, level
);
346 case ASN1_TAG_OCTET_STRING
:
347 asn1_tag_dump_octet_string(tlv
, tag
, level
, candump
);
349 case ASN1_TAG_BOOLEAN
:
350 asn1_tag_dump_boolean(tlv
, tag
, level
);
353 case ASN1_TAG_INTEGER
:
354 asn1_tag_dump_integer(tlv
, tag
, level
);
357 case ASN1_TAG_UTC_TIME
:
358 asn1_tag_dump_str_time(tlv
, tag
, level
, false, candump
);
360 case ASN1_TAG_STR_TIME
:
361 asn1_tag_dump_str_time(tlv
, tag
, level
, true, candump
);
363 case ASN1_TAG_OBJECT_ID
:
364 asn1_tag_dump_object_id(tlv
, tag
, level
);
368 asn1_tag_dump_hex(tlv
, tag
, level
);