Porting BlackBerry Java NFC Applications to BlackBerry 10 Part 6: Card Emulation with a SIM-based Secure Element

Open Source

NFC Part 6

This is the final part of a six-part series on porting BlackBerry Java applications that use NFC to BlackBerry 10. So far we’ve looked at Tag Reading, Tag Writing, Peer to Peer mode, the reading of contactless cards and virtual target emulation. In this post, we’ll review the porting of code that implements card emulation using a secure element.

Here’s where we are in the series as a whole:

  1. Reading NFC Tags
  2. Writing NFC Tags
  3. Peer to Peer Mode
  4. Reading NFC Contactless Cards
  5. NFC Virtual Tag and Card Emulation
  6. NFC Card Emulation

Issues for Java Developers:

  1. Switch the required ISO14 protocol routing to a selected secure element (UICC vs embedded SE): BlackBerry devices that support NFC may have a choice of up to two secure elements available: one in the UICC (SIM card), and one embedded in the Blackberry device itself (the “embedded SE”). Applications can switch specific ISO14 protocols (A, B or B prime) to a specific secure element using the SecureElementManager and SecureElement APIs.
  1. Connect to an applet and exchange ISO7816-4 APDUs with it: Java developers use the JSR177 API to open logical connections to applets and to exchange APDUs.
  1. Receive notification of “card transaction events”: The BlackBerry 7 Java developer implements the TransactionListener interface and registers with the system by calling SecureElement.addTransactionListener. They must indicate the AID(s) of the applet(s) whose transactions their app is responsible for monitoring in this call.

The BlackBerry 10 Native approach:

1. Switch the required ISO14 protocol routing to a selected secure element (UICC vs embedded SE)

At the time of writing, only secure elements in a UICC/SIM are available from a BlackBerry 10 application. As such there is no need for protocol switching and the issue is moot.

2. Connect to an applet and exchange ISO7816-4 APDUs with it

Developers must use BPS (BlackBerry Platform Services) APIs to connect to and interact with applets in a secure element. The following example illustrates the key steps:

// variables for handles
      uint32_t hSESession;
      uint32_t seChannel;
      uint32_t uiccSeReaderID;

      // variables for retrieving the Readers, holders of possible secure elements
      nfc_result_t rc;
      uint32_t numberOfReaders = 0;
      uint32_t *phReaders = NULL;
      static int DEF_LEN = 10;
      char readerName[DEF_LEN];
      uint32_t len = 10;

      //variables for opening and exchanging data
      fcp_type_t fcpResponseType;
      int32_t openResponseLen;
      uint32_t exchangeResponseLen;
      uint32_t nReceiveAPDUBufferSize;
      uint8_t* result;

      QByteArray hex_encoded = QByteArray(aid.toByteArray());

      int aid_size = _aid.length() / 2;
      uint8_t the_aid[aid_size];

      int apdu_size = apdu.length() / 2;
      uint8_t the_apdu[apdu_size];

      Utilities::hexToIntArray(_aid, the_aid);
      Utilities::hexToIntArray(apdu, the_apdu);

      // loop variable
      uint32_t i;

      // Call nfc_se_service_get_num_readers() with the handle acquired in previous step to get the number of available Readers in the system
      CHECK(nfc_se_service_get_num_readers(&numberOfReaders));
      emit message(QString("number of readers=%1").arg(numberOfReaders));

      // Allocate space for the readers
      phReaders = (uint32_t*) malloc(sizeof(uint32_t) * numberOfReaders);
      emit message(QString("space allocated for readers"));

      // get the handles for the readers
      CHECK(nfc_se_service_get_readers(phReaders, &numberOfReaders));
      emit message(QString("got handles for readers"));

      // Iterate through the readers to find the SIM reader.
      int sim_readers_found = 0;
      for (i = 0; i < numberOfReaders; i++) {
            len = 10;
            CHECK(nfc_se_reader_get_name(phReaders[i], readerName, &len));
            if ((len == 3) && (strcmp(readerName, "SIM") == 0)) {
                  uiccSeReaderID = phReaders[i];
                  sim_readers_found++;
                  break;
            }
      }

      if (sim_readers_found == 0) {
            free(phReaders);
            return;
      }

      // Deallocate the array for holding the readers.
      free(phReaders);

      // Open a session with the SIM Reader
      // Note: You may hold onto this session for the lifetime
      // of you application.
      rc = nfc_se_reader_open_session(uiccSeReaderID, &hSESession);
      if (rc != NFC_RESULT_SUCCESS) {
            qDebug() << QString("XXXX ERROR opening session:%1").arg(rc);
            return;
      }

      // Open a channel to AID
      fcpResponseType = OPEN_NO_FCP_INFO;
      openResponseLen = 0;

      rc = nfc_se_session_open_logical_channel(hSESession, the_aid, aid_size, fcpResponseType, &seChannel, &openResponseLen);
      if (rc != NFC_RESULT_SUCCESS) {
            qDebug() << QString("XXXX ERROR opening logical channel:%1").arg(rc);
            return;
      }

      if (!select_only) {
            // send APDU command

            rc = nfc_se_channel_transmit_apdu(seChannel, the_apdu, apdu_size, &exchangeResponseLen);
            if (rc != NFC_RESULT_SUCCESS) {
                  qDebug() << QString("XXXX ERROR transmitting APDU:%1").arg(rc);
            }

            // uint8_t is an 8 bit unsigned type
            result = (uint8_t*) malloc(sizeof(uint8_t) * exchangeResponseLen);
            //get the response of the open call

            nReceiveAPDUBufferSize = exchangeResponseLen;

            if (exchangeResponseLen >= 2) {
                  CHECK( nfc_se_channel_get_transmit_data(seChannel, &result[0], &nReceiveAPDUBufferSize));
                  QByteArray responseData = QByteArray::fromRawData(reinterpret_cast<const char *>(result), nReceiveAPDUBufferSize);
                  QString responseAsHex = QString::fromAscii(responseData.toHex());
                  emit message(QString("APDU response: %1").arg(responseAsHex));
            }
      }
      free(result);

