libfreefare icon indicating copy to clipboard operation
libfreefare copied to clipboard

Generalized API and PC/SC support

Open GoogleCodeExporter opened this issue 10 years ago • 6 comments
trafficstars

Thanks to time set apart for this purpose by my employer, I've been working in the month of January on enhancing libfreefare and solving a couple of the existing issues (some of which I previously opened myself :).

The primary goal was decoupling libfreefare from libnfc and allowing other reader subsystems to be used. I implemented that for PC/SC as a first step, other projects that one could think of would be librfid and the new "Linux NFC" stack (https://01.org/linux-nfc).

A secondary goal was making the API easier to use and removing unnecessary -- and libnfc-version specific -- boilerplate code. To this end the new API that I built is reader subsystem agnostic and I spent some effort into making it future-compatible with no API or ABI changes.

I have looked at the work that has been done on the "pcsc" branch and decided that that is not the way to go forward. Creating "-pcsc" versions of everything and replicating a second flurry of boilerplate code among the code examples is exactly what I strive to avoid.

The new API is centered around a new FreefareContext object that holds a library context and references to either automatically acquired or externally provided reader subsystem contexts (e.g. nfc_context) or devices (e.g. nfc_device) and provides an easy to use and unified way to retrieve MifareTag objects. The freefare_get_tags() and freefare_tag_new() methods are still there but marked deprecated (since they are libnfc specific). The latter is superseded by a new freefare_tag_new_ex() function that works with all supported reader subsystems using unions as a way to allow it to accept both libnfc or PC/SC arguments.

The new freefare_init() takes a flags argument that can be a combination of FREEFARE_FLAG_READER_LIBNFC or FREEFARE_FLAG_READER_PCSC to automatically establish a context to the given reader subsystems, or the special value FREEFARE_FLAG_READER_ALL to establish a context with all supported subsystems, even future ones. The latter is the recommended value, which means that a program using the library needs not to be updated to gain access to a future reader subsystem support by the library. The flags can also include FREEFARE_FLAG_DISABLE_ISO14443_4 to disable 14443-4 support where possible (currently only libnfc) to select the -3 version on hybrid cards.

Alternatively, freefare_context/device_add/remove are available to manually manage associating or dissociating reader subsystem contexts or devices with the libfreefare library. A FREEFARE_FLAG_AUTOCLOSE in _add will have libfreefare take over responsibility of the passed in object and automatically call the respective close function (nfc_close()/nfc_exit()) when it is no longer needed.

Once a library context has been retrieved, the freefare_tags_get() method enumerates all supported tags on all on readers on all contexts and returns a list. Alternatively freefare_tag_first() and freefare_tag_next() can be used to iterate over the same set without creating the entire list at once. Both accept an enum mifare_tag_type argument to limit the type of tags eligible (the new type NO_TAG_TYPE means no limit).

The boilerplate code can thus (without error checking) be reduced to:

    FreefareContext ctx = freefare_init(FREEFARE_FLAG_READER_ALL); 
    for(MifareTag tag = freefare_tag_first(ctx, NO_TAG_TYPE); tag; tag = freefare_tag_next(ctx)) { 
        /* Actual code here... */
    }
    freefare_exit(ctx);

The PC/SC support currently is not complete, only DESfire is working. No functional changes to libnfc support should be present (I even added a working FREEFARE_FLAG_DISABLE_ISO14443_4).

Late in the process I added freefare_tag_wait_* which allows non-busy polling for tags (e.g. like the pcsc_scan tool does). This is only implemented for PC/SC and only works on a single context. libnfc has a similar function in nfc_initiator_poll_target() which only works for a single device, implementing support for that is possible. Anything further (waiting for multiple devices/contexts) would require a new threaded approach.

Before I could prepare my code for publication, freefare_selected_tag_is_present() was added in the main libfreefare branch. This was another libnfc specific function, which I choose not to continue supporting (it hasn't been out long, there should be minimal code breakage). Instead I added freefare_tag_is_present() as a reader subsystem agnostic alternative.

I pushed all the code changes to https://code.google.com/r/henryk-libfreefare-extended-reader-support for easy pulling and request inclusion in libfreefare (sadly Google has no pull request support).

Original issue reported on code.google.com by [email protected] on 27 Feb 2014 at 3:19

GoogleCodeExporter avatar Mar 14 '15 12:03 GoogleCodeExporter

Thanks a lot Henryk for your very valuable contribution! Sorry we didn't have time yet to review your code, that's not like it can be done in 5 mins ;-) Thanks for your comprehension.

Original comment by [email protected] on 13 Mar 2014 at 1:03

  • Changed state: Accepted
  • Added labels: Type-Enhancement
  • Removed labels: Type-Defect

GoogleCodeExporter avatar Mar 14 '15 12:03 GoogleCodeExporter

Henryks PC/SC interface work fine for me. Migrating existing code was quite easy due to the simplifications made.

I want to extend supported_tags from freefare.c with a tag that is recognized by calling its function check_tag_on_reader. I have done this for plain libfreefare by connecting, transceiving bytes and disconnecting from the tag (similar to is_mifare_ultralightc_on_reader). With Henryks implementation, however, I did not find out how to connect to the tag in a non-reader-specific way. AFAICS, the supplied FreefareReaderTag object does not allow to create a usable MifareTag obect (Henryks wrapper mifare_ultralightc_is_on_reader is implemented for libnfc only). Henryk, do you have any hints on that?

Original comment by [email protected] on 2 Jun 2014 at 11:56

GoogleCodeExporter avatar Mar 14 '15 12:03 GoogleCodeExporter

any updates on this?

I saved Henryk's initial approach, which I used, here https://github.com/frankmorgner/libfreefare/tree/pcsc-henryk

frankmorgner avatar May 30 '16 18:05 frankmorgner

Any recommended way to move forward with this ?

I'd like to add support for JCOP 2.4.2r2 card, which comes with DESFire and ISO 14443-4 layer APDUs. The current detection code inspects the ATR as returned by the PC/SC subsystem, but does not consider the JCOP ATR as a suitable candidate.

CardContact avatar Apr 26 '17 09:04 CardContact

Is this related to #71?

darconeous avatar Jan 08 '18 06:01 darconeous

Yes and No. It has the same goal (i.e. run libfreefare over PC/SC), but it's a completely different implementation.

I never got #71 running, whereas https://github.com/frankmorgner/libfreefare/tree/pcsc-henryk worked as expected.

frankmorgner avatar Jan 08 '18 07:01 frankmorgner