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.
This commit is contained in:
Romain Tartiere 2011-02-13 14:13:35 +00:00
parent 04fe89e78c
commit 22e9854995
8 changed files with 103 additions and 14 deletions

1
NEWS
View file

@ -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 *) Fix mifare_classic_transfer() for devices returning a 1 byte response on
success. success.
*) New API function mifare_desfire_last_pcd_error().
Changes between 0.2.3 and 0.3.0 [23 dec 2010] Changes between 0.2.3 and 0.3.0 [23 dec 2010]

View file

@ -51,6 +51,7 @@ linkedman = \
freefare_error.3 freefare_perror.3 \ freefare_error.3 freefare_perror.3 \
freefare_error.3 freefare_strerror.3 \ freefare_error.3 freefare_strerror.3 \
freefare_error.3 freefare_strerror_r.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 \ freefare_error.3 mifare_desfire_last_picc_error.3 \
mad.3 mad_free.3 \ mad.3 mad_free.3 \
mad.3 mad_get_aid.3 \ mad.3 mad_get_aid.3 \

View file

@ -244,6 +244,10 @@ enum mifare_desfire_file_types {
#define FILE_NOT_FOUND 0xF0 #define FILE_NOT_FOUND 0xF0
#define FILE_INTEGRITY_ERROR 0xF1 #define FILE_INTEGRITY_ERROR 0xF1
/* Error code managed by the library */
#define CRYPTO_ERROR 0x01
struct mifare_desfire_aid; struct mifare_desfire_aid;
typedef struct mifare_desfire_aid *MifareDESFireAID; 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); MifareDESFireAID mifare_desfire_aid_new_with_mad_aid (MadAid mad_aid, uint8_t n);
uint32_t mifare_desfire_aid_get_aid (MifareDESFireAID aid); 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); uint8_t mifare_desfire_last_picc_error (MifareTag tag);
#pragma pack (push) #pragma pack (push)

View file

@ -53,6 +53,8 @@ Mifare card manipulation library (libfreefare, \-lfreefare)
.Ft "void" .Ft "void"
.Fn freefare_strerror "MifareTag tag" "char *string" .Fn freefare_strerror "MifareTag tag" "char *string"
.Ft uint8_t .Ft uint8_t
.Fm mifare_desfire_last_pcd_error "MifareTag tag"
.Ft uint8_t
.Fm mifare_desfire_last_picc_error "MifareTag tag" .Fm mifare_desfire_last_picc_error "MifareTag tag"
.\" ____ _ _ _ .\" ____ _ _ _
.\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __ .\" | _ \ ___ ___ ___ _ __(_)_ __ | |_(_) ___ _ __
@ -84,6 +86,10 @@ function displays the last PCD or PICC error encounred using
to stderr. to stderr.
.Pp .Pp
The 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 .Fn mifare_desfire_last_picc_error
function returns the error code returned by the last command run on function returns the error code returned by the last command run on
.Vt tag . .Vt tag .
@ -97,9 +103,11 @@ function returns the error code returned by the last command run on
.Fn freefare_strerror .Fn freefare_strerror
returns the error message, returns the error message,
.Fn freefare_strerror_r .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 .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 .Vt tag
is not a Mifare DESFire target. is not a Mifare DESFire target.
.\" ____ _ .\" ____ _

View file

