diff --git a/NEWS b/NEWS index 0c20042..b84a1e5 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ Changes between 0.3.0 and 0.3.1 [XX xxx XXXX] *) Fix mifare_classic_transfer() for devices returning a 1 byte response on success. + *) New API function mifare_desfire_last_pcd_error(). Changes between 0.2.3 and 0.3.0 [23 dec 2010] diff --git a/libfreefare/Makefile.am b/libfreefare/Makefile.am index af47a9d..d530df3 100644 --- a/libfreefare/Makefile.am +++ b/libfreefare/Makefile.am @@ -51,6 +51,7 @@ linkedman = \ freefare_error.3 freefare_perror.3 \ freefare_error.3 freefare_strerror.3 \ freefare_error.3 freefare_strerror_r.3 \ + freefare_error.3 mifare_desfire_last_pcd_error.3 \ freefare_error.3 mifare_desfire_last_picc_error.3 \ mad.3 mad_free.3 \ mad.3 mad_get_aid.3 \ diff --git a/libfreefare/freefare.h b/libfreefare/freefare.h index bc608ca..842c65e 100644 --- a/libfreefare/freefare.h +++ b/libfreefare/freefare.h @@ -244,6 +244,10 @@ enum mifare_desfire_file_types { #define FILE_NOT_FOUND 0xF0 #define FILE_INTEGRITY_ERROR 0xF1 +/* Error code managed by the library */ + +#define CRYPTO_ERROR 0x01 + struct mifare_desfire_aid; typedef struct mifare_desfire_aid *MifareDESFireAID; @@ -251,6 +255,7 @@ MifareDESFireAID mifare_desfire_aid_new (uint32_t aid); MifareDESFireAID mifare_desfire_aid_new_with_mad_aid (MadAid mad_aid, uint8_t n); uint32_t mifare_desfire_aid_get_aid (MifareDESFireAID aid); +uint8_t mifare_desfire_last_pcd_error (MifareTag tag); uint8_t mifare_desfire_last_picc_error (MifareTag tag); #pragma pack (push) diff --git a/libfreefare/freefare_error.3 b/libfreefare/freefare_error.3 index 12c4a08..c865757 100644 --- a/libfreefare/freefare_error.3 +++ b/libfreefare/freefare_error.3 @@ -53,6 +53,8 @@ Mifare card manipulation library (libfreefare, \-lfreefare) .Ft "void" .Fn freefare_strerror "MifareTag tag" "char *string" .Ft uint8_t +.Fm mifare_desfire_last_pcd_error "MifareTag tag" +.Ft uint8_t .Fm mifare_desfire_last_picc_error "MifareTag tag" .\" ____ _ _ _ .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ @@ -84,6 +86,10 @@ function displays the last PCD or PICC error encounred using to stderr. .Pp The +.Fn mifare_desfire_last_pcd_error +function returns the error code of the last function call from the library. +.Pp +The .Fn mifare_desfire_last_picc_error function returns the error code returned by the last command run on .Vt tag . @@ -97,9 +103,11 @@ function returns the error code returned by the last command run on .Fn freefare_strerror returns the error message, .Fn freefare_strerror_r -returns 0 on success, -1 on failure, and +returns 0 on success, -1 on failure; +.Fn mifare_desfire_last_pcd_error +and .Fn mifare_desfire_last_picc_error -returns an error code or 0 if no error is known or +return an error code or 0 if no error occured or if .Vt tag is not a Mifare DESFire target. .\" ____ _ diff --git a/libfreefare/mifare_desfire.c b/libfreefare/mifare_desfire.c index 4affbce..a8d378a 100644 --- a/libfreefare/mifare_desfire.c +++ b/libfreefare/mifare_desfire.c @@ -169,6 +169,7 @@ static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_ /* 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, "===> "); \ if (!(nfc_initiator_transceive_bytes (tag->device, __msg, __len, __res, &__##res##_n))) { \ return errno = EIO, -1; \ @@ -326,8 +327,6 @@ authenticate (MifareTag tag, uint8_t cmd, uint8_t key_no, MifareDESFireKey key) memset (MIFARE_DESFIRE (tag)->ivect, 0, MAX_CRYPTO_BLOCK_SIZE); - MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; - MIFARE_DESFIRE (tag)->authenticated_key_no = NOT_YET_AUTHENTICATED; free (MIFARE_DESFIRE (tag)->session_key); MIFARE_DESFIRE (tag)->session_key = NULL; @@ -1305,7 +1304,7 @@ read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_t break; } } - uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 8, cs | CMAC_COMMAND); + uint8_t *p = mifare_cryto_preprocess_data (tag, cmd, &__cmd_n, 8, MDCM_PLAIN | CMAC_COMMAND); cs = ocs; /* @@ -1329,7 +1328,7 @@ read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_t ssize_t sr = bytes_received; p = mifare_cryto_postprocess_data (tag, data, &sr, cs | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY); - return sr - 1; + return (sr <= 0) ? sr : sr - 1; } ssize_t @@ -1387,7 +1386,7 @@ write_data (MifareTag tag, uint8_t command, uint8_t file_no, off_t offset, size_ } ssize_t sn = __res_n; - p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_MACED | CMAC_COMMAND | CMAC_VERIFY); + p = mifare_cryto_postprocess_data (tag, res, &sn, MDCM_PLAIN | CMAC_COMMAND | CMAC_VERIFY); if (0x00 == p[__res_n-1]) { // Remove header length diff --git a/libfreefare/mifare_desfire_crypto.c b/libfreefare/mifare_desfire_crypto.c index 8f7dfa2..59f7890 100644 --- a/libfreefare/mifare_desfire_crypto.c +++ b/libfreefare/mifare_desfire_crypto.c @@ -473,12 +473,12 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c mifare_cypher_blocks_chained (tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER); if (0 != memcmp ((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) { - warnx ("MACing not verified"); #if WITH_DEBUG + warnx ("MACing not verified"); hexdump ((uint8_t *)data + *nbytes - 1, key_macing_length (key), "Expect ", 0); hexdump ((uint8_t *)edata + edl - 8, key_macing_length (key), "Actual ", 0); - abort (); #endif + MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; *nbytes = -1; res = NULL; } @@ -507,8 +507,8 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c warnx ("CMAC NOT verified :-("); hexdump ((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0); hexdump (MIFARE_DESFIRE (tag)->cmac, 8, "Actual ", 0); - abort (); #endif + MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; *nbytes = -1; res = NULL; } else { @@ -555,10 +555,10 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c } while (!verified && (end_crc_pos < *nbytes)); if (!verified) { - warnx ("(3)DES not verified"); #if WITH_DEBUG - abort (); + warnx ("(3)DES not verified"); #endif + MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; *nbytes = -1; res = NULL; } @@ -582,12 +582,12 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c desfire_crc32 (res, p - (uint8_t *)res, crc); if (memcmp (crc, crc_ref, 4)) { - warnx ("AES CRC32 not verified in AES stream"); #if WITH_DEBUG + warnx ("AES CRC32 not verified in AES stream"); hexdump (crc_ref, 4, "Expect ", 0); hexdump (crc, 4, "Actual ", 0); - abort (); #endif + MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR; *nbytes = -1; res = NULL; } diff --git a/libfreefare/mifare_desfire_error.c b/libfreefare/mifare_desfire_error.c index 61f86c4..9f4888e 100644 --- a/libfreefare/mifare_desfire_error.c +++ b/libfreefare/mifare_desfire_error.c @@ -54,6 +54,7 @@ static struct error_message { EM(EEPROM_ERROR), EM(FILE_NOT_FOUND), EM(FILE_INTEGRITY_ERROR), + EM(CRYPTO_ERROR), { 0, NULL } }; @@ -70,6 +71,15 @@ mifare_desfire_error_lookup (uint8_t code) return "Invalid error code"; } +uint8_t +mifare_desfire_last_pcd_error (MifareTag tag) +{ + if (tag->tag_info->type != DESFIRE) + return 0; + + return MIFARE_DESFIRE (tag)->last_pcd_error; +} + uint8_t mifare_desfire_last_picc_error (MifareTag tag) { diff --git a/test/test_mifare_desfire.c b/test/test_mifare_desfire.c index b865edb..92354fe 100644 --- a/test/test_mifare_desfire.c +++ b/test/test_mifare_desfire.c @@ -930,3 +930,68 @@ test_mifare_desfire_des_macing (void) mifare_desfire_key_free (key); } + +void +test_mifare_desfire_free_read (void) +{ + int res; + + mifare_desfire_auto_authenticate (tag, 0); + + /* Wipeout the card */ + res = mifare_desfire_format_picc (tag); + cut_assert_success ("mifare_desfire_format_picc()"); + + mifare_desfire_auto_authenticate (tag, 0); + + MifareDESFireKey key = mifare_desfire_des_key_new_with_version (key_data_null); + res = mifare_desfire_change_key (tag, 0, key, NULL); + cut_assert_success ("mifare_desfire_change_key()"); + + res = mifare_desfire_authenticate (tag, 0, key); + cut_assert_success ("mifare_desfire_authenticate()"); + + MifareDESFireAID aid = mifare_desfire_aid_new (0x00123456); + res = mifare_desfire_create_application (tag, aid, 0xFF, 2); + cut_assert_success ("mifare_desfire_create_application()"); + + res = mifare_desfire_select_application (tag, aid); + cut_assert_success ("mifare_desfire_select_application"); + free (aid); + + res = mifare_desfire_authenticate (tag, 0, key); + cut_assert_success ("mifare_desfire_authenticate()"); + + res = mifare_desfire_create_std_data_file (tag, 1, MDCM_MACED, 0x0000, 20); + cut_assert_success ("mifare_desfire_create_std_data_file()"); + + char *s= "Hello World"; + res = mifare_desfire_write_data (tag, 1, 0, strlen (s), s); + cut_assert_success ("mifare_desfire_write_data()"); + + res = mifare_desfire_change_file_settings (tag, 1, MDCM_ENCIPHERED, 0xEFFF); + cut_assert_success ("mifare_desfire_change_file_settings"); + + char buffer[20]; + res = mifare_desfire_read_data (tag, 1, 0, 0, buffer); + cut_assert_equal_int (sizeof (buffer), res, cut_message ("Data with free access should be read in PLAIN mode only.")); + cut_assert_equal_int (OPERATION_OK, mifare_desfire_last_pcd_error (tag), cut_message ("Wrong PCD error")); + + res = mifare_desfire_read_data_ex (tag, 1, 0, 0, buffer, MDCM_MACED); + cut_assert_equal_int (-1, res, cut_message ("Data with free access should be read in PLAIN mode only.")); + cut_assert_equal_int (CRYPTO_ERROR, mifare_desfire_last_pcd_error (tag), cut_message ("Wrong PCD error")); + + res = mifare_desfire_read_data_ex (tag, 1, 0, 0, buffer, MDCM_ENCIPHERED); + cut_assert_equal_int (-1, res, cut_message ("Data with free access should be read in PLAIN mode only.")); + cut_assert_equal_int (CRYPTO_ERROR, mifare_desfire_last_pcd_error (tag), cut_message ("Wrong PCD error")); + + /* Wipeout the card */ + mifare_desfire_select_application (tag, NULL); + cut_assert_equal_int (OPERATION_OK, mifare_desfire_last_pcd_error (tag), cut_message ("Wrong PCD error")); + res = mifare_desfire_authenticate (tag, 0, key); + + res = mifare_desfire_format_picc (tag); + cut_assert_success ("mifare_desfire_format_picc()"); + + mifare_desfire_key_free (key); +}