communication fido chaining + iso14443-4 chaining. needs refactoring...

This commit is contained in:
merlokk 2018-10-17 17:52:16 +03:00
commit a1c6c8f937
6 changed files with 107 additions and 19 deletions

View file

@ -116,7 +116,7 @@ int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response)
switch(iso_type)
{
case 'a':
return iso14_apdu(apdu, (uint16_t) length, response);
return iso14_apdu(apdu, (uint16_t) length, response, NULL);
break;
case 'b':
return iso14443b_apdu(apdu, length, response);

View file

@ -1935,15 +1935,21 @@ b8 b7 b6 b5 b4 b3 b2 b1
b5,b6 = 00 - DESELECT
11 - WTX
*/
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) {
uint8_t parity[MAX_PARITY_SIZE];
uint8_t real_cmd[cmd_len + 4];
// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00)
// put block number into the PCB
real_cmd[0] |= iso14_pcb_blocknum;
memcpy(real_cmd + 1, cmd, cmd_len);
if (cmd_len) {
// ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02
real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00)
// put block number into the PCB
real_cmd[0] |= iso14_pcb_blocknum;
memcpy(real_cmd + 1, cmd, cmd_len);
} else {
// R-block. ACK
real_cmd[0] = 0xA2; // r-block + ACK
real_cmd[0] |= iso14_pcb_blocknum;
}
AppendCrc14443a(real_cmd, cmd_len + 1);
ReaderTransmit(real_cmd, cmd_len + 3, NULL);
@ -1982,6 +1988,10 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) {
{
iso14_pcb_blocknum ^= 1;
}
// if we received I-block with chaining we need to send ACK and receive another block of data
if (res)
*res = data_bytes[0];
// crc check
if (len >=3 && !CheckCrc14443(CRC_14443_A, data_bytes, len)) {
@ -2050,9 +2060,10 @@ void ReaderIso14443a(UsbCommand *c)
}
if(param & ISO14A_APDU && !cantSELECT) {
arg0 = iso14_apdu(cmd, len, buf);
uint8_t res;
arg0 = iso14_apdu(cmd, len, buf, &res);
LED_B_ON();
cmd_send(CMD_ACK, arg0, 0, 0, buf, sizeof(buf));
cmd_send(CMD_ACK, arg0, res, 0, buf, sizeof(buf));
LED_B_OFF();
}

View file

@ -49,7 +49,7 @@ extern int EmSendPrecompiledCmd(tag_response_info_t *response_info);
extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size);
extern void iso14443a_setup(uint8_t fpga_minor_mode);
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data);
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res);
extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
extern void iso14a_set_trigger(bool enable);
extern void iso14a_set_timeout(uint32_t timeout);

View file

@ -749,6 +749,8 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
uint16_t cmdc = 0;
int dlen;
*dataoutlen = 0;
if (activateField) {
cmdc |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE;
@ -760,7 +762,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
// here length USB_CMD_DATA_SIZE=512
// timeout must be authomatically set by "get ATS"
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | cmdc, (datainlen & 0xFFFF), 0}};
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0xFFFF), 0}};
memcpy(c.d.asBytes, datain, datainlen);
SendCommand(&c);
@ -781,10 +783,12 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
recv = resp.d.asBytes;
int iLen = resp.arg[0];
uint8_t res = resp.arg[1];
*dataoutlen = iLen - 2;
if (*dataoutlen < 0)
*dataoutlen = 0;
dlen = iLen - 2;
if (dlen < 0)
dlen = 0;
*dataoutlen += dlen;
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
@ -792,7 +796,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
}
memcpy(dataout, recv, *dataoutlen);
if(!iLen) {
PrintAndLog("APDU ERROR: No APDU response.");
return 1;
@ -810,6 +814,33 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
return 3;
}
if ((res & 0x10) != 0) {
// I-block with chaining
int oldlen = *dataoutlen;
printf("-->%02x oldlen:%d\n", res, oldlen);
UsbCommand c1 = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_NO_DISCONNECT, 0, 0}};
SendCommand(&c1);
uint8_t *recv1;
UsbCommand resp1;
if (WaitForResponseTimeout(CMD_ACK, &resp1, 1500)) {
dlen = resp1.arg[0] - 2;
if (dlen < 0)
dlen = 0;
*dataoutlen += dlen;
recv1 = resp1.d.asBytes;
printf("vlen:%d dlen:%d\n", resp1.arg[0] & 0xFFFF, dlen);
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
return 2;
}
memcpy(&dataout[oldlen], recv1, dlen);
}
}
// check apdu length
if (iLen < 4) {
PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen);
@ -821,6 +852,9 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
return 4;
}
if (!leaveSignalON)
DropField();
return 0;
}

View file

@ -43,6 +43,21 @@ int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t Ma
return EMVSelect(ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL);
}
int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
int res = EMVExchange(true, apdu, Result, MaxResultLen, ResultLen, sw, NULL);
// software chaining
while ((*sw >> 8) == 0x61) {
size_t oldlen = *ResultLen;
res = EMVExchange(true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen, ResultLen, sw, NULL);
*ResultLen += oldlen;
}
return res;
}
int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) {
return FIDOExchange((sAPDU){0x00, 0x01, 0x03, 0x00, 64, params}, Result, MaxResultLen, ResultLen, sw);
}
int CmdHFFidoInfo(const char *cmd) {
if (cmd && strlen(cmd) > 0)
@ -92,24 +107,48 @@ int CmdHFFidoRegister(const char *cmd) {
// challenge parameter [32 bytes] - The challenge parameter is the SHA-256 hash of the Client Data, a stringified JSON data structure that the FIDO Client prepares
// application parameter [32 bytes] - The application parameter is the SHA-256 hash of the UTF-8 encoding of the application identity
uint8_t data[64] = {0};
SetAPDULogging(true);
uint8_t buf[APDU_RES_LEN] = {0};
uint8_t buf[2048] = {0};
size_t len = 0;
uint16_t sw = 0;
int res = FIDOSelect(true, false, buf, sizeof(buf), &len, &sw);
int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw);
if (res) {
PrintAndLog("Can't select authenticator. Exit...");
PrintAndLog("Can't select authenticator. res=%x. Exit...", res);
return res;
}
if (sw != 0x9000) {
PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return 2;
}
res = FIDORegister(data, buf, sizeof(buf), &len, &sw);
/* if (res) {
PrintAndLog("Can't execute register command. res=%x. Exit...", res);
return res;
}
if (sw != 0x9000) {
PrintAndLog("Can't execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
return 3;
}*/
//PrintAndLog("data: %s", sprint_hex(buf, len));
if (buf[0] != 0x05) {
PrintAndLog("ERROR: First byte must be 0x05, but it %2x", buf[0]);
return 5;
}
PrintAndLog("User public key: %s", sprint_hex(&buf[1], 65));
uint8_t keyHandleLen = buf[66];
PrintAndLog("Key handle[%d]: %s", keyHandleLen, sprint_hex(&buf[67], keyHandleLen));
PrintAndLog("DER certificate[%d]: %s", keyHandleLen, sprint_hex(&buf[67 + keyHandleLen], 20));
return 0;

View file

@ -68,6 +68,10 @@ extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2);
extern void SetAPDULogging(bool logging);
// exchange
extern int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv);
// search application
extern int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);
extern int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv);