Mobile native Wearable native

SmartCard: Accessing Secure Elements

This tutorial demonstrates how you can manage smart card features and access secure elements (SE).

Warm-up

Become familiar with the SmartCard API basics by learning about:

  • Using the SE Service

    Initialize the SE service and retrieve available readers.

  • Managing the Reader

    Retrieve the reader name, check whether the SE is present in the reader, open sessions, and close all sessions.

  • Managing Sessions

    Retrieve session information, open basic and logical channels, and close channels and the session.

  • Managing Channels

    Retrieve channel information, select the next applet, transmit APDU commands, and close the channel.

  • Sending a Transmission

    Retrieve a reader, open a session and a logical channel, and transmit an APDU command over the channel.

Using the SE Service

To use the SE service:

  1. Initialize the smart card service for use:

    int ret;
    ret = smartcard_initialize();
    
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard initialize success");
    else
       TC_PRT("smartcard initialize failed");
    

    The service is no longer needed, deinitialize it:

    int ret;
    ret = smartcard_deinitialize();
    
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard deinitialize success");
    else
       TC_PRT("smartcard deinitialize failed");
    
  2. Retrieve the available readers with the smartcard_get_readers() function:

    int pLength;
    int *phReaders = NULL;
    
    ret = smartcard_get_readers(&phReaders, &pLength);
    
    if (ret == SMARTCARD_ERROR_NONE)
    {
       TC_PRT("smartcard_get_readers is success");
       TC_PRT("reader handle : %d", phReaders[0]);
       TC_PRT("readers length : %d", pLength);
    }
    else
    {
       TC_PRT("smartcard_get_readers failed : %d", ret);
    }
    

Managing the Reader

To manage a reader:

  1. Retrieve the name of the reader with the smartcard_reader_get_name() function:

    int ret;
    char * pReader = NULL;
    
    ret = smartcard_reader_get_name(reader, &pReader);
    if (ret == SMARTCARD_ERROR_NONE)
    {
       TC_PRT("smartcard_reader_get_name success");
       TC_PRT("reader name : %s", pReader);
    }
    else
    {
       TC_PRT("smartcard_reader_get_name failed : %d", ret);
    }
    
  2. Before establishing a session, use the smartcard_reader_is_secure_element_present() function to make sure that the SE is present in the reader:

    int ret;
    bool is_present = false;
    
    ret = smartcard_reader_is_secure_element_present(reader, &is_present);
    if (ret == SMARTCARD_ERROR_NONE)
    {
       TC_PRT("smartcard_reader_is_secure_element_present is success");
       TC_PRT("reader secure element present : %d", is_present);
    }
    else
    {
       TC_PRT("smartcard_reader_is_secure_element_present failed : %d", ret);
    }
    
  3. Open a session to connect to the SE in the reader using the smartcard_reader_open_session() function.

    When you no longer need the session, use the smartcard_reader_close_sessions() function to close all sessions opened on the specific reader.

    int ret;
    int session;
    ret = smartcard_reader_open_session(reader, &session);
    
    if (ret == SMARTCARD_ERROR_NONE)
    {
       ret = smartcard_reader_close_sessions(reader);
       if (ret == SMARTCARD_ERROR_NONE)
       {
          TC_PRT("smartcard_reader_close_sessions success");
       }
       else
       {
          TC_PRT("smartcard_reader_close_sessions failed : %d", ret);
       }
    }
    else
    {
       TC_PRT("open session failed : %d", ret);
    }
    

Managing Sessions

You can manage a session using the session instance that you have created when opening the session with a reader. The session instance is the first parameter in all session-related APIs.

