Topic: How to send 7816 APDUs using libnfc

Hi,

I am attempting to use a "PN531USB" to communicate with a Java Smart Card (complies with 14443,7816,contactless).

I have successfully used WinSCard (using SCARD_PROTOCOL_T0) and an OMNIKey device to talk to the card.

How do I send 7816 APDUs using libnfc? 

I understand you first need to do an anti-collision, then a selection before you can send the APDUs, but I don't know how that is coded, or how to use 7816 APDUs with the libnfc API.

The output of the supplied "anticol.exe" is

Connected to NFC reader: PN531USB

R: 26
T: 04  00
R: 93  20
T: 08  3a  46  3a  4e
R: 93  70  08  3a  46  3a  4e  e7  23
T: 20  fc  70
R: e0  50  bc  a5
T: 08  57  80  02  01  10  00  09  94  da
R: 50  00  57  cd

Found tag with UID: 083a463a

The output of list is

Connected to NFC reader: PN531USB

The following (NFC) ISO14443A tag was found:

 ATQA (SENS_RES): 04  00
    UID (NFCID1): 08  24  27  ba
   SAK (SEL_RES): 20
       ATS (ATR): 08  57  80  02  01  10  00  09

I am using WinXP with libusb-win32.

Thanks,

snapdev

Last edited by snapdev (2009-06-22 22:19:59)

Re: How to send 7816 APDUs using libnfc

I have made some progress by selecting the card first with

