nfc-tools / libfreefare

A convenience API for NFC cards manipulations on top of libnfc.
Other
407 stars 105 forks source link

On Error Handling/Raw Libnfc Access #10

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
I'm using libfreefare for multiple DESfire projects (as of yet: 
https://github.com/henryk/libopenkey and 
https://github.com/henryk/desfire-tools). One issue that's come up multiple 
times is handling a "card removed" error.

From the PC/SC environment I'm used to having the framework handle that: Once a 
card connection is lost, all further attempts to submit commands will 
immediately return with an error. libfreefare doesn't do that. Calling for 
example mifare_desfire_select_application() on a card that's been removed will 
actually try to transmit the command (as seen in DEBUG_XFER output) and return 
after a timeout.

libnfc provides nfc_device_get_last_error() which will return NFC_ERFTRANS in 
this case, but it can't be accessed properly from libfreefare. I've discovered 
that MifareTag can be cast to nfc_device** and then dereferenced to call libnfc 
functions (see 
https://github.com/henryk/desfire-tools/blob/64dbb9d51c3feecd1aa99da8556273ebc7c
7db84/src/mifare-desfire-analyze.c#L45) and am using this as a workaround, but 
that's hardly proper methodology.

Could libfreefare either:
a) Provide a defined way to access the nfc_device pointer and call libnfc 
functions (even just defining the above cast as proper and promising to always 
keep the structure to allow it would suffice for this)
b) Track permanent errors and not carry out any timeout-inducing actions 
afterwards. Or at least give a defined feedback to the caller that he may not 
attempt any further action on the tag. (Currently you could do something like 
"if mifare_desfire_select_application() fails but both 
mifare_desfire_last_picc_error() and mifare_desfire_last_pcd_error() return 0 
then maybe the tag is gone" but that's only a heuristic and not easily 
universally used.)

Actually it would be best if both happen. The point where I initially 
discovered the cast is for 
https://github.com/henryk/desfire-tools/blob/64dbb9d51c3feecd1aa99da8556273ebc7c
7db84/src/mifare-desfire-analyze.c#L296 where I want to find out if an AES or 
DES authentication is directly answered with an authentication error (meaning 
that the authentication mode is not supported) or an additional frame status 
(meaning that the authentication mode is supported). 
mifare_desfire_authenticate() handles these internally and 
mifare_desfire_last_picc_error() doesn't distinguish between "authentication 
mode not supported" and "key wrong". So I still need the ability to issue raw 
libnfc commands, or maybe a status flag that I can interrogate that shows 
whether the authentication failed after the first or second command.

Original issue reported on code.google.com by hen...@ploetzli.ch on 17 May 2013 at 11:43

GoogleCodeExporter commented 9 years ago
Hello,

Your suggests are really good but there is no active developer, ie. no feature 
improvement.

I usually do the job to port this library to new libnfc and apply patches when 
relevant.
I can't handle your issue, so if you want it and your are able to wrote it, 
feel free to submit patches (clone git repo, etc). I will be really happy to 
apply your patches upstream.

Original comment by romu...@libnfc.org on 21 May 2013 at 9:42

GoogleCodeExporter commented 9 years ago
Hi Henryk,

for a):
Maybe I overlooked something but why don't you use simply the nfc_device 
pointer you have in main() e.g. by making it global?

-#define RFERROR(tag) (nfc_device_get_last_error(*(nfc_device**)tag) == 
NFC_ERFTRANS)

+nfc_device * device = NULL;
+#define RFERROR(tag) (nfc_device_get_last_error(device) == NFC_ERFTRANS)

 int main(int argc, char *argv[])
 {
        int error = EXIT_SUCCESS;
-       nfc_device *device = NULL;
+//     nfc_device *device = NULL;

and RFERROR(tag) can be just RFERROR

Original comment by yob...@gmail.com on 27 Jan 2014 at 4:00