]> git.zerfleddert.de Git - proxmark3-svn/blame - client/emv/emvcore.c
restore #755 reverted after #757 (#761)
[proxmark3-svn] / client / emv / emvcore.c
CommitLineData
a2bb2735 1//-----------------------------------------------------------------------------
2// Copyright (C) 2017 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 core functions
9//-----------------------------------------------------------------------------
10
11#include "emvcore.h"
95b697f0 12#include "emvjson.h"
8fa68384 13#include "util_posix.h"
8d7d7b61 14#ifdef WITH_SMARTCARD
15#include "cmdsmartcard.h"
16#endif
a2bb2735 17
3c5fce2b
OM
18// Got from here. Thanks)
19// https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix
151a33c0 20static const char *PSElist [] = {
3c5fce2b
OM
21 "325041592E5359532E4444463031", // 2PAY.SYS.DDF01 - Visa Proximity Payment System Environment - PPSE
22 "315041592E5359532E4444463031" // 1PAY.SYS.DDF01 - Visa Payment System Environment - PSE
23};
d03fb293 24//static const size_t PSElistLen = sizeof(PSElist)/sizeof(char*);
3c5fce2b 25
95b697f0
OM
26char *TransactionTypeStr[] = {
27 "MSD",
28 "VSDC",
29 "qVCDCMCHIP",
30 "CDA"
31};
32
87fc2dad 33typedef struct {
34 enum CardPSVendor vendor;
35 const char* aid;
36} TAIDList;
37
151a33c0 38static const TAIDList AIDlist [] = {
3c5fce2b 39 // Visa International
151a33c0 40 { CV_VISA, "A00000000305076010"}, // VISA ELO Credit
41 { CV_VISA, "A0000000031010" }, // VISA Debit/Credit (Classic)
42 { CV_VISA, "A000000003101001" }, // VISA Credit
43 { CV_VISA, "A000000003101002" }, // VISA Debit
87fc2dad 44 { CV_VISA, "A0000000032010" }, // VISA Electron
151a33c0 45 { CV_VISA, "A0000000032020" }, // VISA
46 { CV_VISA, "A0000000033010" }, // VISA Interlink
47 { CV_VISA, "A0000000034010" }, // VISA Specific
48 { CV_VISA, "A0000000035010" }, // VISA Specific
49 { CV_VISA, "A0000000036010" }, // Domestic Visa Cash Stored Value
50 { CV_VISA, "A0000000036020" }, // International Visa Cash Stored Value
51 { CV_VISA, "A0000000038002" }, // VISA Auth, VisaRemAuthen EMV-CAP (DPA)
52 { CV_VISA, "A0000000038010" }, // VISA Plus
53 { CV_VISA, "A0000000039010" }, // VISA Loyalty
54 { CV_VISA, "A000000003999910" }, // VISA Proprietary ATM
3c5fce2b 55 // Visa USA
87fc2dad 56 { CV_VISA, "A000000098" }, // Debit Card
57 { CV_VISA, "A0000000980848" }, // Debit Card
3c5fce2b 58 // Mastercard International
151a33c0 59 { CV_MASTERCARD, "A00000000401" }, // MasterCard PayPass
87fc2dad 60 { CV_MASTERCARD, "A0000000041010" }, // MasterCard Credit
61 { CV_MASTERCARD, "A00000000410101213" }, // MasterCard Credit
62 { CV_MASTERCARD, "A00000000410101215" }, // MasterCard Credit
63 { CV_MASTERCARD, "A0000000042010" }, // MasterCard Specific
64 { CV_MASTERCARD, "A0000000043010" }, // MasterCard Specific
65 { CV_MASTERCARD, "A0000000043060" }, // Maestro (Debit)
66 { CV_MASTERCARD, "A000000004306001" }, // Maestro (Debit)
67 { CV_MASTERCARD, "A0000000044010" }, // MasterCard Specific
68 { CV_MASTERCARD, "A0000000045010" }, // MasterCard Specific
69 { CV_MASTERCARD, "A0000000046000" }, // Cirrus
70 { CV_MASTERCARD, "A0000000048002" }, // SecureCode Auth EMV-CAP
151a33c0 71 { CV_MASTERCARD, "A0000000049999" }, // MasterCard PayPass
3c5fce2b 72 // American Express
87fc2dad 73 { CV_AMERICANEXPRESS, "A000000025" },
74 { CV_AMERICANEXPRESS, "A0000000250000" },
75 { CV_AMERICANEXPRESS, "A00000002501" },
76 { CV_AMERICANEXPRESS, "A000000025010402" },
77 { CV_AMERICANEXPRESS, "A000000025010701" },
78 { CV_AMERICANEXPRESS, "A000000025010801" },
3c5fce2b 79 // Groupement des Cartes Bancaires "CB"
151a33c0 80 { CV_CB, "A0000000421010" }, // Cartes Bancaire EMV Card
81 { CV_CB, "A0000000422010" },
82 { CV_CB, "A0000000423010" },
83 { CV_CB, "A0000000424010" },
84 { CV_CB, "A0000000425010" },
3c5fce2b 85 // JCB CO., LTD.
151a33c0 86 { CV_JCB, "A00000006510" }, // JCB
87 { CV_JCB, "A0000000651010" }, // JCB J Smart Credit
87fc2dad 88 // Other
89 { CV_OTHER, "A0000001544442" }, // Banricompras Debito - Banrisul - Banco do Estado do Rio Grande do SUL - S.A.
90 { CV_OTHER, "F0000000030001" }, // BRADESCO
91 { CV_OTHER, "A0000005241010" }, // RuPay - RuPay
92 { CV_OTHER, "D5780000021010" } // Bankaxept - Bankaxept
3c5fce2b 93};
87fc2dad 94static const size_t AIDlistLen = sizeof(AIDlist)/sizeof(TAIDList);
3c5fce2b
OM
95
96static bool APDULogging = false;
97void SetAPDULogging(bool logging) {
98 APDULogging = logging;
99}
100
87fc2dad 101enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen) {
102 char buf[100] = {0};
103 if (AIDlen < 1)
104 return CV_NA;
105
106 hex_to_buffer((uint8_t *)buf, AID, AIDlen, sizeof(buf) - 1, 0, 0, true);
107
108 for(int i = 0; i < AIDlistLen; i ++) {
109 if (strncmp(AIDlist[i].aid, buf, strlen(AIDlist[i].aid)) == 0){
110 return AIDlist[i].vendor;
111 }
151a33c0 112 }
113
87fc2dad 114 return CV_NA;
115}
116
33a9982c 117static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) {
43912d63 118 emv_tag_dump(tlv, stdout, level);
33a9982c 119 if (is_leaf) {
120 dump_buffer(tlv->value, tlv->len, stdout, level);
121 }
a2bb2735 122
123 return true;
124}
125
126void TLVPrintFromBuffer(uint8_t *data, int datalen) {
127 struct tlvdb *t = NULL;
23207d74 128 t = tlvdb_parse_multi(data, datalen);
a2bb2735 129 if (t) {
151a33c0 130 PrintAndLogEx(NORMAL, "-------------------- TLV decoded --------------------");
131
43912d63 132 tlvdb_visit(t, print_cb, NULL, 0);
a2bb2735 133 tlvdb_free(t);
134 } else {
151a33c0 135 PrintAndLogEx(WARNING, "TLV ERROR: Can't parse response as TLV tree.");
a2bb2735 136 }
137}
3c5fce2b 138
87fc2dad 139void TLVPrintFromTLVLev(struct tlvdb *tlv, int level) {
151a33c0 140 if (!tlv)
3c5fce2b 141 return;
151a33c0 142
87fc2dad 143 tlvdb_visit(tlv, print_cb, NULL, level);
144}
145
146void TLVPrintFromTLV(struct tlvdb *tlv) {
147 TLVPrintFromTLVLev(tlv, 0);
3c5fce2b
OM
148}
149
150void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv) {
151a33c0 151 PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|");
152 PrintAndLogEx(NORMAL, "| AID |Priority| Name |");
153 PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|");
3c5fce2b
OM
154
155 struct tlvdb *ttmp = tlvdb_find(tlv, 0x6f);
156 if (!ttmp)
151a33c0 157 PrintAndLogEx(NORMAL, "| none |");
158
3c5fce2b
OM
159 while (ttmp) {
160 const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x84, NULL);
161 const struct tlv *tgName = tlvdb_get_inchild(ttmp, 0x50, NULL);
162 const struct tlv *tgPrio = tlvdb_get_inchild(ttmp, 0x87, NULL);
163 if (!tgAID)
164 break;
151a33c0 165 PrintAndLogEx(NORMAL, "|%s| %s |%s|",
166 sprint_hex_inrow_ex(tgAID->value, tgAID->len, 18),
167 (tgPrio) ? sprint_hex(tgPrio->value, 1) : " ",
3c5fce2b 168 (tgName) ? sprint_ascii_ex(tgName->value, tgName->len, 25) : " ");
151a33c0 169
3c5fce2b
OM
170 ttmp = tlvdb_find_next(ttmp, 0x6f);
171 }
172
151a33c0 173 PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|");
3c5fce2b
OM
174}
175
87fc2dad 176struct tlvdb *GetPANFromTrack2(const struct tlv *track2) {
177 char track2Hex[200] = {0};
178 uint8_t PAN[100] = {0};
179 int PANlen = 0;
180 char *tmp = track2Hex;
3c5fce2b 181
87fc2dad 182 if (!track2)
183 return NULL;
184
185 for (int i = 0; i < track2->len; ++i, tmp += 2)
186 sprintf(tmp, "%02x", (unsigned int)track2->value[i]);
151a33c0 187
87fc2dad 188 int posD = strchr(track2Hex, 'd') - track2Hex;
189 if (posD < 1)
190 return NULL;
151a33c0 191
87fc2dad 192 track2Hex[posD] = 0;
193 if (strlen(track2Hex) % 2) {
194 track2Hex[posD] = 'F';
195 track2Hex[posD + 1] = '\0';
196 }
151a33c0 197
87fc2dad 198 param_gethex_to_eol(track2Hex, 0, PAN, sizeof(PAN), &PANlen);
151a33c0 199
87fc2dad 200 return tlvdb_fixed(0x5a, PANlen, PAN);
201}
202
203struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) {
204 char track2Hex[200] = {0};
205 char dCVVHex[100] = {0};
206 uint8_t dCVV[100] = {0};
207 int dCVVlen = 0;
208 const int PINlen = 5; // must calculated from 9F67 MSD Offset but i have not seen this tag)
209 char *tmp = track2Hex;
151a33c0 210
87fc2dad 211 if (!track2)
212 return NULL;
151a33c0 213
87fc2dad 214 for (int i = 0; i < track2->len; ++i, tmp += 2)
215 sprintf(tmp, "%02x", (unsigned int)track2->value[i]);
151a33c0 216
87fc2dad 217 int posD = strchr(track2Hex, 'd') - track2Hex;
218 if (posD < 1)
219 return NULL;
220
221 memset(dCVVHex, '0', 32);
222 // ATC
223 memcpy(dCVVHex + 0, track2Hex + posD + PINlen + 11, 4);
224 // PAN 5 hex
225 memcpy(dCVVHex + 4, track2Hex, 5);
226 // expire date
227 memcpy(dCVVHex + 9, track2Hex + posD + 1, 4);
228 // service code
229 memcpy(dCVVHex + 13, track2Hex + posD + 5, 3);
151a33c0 230
87fc2dad 231 param_gethex_to_eol(dCVVHex, 0, dCVV, sizeof(dCVV), &dCVVlen);
151a33c0 232
87fc2dad 233 return tlvdb_fixed(0x02, dCVVlen, dCVV);
234}
235
8d7d7b61 236int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
3c5fce2b 237 uint8_t data[APDU_RES_LEN] = {0};
87fc2dad 238
3c5fce2b
OM
239 *ResultLen = 0;
240 if (sw) *sw = 0;
241 uint16_t isw = 0;
8d7d7b61 242 int res = 0;
151a33c0 243
244 if (ActivateField) {
3c5fce2b 245 DropField();
8fa68384
OM
246 msleep(50);
247 }
151a33c0 248
87fc2dad 249 // COMPUTE APDU
250 memcpy(data, &apdu, 5);
251 if (apdu.data)
252 memcpy(&data[5], apdu.data, apdu.Lc);
151a33c0 253
3c5fce2b 254 if (APDULogging)
151a33c0 255 PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc));
3c5fce2b 256
8d7d7b61 257 switch(channel) {
258 case ECC_CONTACTLESS:
259 // 6 byes + data = INS + CLA + P1 + P2 + Lc + <data = Nc> + Le(?IncludeLe)
260 res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
261 if (res) {
262 return res;
263 }
264 break;
265 case ECC_CONTACT:
266 //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
151a33c0 267#ifdef WITH_SMARTCARD
8d7d7b61 268 res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
269 if (res) {
270 return res;
271 }
272#endif
273 break;
3c5fce2b 274 }
87fc2dad 275
10d4f823 276 if (APDULogging)
151a33c0 277 PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen));
10d4f823 278
8d7d7b61 279 if (*ResultLen < 2) {
280 return 200;
281 }
151a33c0 282
3c5fce2b
OM
283 *ResultLen -= 2;
284 isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1];
285 if (sw)
286 *sw = isw;
287
288 if (isw != 0x9000) {
39cc1c87
OM
289 if (APDULogging) {
290 if (*sw >> 8 == 0x61) {
151a33c0 291 PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff);
39cc1c87 292 } else {
151a33c0 293 PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff));
39cc1c87
OM
294 return 5;
295 }
296 }
3c5fce2b
OM
297 }
298
299 // add to tlv tree
300 if (tlv) {
301 struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen);
302 tlvdb_add(tlv, t);
303 }
151a33c0 304
3c5fce2b
OM
305 return 0;
306}
307
8d7d7b61 308int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
151a33c0 309 return EMVExchangeEx(channel, false, LeaveFieldON, apdu, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv);
87fc2dad 310}
311
8d7d7b61 312int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
151a33c0 313 return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv);
87fc2dad 314}
315
8d7d7b61 316int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
3c5fce2b
OM
317 uint8_t buf[APDU_AID_LEN] = {0};
318 *ResultLen = 0;
319 int len = 0;
320 int res = 0;
321 switch (PSENum) {
322 case 1:
323 param_gethex_to_eol(PSElist[1], 0, buf, sizeof(buf), &len);
324 break;
325 case 2:
326 param_gethex_to_eol(PSElist[0], 0, buf, sizeof(buf), &len);
327 break;
328 default:
329 return -1;
330 }
151a33c0 331
3c5fce2b 332 // select
8d7d7b61 333 res = EMVSelect(channel, ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL);
3c5fce2b
OM
334
335 return res;
336}
337
8d7d7b61 338int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
3c5fce2b
OM
339 uint8_t data[APDU_RES_LEN] = {0};
340 size_t datalen = 0;
341 uint16_t sw = 0;
342 int res;
343
344 // select PPSE
8d7d7b61 345 res = EMVSelectPSE(channel, ActivateField, true, 2, data, sizeof(data), &datalen, &sw);
3c5fce2b
OM
346
347 if (!res){
348 struct tlvdb *t = NULL;
349 t = tlvdb_parse_multi(data, datalen);
350 if (t) {
351 int retrycnt = 0;
352 struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00});
353 if (!ttmp)
151a33c0 354 PrintAndLogEx(FAILED, "PPSE don't have records.");
355
3c5fce2b
OM
356 while (ttmp) {
357 const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL);
358 if (tgAID) {
8d7d7b61 359 res = EMVSelect(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv);
3c5fce2b
OM
360
361 // retry if error and not returned sw error
362 if (res && res != 5) {
363 if (++retrycnt < 3){
364 continue;
365 } else {
366 // card select error, proxmark error
367 if (res == 1) {
151a33c0 368 PrintAndLogEx(WARNING, "Exit...");
3c5fce2b
OM
369 return 1;
370 }
151a33c0 371
3c5fce2b 372 retrycnt = 0;
151a33c0 373 PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(tgAID->value, tgAID->len));
3c5fce2b 374 }
151a33c0 375
3c5fce2b
OM
376 // next element
377 ttmp = tlvdb_find_next(ttmp, 0x61);
378 continue;
379 }
380 retrycnt = 0;
381
382 // all is ok
383 if (decodeTLV){
151a33c0 384 PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len));
3c5fce2b
OM
385 TLVPrintFromBuffer(data, datalen);
386 }
387 }
151a33c0 388
3c5fce2b
OM
389 ttmp = tlvdb_find_next(ttmp, 0x61);
390 }
391
392 tlvdb_free(t);
393 } else {
151a33c0 394 PrintAndLogEx(WARNING, "PPSE ERROR: Can't get TLV from response.");
395 }
3c5fce2b 396 } else {
151a33c0 397 PrintAndLogEx(WARNING, "PPSE ERROR: Can't select PPSE AID. Error: %d", res);
3c5fce2b 398 }
151a33c0 399
3c5fce2b
OM
400 if(!LeaveFieldON)
401 DropField();
151a33c0 402
3c5fce2b
OM
403 return res;
404}
405
8d7d7b61 406int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) {
3c5fce2b
OM
407 uint8_t aidbuf[APDU_AID_LEN] = {0};
408 int aidlen = 0;
409 uint8_t data[APDU_RES_LEN] = {0};
410 size_t datalen = 0;
411 uint16_t sw = 0;
151a33c0 412
3c5fce2b
OM
413 int res = 0;
414 int retrycnt = 0;
415 for(int i = 0; i < AIDlistLen; i ++) {
87fc2dad 416 param_gethex_to_eol(AIDlist[i].aid, 0, aidbuf, sizeof(aidbuf), &aidlen);
8d7d7b61 417 res = EMVSelect(channel, (i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv);
3c5fce2b
OM
418 // retry if error and not returned sw error
419 if (res && res != 5) {
420 if (++retrycnt < 3){
421 i--;
422 } else {
8d7d7b61 423 // (1) - card select error, proxmark error OR (200) - result length = 0
424 if (res == 1 || res == 200) {
151a33c0 425 PrintAndLogEx(WARNING, "Exit...");
3c5fce2b
OM
426 return 1;
427 }
151a33c0 428
3c5fce2b 429 retrycnt = 0;
151a33c0 430 PrintAndLogEx(FAILED, "Retry failed [%s]. Skipped...", AIDlist[i].aid);
3c5fce2b
OM
431 }
432 continue;
433 }
434 retrycnt = 0;
151a33c0 435
3c5fce2b
OM
436 if (res)
437 continue;
151a33c0 438
439 if (!datalen)
440 continue;
441
442 if (decodeTLV) {
443 PrintAndLogEx(SUCCESS, "%s", AIDlist[i].aid);
3c5fce2b
OM
444 TLVPrintFromBuffer(data, datalen);
445 }
446 }
447
448 return 0;
449}
450
451int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) {
87fc2dad 452 // check priority. 0x00 - highest
3c5fce2b 453 int prio = 0xffff;
151a33c0 454
3c5fce2b
OM
455 *AIDlen = 0;
456
457 struct tlvdb *ttmp = tlvdb_find(tlv, 0x6f);
458 if (!ttmp)
459 return 1;
151a33c0 460
3c5fce2b
OM
461 while (ttmp) {
462 const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x84, NULL);
463 const struct tlv *tgPrio = tlvdb_get_inchild(ttmp, 0x87, NULL);
151a33c0 464
3c5fce2b
OM
465 if (!tgAID)
466 break;
467
468 if (tgPrio) {
151a33c0 469 int pt = bytes_to_num((uint8_t*)tgPrio->value, (tgPrio->len < 2) ? tgPrio->len : 2);
3c5fce2b
OM
470 if (pt < prio) {
471 prio = pt;
151a33c0 472
3c5fce2b
OM
473 memcpy(AID, tgAID->value, tgAID->len);
474 *AIDlen = tgAID->len;
475 }
476 } else {
477 // takes the first application from list wo priority
478 if (!*AIDlen) {
479 memcpy(AID, tgAID->value, tgAID->len);
151a33c0 480 *AIDlen = tgAID->len;
3c5fce2b
OM
481 }
482 }
151a33c0 483
3c5fce2b
OM
484 ttmp = tlvdb_find_next(ttmp, 0x6f);
485 }
151a33c0 486
3c5fce2b
OM
487 return 0;
488}
489
8d7d7b61 490int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
491 return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
3c5fce2b
OM
492}
493
8d7d7b61 494int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
495 int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
c80eb8ba 496 if (*sw == 0x6700) {
151a33c0 497 PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le...");
8d7d7b61 498 res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
c80eb8ba
OM
499 }
500 return res;
87fc2dad 501}
3c5fce2b 502
8d7d7b61 503int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
504 return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
3c5fce2b
OM
505}
506
8d7d7b61 507int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
508 int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv);
c80eb8ba 509 if (*sw == 0x6700) {
151a33c0 510 PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le...");
8d7d7b61 511 res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv);
c80eb8ba
OM
512 }
513 return res;
87fc2dad 514}
3c5fce2b 515
8d7d7b61 516int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
517 return EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
d03fb293
OM
518}
519
8d7d7b61 520int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) {
521 return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv);
87fc2dad 522}
10d4f823 523
151a33c0 524// Authentication
d03fb293
OM
525static struct emv_pk *get_ca_pk(struct tlvdb *db) {
526 const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL);
527 const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL);
528
529 if (!df_tlv || !caidx_tlv || df_tlv->len < 6 || caidx_tlv->len != 1)
530 return NULL;
531
151a33c0 532 PrintAndLogEx(NORMAL, "CA public key index 0x%0x", caidx_tlv->value[0]);
d03fb293
OM
533 return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]);
534}
535
536int trSDA(struct tlvdb *tlv) {
537
538 struct emv_pk *pk = get_ca_pk(tlv);
539 if (!pk) {
151a33c0 540 PrintAndLogEx(WARNING, "Error: Key not found. Exit.");
d03fb293
OM
541 return 2;
542 }
151a33c0 543
d03fb293
OM
544 struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
545 if (!issuer_pk) {
546 emv_pk_free(pk);
151a33c0 547 PrintAndLogEx(WARNING, "Error: Issuer certificate not found. Exit.");
d03fb293
OM
548 return 2;
549 }
550
151a33c0 551 PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx",
d03fb293
OM
552 issuer_pk->rid[0],
553 issuer_pk->rid[1],
554 issuer_pk->rid[2],
555 issuer_pk->rid[3],
556 issuer_pk->rid[4],
557 issuer_pk->index,
558 issuer_pk->serial[0],
559 issuer_pk->serial[1],
560 issuer_pk->serial[2]
561 );
562
563 const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
564 if (!sda_tlv || sda_tlv->len < 1) {
565 emv_pk_free(issuer_pk);
566 emv_pk_free(pk);
151a33c0 567 PrintAndLogEx(WARNING, "Can't find input list for Offline Data Authentication. Exit.");
d03fb293
OM
568 return 3;
569 }
151a33c0 570
d03fb293
OM
571 struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
572 if (dac_db) {
573 const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
151a33c0 574 PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
d03fb293
OM
575 tlvdb_add(tlv, dac_db);
576 } else {
577 emv_pk_free(issuer_pk);
578 emv_pk_free(pk);
151a33c0 579 PrintAndLogEx(WARNING, "SSAD verify error");
d03fb293
OM
580 return 4;
581 }
151a33c0 582
d03fb293
OM
583 emv_pk_free(issuer_pk);
584 emv_pk_free(pk);
585 return 0;
586}
587
588static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04};
589static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value };
590
8d7d7b61 591int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) {
d03fb293
OM
592 uint8_t buf[APDU_RES_LEN] = {0};
593 size_t len = 0;
594 uint16_t sw = 0;
595
596 struct emv_pk *pk = get_ca_pk(tlv);
597 if (!pk) {
151a33c0 598 PrintAndLogEx(WARNING, "Error: Key not found. Exit.");
d03fb293
OM
599 return 2;
600 }
601
602 const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
603 if (!sda_tlv || sda_tlv->len < 1) {
604 emv_pk_free(pk);
151a33c0 605 PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit.");
d03fb293
OM
606 return 3;
607 }
608
609 struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
610 if (!issuer_pk) {
611 emv_pk_free(pk);
151a33c0 612 PrintAndLogEx(WARNING, "Error: Issuer certificate not found. Exit.");
d03fb293
OM
613 return 2;
614 }
151a33c0 615 PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
d03fb293
OM
616 issuer_pk->rid[0],
617 issuer_pk->rid[1],
618 issuer_pk->rid[2],
619 issuer_pk->rid[3],
620 issuer_pk->rid[4],
621 issuer_pk->index,
622 issuer_pk->serial[0],
623 issuer_pk->serial[1],
624 issuer_pk->serial[2]
625 );
151a33c0 626
d03fb293
OM
627 struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
628 if (!icc_pk) {
629 emv_pk_free(pk);
630 emv_pk_free(issuer_pk);
151a33c0 631 PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit.");
d03fb293
OM
632 return 2;
633 }
151a33c0 634 PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
d03fb293
OM
635 icc_pk->rid[0],
636 icc_pk->rid[1],
637 icc_pk->rid[2],
638 icc_pk->rid[3],
639 icc_pk->rid[4],
640 icc_pk->index,
641 icc_pk->serial[0],
642 icc_pk->serial[1],
643 icc_pk->serial[2]
644 );
645
646 struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv);
647 if (!icc_pe_pk) {
151a33c0 648 PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. ");
d03fb293 649 } else {
151a33c0 650 PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
d03fb293
OM
651 icc_pe_pk->rid[0],
652 icc_pe_pk->rid[1],
653 icc_pe_pk->rid[2],
654 icc_pe_pk->rid[3],
655 icc_pe_pk->rid[4],
656 icc_pe_pk->index,
657 icc_pe_pk->serial[0],
658 icc_pe_pk->serial[1],
659 icc_pe_pk->serial[2]
660 );
661 }
662
663 // 9F4B: Signed Dynamic Application Data
664 const struct tlv *sdad_tlv = tlvdb_get(tlv, 0x9f4b, NULL);
665 // DDA with internal authenticate OR fDDA with filled 0x9F4B tag (GPO result)
666 // EMV kernel3 v2.4, contactless book C-3, C.1., page 147
667 if (sdad_tlv) {
151a33c0 668 PrintAndLogEx(NORMAL, "\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA...");
d03fb293
OM
669
670 const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true);
671 if (!atc_db) {
151a33c0 672 PrintAndLogEx(WARNING, "Error: Can't recover IDN (ICC Dynamic Number)");
d03fb293
OM
673 emv_pk_free(pk);
674 emv_pk_free(issuer_pk);
675 emv_pk_free(icc_pk);
676 return 8;
677 }
678
679 // 9f36 Application Transaction Counter (ATC)
680 const struct tlv *atc_tlv = tlvdb_get(atc_db, 0x9f36, NULL);
681 if(atc_tlv) {
151a33c0 682 PrintAndLogEx(NORMAL, "\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len));
683
d03fb293
OM
684 const struct tlv *core_atc_tlv = tlvdb_get(tlv, 0x9f36, NULL);
685 if(tlv_equal(core_atc_tlv, atc_tlv)) {
151a33c0 686 PrintAndLogEx(SUCCESS, "ATC check OK.");
687 PrintAndLogEx(SUCCESS, "fDDA (fast DDA) verified OK.");
d03fb293 688 } else {
151a33c0 689 PrintAndLogEx(WARNING, "Error: fDDA verified, but ATC in the certificate and ATC in the record not the same.");
d03fb293
OM
690 }
691 } else {
151a33c0 692 PrintAndLogEx(NORMAL, "\nERROR: fDDA (fast DDA) verify error");
d03fb293
OM
693 emv_pk_free(pk);
694 emv_pk_free(issuer_pk);
695 emv_pk_free(icc_pk);
696 return 9;
697 }
698 } else {
699 struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
700 if (dac_db) {
701 const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
151a33c0 702 PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]);
d03fb293
OM
703 tlvdb_add(tlv, dac_db);
704 } else {
151a33c0 705 PrintAndLogEx(WARNING, "Error: SSAD verify error");
d03fb293
OM
706 emv_pk_free(pk);
707 emv_pk_free(issuer_pk);
708 emv_pk_free(icc_pk);
709 return 4;
710 }
151a33c0 711
712 PrintAndLogEx(NORMAL, "\n* Calc DDOL");
d03fb293
OM
713 const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL);
714 if (!ddol_tlv) {
715 ddol_tlv = &default_ddol_tlv;
151a33c0 716 PrintAndLogEx(NORMAL, "DDOL [9f49] not found. Using default DDOL");
d03fb293
OM
717 }
718
719 struct tlv *ddol_data_tlv = dol_process(ddol_tlv, tlv, 0);
720 if (!ddol_data_tlv) {
151a33c0 721 PrintAndLogEx(WARNING, "Error: Can't create DDOL TLV");
d03fb293
OM
722 emv_pk_free(pk);
723 emv_pk_free(issuer_pk);
724 emv_pk_free(icc_pk);
725 return 5;
726 }
727
151a33c0 728 PrintAndLogEx(NORMAL, "DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len));
d03fb293 729
151a33c0 730 PrintAndLogEx(NORMAL, "\n* Internal Authenticate");
8d7d7b61 731 int res = EMVInternalAuthenticate(channel, true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL);
151a33c0 732 if (res) {
733 PrintAndLogEx(WARNING, "Internal Authenticate error(%d): %4x. Exit...", res, sw);
d03fb293
OM
734 free(ddol_data_tlv);
735 emv_pk_free(pk);
736 emv_pk_free(issuer_pk);
737 emv_pk_free(icc_pk);
738 return 6;
739 }
740
741 struct tlvdb *dda_db = NULL;
742 if (buf[0] == 0x80) {
743 if (len < 3 ) {
151a33c0 744 PrintAndLogEx(WARNING, "Error: Internal Authenticate format1 parsing error. length=%d", len);
d03fb293
OM
745 } else {
746 // 9f4b Signed Dynamic Application Data
747 dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2);
748 tlvdb_add(tlv, dda_db);
749 if (decodeTLV){
151a33c0 750 PrintAndLogEx(NORMAL, "* * Decode response format 1:");
d03fb293
OM
751 TLVPrintFromTLV(dda_db);
752 }
753 }
754 } else {
755 dda_db = tlvdb_parse_multi(buf, len);
756 if(!dda_db) {
151a33c0 757 PrintAndLogEx(WARNING, "Error: Can't parse Internal Authenticate result as TLV");
d03fb293
OM
758 free(ddol_data_tlv);
759 emv_pk_free(pk);
760 emv_pk_free(issuer_pk);
761 emv_pk_free(icc_pk);
762 return 7;
763 }
764 tlvdb_add(tlv, dda_db);
151a33c0 765
d03fb293
OM
766 if (decodeTLV)
767 TLVPrintFromTLV(dda_db);
768 }
769
770 struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true);
771 free(ddol_data_tlv);
772 if (!idn_db) {
151a33c0 773 PrintAndLogEx(WARNING, "Error: Can't recover IDN (ICC Dynamic Number)");
d03fb293
OM
774 tlvdb_free(dda_db);
775 emv_pk_free(pk);
776 emv_pk_free(issuer_pk);
777 emv_pk_free(icc_pk);
778 return 8;
779 }
780 tlvdb_free(dda_db);
781
782 // 9f4c ICC Dynamic Number
783 const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
784 if(idn_tlv) {
151a33c0 785 PrintAndLogEx(NORMAL, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
786 PrintAndLogEx(NORMAL, "DDA verified OK.");
d03fb293
OM
787 tlvdb_add(tlv, idn_db);
788 tlvdb_free(idn_db);
789 } else {
151a33c0 790 PrintAndLogEx(NORMAL, "\nERROR: DDA verify error");
d03fb293
OM
791 tlvdb_free(idn_db);
792
793 emv_pk_free(pk);
794 emv_pk_free(issuer_pk);
795 emv_pk_free(icc_pk);
796 return 9;
797 }
798 }
151a33c0 799
d03fb293
OM
800 emv_pk_free(pk);
801 emv_pk_free(issuer_pk);
802 emv_pk_free(icc_pk);
10d4f823 803 return 0;
804}
805
d03fb293
OM
806int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv) {
807
808 struct emv_pk *pk = get_ca_pk(tlv);
809 if (!pk) {
151a33c0 810 PrintAndLogEx(WARNING, "Error: Key not found. Exit.");
d03fb293
OM
811 return 2;
812 }
813
814 const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL);
815 if (!sda_tlv || sda_tlv->len < 1) {
151a33c0 816 PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit.");
d03fb293
OM
817 emv_pk_free(pk);
818 return 3;
819 }
820
821 struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv);
822 if (!issuer_pk) {
151a33c0 823 PrintAndLogEx(WARNING, "Error: Issuer certificate not found. Exit.");
d03fb293
OM
824 emv_pk_free(pk);
825 return 2;
826 }
151a33c0 827 PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
d03fb293
OM
828 issuer_pk->rid[0],
829 issuer_pk->rid[1],
830 issuer_pk->rid[2],
831 issuer_pk->rid[3],
832 issuer_pk->rid[4],
833 issuer_pk->index,
834 issuer_pk->serial[0],
835 issuer_pk->serial[1],
836 issuer_pk->serial[2]
837 );
151a33c0 838
d03fb293
OM
839 struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv);
840 if (!icc_pk) {
151a33c0 841 PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit.");
d03fb293
OM
842 emv_pk_free(pk);
843 emv_pk_free(issuer_pk);
844 return 2;
845 }
151a33c0 846 PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
d03fb293
OM
847 icc_pk->rid[0],
848 icc_pk->rid[1],
849 icc_pk->rid[2],
850 icc_pk->rid[3],
851 icc_pk->rid[4],
852 icc_pk->index,
853 icc_pk->serial[0],
854 icc_pk->serial[1],
855 icc_pk->serial[2]
856 );
857
858 struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv);
859 if (dac_db) {
860 const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL);
151a33c0 861 PrintAndLogEx(NORMAL, "SSAD verified OK. (%02hhx:%02hhx)", dac_tlv->value[0], dac_tlv->value[1]);
d03fb293
OM
862 tlvdb_add(tlv, dac_db);
863 } else {
151a33c0 864 PrintAndLogEx(WARNING, "Error: SSAD verify error");
d03fb293
OM
865 emv_pk_free(pk);
866 emv_pk_free(issuer_pk);
867 emv_pk_free(icc_pk);
868 return 4;
869 }
151a33c0 870
871 PrintAndLogEx(NORMAL, "\n* * Check Signed Dynamic Application Data (SDAD)");
d03fb293
OM
872 struct tlvdb *idn_db = emv_pki_perform_cda_ex(icc_pk, tlv, ac_tlv,
873 pdol_data_tlv, // pdol
874 ac_data_tlv, // cdol1
151a33c0 875 NULL, // cdol2
d03fb293
OM
876 true);
877 if (idn_db) {
878 const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL);
151a33c0 879 PrintAndLogEx(NORMAL, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len));
880 PrintAndLogEx(NORMAL, "CDA verified OK.");
d03fb293
OM
881 tlvdb_add(tlv, idn_db);
882 } else {
151a33c0 883 PrintAndLogEx(NORMAL, "\nERROR: CDA verify error");
d03fb293
OM
884 }
885
886 emv_pk_free(pk);
887 emv_pk_free(issuer_pk);
888 emv_pk_free(icc_pk);
889 return 0;
890}
95b697f0
OM
891
892int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) {
151a33c0 893
95b697f0
OM
894 struct emv_pk *pk = get_ca_pk(tlvRoot);
895 if (!pk) {
896 PrintAndLog("ERROR: Key not found. Exit.");
897 return 1;
898 }
899
900 struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlvRoot);
901 if (!issuer_pk) {
902 emv_pk_free(pk);
903 PrintAndLog("WARNING: Issuer certificate not found. Exit.");
904 return 2;
905 }
906 PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx",
907 issuer_pk->rid[0],
908 issuer_pk->rid[1],
909 issuer_pk->rid[2],
910 issuer_pk->rid[3],
911 issuer_pk->rid[4],
912 issuer_pk->index,
913 issuer_pk->serial[0],
914 issuer_pk->serial[1],
915 issuer_pk->serial[2]
916 );
917
918 JsonSaveBufAsHex(root, "$.ApplicationData.RID", issuer_pk->rid, 5);
919
920 char *issuer_pk_c = emv_pk_dump_pk(issuer_pk);
921 JsonSaveStr(root, "$.ApplicationData.IssuerPublicKeyDec", issuer_pk_c);
922 JsonSaveBufAsHex(root, "$.ApplicationData.IssuerPublicKeyModulus", issuer_pk->modulus, issuer_pk->mlen);
923 free(issuer_pk_c);
924
925 struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL);
926 if (!icc_pk) {
927 emv_pk_free(pk);
928 emv_pk_free(issuer_pk);
929 PrintAndLog("WARNING: ICC certificate not found. Exit.");
930 return 2;
931 }
932 printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n",
933 icc_pk->rid[0],
934 icc_pk->rid[1],
935 icc_pk->rid[2],
936 icc_pk->rid[3],
937 icc_pk->rid[4],
938 icc_pk->index,
939 icc_pk->serial[0],
940 icc_pk->serial[1],
941 icc_pk->serial[2]
942 );
151a33c0 943
95b697f0
OM
944 char *icc_pk_c = emv_pk_dump_pk(icc_pk);
945 JsonSaveStr(root, "$.ApplicationData.ICCPublicKeyDec", icc_pk_c);
946 JsonSaveBufAsHex(root, "$.ApplicationData.ICCPublicKeyModulus", icc_pk->modulus, icc_pk->mlen);
947 free(issuer_pk_c);
151a33c0 948
95b697f0
OM
949 return 0;
950}
Impressum, Datenschutz