textual
[RRG-proxmark3.git] / client / src / emv / emvjson.c
blob0931fb2e8982430db1f99ec3a7ef98d892cc5e79
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 // EMV json logic
9 //-----------------------------------------------------------------------------
11 #include "emvjson.h"
12 #include <string.h>
13 #include "commonutil.h" // ARRAYLEN
14 #include "ui.h"
15 #include "util.h"
16 #include "proxmark3.h"
17 #include "emv_tags.h"
18 #include "fileutils.h"
19 #include "pm3_cmd.h"
21 static const ApplicationDataElm ApplicationData[] = {
22 {0x82, "AIP"},
23 {0x94, "AFL"},
25 {0x5A, "PAN"},
26 {0x5F34, "PANSeqNo"},
27 {0x5F24, "ExpirationDate"},
28 {0x5F25, "EffectiveDate"},
29 {0x5F28, "IssuerCountryCode"},
31 {0x50, "ApplicationLabel"},
32 {0x9F08, "VersionNumber"},
33 {0x9F42, "CurrencyCode"},
34 {0x5F2D, "LanguagePreference"},
35 {0x87, "PriorityIndicator"},
36 {0x9F36, "ATC"}, //Application Transaction Counter
38 {0x5F20, "CardholderName"},
40 {0x9F38, "PDOL"},
41 {0x8C, "CDOL1"},
42 {0x8D, "CDOL2"},
44 {0x9F07, "AUC"}, // Application Usage Control
45 {0x9F6C, "CTQ"},
46 {0x8E, "CVMList"},
47 {0x9F0D, "IACDefault"},
48 {0x9F0E, "IACDeny"},
49 {0x9F0F, "IACOnline"},
51 {0x8F, "CertificationAuthorityPublicKeyIndex"},
52 {0x9F32, "IssuerPublicKeyExponent"},
53 {0x92, "IssuerPublicKeyRemainder"},
54 {0x90, "IssuerPublicKeyCertificate"},
55 {0x9F47, "ICCPublicKeyExponent"},
56 {0x9F46, "ICCPublicKeyCertificate"},
58 {0x00, "end..."}
61 const char *GetApplicationDataName(tlv_tag_t tag) {
62 for (int i = 0; i < ARRAYLEN(ApplicationData); i++)
63 if (ApplicationData[i].Tag == tag)
64 return ApplicationData[i].Name;
66 return NULL;
69 int JsonSaveJsonObject(json_t *root, const char *path, json_t *value) {
70 json_error_t error;
72 if (strlen(path) < 1)
73 return 1;
75 if (path[0] == '$') {
76 if (json_path_set_new(root, path, value, 0, &error)) {
77 PrintAndLogEx(ERR, "ERROR: can't set json path: %s", error.text);
78 return 2;
79 } else {
80 return 0;
82 } else {
83 return json_object_set_new(root, path, value);
87 int JsonSaveInt(json_t *root, const char *path, int value) {
88 return JsonSaveJsonObject(root, path, json_integer(value));
91 int JsonSaveStr(json_t *root, const char *path, const char *value) {
92 return JsonSaveJsonObject(root, path, json_string(value));
95 int JsonSaveBoolean(json_t *root, const char *path, bool value) {
96 return JsonSaveJsonObject(root, path, json_boolean(value));
99 int JsonSaveBufAsHexCompact(json_t *elm, const char *path, uint8_t *data, size_t datalen) {
100 char *msg = sprint_hex_inrow(data, datalen);
101 if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
102 msg[strlen(msg) - 1] = '\0';
104 return JsonSaveStr(elm, path, msg);
107 int JsonSaveBufAsHex(json_t *elm, const char *path, uint8_t *data, size_t datalen) {
108 char *msg = sprint_hex(data, datalen);
109 if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
110 msg[strlen(msg) - 1] = '\0';
112 return JsonSaveStr(elm, path, msg);
115 int JsonSaveHex(json_t *elm, const char *path, uint64_t data, int datalen) {
116 uint8_t bdata[8] = {0};
117 int len = 0;
118 if (!datalen) {
119 for (uint64_t u = 0xffffffffffffffff; u; u = u << 8) {
120 if (!(data & u)) {
121 break;
123 len++;
125 if (!len)
126 len = 1;
127 } else {
128 len = datalen;
130 num_to_bytes(data, len, bdata);
132 return JsonSaveBufAsHex(elm, path, bdata, len);
135 int JsonSaveTLVValue(json_t *root, const char *path, struct tlvdb *tlvdbelm) {
136 const struct tlv *tlvelm = tlvdb_get_tlv(tlvdbelm);
137 if (tlvelm)
138 return JsonSaveBufAsHex(root, path, (uint8_t *)tlvelm->value, tlvelm->len);
139 else
140 return 1;
143 int JsonSaveTLVElm(json_t *elm, const char *path, struct tlv *tlvelm, bool saveName, bool saveValue, bool saveAppDataLink) {
144 json_error_t error;
146 if (strlen(path) < 1 || !tlvelm)
147 return 1;
149 if (path[0] == '$') {
151 json_t *obj = json_path_get(elm, path);
152 if (!obj) {
153 obj = json_object();
155 if (json_is_array(elm)) {
156 if (json_array_append_new(elm, obj)) {
157 PrintAndLogEx(ERR, "ERROR: can't append array: %s", path);
158 return 2;
160 } else {
161 if (json_path_set(elm, path, obj, 0, &error)) {
162 PrintAndLogEx(ERR, "ERROR: can't set json path: %s", error.text);
163 return 2;
168 if (saveAppDataLink) {
169 const char *AppDataName = GetApplicationDataName(tlvelm->tag);
170 if (AppDataName)
171 JsonSaveStr(obj, "appdata", AppDataName);
172 } else {
173 const char *name = emv_get_tag_name(tlvelm);
174 if (saveName && name && strlen(name) > 0 && strncmp(name, "Unknown", 7))
175 JsonSaveStr(obj, "name", emv_get_tag_name(tlvelm));
176 JsonSaveHex(obj, "tag", tlvelm->tag, 0);
177 if (saveValue) {
178 JsonSaveHex(obj, "length", tlvelm->len, 0);
179 JsonSaveBufAsHex(obj, "value", (uint8_t *)tlvelm->value, tlvelm->len);
184 return 0;
187 int JsonSaveTLVTreeElm(json_t *elm, const char *path, struct tlvdb *tlvdbelm, bool saveName, bool saveValue, bool saveAppDataLink) {
188 return JsonSaveTLVElm(elm, path, (struct tlv *)tlvdb_get_tlv(tlvdbelm), saveName, saveValue, saveAppDataLink);
191 int JsonSaveTLVTree(json_t *root, json_t *elm, const char *path, struct tlvdb *tlvdbelm) {
192 struct tlvdb *tlvp = tlvdbelm;
193 while (tlvp) {
194 const struct tlv *tlvpelm = tlvdb_get_tlv(tlvp);
195 const char *AppDataName = NULL;
196 if (tlvpelm)
197 AppDataName = GetApplicationDataName(tlvpelm->tag);
199 if (AppDataName) {
200 char appdatalink[200] = {0};
201 sprintf(appdatalink, "$.ApplicationData.%s", AppDataName);
202 JsonSaveBufAsHex(root, appdatalink, (uint8_t *)tlvpelm->value, tlvpelm->len);
205 json_t *pelm = json_path_get(elm, path);
206 if (pelm && json_is_array(pelm)) {
207 json_t *appendelm = json_object();
208 json_array_append_new(pelm, appendelm);
209 JsonSaveTLVTreeElm(appendelm, "$", tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
210 pelm = appendelm;
211 } else {
212 JsonSaveTLVTreeElm(elm, path, tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
213 pelm = json_path_get(elm, path);
216 if (tlvdb_elm_get_children(tlvp)) {
217 // get path element
218 if (!pelm)
219 return 1;
221 // check childs element and add it if not found
222 json_t *chjson = json_path_get(pelm, "$.Childs");
223 if (!chjson) {
224 json_object_set_new(pelm, "Childs", json_array());
226 chjson = json_path_get(pelm, "$.Childs");
229 // check
230 if (!json_is_array(chjson)) {
231 PrintAndLogEx(ERR, "E->Internal logic error. `$.Childs` is not an array.");
232 break;
235 // Recursion
236 JsonSaveTLVTree(root, chjson, "$", tlvdb_elm_get_children(tlvp));
239 tlvp = tlvdb_elm_get_next(tlvp);
241 return 0;
244 static bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t *buffer, size_t maxbufferlen, size_t *bufferlen) {
245 int buflen = 0;
247 switch (param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) {
248 case 1:
249 PrintAndLogEx(ERR, "%s Invalid HEX value.", errormsg);
250 return false;
251 case 2:
252 PrintAndLogEx(ERR, "%s Hex value too large.", errormsg);
253 return false;
254 case 3:
255 PrintAndLogEx(ERR, "%s Hex value must have even number of digits.", errormsg);
256 return false;
259 if (buflen > maxbufferlen) {
260 PrintAndLogEx(ERR, "%s HEX length (%zu) more than %zu", errormsg, (bufferlen) ? *bufferlen : -1, maxbufferlen);
261 return false;
264 if (bufferlen)
265 *bufferlen = buflen;
267 return true;
270 int JsonLoadStr(json_t *root, const char *path, char *value) {
271 if (!value)
272 return 1;
274 json_t *jelm = json_path_get((const json_t *)root, path);
275 if (!jelm || !json_is_string(jelm))
276 return 2;
278 const char *strval = json_string_value(jelm);
279 if (!strval)
280 return 1;
282 memcpy(value, strval, strlen(strval));
284 return 0;
287 int JsonLoadBufAsHex(json_t *elm, const char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen) {
288 if (datalen)
289 *datalen = 0;
291 json_t *jelm = json_path_get((const json_t *)elm, path);
292 if (!jelm || !json_is_string(jelm))
293 return 1;
295 if (!HexToBuffer("ERROR load", json_string_value(jelm), data, maxbufferlen, datalen))
296 return 2;
298 return 0;
301 bool ParamLoadFromJson(struct tlvdb *tlv) {
302 json_t *root;
303 json_error_t error;
305 if (!tlv) {
306 PrintAndLogEx(ERR, "ERROR load params: tlv tree is NULL.");
307 return false;
310 char *path;
311 if (searchFile(&path, RESOURCES_SUBDIR, "emv_defparams", ".json", false) != PM3_SUCCESS) {
312 return false;
314 root = json_load_file(path, 0, &error);
315 free(path);
316 if (!root) {
317 PrintAndLogEx(ERR, "Load params: json error on line " _YELLOW_("%d") ": %s", error.line, error.text);
318 return false;
321 if (!json_is_array(root)) {
322 PrintAndLogEx(ERR, "Load params: Invalid json format. root must be array.");
323 return false;
326 PrintAndLogEx(SUCCESS, "Load params: json(%zu) (%s)", json_array_size(root), _GREEN_("OK"));
328 for (int i = 0; i < json_array_size(root); i++) {
329 json_t *data, *jtag, *jlength, *jvalue;
331 data = json_array_get(root, i);
332 if (!json_is_object(data)) {
333 PrintAndLogEx(ERR, "Load params: data [%d] is not an object", i + 1);
334 json_decref(root);
335 return false;
338 jtag = json_object_get(data, "tag");
339 if (!json_is_string(jtag)) {
340 PrintAndLogEx(ERR, "Load params: data [%d] tag is not a string", i + 1);
341 json_decref(root);
342 return false;
344 const char *tlvTag = json_string_value(jtag);
346 jvalue = json_object_get(data, "value");
347 if (!json_is_string(jvalue)) {
348 PrintAndLogEx(ERR, "Load params: data [%d] value is not a string", i + 1);
349 json_decref(root);
350 return false;
352 const char *tlvValue = json_string_value(jvalue);
354 jlength = json_object_get(data, "length");
355 if (!json_is_number(jlength)) {
356 PrintAndLogEx(ERR, "Load params: data [%d] length is not a number", i + 1);
357 json_decref(root);
358 return false;
361 int tlvLength = json_integer_value(jlength);
362 if (tlvLength > 250) {
363 PrintAndLogEx(ERR, "Load params: data [%d] length more than 250", i + 1);
364 json_decref(root);
365 return false;
368 PrintAndLogEx(SUCCESS, "TLV param: %s[%d]=%s", tlvTag, tlvLength, tlvValue);
369 uint8_t buf[251] = {0};
370 size_t buflen = 0;
372 if (!HexToBuffer("TLV Error type:", tlvTag, buf, 4, &buflen)) {
373 json_decref(root);
374 return false;
376 tlv_tag_t tag = 0;
377 for (int j = 0; j < buflen; j++) {
378 tag = (tag << 8) | buf[j];
381 if (!HexToBuffer("TLV Error value:", tlvValue, buf, sizeof(buf) - 1, &buflen)) {
382 json_decref(root);
383 return false;
386 if (buflen != tlvLength) {
387 PrintAndLogEx(ERR, "Load params: data [%d] length of HEX must(%zu) be identical to length in TLV param(%d)", i + 1, buflen, tlvLength);
388 json_decref(root);
389 return false;
392 tlvdb_change_or_add_node(tlv, tag, tlvLength, (const unsigned char *)buf);
395 json_decref(root);
397 return true;