022974358c4d04d0256a97faeef4334a2864aa86
[proxmark3-svn] / client / emv / emvjson.c
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
22 static 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 };
61 int ApplicationDataLen = sizeof(ApplicationData) / sizeof(ApplicationDataElm);
62
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;
67
68 return NULL;
69 }
70
71 int JsonSaveStr(json_t *root, char *path, char *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, json_string(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, json_string(value));
86 }
87 };
88
89 int JsonSaveBufAsHex(json_t *elm, char *path, uint8_t *data, size_t datalen) {
90 char * msg = sprint_hex(data, datalen);
91 if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
92 msg[strlen(msg) - 1] = '\0';
93
94 return JsonSaveStr(elm, path, msg);
95 }
96
97 int JsonSaveHex(json_t *elm, char *path, uint64_t data, int datalen) {
98 uint8_t bdata[8] = {0};
99 int len = 0;
100 if (!datalen) {
101 for (uint64_t u = 0xffffffffffffffff; u; u = u << 8) {
102 if (!(data & u)) {
103 break;
104 }
105 len++;
106 }
107 if (!len)
108 len = 1;
109 } else {
110 len = datalen;
111 }
112 num_to_bytes(data, len, bdata);
113
114 return JsonSaveBufAsHex(elm, path, bdata, len);
115 }
116
117 int JsonSaveTLVValue(json_t *root, char *path, struct tlvdb *tlvdbelm) {
118 const struct tlv *tlvelm = tlvdb_get_tlv(tlvdbelm);
119 if (tlvelm)
120 return JsonSaveBufAsHex(root, path, (uint8_t *)tlvelm->value, tlvelm->len);
121 else
122 return 1;
123 }
124
125 int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, bool saveValue, bool saveAppDataLink) {
126 json_error_t error;
127
128 if (strlen(path) < 1 || !tlvelm)
129 return 1;
130
131 if (path[0] == '$') {
132
133 json_t *obj = json_path_get(elm, path);
134 if (!obj) {
135 obj = json_object();
136
137 if (json_is_array(elm)) {
138 if (json_array_append_new(elm, obj)) {
139 PrintAndLog("ERROR: can't append array: %s", path);
140 return 2;
141 }
142 } else {
143 if (json_path_set(elm, path, obj, 0, &error)) {
144 PrintAndLog("ERROR: can't set json path: ", error.text);
145 return 2;
146 }
147 }
148 }
149
150 if (saveAppDataLink) {
151 char * AppDataName = GetApplicationDataName(tlvelm->tag);
152 if (AppDataName)
153 JsonSaveStr(obj, "appdata", AppDataName);
154 } else {
155 char * name = emv_get_tag_name(tlvelm);
156 if (saveName && name && strlen(name) > 0 && strncmp(name, "Unknown", 7))
157 JsonSaveStr(obj, "name", emv_get_tag_name(tlvelm));
158 JsonSaveHex(obj, "tag", tlvelm->tag, 0);
159 if (saveValue) {
160 JsonSaveHex(obj, "length", tlvelm->len, 0);
161 JsonSaveBufAsHex(obj, "value", (uint8_t *)tlvelm->value, tlvelm->len);
162 };
163 }
164 }
165
166 return 0;
167 }
168
169 int JsonSaveTLVTreeElm(json_t *elm, char *path, struct tlvdb *tlvdbelm, bool saveName, bool saveValue, bool saveAppDataLink) {
170 return JsonSaveTLVElm(elm, path, (struct tlv *)tlvdb_get_tlv(tlvdbelm), saveName, saveValue, saveAppDataLink);
171 }
172
173 int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm) {
174 struct tlvdb *tlvp = tlvdbelm;
175 while (tlvp) {
176 const struct tlv * tlvpelm = tlvdb_get_tlv(tlvp);
177 char * AppDataName = NULL;
178 if (tlvpelm)
179 AppDataName = GetApplicationDataName(tlvpelm->tag);
180
181 if (AppDataName) {
182 char appdatalink[200] = {0};
183 sprintf(appdatalink, "$.ApplicationData.%s", AppDataName);
184 JsonSaveBufAsHex(root, appdatalink, (uint8_t *)tlvpelm->value, tlvpelm->len);
185 }
186
187 json_t *pelm = json_path_get(elm, path);
188 if (pelm && json_is_array(pelm)) {
189 json_t *appendelm = json_object();
190 json_array_append_new(pelm, appendelm);
191 JsonSaveTLVTreeElm(appendelm, "$", tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
192 pelm = appendelm;
193 } else {
194 JsonSaveTLVTreeElm(elm, path, tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
195 pelm = json_path_get(elm, path);
196 }
197
198 if (tlvdb_elm_get_children(tlvp)) {
199 // get path element
200 if(!pelm)
201 return 1;
202
203 // check childs element and add it if not found
204 json_t *chjson = json_path_get(pelm, "$.Childs");
205 if (!chjson) {
206 json_object_set_new(pelm, "Childs", json_array());
207
208 chjson = json_path_get(pelm, "$.Childs");
209 }
210
211 // check
212 if (!json_is_array(chjson)) {
213 PrintAndLog("E->Internal logic error. `$.Childs` is not an array.");
214 break;
215 }
216
217 // Recursion
218 JsonSaveTLVTree(root, chjson, "$", tlvdb_elm_get_children(tlvp));
219 }
220
221 tlvp = tlvdb_elm_get_next(tlvp);
222 }
223 return 0;
224 }
225
226 bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, size_t maxbufferlen, size_t *bufferlen) {
227 int buflen = 0;
228
229 switch(param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) {
230 case 1:
231 PrintAndLog("%s Invalid HEX value.", errormsg);
232 return false;
233 case 2:
234 PrintAndLog("%s Hex value too large.", errormsg);
235 return false;
236 case 3:
237 PrintAndLog("%s Hex value must have even number of digits.", errormsg);
238 return false;
239 }
240
241 if (buflen > maxbufferlen) {
242 PrintAndLog("%s HEX length (%d) more than %d", errormsg, *bufferlen, maxbufferlen);
243 return false;
244 }
245
246 *bufferlen = buflen;
247
248 return true;
249 }
250
251 bool ParamLoadFromJson(struct tlvdb *tlv) {
252 json_t *root;
253 json_error_t error;
254
255 if (!tlv) {
256 PrintAndLog("ERROR load params: tlv tree is NULL.");
257 return false;
258 }
259
260 // current path + file name
261 const char *relfname = "emv/defparams.json";
262 char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
263 strcpy(fname, get_my_executable_directory());
264 strcat(fname, relfname);
265
266 root = json_load_file(fname, 0, &error);
267 if (!root) {
268 PrintAndLog("Load params: json error on line %d: %s", error.line, error.text);
269 return false;
270 }
271
272 if (!json_is_array(root)) {
273 PrintAndLog("Load params: Invalid json format. root must be array.");
274 return false;
275 }
276
277 PrintAndLog("Load params: json(%d) OK", json_array_size(root));
278
279 for(int i = 0; i < json_array_size(root); i++) {
280 json_t *data, *jtag, *jlength, *jvalue;
281
282 data = json_array_get(root, i);
283 if(!json_is_object(data))
284 {
285 PrintAndLog("Load params: data [%d] is not an object", i + 1);
286 json_decref(root);
287 return false;
288 }
289
290 jtag = json_object_get(data, "tag");
291 if(!json_is_string(jtag))
292 {
293 PrintAndLog("Load params: data [%d] tag is not a string", i + 1);
294 json_decref(root);
295 return false;
296 }
297 const char *tlvTag = json_string_value(jtag);
298
299 jvalue = json_object_get(data, "value");
300 if(!json_is_string(jvalue))
301 {
302 PrintAndLog("Load params: data [%d] value is not a string", i + 1);
303 json_decref(root);
304 return false;
305 }
306 const char *tlvValue = json_string_value(jvalue);
307
308 jlength = json_object_get(data, "length");
309 if(!json_is_number(jlength))
310 {
311 PrintAndLog("Load params: data [%d] length is not a number", i + 1);
312 json_decref(root);
313 return false;
314 }
315
316 int tlvLength = json_integer_value(jlength);
317 if (tlvLength > 250) {
318 PrintAndLog("Load params: data [%d] length more than 250", i + 1);
319 json_decref(root);
320 return false;
321 }
322
323 PrintAndLog("TLV param: %s[%d]=%s", tlvTag, tlvLength, tlvValue);
324 uint8_t buf[251] = {0};
325 size_t buflen = 0;
326
327 // 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...
328 if (!HexToBuffer("TLV Error type:", tlvTag, buf, 2, &buflen)) {
329 json_decref(root);
330 return false;
331 }
332 tlv_tag_t tag = 0;
333 for (int i = 0; i < buflen; i++) {
334 tag = (tag << 8) + buf[i];
335 }
336
337 if (!HexToBuffer("TLV Error value:", tlvValue, buf, sizeof(buf) - 1, &buflen)) {
338 json_decref(root);
339 return false;
340 }
341
342 if (buflen != tlvLength) {
343 PrintAndLog("Load params: data [%d] length of HEX must(%d) be identical to length in TLV param(%d)", i + 1, buflen, tlvLength);
344 json_decref(root);
345 return false;
346 }
347
348 tlvdb_change_or_add_node(tlv, tag, tlvLength, (const unsigned char *)buf);
349 }
350
351 json_decref(root);
352
353 return true;
354 }
355
Impressum, Datenschutz