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 //-----------------------------------------------------------------------------
19 #include "proxmark3.h"
22 static const ApplicationDataElm ApplicationData
[] = {
28 {0x5F24, "ExpirationDate"},
29 {0x5F25, "EffectiveDate"},
30 {0x5F28, "IssuerCountryCode"},
32 {0x50, "ApplicationLabel"},
33 {0x9F08, "VersionNumber"},
34 {0x9F42, "CurrencyCode"},
35 {0x5F2D, "LanguagePreference"},
36 {0x87, "PriorityIndicator"},
37 {0x9F36, "ATC"}, //Application Transaction Counter
39 {0x5F20, "CardholderName"},
45 {0x9F07, "AUC"}, // Application Usage Control
48 {0x9F0D, "IACDefault"},
50 {0x9F0F, "IACOnline"},
52 {0x8F, "CertificationAuthorityPublicKeyIndex"},
53 {0x9F32, "IssuerPublicKeyExponent"},
54 {0x92, "IssuerPublicKeyRemainder"},
55 {0x90, "IssuerPublicKeyCertificate"},
56 {0x9F47, "ICCPublicKeyExponent"},
57 {0x9F46, "ICCPublicKeyCertificate"},
61 int ApplicationDataLen
= sizeof(ApplicationData
) / sizeof(ApplicationDataElm
);
63 char* GetApplicationDataName(tlv_tag_t tag
) {
64 for (int i
= 0; i
< ApplicationDataLen
; i
++)
65 if (ApplicationData
[i
].Tag
== tag
)
66 return ApplicationData
[i
].Name
;
71 int JsonSaveJsonObject(json_t
*root
, char *path
, json_t
*value
) {
78 if (json_path_set(root
, path
, value
, 0, &error
)) {
79 PrintAndLog("ERROR: can't set json path: ", error
.text
);
85 return json_object_set_new(root
, path
, value
);
89 int JsonSaveInt(json_t
*root
, char *path
, int value
) {
90 return JsonSaveJsonObject(root
, path
, json_integer(value
));
93 int JsonSaveStr(json_t
*root
, char *path
, char *value
) {
94 return JsonSaveJsonObject(root
, path
, json_string(value
));
97 int JsonSaveBufAsHexCompact(json_t
*elm
, char *path
, uint8_t *data
, size_t datalen
) {
98 char * msg
= sprint_hex_inrow(data
, datalen
);
99 if (msg
&& strlen(msg
) && msg
[strlen(msg
) - 1] == ' ')
100 msg
[strlen(msg
) - 1] = '\0';
102 return JsonSaveStr(elm
, path
, msg
);
105 int JsonSaveBufAsHex(json_t
*elm
, char *path
, uint8_t *data
, size_t datalen
) {
106 char * msg
= sprint_hex(data
, datalen
);
107 if (msg
&& strlen(msg
) && msg
[strlen(msg
) - 1] == ' ')
108 msg
[strlen(msg
) - 1] = '\0';
110 return JsonSaveStr(elm
, path
, msg
);
113 int JsonSaveHex(json_t
*elm
, char *path
, uint64_t data
, int datalen
) {
114 uint8_t bdata
[8] = {0};
117 for (uint64_t u
= 0xffffffffffffffff; u
; u
= u
<< 8) {
128 num_to_bytes(data
, len
, bdata
);
130 return JsonSaveBufAsHex(elm
, path
, bdata
, len
);
133 int JsonSaveTLVValue(json_t
*root
, char *path
, struct tlvdb
*tlvdbelm
) {
134 const struct tlv
*tlvelm
= tlvdb_get_tlv(tlvdbelm
);
136 return JsonSaveBufAsHex(root
, path
, (uint8_t *)tlvelm
->value
, tlvelm
->len
);
141 int JsonSaveTLVElm(json_t
*elm
, char *path
, struct tlv
*tlvelm
, bool saveName
, bool saveValue
, bool saveAppDataLink
) {
144 if (strlen(path
) < 1 || !tlvelm
)
147 if (path
[0] == '$') {
149 json_t
*obj
= json_path_get(elm
, path
);
153 if (json_is_array(elm
)) {
154 if (json_array_append_new(elm
, obj
)) {
155 PrintAndLog("ERROR: can't append array: %s", path
);
159 if (json_path_set(elm
, path
, obj
, 0, &error
)) {
160 PrintAndLog("ERROR: can't set json path: ", error
.text
);
166 if (saveAppDataLink
) {
167 char * AppDataName
= GetApplicationDataName(tlvelm
->tag
);
169 JsonSaveStr(obj
, "appdata", AppDataName
);
171 char * name
= emv_get_tag_name(tlvelm
);
172 if (saveName
&& name
&& strlen(name
) > 0 && strncmp(name
, "Unknown", 7))
173 JsonSaveStr(obj
, "name", emv_get_tag_name(tlvelm
));
174 JsonSaveHex(obj
, "tag", tlvelm
->tag
, 0);
176 JsonSaveHex(obj
, "length", tlvelm
->len
, 0);
177 JsonSaveBufAsHex(obj
, "value", (uint8_t *)tlvelm
->value
, tlvelm
->len
);
185 int JsonSaveTLVTreeElm(json_t
*elm
, char *path
, struct tlvdb
*tlvdbelm
, bool saveName
, bool saveValue
, bool saveAppDataLink
) {
186 return JsonSaveTLVElm(elm
, path
, (struct tlv
*)tlvdb_get_tlv(tlvdbelm
), saveName
, saveValue
, saveAppDataLink
);
189 int JsonSaveTLVTree(json_t
*root
, json_t
*elm
, char *path
, struct tlvdb
*tlvdbelm
) {
190 struct tlvdb
*tlvp
= tlvdbelm
;
192 const struct tlv
* tlvpelm
= tlvdb_get_tlv(tlvp
);
193 char * AppDataName
= NULL
;
195 AppDataName
= GetApplicationDataName(tlvpelm
->tag
);
198 char appdatalink
[200] = {0};
199 sprintf(appdatalink
, "$.ApplicationData.%s", AppDataName
);
200 JsonSaveBufAsHex(root
, appdatalink
, (uint8_t *)tlvpelm
->value
, tlvpelm
->len
);
203 json_t
*pelm
= json_path_get(elm
, path
);
204 if (pelm
&& json_is_array(pelm
)) {
205 json_t
*appendelm
= json_object();
206 json_array_append_new(pelm
, appendelm
);
207 JsonSaveTLVTreeElm(appendelm
, "$", tlvp
, !AppDataName
, !tlvdb_elm_get_children(tlvp
), AppDataName
);
210 JsonSaveTLVTreeElm(elm
, path
, tlvp
, !AppDataName
, !tlvdb_elm_get_children(tlvp
), AppDataName
);
211 pelm
= json_path_get(elm
, path
);
214 if (tlvdb_elm_get_children(tlvp
)) {
219 // check childs element and add it if not found
220 json_t
*chjson
= json_path_get(pelm
, "$.Childs");
222 json_object_set_new(pelm
, "Childs", json_array());
224 chjson
= json_path_get(pelm
, "$.Childs");
228 if (!json_is_array(chjson
)) {
229 PrintAndLog("E->Internal logic error. `$.Childs` is not an array.");
234 JsonSaveTLVTree(root
, chjson
, "$", tlvdb_elm_get_children(tlvp
));
237 tlvp
= tlvdb_elm_get_next(tlvp
);
242 bool HexToBuffer(const char *errormsg
, const char *hexvalue
, uint8_t * buffer
, size_t maxbufferlen
, size_t *bufferlen
) {
245 switch(param_gethex_to_eol(hexvalue
, 0, buffer
, maxbufferlen
, &buflen
)) {
247 PrintAndLog("%s Invalid HEX value.", errormsg
);
250 PrintAndLog("%s Hex value too large.", errormsg
);
253 PrintAndLog("%s Hex value must have even number of digits.", errormsg
);
257 if (buflen
> maxbufferlen
) {
258 PrintAndLog("%s HEX length (%d) more than %d", errormsg
, *bufferlen
, maxbufferlen
);
267 int JsonLoadBufAsHex(json_t
*elm
, char *path
, uint8_t *data
, size_t maxbufferlen
, size_t *datalen
) {
271 json_t
*jelm
= json_path_get((const json_t
*)elm
, path
);
272 if (!jelm
|| !json_is_string(jelm
))
275 if (!HexToBuffer("ERROR load", json_string_value(jelm
), data
, maxbufferlen
, datalen
))
281 bool ParamLoadFromJson(struct tlvdb
*tlv
) {
286 PrintAndLog("ERROR load params: tlv tree is NULL.");
290 // current path + file name
291 const char *relfname
= "emv/defparams.json";
292 char fname
[strlen(get_my_executable_directory()) + strlen(relfname
) + 1];
293 strcpy(fname
, get_my_executable_directory());
294 strcat(fname
, relfname
);
296 root
= json_load_file(fname
, 0, &error
);
298 PrintAndLog("Load params: json error on line %d: %s", error
.line
, error
.text
);
302 if (!json_is_array(root
)) {
303 PrintAndLog("Load params: Invalid json format. root must be array.");
307 PrintAndLog("Load params: json(%d) OK", json_array_size(root
));
309 for(int i
= 0; i
< json_array_size(root
); i
++) {
310 json_t
*data
, *jtag
, *jlength
, *jvalue
;
312 data
= json_array_get(root
, i
);
313 if(!json_is_object(data
))
315 PrintAndLog("Load params: data [%d] is not an object", i
+ 1);
320 jtag
= json_object_get(data
, "tag");
321 if(!json_is_string(jtag
))
323 PrintAndLog("Load params: data [%d] tag is not a string", i
+ 1);
327 const char *tlvTag
= json_string_value(jtag
);
329 jvalue
= json_object_get(data
, "value");
330 if(!json_is_string(jvalue
))
332 PrintAndLog("Load params: data [%d] value is not a string", i
+ 1);
336 const char *tlvValue
= json_string_value(jvalue
);
338 jlength
= json_object_get(data
, "length");
339 if(!json_is_number(jlength
))
341 PrintAndLog("Load params: data [%d] length is not a number", i
+ 1);
346 int tlvLength
= json_integer_value(jlength
);
347 if (tlvLength
> 250) {
348 PrintAndLog("Load params: data [%d] length more than 250", i
+ 1);
353 PrintAndLog("TLV param: %s[%d]=%s", tlvTag
, tlvLength
, tlvValue
);
354 uint8_t buf
[251] = {0};
357 // here max length must be 4, but now tlv_tag_t is 2-byte var. so let it be 2 by now... TODO: needs refactoring tlv_tag_t...
358 if (!HexToBuffer("TLV Error type:", tlvTag
, buf
, 2, &buflen
)) {
363 for (int i
= 0; i
< buflen
; i
++) {
364 tag
= (tag
<< 8) + buf
[i
];
367 if (!HexToBuffer("TLV Error value:", tlvValue
, buf
, sizeof(buf
) - 1, &buflen
)) {
372 if (buflen
!= tlvLength
) {
373 PrintAndLog("Load params: data [%d] length of HEX must(%d) be identical to length in TLV param(%d)", i
+ 1, buflen
, tlvLength
);
378 tlvdb_change_or_add_node(tlv
, tag
, tlvLength
, (const unsigned char *)buf
);