diff --git a/libfreefare/freefare.c b/libfreefare/freefare.c index 1364d17..45c75b2 100644 --- a/libfreefare/freefare.c +++ b/libfreefare/freefare.c @@ -230,7 +230,7 @@ freefare_tag_new_pcsc (struct pcsc_context *context, const char *reader) tag->tag_info = tag_info; FILL_SZREADER(tag, reader); - tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_LEAVE_CARD); + tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_RESET_CARD); return tag; } @@ -310,16 +310,19 @@ MifareTag * freefare_get_tags_pcsc (struct pcsc_context *context, const char *reader) { MifareTag *tags = NULL; + + MifareTag tag = freefare_tag_new_pcsc(context, reader); + if(tag == NULL) { + return NULL; + } tags = malloc(2*sizeof (MifareTag)); if(!tags) { return NULL; } - tags[0] = freefare_tag_new_pcsc(context, reader); + tags[0] = tag; tags[1] = NULL; - if(tags[0] == NULL) - return NULL; return tags; } @@ -451,8 +454,9 @@ pcsc_init(struct pcsc_context** context) LONG err; struct pcsc_context *con = malloc(sizeof(struct pcsc_context)); err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &con->context); - if (err < 0) + if (err != SCARD_S_SUCCESS) { + free(con); *context = NULL; return; } @@ -468,6 +472,7 @@ pcsc_exit(struct pcsc_context* context) if (context->readers) SCardFreeMemory(context->context, context->readers); SCardReleaseContext(context->context); + free(context); } /* diff --git a/libfreefare/freefare_internal.h b/libfreefare/freefare_internal.h index 13573e1..805faf2 100644 --- a/libfreefare/freefare_internal.h +++ b/libfreefare/freefare_internal.h @@ -314,8 +314,10 @@ struct mifare_ultralight_tag { #define TB_AB(ab) ((ab == C_DEFAULT) ? C_100 : ab) #ifdef WITH_DEBUG +#define DEBUG_FUNCTION() do { printf("*** \033[033;1m%s\033[0m ***\n", __FUNCTION__); } while (0) #define DEBUG_XFER(data, nbytes, hint) do { hexdump (data, nbytes, hint, 0); } while (0) #else +#define DEBUG_FUNCTION() do {} while (0) #define DEBUG_XFER(data, nbytes, hint) do {} while (0) #endif diff --git a/libfreefare/mifare_classic.c b/libfreefare/mifare_classic.c index 27d9247..a317a79 100644 --- a/libfreefare/mifare_classic.c +++ b/libfreefare/mifare_classic.c @@ -299,7 +299,7 @@ mifare_classic_disconnect (MifareTag tag) } else // pcsc way { - tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_LEAVE_CARD); + tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_RESET_CARD); if(SCARD_S_SUCCESS == tag->lastPCSCerror) { tag->active = 0; diff --git a/libfreefare/mifare_desfire.c b/libfreefare/mifare_desfire.c index b084694..e3d9952 100644 --- a/libfreefare/mifare_desfire.c +++ b/libfreefare/mifare_desfire.c @@ -157,56 +157,99 @@ static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_ * The Mifare DESFire function return value which is returned at the end of the * response is copied at the beginning to match the PICC documentation. */ -#define DESFIRE_TRANSCEIVE(tag, msg, res) \ - DESFIRE_TRANSCEIVE2 (tag, msg, __##msg##_n, res) /* Native DESFire APDUs will be wrapped in ISO7816-4 APDUs: CAPDUs will be 5 bytes longer (CLA+P1+P2+Lc+Le) RAPDUs will be 1 byte longer (SW1 SW2 instead of 1 status byte) */ -#define DESFIRE_TRANSCEIVE2(tag, msg, msg_len, res) \ - do { \ - static uint8_t __msg[MAX_CAPDU_SIZE + 5] = { 0x90, 0x00, 0x00, 0x00, 0x00, /* ..., */ 0x00 }; \ - /* CLA INS P1 P2 Lc PAYLOAD LE*/ \ - static uint8_t __res[MAX_RAPDU_SIZE + 1]; \ - size_t __len = 5; \ - errno = 0; \ - if (!msg) return errno = EINVAL, -1; \ - __msg[1] = msg[0]; \ - if (msg_len > 1) { \ - __len += msg_len; \ - __msg[4] = msg_len - 1; \ - memcpy (__msg + 5, msg + 1, msg_len - 1); \ - } \ - /* reply length */ \ - __msg[__len-1] = 0x00; \ - MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; \ - MIFARE_DESFIRE (tag)->last_pcd_error = OPERATION_OK; \ - DEBUG_XFER (__msg, __len, "===> "); \ - int _res; \ - if (tag->device == NULL) { /* pcsc branch */ \ - SCARD_IO_REQUEST __pcsc_rcv_pci; \ - DWORD __pcsc_recv_len = __##res##_size + 1; \ - if (SCARD_S_SUCCESS != SCardTransmit(tag->hCard, &tag->pioSendPci, __msg, __len, &__pcsc_rcv_pci, __res, &__pcsc_recv_len)) { \ - return errno = EIO, -1; \ - } \ - _res = __pcsc_recv_len; \ - } \ - else { /* nfc branch */ \ - if ((_res = nfc_initiator_transceive_bytes (tag->device, __msg, __len, __res, __##res##_size + 1, 0)) < 0) { \ - return errno = EIO, -1; \ - } \ - } \ - __##res##_n = _res; \ - DEBUG_XFER (__res, __##res##_n, "<=== "); \ - res[__##res##_n-2] = __res[__##res##_n-1]; \ - __##res##_n--; \ - if ((1 == __##res##_n) && (ADDITIONAL_FRAME != res[__##res##_n-1]) && (OPERATION_OK != res[__##res##_n-1])) { \ - return MIFARE_DESFIRE (tag)->last_picc_error = res[0], -1; \ - } \ - memcpy (res, __res, __##res##_n - 1); \ - } while (0) +static int +desfire_transceive(MifareTag tag, const uint8_t *msg, size_t msg_len, uint8_t *res, size_t res_size, size_t *res_len) +{ + uint8_t msg_buf[MAX_CAPDU_SIZE + 5]; + uint8_t res_buf[MAX_RAPDU_SIZE + 1]; + + size_t len = 5; + int rc; + + if (!msg) { + errno = EINVAL; + return -1; + } + + memset (msg_buf, 0, sizeof(msg_buf)); + msg_buf[0] = 0x90; // CLA + msg_buf[1] = msg[0]; // INS + // P1 & P2 is zero by default + + if (msg_len > 1) { + len += msg_len; + msg_buf[4] = msg_len - 1; // Lc + memcpy (msg_buf + 5, msg + 1, msg_len - 1); + } + + MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; + MIFARE_DESFIRE (tag)->last_pcd_error = OPERATION_OK; + + DEBUG_XFER (msg_buf, len, "===> "); + + if (tag->device == NULL) { + SCARD_IO_REQUEST __pcsc_rcv_pci; + DWORD __pcsc_recv_len = sizeof(res_buf); + if ((SCARD_S_SUCCESS != SCardTransmit(tag->hCard, SCARD_PCI_T1, msg_buf, len, &__pcsc_rcv_pci, res_buf, &__pcsc_recv_len)) < 0) { + return errno = EIO, -1; + } + rc = __pcsc_recv_len; + } else { + if ((rc = nfc_initiator_transceive_bytes (tag->device, msg_buf, len, res_buf, sizeof(res_buf), 0)) < 2) { + errno = (errno == ETIMEDOUT) ? errno : EIO; + return -1; + } + } + + DEBUG_XFER (res_buf, rc, "<=== "); + if (rc == 0) { + return errno = EIO, -1; + } + rc--; + if (rc > (int)res_size) { + errno = ENOBUFS; + return -1; + } + + int lpe = res_buf[rc]; + + res[rc - 1] = lpe; + + if ((1 == rc) && (ADDITIONAL_FRAME != res_buf[rc]) && (OPERATION_OK != res_buf[rc])) { + if (AUTHENTICATION_ERROR == lpe) + errno = EACCES; + + MIFARE_DESFIRE (tag)->last_picc_error = lpe; + return -1; + } + + if (res_len) + *res_len = rc; + memcpy (res, res_buf, rc - 1); + + errno = 0; + return 0; +} + +#ifdef WITH_DEBUG +// define a small but cute wrapper to allow debug output +#define MIFARE_DESFIRE_TRANSCEIVE(tag, msg, msg_len, res, res_size, res_len) ({ \ + int __err = 0; \ + do { \ + DEBUG_FUNCTION(); \ + __err = desfire_transceive(tag, msg, msg_len, res, res_size, res_len); \ + } while (0); \ + __err; \ + }) +#else +#define MIFARE_DESFIRE_TRANSCEIVE desfire_transceive +#endif /* * Miscellaneous low-level memory manipulation functions. @@ -364,7 +407,7 @@ mifare_desfire_disconnect (MifareTag tag) } else // pcsc way { - tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_LEAVE_CARD); + tag->lastPCSCerror = SCardDisconnect(tag->hCard, SCARD_RESET_CARD); if(SCARD_S_SUCCESS == tag->lastPCSCerror) { tag->active = 0; @@ -400,7 +443,9 @@ authenticate (MifareTag tag, uint8_t cmd, uint8_t key_no, MifareDESFireKey key) BUFFER_APPEND (cmd1, cmd); BUFFER_APPEND (cmd1, key_no); - DESFIRE_TRANSCEIVE (tag, cmd1, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, cmd1, __cmd1_n, res, __res_size, &__res_n)) < 0) + return rc; size_t key_length = __res_n - 1; @@ -429,7 +474,8 @@ authenticate (MifareTag tag, uint8_t cmd, uint8_t key_no, MifareDESFireKey key) BUFFER_APPEND (cmd2, 0xAF); BUFFER_APPEND_BYTES (cmd2, token, 2*key_length); - DESFIRE_TRANSCEIVE (tag, cmd2, res); + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, cmd2, __cmd2_n, res, __res_size, &__res_n)) < 0) + return rc; uint8_t PICC_E_RndA_s[16]; memcpy (PICC_E_RndA_s, res, key_length); @@ -512,7 +558,9 @@ mifare_desfire_change_key_settings (MifareTag tag, uint8_t settings) char *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 1, MDCM_ENCIPHERED | ENC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t n = __res_n; p = mifare_cryto_postprocess_data (tag, res, &n, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY | MAC_COMMAND | MAC_VERIFY); @@ -536,7 +584,9 @@ mifare_desfire_get_key_settings (MifareTag tag, uint8_t *settings, uint8_t *max_ char *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 1, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t n = __res_n; p = mifare_cryto_postprocess_data (tag, res, &n, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -643,7 +693,9 @@ mifare_desfire_change_key (MifareTag tag, uint8_t key_no, MifareDESFireKey new_k uint8_t * p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, MDCM_ENCIPHERED | ENC_COMMAND | NO_CRC); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -682,7 +734,9 @@ mifare_desfire_get_key_version (MifareTag tag, uint8_t key_no, uint8_t *version) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY); @@ -721,7 +775,9 @@ create_application (MifareTag tag, MifareDESFireAID aid, uint8_t settings1, uint uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY); @@ -782,7 +838,9 @@ mifare_desfire_delete_application (MifareTag tag, MifareDESFireAID aid) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -806,6 +864,7 @@ mifare_desfire_delete_application (MifareTag tag, MifareDESFireAID aid) int mifare_desfire_get_application_ids (MifareTag tag, MifareDESFireAID *aids[], size_t *count) { + int rc; ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); @@ -819,7 +878,8 @@ mifare_desfire_get_application_ids (MifareTag tag, MifareDESFireAID *aids[], siz uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; // FIXME This code needs refactoring! memcpy (buffer, res, __res_n); @@ -827,7 +887,8 @@ mifare_desfire_get_application_ids (MifareTag tag, MifareDESFireAID *aids[], siz if (res[__res_n-1] == 0xAF) { off_t offset = __res_n - 1; p[0] = 0xAF; - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; memcpy ((uint8_t *)buffer + offset, res, __res_n); __res_n += offset; @@ -841,7 +902,6 @@ mifare_desfire_get_application_ids (MifareTag tag, MifareDESFireAID *aids[], siz *count = (sn - 1)/3; - *aids = malloc (sn - 1); if (!(*aids = malloc ((*count + 1) * sizeof (MifareDESFireAID)))) return -1; @@ -876,7 +936,9 @@ mifare_desfire_get_df_names (MifareTag tag, MifareDESFireDF *dfs[], size_t *coun uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); do { - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; if (__res_n > 1) { MifareDESFireDF *new_dfs; @@ -928,7 +990,9 @@ mifare_desfire_select_application (MifareTag tag, MifareDESFireAID aid) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND); @@ -961,7 +1025,9 @@ mifare_desfire_format_picc (MifareTag tag) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -982,6 +1048,7 @@ mifare_desfire_format_picc (MifareTag tag) int mifare_desfire_get_version (MifareTag tag, struct mifare_desfire_version_info *version_info) { + int rc; ASSERT_ACTIVE (tag); ASSERT_MIFARE_DESFIRE (tag); @@ -995,16 +1062,19 @@ mifare_desfire_get_version (MifareTag tag, struct mifare_desfire_version_info *v BUFFER_APPEND (cmd, 0x60); uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; memcpy (&(version_info->hardware), res, 7); memcpy (buffer, res, 7); p[0] = 0xAF; - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; memcpy (&(version_info->software), res, 7); memcpy (buffer + 7, res, 7); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; memcpy (&(version_info->uid), res, 14); memcpy (buffer + 14, res, __res_n); @@ -1032,7 +1102,9 @@ mifare_desfire_free_mem (MifareTag tag, uint32_t *size) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1060,7 +1132,9 @@ mifare_desfire_set_configuration (MifareTag tag, bool disable_format, bool enabl uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, MDCM_ENCIPHERED | ENC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1100,7 +1174,9 @@ mifare_desfire_set_default_key (MifareTag tag, MifareDESFireKey key) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, MDCM_ENCIPHERED | ENC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1137,7 +1213,9 @@ mifare_desfire_set_ats (MifareTag tag, uint8_t *ats) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, MDCM_ENCIPHERED | NO_CRC | ENC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1163,7 +1241,9 @@ mifare_desfire_get_card_uid (MifareTag tag, char **uid) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 1, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_ENCIPHERED); @@ -1199,7 +1279,9 @@ mifare_desfire_get_file_ids (MifareTag tag, uint8_t *files[], size_t *count) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1238,7 +1320,9 @@ mifare_desfire_get_iso_file_ids (MifareTag tag, uint16_t *files[], size_t *count uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); do { - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; memcpy (data + offset, res, __res_n - 1); offset += __res_n - 1; @@ -1283,7 +1367,9 @@ mifare_desfire_get_file_settings (MifareTag tag, uint8_t file_no, struct mifare_ uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1346,7 +1432,9 @@ mifare_desfire_change_file_settings (MifareTag tag, uint8_t file_no, uint8_t com BUFFER_APPEND_LE (cmd, access_rights, 2, sizeof (uint16_t)); uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1364,7 +1452,9 @@ mifare_desfire_change_file_settings (MifareTag tag, uint8_t file_no, uint8_t com uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, MDCM_ENCIPHERED | ENC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1395,7 +1485,9 @@ create_file1 (MifareTag tag, uint8_t command, uint8_t file_no, int has_iso_file_ char *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1452,7 +1544,9 @@ mifare_desfire_create_value_file (MifareTag tag, uint8_t file_no, uint8_t commun char *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1485,7 +1579,9 @@ create_file2 (MifareTag tag, uint8_t command, uint8_t file_no, int has_iso_file_ char *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1536,7 +1632,9 @@ mifare_desfire_delete_file (MifareTag tag, uint8_t file_no) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1568,6 +1666,8 @@ read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_t BUFFER_APPEND_LE (cmd, offset, 3, sizeof (off_t)); BUFFER_APPEND_LE (cmd, length, 3, sizeof (size_t)); + int record_size = 1; + uint8_t ocs = cs; if ((MIFARE_DESFIRE (tag)->session_key) && (cs | MDCM_MACED)) { switch (MIFARE_DESFIRE (tag)->authentication_scheme) { @@ -1581,26 +1681,45 @@ read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_t uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 8, MDCM_PLAIN | CMAC_COMMAND); cs = ocs; + /* + * Depending on the communication settings, we might read more bytes than + * the actual data length (a MAC or padding padding might follow). This + * can be a problem if the destination buffer is long enouth for the data + * but the MAC / padding overflows. + * + * Create a temporary read buffer to collect all read data, post-process it + * through the cryptography code and copy the actual data to the + * destination buffer. + */ + uint8_t *read_buffer = malloc(enciphered_data_length(tag, length * record_size, 0) + 1); + /* * FIXME: This is bogus: the user has to provide a data buffer with enougth * room to store CRC + padding or MAC. If the user wants to read 1 byte, * there is no reason to provide a 16 bytes buffer. */ do { - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; size_t frame_bytes = BUFFER_SIZE (res) - 1; - memcpy ((uint8_t *)data + bytes_received, res, frame_bytes); + memcpy(read_buffer + bytes_received, res, frame_bytes); bytes_received += frame_bytes; p[0] = 0xAF; __cmd_n = 1; } while (0xAF == res[__res_n-1]); - ((uint8_t *)data)[bytes_received++] = 0x00; + read_buffer[bytes_received++] = 0x00; ssize_t sr = bytes_received; - p = mifare_cryto_postprocess_data (tag, data, &sr, cs | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY); + p = mifare_cryto_postprocess_data (tag, read_buffer, &sr, cs | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY); + + if (sr > 0) + memcpy(data, read_buffer, sr - 1); + + free(read_buffer); if (!p) return errno = EINVAL, -1; @@ -1649,7 +1768,9 @@ write_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_ size_t frame_bytes = MIN(bytes_left, __cmd_n - bytes_send); BUFFER_APPEND_BYTES (d, p + bytes_send, frame_bytes); - DESFIRE_TRANSCEIVE (tag, d, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, d, __d_n, res, __res_size, &__res_n)) < 0) + return rc; bytes_send += frame_bytes; @@ -1718,7 +1839,9 @@ mifare_desfire_get_value_ex (MifareTag tag, uint8_t file_no, int32_t *value, int uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, cs | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY); @@ -1752,7 +1875,9 @@ mifare_desfire_credit_ex (MifareTag tag, uint8_t file_no, int32_t amount, int cs BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t)); uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1785,7 +1910,9 @@ mifare_desfire_debit_ex (MifareTag tag, uint8_t file_no, int32_t amount, int cs) BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t)); uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1818,7 +1945,9 @@ mifare_desfire_limited_credit_ex (MifareTag tag, uint8_t file_no, int32_t amount BUFFER_APPEND_LE (cmd, amount, 4, sizeof (int32_t)); uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 2, cs | MAC_COMMAND | CMAC_COMMAND | ENC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1868,7 +1997,9 @@ mifare_desfire_clear_record_file (MifareTag tag, uint8_t file_no) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1894,7 +2025,9 @@ mifare_desfire_commit_transaction (MifareTag tag) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1918,7 +2051,9 @@ mifare_desfire_abort_transaction (MifareTag tag) uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 0, MDCM_PLAIN | CMAC_COMMAND); - DESFIRE_TRANSCEIVE2 (tag, p, __cmd_n, res); + int rc; + if ((rc = MIFARE_DESFIRE_TRANSCEIVE(tag, p, __cmd_n, res, __res_size, &__res_n)) < 0) + return rc; ssize_t sn = __res_n; p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); @@ -1928,4 +2063,3 @@ mifare_desfire_abort_transaction (MifareTag tag) return 0; } -