javacardsim-cardsim-toolkit

Why SIMToolkit does not trigger registerred EVENTs for my Applet?


In order to debug a problem, I wrote the following applet. This applet simply registers itself for multiple events and then when an event triggers, it set correponding bits (based on the received event type) in a variable named receivedEvents. Finally we can receive the value of this variable using a SELECT APDU command.

package f0r.god.sake;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISOException;

import sim.toolkit.EnvelopeHandler;
import sim.toolkit.ProactiveHandler;
import sim.toolkit.ToolkitConstants;
import sim.toolkit.ToolkitException;
import sim.toolkit.ToolkitInterface;
import sim.toolkit.ToolkitRegistry;

public class SampleSTKApplet extends Applet implements ToolkitInterface, ToolkitConstants {
  private ToolkitRegistry toolkitRegistry;
  private byte receivedEvents = (byte) 0;

  private byte timerId;
  private static byte[] TIMER_VALUE = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x01};

  private byte menuItemId;
  static byte[] menuItemText = new byte[] { 'C', 'l', 'i', 'c', 'k', ' ', 'H', 'e', 'r', 'e'};
 

  private SampleSTKApplet() {
    toolkitRegistry = ToolkitRegistry.getEntry();

    menuItemId = toolkitRegistry.initMenuEntry(menuItemText, (short)0, (short)menuItemText.length,
        PRO_CMD_SELECT_ITEM, false, (byte)0, (short)0);

    toolkitRegistry.setEvent(EVENT_PROFILE_DOWNLOAD);
    toolkitRegistry.requestPollInterval((short)15);
    timerId = toolkitRegistry.allocateTimer();
  }
  

  public static void install(byte[] bArray, short bOffset, byte bLength) {
    SampleSTKApplet applet = new SampleSTKApplet();
    applet.register();
  }
  

  public void process(APDU apdu) throws ISOException {
    if (selectingApplet())
      ISOException.throwIt((short)((short)0x9000 | receivedEvents));
  }


  public void processToolkit(byte event) throws ToolkitException {
    EnvelopeHandler envHdlr = EnvelopeHandler.getTheHandler();
    ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();

    switch(event){
      case EVENT_MENU_SELECTION:
        receivedEvents = (byte)(receivedEvents | 0x01); // 0b00000001
        byte selectedItemId = envHdlr.getItemIdentifier();

        if (selectedItemId == menuItemId) {
          proHdlr.init((byte) PRO_CMD_TIMER_MANAGEMENT, (byte) 0, DEV_ID_ME);
          proHdlr.appendTLV((byte) (TAG_TIMER_IDENTIFIER | TAG_SET_CR), timerId);
          proHdlr.appendTLV((byte) (TAG_TIMER_VALUE | TAG_SET_CR), TIMER_VALUE, (short) 0,
                  (short) TIMER_VALUE.length);
          proHdlr.send();
        }
        break;

    case EVENT_TIMER_EXPIRATION:
        receivedEvents = (byte)(receivedEvents | 0x02); // 0b00000010
      break;

    case EVENT_PROFILE_DOWNLOAD:
        receivedEvents = (byte)(receivedEvents | 0x04); // 0b00000100
      break;

    case EVENT_STATUS_COMMAND:
        receivedEvents = (byte)(receivedEvents | 0x08); // 0b00001000
      break;

    default:
        receivedEvents = (byte)(receivedEvents | 0x10); // 0b00010000
    }
  }
}

I compiled it and installed it successfuly on my SIM card.

Then:

  1. I put that SIM card inside the SIM slot of a turned-off mobile phone.
  2. I turned the phone on.
  3. I opened the SIM Toolkit applicaiton and then I clicked on the Click Here button.
  4. I waited about 2 minutes to give enough time to ME to trigger EVENT_TIMER_EXPIRATION, EVENT_STATUS_COMMAND and EVENT_PROFILE_DOWNLOAD events.
  5. I turned off the mobile phone and put that SIM Card inside my card reader.