@ -169,6 +169,7 @@ static ssize_t read_data (MifareTag tag, uint8_t command, uint8_t file_no, off_
/* reply length */ \ /* reply length */ \
__msg[__len-1] = 0x00; \ __msg[__len-1] = 0x00; \
MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; \ MIFARE_DESFIRE (tag)->last_picc_error = OPERATION_OK; \
MIFARE_DESFIRE (tag)->last_pcd_error = OPERATION_OK; \
DEBUG_XFER (__msg, __len, "===> "); \ DEBUG_XFER (__msg, __len, "===> "); \
if (!(nfc_initiator_transceive_bytes (tag->device, __msg, __len, __res, &__##res##_n))) { \ if (!(nfc_initiator_transceive_bytes (tag->device, __msg, __len, __res, &__##res##_n))) { \
return errno = EIO, -1; \ 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); 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; MIFARE_DESFIRE (tag)->authenticated_key_no = NOT_YET_AUTHENTICATED;
free (MIFARE_DESFIRE (tag)->session_key); free (MIFARE_DESFIRE (tag)->session_key);
MIFARE_DESFIRE (tag)->session_key = NULL; 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; 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; 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; 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, data, &sr, cs | CMAC_COMMAND | CMAC_VERIFY | MAC_VERIFY);
return sr - 1; return (sr <= 0) ? sr : sr - 1;
} }
ssize_t 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; 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]) { if (0x00 == p[__res_n-1]) {
// Remove header length // Remove header length

View file

@ -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); 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)) { if (0 != memcmp ((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) {
warnx ("MACing not verified");
#if WITH_DEBUG #if WITH_DEBUG
warnx ("MACing not verified");
hexdump ((uint8_t *)data + *nbytes - 1, key_macing_length (key), "Expect ", 0); hexdump ((uint8_t *)data + *nbytes - 1, key_macing_length (key), "Expect ", 0);
hexdump ((uint8_t *)edata + edl - 8, key_macing_length (key), "Actual ", 0); hexdump ((uint8_t *)edata + edl - 8, key_macing_length (key), "Actual ", 0);
abort ();
#endif #endif
MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1; *nbytes = -1;
res = NULL; res = NULL;
} }
@ -507,8 +507,8 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c
warnx ("CMAC NOT verified :-("); warnx ("CMAC NOT verified :-(");
hexdump ((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0); hexdump ((uint8_t *)data + *nbytes - 9, 8, "Expect ", 0);
hexdump (MIFARE_DESFIRE (tag)->cmac, 8, "Actual ", 0); hexdump (MIFARE_DESFIRE (tag)->cmac, 8, "Actual ", 0);
abort ();
#endif #endif
MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1; *nbytes = -1;
res = NULL; res = NULL;
} else { } else {
@ -555,10 +555,10 @@ mifare_cryto_postprocess_data (MifareTag tag, void *data, ssize_t *nbytes, int c
} while (!verified && (end_crc_pos < *nbytes)); } while (!verified && (end_crc_pos < *nbytes));
if (!verified) { if (!verified) {
warnx ("(3)DES not verified");
#if WITH_DEBUG #if WITH_DEBUG
abort (); warnx ("(3)DES not verified");
#endif #endif
MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1; *nbytes = -1;
res = NULL; 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); desfire_crc32 (res, p - (uint8_t *)res, crc);
if (memcmp (crc, crc_ref, 4)) { if (memcmp (crc, crc_ref, 4)) {
warnx ("AES CRC32 not verified in AES stream");
#if WITH_DEBUG #if WITH_DEBUG
warnx ("AES CRC32 not verified in AES stream");
hexdump (crc_ref, 4, "Expect ", 0); hexdump (crc_ref, 4, "Expect ", 0);
hexdump (crc, 4, "Actual ", 0); hexdump (crc, 4, "Actual ", 0);
abort ();
#endif #endif
MIFARE_DESFIRE (tag)->last_pcd_error = CRYPTO_ERROR;
*nbytes = -1; *nbytes = -1;
res = NULL; res = NULL;
} }

View file

@ -54,6 +54,7 @@ static struct error_message {
EM(EEPROM_ERROR), EM(EEPROM_ERROR),
EM(FILE_NOT_FOUND), EM(FILE_NOT_FOUND),
EM(FILE_INTEGRITY_ERROR), EM(FILE_INTEGRITY_ERROR),
EM(CRYPTO_ERROR),
{ 0, NULL } { 0, NULL }
}; };
@ -70,6 +71,15 @@ mifare_desfire_error_lookup (uint8_t code)
return "Invalid error 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 uint8_t
mifare_desfire_last_picc_error (MifareTag tag) mifare_desfire_last_picc_error (MifareTag tag)
{ {

View file

@ -930,3 +930,68 @@ test_mifare_desfire_des_macing (void)
mifare_desfire_key_free (key); 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);
}