To manage sessions:

  • Retrieve the reader that provides the session:
    int ret;
    int reader;
    
    ret = smartcard_session_get_reader(session, &reader);
    ret = smartcard_reader_get_name(reader, &pReader);
    if (ret == SMARTCARD_ERROR_NONE)
    {
       TC_PRT("smartcard_session_get_reader success");
       TC_PRT("reader name : %s", pReader);
    }
    else
    {
       TC_PRT("smartcard_session_get_reader failed");
    }
    
  • Retrieve the answer to reset (ATR) of the SE:
    int ret;
    unsigned char *pAtr;
    int pLength;
    
    ret = smartcard_session_get_atr(session, &pAtr, &pLength);
    
    if (ret == SMARTCARD_ERROR_NONE)
    {
       TC_PRT("smartcard_session_get_atr success : %d", pLength);
       for (i = 0; i < pLength; i++)
          TC_PRT("%x ", (int)pAtr[i]);
    }
    else
    {
       TC_PRT("smartcard_session_get_atr failed");
    }
    
  • Open a basic or logical channel.

    A basic channel is defined in the ISO/IEC 7816-4 specification (the one that has number 0). To open a logical channel with the SE, you must select the applet represented by the given Application ID (AID).

    int ret;
    unsigned char aid[] = {0x00, 0x01, 0x02, 0x03};
    int channel;
    
    // Open basic channel
    ret = smartcard_session_open_basic_channel(session, aid, 4, 0x00, &channel);
    
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard_session_open_basic_channel is success : %d", channel);
    else
       TC_PRT("smartcard_session_open_basic_channel failed");
    
    // Open logical channel
    ret = smartcard_session_open_logical_channel(session, aid, 12, 0x04, &channel);
    
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard_session_open_basic_channel is success : %d", (channel);
    else
       TC_PRT("smartcard_session_open_basic_channel failed : %d", ret);
    
  • Close all channels opened for a specific session:
    int ret;
    ret = smartcard_session_close_channels(session);
    
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard_session_close_channels is success");
    else
       TC_PRT("smartcard_session_close_channels failed");
    
  • Close a session and check that it is truly closed:
    int ret;
    bool is_closed;
    
    ret = smartcard_session_close(session);
    
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard_session_close is success");
    else
       TC_PRT("smartcard_session_close failed");
    
    ret = smartcard_session_is_closed(session, &is_closed);
    
    if (ret == SMARTCARD_ERROR_NONE && is_closed == true)
       TC_PRT("smartcard_session_is_closed is success");
    else
       TC_PRT("smartcard_session_is_closed failed");
    

Managing Channels

You can manage a channel using the channel instance that you have created when opening the channel with a session. The channel instance is the first parameter in all channel-related APIs.

