1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2017 Merlok
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
7 //-----------------------------------------------------------------------------
8 // ISO7816 core functions
9 //-----------------------------------------------------------------------------
11 #include "iso7816core.h"
15 #include "commonutil.h" // ARRAYLEN
16 #include "comms.h" // DropField
17 #include "cmdparser.h"
18 #include "cmdsmartcard.h" // ExchangeAPDUSC
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) {
35 static isodep_state_t isodep_state
= ISODEP_INACTIVE
;
37 void SetISODEPState(isodep_state_t state
) {
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) {
52 int Iso7816Connect(Iso7816CommandChannel channel
) {
53 if (channel
== CC_CONTACT
) {
57 // select with no disconnect and set frameLength
58 int res
= SelectCard14443A_4(false, NULL
);
59 if (res
== PM3_SUCCESS
) {
60 SetISODEPState(ISODEP_NFCA
);
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
);
72 PrintAndLogEx(DEBUG
, "No 14b tag spotted, failed to find any tag.");
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
) {
100 uint8_t data
[APDU_RES_LEN
] = {0};
101 if (APDUEncodeS(&apdu
, false, le
, data
, &datalen
)) {
102 PrintAndLogEx(ERR
, "APDU encoding error.");
107 PrintAndLogEx(SUCCESS
, ">>>> %s", sprint_hex(data
, datalen
));
112 case CC_CONTACTLESS
: {
114 switch (GetISODEPState()) {
116 res
= ExchangeAPDU14a(data
, datalen
, activate_field
, leave_field_on
, result
, (int)max_result_len
, (int *)result_len
);
119 res
= exchange_14b_apdu(data
, datalen
, activate_field
, leave_field_on
, result
, (int)max_result_len
, (int *)result_len
, 4000);
121 case ISODEP_INACTIVE
:
122 if (activate_field
== false) {
123 PrintAndLogEx(FAILED
, "Field currently inactive, cannot send an APDU");
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);
133 if (res
!= PM3_SUCCESS
) {
140 if (IfPm3Smartcard()) {
141 res
= ExchangeAPDUSC(false, data
, datalen
, activate_field
, leave_field_on
, result
, (int)max_result_len
, (int *)result_len
);
152 PrintAndLogEx(SUCCESS
, "<<<< %s", sprint_hex(result
, *result_len
));
154 if (*result_len
< 2) {
159 uint16_t isw
= (result
[*result_len
] * 0x0100) + result
[*result_len
+ 1];
167 if (*sw
>> 8 == 0x61) {
168 PrintAndLogEx(ERR
, "APDU chaining len %02x", *sw
& 0xFF);
170 PrintAndLogEx(ERR
, "APDU(%02x%02x) ERROR: [%4X] %s", apdu
.CLA
, apdu
.INS
, isw
, GetAPDUCodeDescription(*sw
>> 8, *sw
& 0xFF));
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
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
198 , (sAPDU
) {0x00, 0xa4, 0x04, 0x00, aid_len
, aid
}
199 , (channel
== CC_CONTACTLESS
)