3. Receive notification of “card transaction events”

Developers include a special entry in their application’s bar-descriptor.xml file to register for transaction events from a specified applet. The invocation framework is used to dispatch such events to applications when they arise. Applications use the InvokeManager class to receive and decode transaction details.

BlackBerry 10 and BlackBerry 7 differ in that transaction events can include “supplementary parameters” as defined in ETSI TS 102 622. This data will be included in any data delivered by the invocation framework and be in Base64 encoding.

An example bar-descriptor.xml entry follows. Note the syntax for specifying the AID.

<invoke-target id="com.sample.NfcTool.tl">
            <entry-point>1</entry-point>
            <type>APPLICATION</type>
            <filter>
                  <action>bb.action.NOTIFY</action>
                  <mime-type>application/vnd.bb.nfc_transaction</mime-type>
                  <property var="uris" value="aid://SIM/6e.66.63.74.65.73.74.30.31/"/>
            </filter>
      </invoke-target>

Code showing how to receive transaction notifications from the invocation framework appears next. Note that the MIME type that transaction notifications have is “application/vnd.bb.nfc_transaction” and the payload is in JSON format with binary data in Base64 encoding.

....
_invokeManager = new bb::system::InvokeManager();
QObject::connect(_invokeManager, SIGNAL(invoked(const bb::system::InvokeRequest&)), this, SLOT(receivedInvokeRequest(const bb::system::InvokeRequest&)));
....
void MainMenu::receivedInvokeRequest(const bb::system::InvokeRequest& request) {

  QByteArray data = request.data();
  if (request.mimeType().compare("application/vnd.bb.nfc_transaction") == 0) {
      QString json = QString(data);
      qDebug() << "XXXX " << json;
      _systemDialog->setBody(json);
      _systemDialog->show();
   }
}

So there you have it: a complete BlackBerry Java NFC porting guide in 6 posts. We hope this was useful for you!

Resources

Knowledge Base Articles:

Sample Code:

Contacts:

About mdwrim

My name’s Martin Woolley and I work in BlackBerry's Developer Relations team as a Senior Application Development Consultant. I’ve been with BlackBerry since 2009 but have worked in software development in various capacities for 30 years in a whole range of industry sectors and on numerous computing platforms small and large. These days I specialise in areas such as Bluetooth Low Energy, NFC, Internet of Things (Iot) and wearable technologies amongst other things.

Join the conversation

Show comments Hide comments
+ -
blog comments powered by Disqus