To manage channels:

  • Retrieve the session that has opened the specific channel:
    int ret;
    int session_handle;
    
    ret = smartcard_session_open_logical_channel(session, aid, 12, 0x00, &channel);
    if (ret == SMARTCARD_ERROR_NONE)
    {
       ret = smartcard_channel_get_session(channel, &session_handle);
    
       if (ret == SMARTCARD_ERROR_NONE)
          TC_PRT("smartcard_channel_get_session is success: %d", session_handle);
       else
          TC_PRT("smartcard_channel_get_session failed");
    }
    
  • Check whether a specific channel is a basic or logical channel:
    int ret;
    bool is_basic;
    
    ret = smartcard_channel_is_basic_channel(channel, &is_basic);
    
    if (ret == SMARTCARD_ERROR_NONE && is_basic == false)
       TC_PRT("smartcard_channel_is_basic_channel is success");
    else
       TC_PRT("smartcard_channel_is_basic_channel failed");
    
  • Select the next applet on the specific channel that matches to the partial Application ID (AID):
    ret = smartcard_session_open_logical_channel(session, aid, 12, 0x00, &channel);
    if (ret == SMARTCARD_ERROR_NONE)
    {
       bool is_next = true;
       ret = smartcard_channel_select_next(channel, &is_next);
       if (ret == SMARTCARD_ERROR_NONE && is_next == false)
          TC_PRT("smartcard_channel_select_next is success");
       else
          TC_PRT("smartcard_channel_select_next failed");
    }
    

    To get a response for the selection command, use the smartcard_channel_get_select_response() function:

    int i, ret;
    unsigned char* pSelectResponse;
    int pLength;
    
    ret = smartcard_channel_get_select_response(channel, &pSelectResponse, &pLength);
    
    if (ret == SMARTCARD_ERROR_NONE)
    {
       TC_PRT("smartcard_channel_get_select_response is success");
       for (i = 0; i < pLength; i++)
          g_print("%x ", (int)pSelectResponse[i]);
    }
    else
    {
       TC_PRT("smartcard_channel_get_select_response failed");
    }
    
  • Check whether a specific channel is closed:
    int ret;
    bool is_close;
    
    ret = smartcard_channel_close(channel);
    ret = smartcard_channel_is_closed(channel, &is_close);
    
    if (ret == SMARTCARD_ERROR_NONE && is_close == true)
       TC_PRT("smartcard_channel_is_closed is success");
    else
       TC_PRT("smartcard_channel_is_closed failed");
    
  • Close the channel opened for a specific SE:
    int ret;
    
    ret = smartcard_channel_close(channel);
                            
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard_channel_close is success");
    else
       TC_PRT("smartcard_channel_close failed : %d", ret);
    
  • Transmit an APDU command (as per ISO/IEC 7816-4) to the SE:
    ret = smartcard_channel_transmit(channel, command, 4, &response, &resp_len);
    
    if (ret == SMARTCARD_ERROR_NONE)
    {
       TC_PRT("smartcard_channel_transmit is success");
       TC_PRT("response is ");
       for (i = 0; i < resp_len; i++)
          TC_PRT("%x ", (int)response[i]);
       TC_PRT("\n"); 
    }
    else
    {
       TC_PRT("smartcard_channel_transmit failed");
    }
    

    To get a response for the transmission, use the smartcard_channel_transmit_retrieve_response() function:

    int i;
    unsigned char * ptransmitResponse;
    
    ret = smartcard_session_open_logical_channel(session, aid, 12, 0x00, &channel);
    if (ret == SMARTCARD_ERROR_NONE)
    {
       ret = smartcard_channel_transmit(channel, command, 11, &response, &resp_len);
       ret = smartcard_channel_transmit_retrieve_response(channel, &ptransmitResponse, &pLength);
    
       if (ret == SMARTCARD_ERROR_NONE)
       {
          TC_PRT("smartcard_channel_transmit_get_response is success");
          TC_PRT("response is ");
          for (i = 0; i < pLength; i++)
             TC_PRT("%x ", (int)ptransmitResponse[i]);
          TC_PRT("\n");
       }
       else
       {
          TC_PRT("smartcard_channel_transmit_get_response failed");
       }
    }
    

Sending a Transmission

This use case covers the entire work flow of sending an APDU transmission from getting a reader to closing the session afterwards.

To send a transmission:

  1. Define the required variables and initialize the smart card service for use:
    int i = 0;
    int pLength;
    int *phReaders = NULL;
    int session;
    int channel;
    unsigned char aid[] = {0xA0, 0x00, 0x00, 0x00, 0x63, 0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35};
    unsigned char command[] = {0x00, 0x28, 0x00, 0x00};
    unsigned char *response = NULL;
    int resp_len = 50;
    
    ret = smartcard_initialize();
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard initialize success");
    else
       TC_PRT("smartcard initialize failed");
  2. Get the available readers:
    ret = smartcard_get_readers(&phReaders, &pLength);
  3. Open a session:
    if (ret == SMARTCARD_ERROR_NONE && pLength != 0)
    {
       ret = smartcard_reader_open_session(phReaders[0], &session);
  4. Open a logical channel:
       if (ret == SMARTCARD_ERROR_NONE && session != 0)
       {
          ret = smartcard_session_open_logical_channel(session, aid, 12, 0x00, &channel);
  5. Transmit the command:
          if (ret == SMARTCARD_ERROR_NONE)
          {
             ret = smartcard_channel_transmit(channel, command, 4, &response, &resp_len);
             if (ret == SMARTCARD_ERROR_NONE)
             {
                TC_PRT("smartcard_channel_transmit is success");
                TC_PRT("response is ");
                for (i = 0; i < resp_len; i++)
                   TC_PRT("%x ", (int)response[i]);
                TC_PRT("\n");
             }
             else
             {
                TC_PRT("smartcard_channel_transmit failed");
             }
          }
       }
  6. Close the session:
       ret = smartcard_session_close(session);
    }
    
  7. Deinitialize the service:
    ret = smartcard_deinitialize();
    
    if (ret == SMARTCARD_ERROR_NONE)
       TC_PRT("smartcard deinitialize success");
    else
       TC_PRT("smartcard deinitialize failed");
    
Go to top