Now as I think that all the events have been triggered, I expect SW = 0x900F (=0x9000 | 0b00001111) or SW = 0x901F (= 0x9000 | 0b00011111) in response of SELECT APDU command. But that's not what I receive:

ebr@him:~/SomePath$ apdu_sender -a 00a4040006112233445566 -d
>>> 00A40400 06 112233445566
<<< 9003

As you see above, the Status Word to SELECT APDU command in 0x9003 (= 0x9000 | 0b00000011) and that means the STK triggered EVENT_MENU_SELECTION and EVENT_TIMER_EXPIRATION only.

Why other event did not triggered?


1st Update 2022-10-13: Simulate ME!

I just put the SIM in a card reader and simulate the role of ME using TERMNINAL PROFILE, FETCH and TERMINAL REPONSE APDU commands to investigate my SIM reaction:

>>> A0100000 08 FFFFFFFFFFFFFFFF   // Simulated Terminal Profile APDU command
<<< 9129  // Card have 0x29 bytes to send

>>> A0120000 29  // Fetch 0x29 bytes 
<<< D027810301250082028182850C53544B2053657276696365738F0B80436C69636B2048657265180124 9000
/*
    D0 27
    81 03 012500 <--- 0x25 = Set Up Menu
    82 02 8182
    85 0C 53544B205365727669636573
    8F 0B 80436C69636B2048657265
    18 01 24
*/

>>> A0140000 0C 810301030002028281030100 // Simulated Terminal Response = Command Performed Successfully.
<<< 910F // Card have 0x0F more bytes to send


>>> A0120000 0F  // Fetch 0x0F bytes
<<< D00D8103010500820281829902090A 9000
/*
    D0 0D
    81 03 010500 <--- 0x05 = Set Up Event List
    82 02 8182
    99 02 090A <-- Event List: Data Available, Channel Status
*/

>>> A0140000 0C 810301030002028281030100 // Simulated Terminal Response = Command Performed Successfully.
<<< 910F // Card have 0x0F more bytes to send

>>> A0120000 0F  // Fetch 0x0F bytes
<<< D00D8103010300820281828402010F 9000
/*
    D0 0D
    81 03 010300 <--- 0x03 = Poll Interval
    82 02 8182
    84 02 010F <--- Duration: 15 seconds
*/

>>> A0140000 10 8103010300020282810301008402010F // Simulated Terminal Response = Command Performed Successfully.
<<< 9000 // No more proactive commands

And try to read the receivedEvents again:

ebr@him:~/SomePath$ apdu_sender -a 00a4040006112233445566 -d
>>> 00A40400 06 112233445566
<<< 9000 <-- Corrected in update! No event received by the applet!

2nd Update 2022-10-14: Type Fixed

I have changed Status Word bytes of the last command above from 9003 to 9000. It was a typo. The applet doesn't triggered by any event in the simulated ME test!


Solution

  • (Transcript of discussion in comments)

    Move the getter for the EnvelopeHandler to the EVENT_MENU_SELECTION as it might throw for events without the ENVELOPE APDU command:

    public void processToolkit(byte event) throws ToolkitException {
        ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
    
        switch(event){
          case EVENT_MENU_SELECTION: {
                EnvelopeHandler envHdlr = EnvelopeHandler.getTheHandler();
                receivedEvents = (byte)(receivedEvents | 0x01); // 0b00000001
                byte selectedItemId = envHdlr.getItemIdentifier();
        
                if (selectedItemId == menuItemId) {
                  proHdlr.init((byte) PRO_CMD_TIMER_MANAGEMENT, (byte) 0, DEV_ID_ME);
                  proHdlr.appendTLV((byte) (TAG_TIMER_IDENTIFIER | TAG_SET_CR), timerId);
                  proHdlr.appendTLV((byte) (TAG_TIMER_VALUE | TAG_SET_CR), TIMER_VALUE, (short) 0,
                          (short) TIMER_VALUE.length);
                  proHdlr.send();
                }
            }
            break;
    
        ...the rest of the code...
    

    Good luck with your project!