diff --git a/client/src/cmdsmartcard.c b/client/src/cmdsmartcard.c index 495b20015..92495f9cf 100644 --- a/client/src/cmdsmartcard.c +++ b/client/src/cmdsmartcard.c @@ -317,6 +317,7 @@ static int smart_wait(uint8_t *out, int maxoutlen, bool verbose) { static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) { int datalen = smart_wait(out, maxoutlen, verbose); + int totallen = datalen; bool needGetData = false; if (datalen < 2) { @@ -327,8 +328,21 @@ static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) { needGetData = true; } - if (needGetData) { + if (needGetData == true) { + // Don't discard data we already received except the SW code + totallen -= 2; + int ofs = totallen; + maxoutlen -= totallen; + int len = out[datalen - 1]; + if (len == 0 || len > MAX_APDU_SIZE) { + // Cap the data length or the smartcard may send us a buffer we can't handle + len = MAX_APDU_SIZE; + } + if (maxoutlen < len) { + // We don't have enough buffer to hold the next part + goto out; + } if (verbose) PrintAndLogEx(INFO, "Requesting " _YELLOW_("0x%02X") " bytes response", len); @@ -342,7 +356,7 @@ static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) { SendCommandNG(CMD_SMART_RAW, (uint8_t *)payload, sizeof(smart_card_raw_t) + sizeof(cmd_getresp)); free(payload); - datalen = smart_wait(out, maxoutlen, verbose); + datalen = smart_wait(&out[ofs], maxoutlen, verbose); if (datalen < 2) { goto out; @@ -352,7 +366,7 @@ static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) { if (datalen != len + 2) { // data with ACK if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK - if (out[0] != ISO7816_GET_RESPONSE) { + if (out[ofs] != ISO7816_GET_RESPONSE) { if (verbose) { PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, out[0]); } @@ -361,7 +375,8 @@ static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) { } datalen--; - memmove(out, &out[1], datalen); + memmove(&out[ofs], &out[ofs + 1], datalen); + totallen += datalen; } else { // wrong length if (verbose) { @@ -372,7 +387,7 @@ static int smart_responseEx(uint8_t *out, int maxoutlen, bool verbose) { } out: - return datalen; + return totallen; } static int smart_response(uint8_t *out, int maxoutlen) { diff --git a/client/src/cmdsmartcard.h b/client/src/cmdsmartcard.h index 65e6ba1c1..72c40fa3b 100644 --- a/client/src/cmdsmartcard.h +++ b/client/src/cmdsmartcard.h @@ -22,6 +22,11 @@ #include "common.h" #include "pm3_cmd.h" // structs +// On ARM side, ISO7816_MAX_FRAME is set to 255 +// This means we can't receive more than 250 bytes of data to leave enough room for +// SW status code and surrounding metadata without creating a buffer overflow. +#define MAX_APDU_SIZE 250 + int CmdSmartcard(const char *Cmd); bool smart_select(bool verbose, smart_card_atr_t *atr);