style, the return codes needs to be adjusted to follow the PM3_E* styled defines.
[RRG-proxmark3.git] / client / src / iso7816 / iso7816core.c
blob9c336c0bcbc3b1513ec085a22d3ec505f6ef8f5a
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 // ISO7816 core functions
9 //-----------------------------------------------------------------------------
11 #include "iso7816core.h"
13 #include <string.h>
15 #include "commonutil.h" // ARRAYLEN
16 #include "comms.h" // DropField
17 #include "cmdparser.h"
18 #include "cmdsmartcard.h" // ExchangeAPDUSC
19 #include "ui.h"
20 #include "cmdhf14a.h"
21 #include "cmdhf14b.h"
22 #include "iso14b.h" // iso14b_raw_cmd_t
23 #include "util_posix.h"
25 //iceman: this logging setting, should be unified with client debug etc.
26 static bool APDULogging = false;
27 void SetAPDULogging(bool logging) {
28 APDULogging = logging;
31 bool GetAPDULogging(void) {
32 return APDULogging;
35 static isodep_state_t isodep_state = ISODEP_INACTIVE;
37 void SetISODEPState(isodep_state_t state) {
38 isodep_state = state;
39 if (APDULogging) {
40 PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s"
41 , isodep_state == ISODEP_INACTIVE ? "inactive" : ""
42 , isodep_state == ISODEP_NFCA ? _GREEN_("NFC-A") : ""
43 , isodep_state == ISODEP_NFCB ? _GREEN_("NFC-B") : ""
48 isodep_state_t GetISODEPState(void) {
49 return isodep_state;
52 int Iso7816Connect(Iso7816CommandChannel channel) {
53 if (channel == CC_CONTACT) {
54 return PM3_ENOTIMPL;
56 // Try to 14a
57 // select with no disconnect and set frameLength
58 int res = SelectCard14443A_4(false, NULL);
59 if (res == PM3_SUCCESS) {
60 SetISODEPState(ISODEP_NFCA);
61 return PM3_SUCCESS;
64 PrintAndLogEx(DEBUG, "No 14a tag spotted, trying 14b");
65 // If not 14a, try to 14b
66 res = select_card_14443b_4(false, NULL);
67 if (res == PM3_SUCCESS) {
68 SetISODEPState(ISODEP_NFCB);
69 return PM3_SUCCESS;
72 PrintAndLogEx(DEBUG, "No 14b tag spotted, failed to find any tag.");
73 return res;
76 int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool leave_field_on,
77 sAPDU apdu, bool include_le, uint16_t le, uint8_t *result,
78 size_t max_result_len, size_t *result_len, uint16_t *sw) {
80 *result_len = 0;
81 if (sw) {
82 *sw = 0;
85 if (activate_field) {
86 DropFieldEx(channel);
87 msleep(50);
90 // COMPUTE APDU
91 int datalen = 0;
92 if (include_le) {
93 if (le == 0) {
94 le = 0x100;
96 } else {
97 le = 0;
100 uint8_t data[APDU_RES_LEN] = {0};
101 if (APDUEncodeS(&apdu, false, le, data, &datalen)) {
102 PrintAndLogEx(ERR, "APDU encoding error.");
103 return 201;
106 if (APDULogging)
107 PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen));
109 int res = 0;
111 switch (channel) {
112 case CC_CONTACTLESS: {
114 switch (GetISODEPState()) {
115 case ISODEP_NFCA:
116 res = ExchangeAPDU14a(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len);
117 break;
118 case ISODEP_NFCB:
119 res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
120 break;
121 case ISODEP_INACTIVE:
122 if (activate_field == false) {
123 PrintAndLogEx(FAILED, "Field currently inactive, cannot send an APDU");
124 return PM3_EIO;
126 res = ExchangeAPDU14a(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len);
127 if (res != PM3_SUCCESS) {
128 res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
130 break;
133 if (res != PM3_SUCCESS) {
134 return res;
136 break;
138 case CC_CONTACT: {
139 res = 1;
140 if (IfPm3Smartcard()) {
141 res = ExchangeAPDUSC(false, data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len);
144 if (res) {
145 return res;
147 break;
151 if (APDULogging)
152 PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len));
154 if (*result_len < 2) {
155 return 200;
158 *result_len -= 2;
159 uint16_t isw = (result[*result_len] * 0x0100) + result[*result_len + 1];
161 if (sw) {
162 *sw = isw;
165 if (isw != 0x9000) {
166 if (APDULogging) {
167 if (*sw >> 8 == 0x61) {
168 PrintAndLogEx(ERR, "APDU chaining len %02x", *sw & 0xFF);
169 } else {
170 PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xFF));
171 return 5;
175 return PM3_SUCCESS;
178 int Iso7816Exchange(Iso7816CommandChannel channel, bool leave_field_on, sAPDU apdu, uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
179 return Iso7816ExchangeEx(channel
180 , false
181 , leave_field_on
182 , apdu
183 , false
185 , result
186 , max_result_len
187 , result_len
188 , sw
192 int Iso7816Select(Iso7816CommandChannel channel, bool activate_field, bool leave_field_on, uint8_t *aid, size_t aid_len,
193 uint8_t *result, size_t max_result_len, size_t *result_len, uint16_t *sw) {
195 return Iso7816ExchangeEx(channel
196 , activate_field
197 , leave_field_on
198 , (sAPDU) {0x00, 0xa4, 0x04, 0x00, aid_len, aid}
199 , (channel == CC_CONTACTLESS)
201 , result
202 , max_result_len
203 , result_len
204 , sw