From 22e9854995af5916fe544cfae66893b4d1cb0bd0 Mon Sep 17 00:00:00 2001 From: Romain Tartiere Date: Sun, 13 Feb 2011 14:13:35 +0000 Subject: [PATCH] Do not abort on crypto error. Because in some circumstances the crypto is skipped regardless of the communication settings by the Mifare DESFire (e.g. when reading a file which is writable with any key), do not abort if the crypto fail, and make it possible to the user to catch such an event to fix his code accordingly. Only display crypto diagnostic if compiled with debug support. --- NEWS | 1 + libfreefare/Makefile.am | 1 + libfreefare/freefare.h | 5 +++ libfreefare/freefare_error.3 | 12 +++++- libfreefare/mifare_desfire.c | 9 ++-- libfreefare/mifare_desfire_crypto.c | 14 +++---- libfreefare/mifare_desfire_error.c | 10 +++++ test/test_mifare_desfire.c | 65 +++++++++++++++++++++++++++++ 8 files changed, 103 insertions(+), 14 deletions(-) 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); +}