nfc_reader_list_passive(pdi,IM_ISO14443A_106,...

and sending an APDU as follows:

        byte cmd[]={
            0x00,0xa4,0x04,0x00,
            0x07,0xd4,0x10,0x00,0x00,0x03,0x00,0x01,
            0x00};
        byte buf[256];
        ui32 i=0;
        byte resp[256];
        ui32 respLen=sizeof(resp);
        buf[i++]=2;
        memcpy(buf+i,cmd,sizeof(cmd));
        i+=sizeof(cmd);

        if (nfc_reader_transceive_bytes(pdi,buf,i,resp,&respLen))
        {
             if (respLen > 19)
             {
                printf("\nCard ID: ");
                print_hex(resp+9,8);
             }
        }

Where "cmd" is what I consider to be the APDU command. To send it I prefixed the 0x02. What is the definition of this byte?

The response also has a similar prefix byte, I've seen both 0x02 and 0x03, what do these mean?

Thanks,

snapdev

Re: How to send 7816 APDUs using libnfc

Interesting to see that you are trying to develop a simple smartcard application using APDU's.
Before you can send an APDU, you need to have the (java)card in a active state. The ISO14443-A documentation describes that a tag will become active after the complete anti-collision process followed by a RATS (Request Answer To Select), in contact cards ofter referred to as ATR (Answer To Reset). Very good that you use the nfc_reader_list_passive() to do the anti-collision and RATS, after that you are ready to go and send your APDU frames.

The APDU frames have some specific format. Status messages for example from the reader start with the 0xBA byte and are answered by the card with byte 0xAB. The OMNIKEY reader (ab)uses these status messages to do a simple "ping" <-> "pong" between reader and card. Using this it is able to detect if a card is still available (and not moved away from the field).

+  92304:  4:     ba  01  37  c8    
+     64:  4: TAG ab  01  7e  44    
+  93160:  4:     ba  01  37  c8    
+     64:  4: TAG ab  01  7e  44    

The documentation (ISO etc.) of this is somewhat ugly to read, at the moment I have not seen any explanation of these frames with descent example traces. But if you look carefully, it seems that the ISO explains it all. This included setting the right bits and flags to select, communicate, request time and deselect. I hope to expand the website (examples?) soon with an detailed description about APDU frames.

Since my focus was more on the lowest level of communication, I have to do more research on the APDU communication frames. Let me come back on this in the future. In the mean while, if you have found anything useful, I hope you are willing to share it with us.

Re: How to send 7816 APDUs using libnfc

Hi, thanks for the quick response.

I am using the NZ Snapper cards with the Snapper "feeder" device based on the PN531 chip.

We have two different types of cards here, a plastic card and also a USB based card that will work as a USB plugin, or as an RF device.

I've found different behaviour between the two card devices. Most importantly I find that I can talk to the plastic card with your default

byte pncmd_exchange_raw_data[266]={0xD4,0x42};

followed by my appending an 0x02 byte before the APDU. The response has a prefixed byte as mentioned in the earlier post.

This approach fails with the USB card device when used as an RF card. Here I have to change your libnfc.c to

byte pncmd_exchange_raw_data[266]={0xD4,0x40};

then append an 0x01 byte before my APDU. The response then has no extra byte prefixed.

Ironically this {0xD4,0x40,0x01} then also works with the plastic card, but means a change to libnfc.c. What does this code actually represent and what should be the strategy to deal with this given this is common code?

While on the topic, these global buffers are not thread safe. smile

The SAK (SEL_RES) as returned by the plastic card is 0x20, and for the USB card is 0x28. What do these bits mean?

I tried compiling the libnfc on Solaris 10 u7 i386 and can happily report it working.

EDIT:

The changes makes me think of...

#define PN5XX_TRANSMIT_FRAME      "\xD4\x42"
#define PN5XX_TRANSMIT_MIFARE     "\xD4\x40\x01"

So are MIFARE frames standard APDU messages?

Last edited by snapdev (2009-06-24 02:49:47)

Re: How to send 7816 APDUs using libnfc

Very interesting test-results. It is hard for me to figure this out without the devices myself. I currently own a Snapper "feeder" device and a Snapper (platic) card. Sadly I do not have the new USB reader/card version.

If someone would be able to supply me one of these USB-thingies, I think it would be much easier to catch the problem. You can find my email address here.

Re: How to send 7816 APDUs using libnfc

Further testing revealed that the one type of message doesn't work with both types of cards and I need to change the type of message depending on the result  received from the card identification.

The plastic card identifies itself as follows:

Connected to NFC reader: PN531USB

The following (NFC) ISO14443A tag was found:

 ATQA (SENS_RES): 04  00
    UID (NFCID1): 08  0e  1c  9c
   SAK (SEL_RES): 20
       ATS (ATR): 08  57  80  02  01  10  00  09

The USB/RF card identifies itself slightly differently

Connected to NFC reader: PN531USB

The following (NFC) ISO14443A tag was found:

 ATQA (SENS_RES): 04  00
    UID (NFCID1): 20  7f  47  ab
   SAK (SEL_RES): 28
       ATS (ATR): 0d  38  33  b1  4a  43  4f  50  33  31  56  32  32

My solution has been to add a new API where I also pass in the result from the identification allowing the API to select the appropriate way of sending an APDU.

bool nfc_reader_transceive_apdu(const dev_info* pdi,
    const tag_info *ti,
    const byte* pbtTx, 
    const ui32 uiTxLen, 
    byte* pbtRx, 
    ui32* puiRxLen)
{
  byte buf[266];
  ui32 replyOffset=1;
  ui32 i=0;

  /* Same check as for nfc_transceive_bytes */

  if (!pdi->bPar) return false;

  /* use the information from the card to determine how to send the APDU */

  if (ti->tia.btSak & 0x8)
  {
      buf[i++]=0xD4;
      buf[i++]=0x40;
      buf[i++]=0x01;
  }
  else
  {
      buf[i++]=0xD4;
      buf[i++]=0x42;
      buf[i++]=0x02;
      replyOffset=2;
  }

  memcpy(buf+i,pbtTx,uiTxLen);

  i+=uiTxLen;

  /* as per nfc_transceive_bytes */

  if (!pn53x_set_tx_bits(pdi,0)) return false;

  /* send the frame with the appropriate header */

  if (!pn53x_transceive(pdi,buf,i)) return false;
 
  /* the prefix to the reply is different depending on the header used */

  if (uiRxLen <= replyOffset) return false;

  *puiRxLen=uiRxLen-replyOffset;
  memcpy(pbtRx,abtRx+replyOffset,*puiRxLen);

  return true;
}

I will have to do some digging to find out exactly why the protocol is different and hence which bit from the tag_info to use.

Re: How to send 7816 APDUs using libnfc

To be honest I think it does not really is the same interface. I think the card is connected to the internal SAM-port of the PN53x chip. Therefor it needs to be accessed in a different way. I have not tested with this feature myself yet. The tikitag readers also seem to have SAM module on board. I can try to get that one working, and find out what would be the right interface/commands to use.

The quickfix (workaround) you use now does not really fix the problem since the SAK can be a lot of things. For example, the JCOP31/JCOP41 cards would not work very good anymore after your fix.

Re: How to send 7816 APDUs using libnfc

I have found the documents http://www.waazaa.org/download/fcd-14443-3.pdf and http://www.waazaa.org/download/fcd-14443-4.pdf which describes all the bytes for SAK and ATS.

What is the difference that 0xD4,0x42,0x02 and 0xD4,0x40,0x01 do to the actual RF protocol sent to the device? From that we can back track to the bytes returned from the cards.

Re: How to send 7816 APDUs using libnfc

I think I have decoded that ATS bytes and noticed that CID is different. Is this the magic descriminator? The plastic card includes a "TC=0x02", the usb card has no TC, hence is considered zero.

Plastic card:

T0=57, FSCI=7
TA=80
TC=02,CID=1,NAD=0
01  10  00  09

USB:

T0=38, FSCI=8
TA=33
TB=B1, FWI=B, SFGI=1
4a  43  4f  50  33  31  56  32  32

Re: How to send 7816 APDUs using libnfc

After looking at the documentation for a PN532, we now know that

0XD4,0X40 is InDataExchange

It takes a single byte parameter of target logical number and then the APDU data.

0xD4,0x42 is InCommunicateThru

This just takes the data and makes a message out of it, so the first byte is actually the PCB.

Hence the difference is that InDataExchange generates the PCB, whereas InCommunicateThru requires the host to provide the PCB and returns the PCB as part of the response.

My theory is that where the card claims it has a CID, the original code is asking the PN531 to
handle the CID, where the card does not have a CID the code is saying alright,  I can keep things simple and provide a simple "I-block" PCB.

We can only say if this is true if somebody can watch the RF data that gets sent to the card and see if the CID was actually included after the PCB.

Why that makes a difference in reality and whether the work around is because of the cards or the reader I can't tell.

Re: How to send 7816 APDUs using libnfc

Hi,

I'm also interested about sending APDU using libnfc. In fact I'm trying to send the GET_CHALLENGE apdu (ISO 7816) to tags like Mifare Classic to analyze randomness. At this time I didn't succeed in sending APDU and I would like to get more information about how it should be possible to do it

Thanks a lot

Re: How to send 7816 APDUs using libnfc

Gymerus,

I wrote some code that will let you do this.  Grab the pynfc.py script out of RFIDIOt, either the latest version at www.rfidiot.org, or my hacked up version at www.lateralsecurity.com/OurTools.html

If you call pynfc.py directly it allows you to manually send APDUs.  Or you can use it in your own code.

Re: How to send 7816 APDUs using libnfc

The IFD handler for libnfc devices lets you use the standard PC/SC interface to send APDUs. Check out http://sourceforge.net/projects/ifdnfc/! This driver even alows you to use wrappers to PC/SC like OpenSC or pyscard.

Last edited by frankmpunkt (2010-06-11 19:44:28)

Re: How to send 7816 APDUs using libnfc

I'm also trying to send APDUs.
First, I'm confused by what I read here: on one hand I read in this thread that I should transmit 0xD4 0x40 0x01 before the APDU.
On the other end, I don't see any such prefix in ifd-nfc.h.
So could anyone please point me to addotional information on the APDU frame?

My sequence is

nfc_list_devices (pnddDevices, MAX_DEVICE_COUNT, &szDeviceFound);
pnd = nfc_connect(&(pnddDevices[j]));
nfc_initiator_init(pnd);
nfc_configure(pnd,NDO_ACTIVATE_FIELD,false);
nfc_configure(pnd,NDO_INFINITE_SELECT,false);
nfc_configure(pnd,NDO_HANDLE_CRC,true);
nfc_configure(pnd,NDO_HANDLE_PARITY,true);
nfc_configure(pnd,NDO_ACTIVATE_FIELD,true);
nfc_initiator_list_passive_targets (pnd, NM_ISO14443A_106, anti, MAX_TARGET_COUNT, &szTargetFound);

at his point I may output the nai
print_nfc_iso14443a_info (anti[n].nai);

Connected to NFC reader: Philips / PN531 - PN531 v4.2

1 ISO14443A passive target(s) was found:
    ATQA (SENS_RES): 00  04
       UID (NFCID1): fd  52  09  37
      SAK (SEL_RES): 28
          ATS (ATR): 78  80  a4  02  00  73  c8  40  13  00  90  00
     Compliant with: ISO/IEC 14443-4

then I would like to send an APDU as in
nfc_initiator_transceive_bytes( pnd, TxBuffer, RxBuffer,&rl);

But I don't know how to construct the APDU frame.
(I have to put the frame, right? If I don't I get an error)
thanks in advance, Ullrich

Last edited by Ullrich (2010-10-20 12:25:26)

Re: How to send 7816 APDUs using libnfc

Have you tried http://sourceforge.net/projects/ifdnfc/ ? It brings a driver for pcscd. So you can use the standard PC/SC interface like you would do for other smart cards. You now can use PC/SC extensions from within java, ruby, python (pyscard), ... or of course C/C++. The driver takes care of the libnfc internals.

Re: How to send 7816 APDUs using libnfc

@frankmpunkt:
I have looked at it, but unfortunately I need it on Windows and it seems that the autoconf stuff is for linux only. Even worse, under windows I don't need the ifdhandler interface but the winscard interface and I can't use pc/sc-lite to get that since windows has it's own pcsc subsystem.
Therefore I had the hope that I could read it and then produce some windows code.
Do you think that I could compile ifdnfc  with MinGW?

Anyway, I think this is an issue in the libnfc documentation. There should be a simple sample code that sends an APDU, even if this code will be replaced by your ifdhandler in a real application. Therefore my request: Could you or someone else please post a valid sequence to send an APDU?
thank you,
Ullrich

Re: How to send 7816 APDUs using libnfc

No, ifdnfc is not what you want to use for windows. It requires pcscd, the linux/mac service for PC/SC. For windows this would be winscard.dll, but my driver works only for pcscd.

Anyway, sending APDUs with libnfc is quite simple, if you know how to do it. In general you don't need to worry about the wrapping with pseudo-APDUs, libnfc provides functionality for that. Try reading my code (ifd-nfc.c) to get the idea which functions to call. Check out my functions get_device and get_target for initialization and IFDHTransmitToICC for sending APDUs.

Re: How to send 7816 APDUs using libnfc

When I try to send an APDU, the APDU sent (as seen in pcscd -adf) is always prefixed with 0xff 0x00 0x00 0x00 & 3-4 bytes.

Is this supposed to be the case?

Re: How to send 7816 APDUs using libnfc

smallming wrote:

When I try to send an APDU, the APDU sent (as seen in pcscd -adf) is always prefixed with 0xff 0x00 0x00 0x00 & 3-4 bytes.

Is this supposed to be the case?

The question is whether it is supposed to be like this in your case. An 7816 APDU starts
with the following bytes:

CLA  INS P1 P2

class instruction parameter 1, 2

Looks like your message gets set the class to 0xFF and the rest to 0x00. BTW. the next
few bytes specify message length data and max reply length.

Maybe you have to preconfigure calss, instruction and parameters with some other commands?

Best regards,

Oliver

Re: How to send 7816 APDUs using libnfc

hi every body ? I think i am late here any body can tell me the theme of discussion ?

Re: How to send 7816 APDUs using libnfc

I think it does not really is the same interface. I think the card is connected to the internal SAM-port of the PN53x chip. Therefor it needs to be accessed in a different way. I have not tested with this feature myself yet.