aimepcsc: fail softly on card transaction errors

This commit is contained in:
nat 2024-01-11 04:41:28 -08:00
parent 6ff46befb4
commit b96ad265a2
2 changed files with 39 additions and 44 deletions

View File

@ -5,6 +5,8 @@ static const uint8_t atr_ios14443_common[] = {0x3B, 0x8F, 0x80, 0x01, 0x80, 0x4F
static const uint8_t cardtype_m1k[] = {0x03, 0x00, 0x01}; static const uint8_t cardtype_m1k[] = {0x03, 0x00, 0x01};
static const uint8_t cardtype_felica[] = {0x11, 0x00, 0x3B}; static const uint8_t cardtype_felica[] = {0x11, 0x00, 0x3B};
static const uint8_t felica_cmd_readidm[] = {0xFF, 0xCA, 0x00, 0x00, 0x00};
static const uint8_t m1k_cmd_loadkey[] = {0xFF, 0x82, 0x00, 0x00, 0x06, 0x57, 0x43, 0x43, 0x46, 0x76, 0x32}; static const uint8_t m1k_cmd_loadkey[] = {0xFF, 0x82, 0x00, 0x00, 0x06, 0x57, 0x43, 0x43, 0x46, 0x76, 0x32};
static const uint8_t m1k_cmd_auth_block2[] = {0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, 0x02, 0x61, 0x00}; static const uint8_t m1k_cmd_auth_block2[] = {0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, 0x02, 0x61, 0x00};
static const uint8_t m1k_cmd_read_block2[] = {0xFF, 0xB0, 0x00, 0x02, 0x10}; static const uint8_t m1k_cmd_read_block2[] = {0xFF, 0xB0, 0x00, 0x02, 0x10};
@ -17,32 +19,7 @@ struct aimepcsc_context {
CHAR last_error[256]; CHAR last_error[256];
}; };
static int read_felica_aime(struct aimepcsc_context *ctx, LPSCARDHANDLE card, struct aime_data *data) { #define APDU_SEND(card, cmd, expected_res_len) \
uint8_t buf[32];
DWORD len;
LONG ret;
/* read card ID */
len = sizeof(buf);
ret = SCardTransmit(*card, SCARD_PCI_T1, (LPCBYTE) "\xFF\xCA\x00\x00\x00", 5, NULL, buf, &len);
if (ret != SCARD_S_SUCCESS) {
snprintf(ctx->last_error, sizeof(ctx->last_error), "SCardTransmit failed: %08lX", (ULONG) ret);
return -1;
}
if (len != 10) {
snprintf(ctx->last_error, sizeof(ctx->last_error), "invalid card ID length: %lu", len);
return -1;
}
data->card_id_len = 8;
memcpy(data->card_id, buf, 8);
return 0;
}
#define M1K_CMD(card, cmd, expected_res_len) \
do { \ do { \
len = sizeof(buf); \ len = sizeof(buf); \
ret = SCardTransmit(*card, SCARD_PCI_T1, cmd, sizeof(cmd), NULL, buf, &len); \ ret = SCardTransmit(*card, SCARD_PCI_T1, cmd, sizeof(cmd), NULL, buf, &len); \
@ -52,23 +29,37 @@ static int read_felica_aime(struct aimepcsc_context *ctx, LPSCARDHANDLE card, st
} \ } \
if (len != expected_res_len || buf[expected_res_len - 2] != 0x90 || buf[expected_res_len - 1] != 0x00) { \ if (len != expected_res_len || buf[expected_res_len - 2] != 0x90 || buf[expected_res_len - 1] != 0x00) { \
snprintf(ctx->last_error, sizeof(ctx->last_error), #cmd " failed; res_len=%lu, res_code=%02x%02x", len, buf[2], buf[3]); \ snprintf(ctx->last_error, sizeof(ctx->last_error), #cmd " failed; res_len=%lu, res_code=%02x%02x", len, buf[2], buf[3]); \
return -1; \ return 1; \
} \ } \
} while (0) } while (0)
static int read_felica_aime(struct aimepcsc_context *ctx, LPSCARDHANDLE card, struct aime_data *data) {
uint8_t buf[32];
DWORD len;
LONG ret;
/* read card ID */
APDU_SEND(card, felica_cmd_readidm, 10);
data->card_id_len = 8;
memcpy(data->card_id, buf, 8);
return 0;
}
static int read_m1k_aime(struct aimepcsc_context *ctx, LPSCARDHANDLE card, struct aime_data *data) { static int read_m1k_aime(struct aimepcsc_context *ctx, LPSCARDHANDLE card, struct aime_data *data) {
uint8_t buf[32]; uint8_t buf[32];
DWORD len; DWORD len;
LONG ret; LONG ret;
/* load key onto reader */ /* load key onto reader */
M1K_CMD(card, m1k_cmd_loadkey, 2); APDU_SEND(card, m1k_cmd_loadkey, 2);
/* authenticate block 2 */ /* authenticate block 2 */
M1K_CMD(card, m1k_cmd_auth_block2, 2); APDU_SEND(card, m1k_cmd_auth_block2, 2);
/* read block 2 */ /* read block 2 */
M1K_CMD(card, m1k_cmd_read_block2, 18); APDU_SEND(card, m1k_cmd_read_block2, 18);
data->card_id_len = 10; data->card_id_len = 10;
memcpy(data->card_id, buf + 6, 10); memcpy(data->card_id, buf + 6, 10);
@ -132,6 +123,9 @@ int aimepcsc_poll(struct aimepcsc_context *ctx, struct aime_data *data) {
LONG ret; LONG ret;
LPBYTE pbAttr = NULL; LPBYTE pbAttr = NULL;
DWORD cByte = SCARD_AUTOALLOCATE; DWORD cByte = SCARD_AUTOALLOCATE;
int retval;
retval = 0;
memset(&rs, 0, sizeof(SCARD_READERSTATE)); memset(&rs, 0, sizeof(SCARD_READERSTATE));
@ -177,40 +171,41 @@ int aimepcsc_poll(struct aimepcsc_context *ctx, struct aime_data *data) {
if (cByte != 20) { if (cByte != 20) {
snprintf(ctx->last_error, sizeof(ctx->last_error), "invalid ATR length: %lu", cByte); snprintf(ctx->last_error, sizeof(ctx->last_error), "invalid ATR length: %lu", cByte);
goto errout; retval = 1;
goto out;
} }
/* check ATR */ /* check ATR */
if (memcmp(pbAttr, atr_ios14443_common, sizeof(atr_ios14443_common)) != 0) { if (memcmp(pbAttr, atr_ios14443_common, sizeof(atr_ios14443_common)) != 0) {
snprintf(ctx->last_error, sizeof(ctx->last_error), "invalid card type."); snprintf(ctx->last_error, sizeof(ctx->last_error), "invalid card type.");
goto errout; retval = 1;
goto out;
} }
/* check card type */ /* check card type */
if (memcmp(pbAttr + sizeof(atr_ios14443_common), cardtype_m1k, sizeof(cardtype_m1k)) == 0) { if (memcmp(pbAttr + sizeof(atr_ios14443_common), cardtype_m1k, sizeof(cardtype_m1k)) == 0) {
data->card_type = Mifare; data->card_type = Mifare;
if (read_m1k_aime(ctx, &hCard, data) != 0) { if (read_m1k_aime(ctx, &hCard, data) < 0) {
goto errout; retval = -1;
goto out;
} }
} else if (memcmp(pbAttr + sizeof(atr_ios14443_common), cardtype_felica, sizeof(cardtype_felica)) == 0) { } else if (memcmp(pbAttr + sizeof(atr_ios14443_common), cardtype_felica, sizeof(cardtype_felica)) == 0) {
data->card_type = FeliCa; data->card_type = FeliCa;
if (read_felica_aime(ctx, &hCard, data) != 0) { if (read_felica_aime(ctx, &hCard, data) < 0) {
goto errout; retval = -1;
goto out;
} }
} else { } else {
snprintf(ctx->last_error, sizeof(ctx->last_error), "invalid card type."); snprintf(ctx->last_error, sizeof(ctx->last_error), "invalid card type.");
goto errout; retval = 1;
goto out;
} }
out:
SCardFreeMemory(ctx->hContext, pbAttr); SCardFreeMemory(ctx->hContext, pbAttr);
SCardDisconnect(hCard, SCARD_LEAVE_CARD); SCardDisconnect(hCard, SCARD_LEAVE_CARD);
return 0; return retval;
errout:
SCardFreeMemory(ctx->hContext, pbAttr);
SCardDisconnect(hCard, SCARD_LEAVE_CARD);
return -1;
} }
const char* aimepcsc_error(struct aimepcsc_context *ctx) { const char* aimepcsc_error(struct aimepcsc_context *ctx) {

View File

@ -3,7 +3,7 @@ aimeio-pcsc
PC/SC-based Aime card reader for `segatools`. `aimeio-pcsc` allows you to use PC/SC compliant smart card readers as your Aime card reader in `segatools`. `aimeio-pcsc` only properly supports the old Mifare Classic 1K-based Aime cards. PC/SC-based Aime card reader for `segatools`. `aimeio-pcsc` allows you to use PC/SC compliant smart card readers as your Aime card reader in `segatools`. `aimeio-pcsc` only properly supports the old Mifare Classic 1K-based Aime cards.
If you scan a newer AIC-based AIME, its FeliCa IDm will be provided to the game. The game will not see the correct "access code," but the IDm should be unique to each card so that particular card can still track your plays. If you scan a newer AIC-based Aime, its FeliCa IDm will be provided to the game. The game will not see the correct "access code," but the IDm should be unique to each card so that particular card can still track your plays.
Tested on SONY's PaSoRi RC-S300. Other readers should, in theory, also work. Tested on SONY's PaSoRi RC-S300. Other readers should, in theory, also work.