3

I'm trying to build a C++ wrapper around libnfc to make a communication between my Android and the PN532 RFID module.

This helped me a lot: http://nfc-tools.org/index.php/Libnfc:APDU_example

This code is meant to send an APDU command where the body is contained in message (I'm not sending any header bytes etc.) and read the response into response.

Problem: If message exceeds 262 characters then I get a buffer overflow detected error. Otherwise it works perfectly well. I don't even think the error is thrown by the NFC library.

bool send(const std::string &message, std::string &response){
    std::vector<uint8_t> apduCmd(message.begin(), message.end());
    uint8_t *capdu = &apduCmd[0];
    size_t capdulen = apduCmd.size();
    uint8_t rapdu[10];
    size_t rapdulen = 10;

    // BUFFER OVERFLOW HERE
    int res = nfc_initiator_transceive_bytes(m_nfcDevice, capdu, capdulen, rapdu, rapdulen, 500);
    if (res<0) {
        return false;
    }

    if(res<2 || rapdu[res-2] != 0x90 || rapdu[res-1] != 0x00){
        return false;
    }

    // byteArrayToString omitting the last two bytes
    response = byteArrayToString(rapdu, 0, res-2);
    return true;
}
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
Omar Aflak
  • 2,918
  • 21
  • 39
  • 1
    You might need to look for support of extended APDU - the problem may be, that your Android device does not support APDU's with data lenght > 255 bytes `cla[1] + ins[1] + param[2] + lc[1] + data[255] + le[1] = 261 bytes` – deR_Ed Dec 17 '17 at 11:35

1 Answers1

1

The limit of 262 bytes is a hard limit imposed the PN532 NFC chip. This is the maximum size of the raw data that can be sent (and received) in one InDataExchange command. libnfc explicitly enforces this limit for the method nfc_initiator_transceive_bytes() (see the definition of abtCmd in pn53x_initiator_transceive_bytes() and the definition of PN53x_EXTENDED_FRAME__DATA_MAX_LEN).

What you could do to overcome this limit, is to compose your own ISO/IEC 14443-4 blocks (using InCommunicateThru, i.e. nfc_initiator_transceive_bytes() with m_nfcDevice->bEasyFraming turned off. While each frame would still be limited to 263 bytes (the PN532 actually allows 264 bytes for InCommunicateThru but libnfc seems to limit this to 263 bytes), you can then pack your extended length APDUs into multiple ISO/IEC 14443-4 I-blocks. However, you would need to handle the whole ISO/IEC 14443-4 framing on your own (which means that you also have to take care of receive acknowledgements, etc.)

Finally, since the other communication endpoint is an Android device: Many Android devices do not support extended length APDUs. Consequently, even if you send longer APDUs, you might not be able to receive and process them on the Android side. Also, be aware that you should send proper APDUs conforming to the structures defined in ISO/IEC 7816-4 (i.e. APDUs with valid header and lengths fields), otherwise you might run into issues when talking to some devices.

Michael Roland
  • 39,663
  • 10
  • 99
  • 206
  • Thank you for such a detailed answer ;) Well, I guess I will have to send multiple blocks and implement the protocol on my own – Omar Aflak Dec 19 '17 at 10:59
  • 1
    @OmarAflak The easier choice would probably be to split the data across multiple APDUs and implement your protocol on top of APDUs. In that case you would not need to take much care about timing (which you would need to if you handle ISO/IEC 14443-4 transmission on your own). – Michael Roland Dec 19 '17 at 11:05