mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-22 06:13:27 -07:00
communication fido chaining + iso14443-4 chaining. needs refactoring...
This commit is contained in:
parent
fbd3f981c6
commit
a1c6c8f937
6 changed files with 107 additions and 19 deletions
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
||||
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);
|
||||
|
@ -1983,6 +1989,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)) {
|
||||
return -1;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue