]> git.zerfleddert.de Git - proxmark3-svn/blame_incremental - client/emv/emvjson.c
Code improved for less memory
[proxmark3-svn] / client / emv / emvjson.c
... / ...
CommitLineData
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//-----------------------------------------------------------------------------
10
11#include "emvjson.h"
12#include <ctype.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <inttypes.h>
16#include <string.h>
17#include "util.h"
18#include "ui.h"
19#include "proxmark3.h"
20#include "emv_tags.h"
21
22static const ApplicationDataElm ApplicationData[] = {
23{0x82, "AIP"},
24{0x94, "AFL"},
25
26{0x5A, "PAN"},
27{0x5F34, "PANSeqNo"},
28{0x5F24, "ExpirationDate"},
29{0x5F25, "EffectiveDate"},
30{0x5F28, "IssuerCountryCode"},
31
32{0x50, "ApplicationLabel"},
33{0x9F08, "VersionNumber"},
34{0x9F42, "CurrencyCode"},
35{0x5F2D, "LanguagePreference"},
36{0x87, "PriorityIndicator"},
37{0x9F36, "ATC"}, //Application Transaction Counter
38
39{0x5F20, "CardholderName"},
40
41{0x9F38, "PDOL"},
42{0x8C, "CDOL1"},
43{0x8D, "CDOL2"},
44
45{0x9F07, "AUC"}, // Application Usage Control
46{0x9F6C, "CTQ"},
47{0x8E, "CVMList"},
48{0x9F0D, "IACDefault"},
49{0x9F0E, "IACDeny"},
50{0x9F0F, "IACOnline"},
51
52{0x8F, "CertificationAuthorityPublicKeyIndex"},
53{0x9F32, "IssuerPublicKeyExponent"},
54{0x92, "IssuerPublicKeyRemainder"},
55{0x90, "IssuerPublicKeyCertificate"},
56{0x9F47, "ICCPublicKeyExponent"},
57{0x9F46, "ICCPublicKeyCertificate"},
58
59{0x00, "end..."}
60};
61int ApplicationDataLen = sizeof(ApplicationData) / sizeof(ApplicationDataElm);
62
63char* GetApplicationDataName(tlv_tag_t tag) {
64 for (int i = 0; i < ApplicationDataLen; i++)
65 if (ApplicationData[i].Tag == tag)
66 return ApplicationData[i].Name;
67
68 return NULL;
69}
70
71int JsonSaveJsonObject(json_t *root, char *path, json_t *value) {
72 json_error_t error;
73
74 if (strlen(path) < 1)
75 return 1;
76
77 if (path[0] == '$') {
78 if (json_path_set(root, path, value, 0, &error)) {
79 PrintAndLog("ERROR: can't set json path: ", error.text);
80 return 2;
81 } else {
82 return 0;
83 }
84 } else {
85 return json_object_set_new(root, path, value);
86 }
87}
88
89int JsonSaveInt(json_t *root, char *path, int value) {
90 return JsonSaveJsonObject(root, path, json_integer(value));
91}
92
93int JsonSaveStr(json_t *root, char *path, char *value) {
94 return JsonSaveJsonObject(root, path, json_string(value));
95};
96
97int 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';
101
102 return JsonSaveStr(elm, path, msg);
103}
104
105int 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';
109
110 return JsonSaveStr(elm, path, msg);
111}
112
113int JsonSaveHex(json_t *elm, char *path, uint64_t data, int datalen) {
114 uint8_t bdata[8] = {0};
115 int len = 0;
116 if (!datalen) {
117 for (uint64_t u = 0xffffffffffffffff; u; u = u << 8) {
118 if (!(data & u)) {
119 break;
120 }
121 len++;
122 }
123 if (!len)
124 len = 1;
125 } else {
126 len = datalen;
127 }
128 num_to_bytes(data, len, bdata);
129
130 return JsonSaveBufAsHex(elm, path, bdata, len);
131}
132
133int JsonSaveTLVValue(json_t *root, char *path, struct tlvdb *tlvdbelm) {
134 const struct tlv *tlvelm = tlvdb_get_tlv(tlvdbelm);
135 if (tlvelm)
136 return JsonSaveBufAsHex(root, path, (uint8_t *)tlvelm->value, tlvelm->len);
137 else
138 return 1;
139}
140
141int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, bool saveValue, bool saveAppDataLink) {
142 json_error_t error;
143
144 if (strlen(path) < 1 || !tlvelm)
145 return 1;
146
147 if (path[0] == '$') {
148
149 json_t *obj = json_path_get(elm, path);
150 if (!obj) {
151 obj = json_object();
152
153 if (json_is_array(elm)) {
154 if (json_array_append_new(elm, obj)) {
155 PrintAndLog("ERROR: can't append array: %s", path);
156 return 2;
157 }
158 } else {
159 if (json_path_set(elm, path, obj, 0, &error)) {
160 PrintAndLog("ERROR: can't set json path: ", error.text);
161 return 2;
162 }
163 }
164 }
165
166 if (saveAppDataLink) {
167 char * AppDataName = GetApplicationDataName(tlvelm->tag);
168 if (AppDataName)
169 JsonSaveStr(obj, "appdata", AppDataName);
170 } else {
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);
175 if (saveValue) {
176 JsonSaveHex(obj, "length", tlvelm->len, 0);
177 JsonSaveBufAsHex(obj, "value", (uint8_t *)tlvelm->value, tlvelm->len);
178 };
179 }
180 }
181
182 return 0;
183}
184
185int 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);
187}
188
189int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm) {
190 struct tlvdb *tlvp = tlvdbelm;
191 while (tlvp) {
192 const struct tlv * tlvpelm = tlvdb_get_tlv(tlvp);
193 char * AppDataName = NULL;
194 if (tlvpelm)
195 AppDataName = GetApplicationDataName(tlvpelm->tag);
196
197 if (AppDataName) {
198 char appdatalink[200] = {0};
199 sprintf(appdatalink, "$.ApplicationData.%s", AppDataName);
200 JsonSaveBufAsHex(root, appdatalink, (uint8_t *)tlvpelm->value, tlvpelm->len);
201 }
202
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);
208 pelm = appendelm;
209 } else {
210 JsonSaveTLVTreeElm(elm, path, tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
211 pelm = json_path_get(elm, path);
212 }
213
214 if (tlvdb_elm_get_children(tlvp)) {
215 // get path element
216 if(!pelm)
217 return 1;
218
219 // check childs element and add it if not found
220 json_t *chjson = json_path_get(pelm, "$.Childs");
221 if (!chjson) {
222 json_object_set_new(pelm, "Childs", json_array());
223
224 chjson = json_path_get(pelm, "$.Childs");
225 }
226
227 // check
228 if (!json_is_array(chjson)) {
229 PrintAndLog("E->Internal logic error. `$.Childs` is not an array.");
230 break;
231 }
232
233 // Recursion
234 JsonSaveTLVTree(root, chjson, "$", tlvdb_elm_get_children(tlvp));
235 }
236
237 tlvp = tlvdb_elm_get_next(tlvp);
238 }
239 return 0;
240}
241
242bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, size_t maxbufferlen, size_t *bufferlen) {
243 int buflen = 0;
244
245 switch(param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) {
246 case 1:
247 PrintAndLog("%s Invalid HEX value.", errormsg);
248 return false;
249 case 2:
250 PrintAndLog("%s Hex value too large.", errormsg);
251 return false;
252 case 3:
253 PrintAndLog("%s Hex value must have even number of digits.", errormsg);
254 return false;
255 }
256
257 if (buflen > maxbufferlen) {
258 PrintAndLog("%s HEX length (%d) more than %d", errormsg, *bufferlen, maxbufferlen);
259 return false;
260 }
261
262 *bufferlen = buflen;
263
264 return true;
265}
266
267int JsonLoadStr(json_t *root, char *path, char *value) {
268 if (!value)
269 return 1;
270
271 json_t *jelm = json_path_get((const json_t *)root, path);
272 if (!jelm || !json_is_string(jelm))
273 return 2;
274
275 const char * strval = json_string_value(jelm);
276 if (!strval)
277 return 1;
278
279 memcpy(value, strval, strlen(strval));
280
281 return 0;
282}
283
284int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen) {
285 if (datalen)
286 *datalen = 0;
287
288 json_t *jelm = json_path_get((const json_t *)elm, path);
289 if (!jelm || !json_is_string(jelm))
290 return 1;
291
292 if (!HexToBuffer("ERROR load", json_string_value(jelm), data, maxbufferlen, datalen))
293 return 2;
294
295 return 0;
296};
297
298bool ParamLoadFromJson(struct tlvdb *tlv) {
299 json_t *root;
300 json_error_t error;
301
302 if (!tlv) {
303 PrintAndLog("ERROR load params: tlv tree is NULL.");
304 return false;
305 }
306
307 // current path + file name
308 const char *relfname = "emv/defparams.json";
309 char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
310 strcpy(fname, get_my_executable_directory());
311 strcat(fname, relfname);
312
313 root = json_load_file(fname, 0, &error);
314 if (!root) {
315 PrintAndLog("Load params: json error on line %d: %s", error.line, error.text);
316 return false;
317 }
318
319 if (!json_is_array(root)) {
320 PrintAndLog("Load params: Invalid json format. root must be array.");
321 return false;
322 }
323
324 PrintAndLog("Load params: json(%d) OK", json_array_size(root));
325
326 for(int i = 0; i < json_array_size(root); i++) {
327 json_t *data, *jtag, *jlength, *jvalue;
328
329 data = json_array_get(root, i);
330 if(!json_is_object(data))
331 {
332 PrintAndLog("Load params: data [%d] is not an object", i + 1);
333 json_decref(root);
334 return false;
335 }
336
337 jtag = json_object_get(data, "tag");
338 if(!json_is_string(jtag))
339 {
340 PrintAndLog("Load params: data [%d] tag is not a string", i + 1);
341 json_decref(root);
342 return false;
343 }
344 const char *tlvTag = json_string_value(jtag);
345
346 jvalue = json_object_get(data, "value");
347 if(!json_is_string(jvalue))
348 {
349 PrintAndLog("Load params: data [%d] value is not a string", i + 1);
350 json_decref(root);
351 return false;
352 }
353 const char *tlvValue = json_string_value(jvalue);
354
355 jlength = json_object_get(data, "length");
356 if(!json_is_number(jlength))
357 {
358 PrintAndLog("Load params: data [%d] length is not a number", i + 1);
359 json_decref(root);
360 return false;
361 }
362
363 int tlvLength = json_integer_value(jlength);
364 if (tlvLength > 250) {
365 PrintAndLog("Load params: data [%d] length more than 250", i + 1);
366 json_decref(root);
367 return false;
368 }
369
370 PrintAndLog("TLV param: %s[%d]=%s", tlvTag, tlvLength, tlvValue);
371 uint8_t buf[251] = {0};
372 size_t buflen = 0;
373
374 // 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...
375 if (!HexToBuffer("TLV Error type:", tlvTag, buf, 2, &buflen)) {
376 json_decref(root);
377 return false;
378 }
379 tlv_tag_t tag = 0;
380 for (int i = 0; i < buflen; i++) {
381 tag = (tag << 8) + buf[i];
382 }
383
384 if (!HexToBuffer("TLV Error value:", tlvValue, buf, sizeof(buf) - 1, &buflen)) {
385 json_decref(root);
386 return false;
387 }
388
389 if (buflen != tlvLength) {
390 PrintAndLog("Load params: data [%d] length of HEX must(%d) be identical to length in TLV param(%d)", i + 1, buflen, tlvLength);
391 json_decref(root);
392 return false;
393 }
394
395 tlvdb_change_or_add_node(tlv, tag, tlvLength, (const unsigned char *)buf);
396 }
397
398 json_decref(root);
399
400 return true;
401}
402
Impressum, Datenschutz