4

Here's some background 1st:

I'm trying to do a proof-of-concept Android application that will check if I can send some APDU commands to a SIM card applet and process the response.

I'm using SEEK for Android as a reference implementation of Open Mobile API.

The application should work on Samsung Galaxy S3 smartphone which comes with Open Mobile API, as stated here.

I am not allowed to use a custom ROM, nor do any modifications to Android source.

What I have done so far:

  1. I've downloaded Android API lvl 18 with Open Mobile API and Open Mobile API packages.
  2. I've created a sample application that should try to access an applet on my SIM card, as described here.
  3. On button click, I'm getting SecurityException

    06-23 12:57:15.620: I/HelloSmartcard(5386): creating SEService object
    06-23 12:57:15.655: I/SEService(5386): Connected
    06-23 12:57:22.525: I/HelloSmartcard(5386): Retrieve available readers...
    06-23 12:57:22.530: I/HelloSmartcard(5386): Create Session from the UICC reader...
    06-23 12:57:23.275: I/HelloSmartcard(5386): Create logical channel within the session...
    06-23 12:57:23.285: E/HelloSmartcard(5386): Error occured:
    06-23 12:57:23.285: E/HelloSmartcard(5386): java.lang.SecurityException: Access Control Enforcer: access denied: EF_DIR not found!!
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at org.simalliance.openmobileapi.SEService.checkForException(SEService.java:234)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at org.simalliance.openmobileapi.Session.openLogicalChannel(Session.java:302)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at com.example.testsmartcardaccess2.MainActivity$1.onClick(MainActivity.java:81)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at android.view.View.performClick(View.java:4475)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at android.view.View$PerformClick.run(View.java:18786)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at android.os.Handler.handleCallback(Handler.java:730)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at android.os.Handler.dispatchMessage(Handler.java:92)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at android.os.Looper.loop(Looper.java:176)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at android.app.ActivityThread.main(ActivityThread.java:5419)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at java.lang.reflect.Method.invokeNative(Native Method)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at java.lang.reflect.Method.invoke(Method.java:525)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
    06-23 12:57:23.285: E/HelloSmartcard(5386):     at dalvik.system.NativeStart.main(Native Method)
    06-23 12:57:23.285: I/Choreographer(5386): Skipped 45 frames!  The application may be doing too much work on its main thread.
    
  4. I have org.simalliance.openmobileapi.jar as dependency:

  5. I have the permission:

    <uses-permission android:name="org.simalliance.openmobileapi.SMARTCARD"/>
    
  6. I have 3 applets on SIM card and I'm trying to call the one under AID F9 F4 0F 65 18 C9 54 1E CD AD

Here is the rough code template I'm using:

package com.example.testsmartcardaccess2;

import org.simalliance.openmobileapi.Channel;
import org.simalliance.openmobileapi.Reader;
import org.simalliance.openmobileapi.SEService;
import org.simalliance.openmobileapi.Session;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.Toast;

public class MainActivity extends Activity implements SEService.CallBack {

    private SEService seService;
    private Reader uuicReader;
    private boolean seServiceConnected;

    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        final String LOG_TAG = "HelloSmartcard";

        try {
            Log.i(LOG_TAG, "creating SEService object");
            this.seServiceConnected = false;
            seService = new SEService(MainActivity.this, MainActivity.this);
        } catch (SecurityException e) {
            Log.e(LOG_TAG,
                    "Binding not allowed, uses-permission org.simalliance.openmobileapi.SMARTCARD?");
        } catch (Exception e) {
            Log.e(LOG_TAG, "Exception: " + e.getMessage());
        }

        super.onCreate(savedInstanceState);

        LinearLayout layout = new LinearLayout(this);
        layout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));

        button = new Button(this);
        button.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));

        button.setText("Click Me");
        button.setEnabled(false);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                try {
                    Log.i(LOG_TAG, "Retrieve available readers...");
                    Reader[] readers = seService.getReaders();
                    if (readers.length < 1)
                        return;

                    uuicReader = null;

                    for (Reader reader : readers) {
                        if (reader.getName().equalsIgnoreCase("SIM - UICC")) {
                            uuicReader = reader;
                            break;
                        }
                    }

                    Log.i(LOG_TAG, "Create Session from the UICC reader...");
                    Session session = uuicReader.openSession();

                    Log.i(LOG_TAG,
                            "Create logical channel within the session...");

                    Channel channel = session.openLogicalChannel(
                            new byte[] {
                                (byte) 0xF9, 
                                (byte) 0xF4, 
                                (byte) 0x0F,
                                (byte) 0x65,
                                (byte) 0x18, 
                                (byte) 0xC9,
                                (byte) 0x54, 
                                (byte) 0x1E, 
                                (byte) 0xCD, 
                                (byte) 0xAD
                            }
                    );

                    Log.d(LOG_TAG, "Send HelloWorld APDU command");
                    byte[] respApdu = channel.transmit(new byte[] {
                            (byte) 0x90, 0x10, 0x00, 0x00, 0x00 });

                    channel.close();

                    // Parse response APDU and show text but remove SW1 SW2
                    // first
                    byte[] helloStr = new byte[respApdu.length - 2];
                    System.arraycopy(respApdu, 0, helloStr, 0,
                            respApdu.length - 2);
                    Toast.makeText(MainActivity.this, new String(helloStr),
                            Toast.LENGTH_LONG).show();
                } catch (Exception e) {
                    Log.e(LOG_TAG, "Error occured:", e);
                    return;
                }

            }
        });

        layout.addView(button);
        setContentView(layout);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void serviceConnected(SEService arg0) {
        Log.i("SEService", "Connected");
        this.seServiceConnected = this.seService.isConnected();

        updateButtonStatus(button, this.seServiceConnected);
    }

    private void updateButtonStatus(Button button, boolean enabled) {
        button.setEnabled(enabled);
    }

    @Override
    protected void onDestroy() {
        if (seService != null && seService.isConnected()) {
            seService.shutdown();
            this.seServiceConnected = false;
            updateButtonStatus(button, this.seServiceConnected);
        }
        super.onDestroy();
    }

}

I believe I don't have something set up right on my SIM card regarding applet access, but since that part is not my domain, I don't know what to do to fix this.

I've ran into this discussion on Google Groups that sound similar to my predicament, but I'm not sure how to interpret it.

Any help is appreciated!

Charles
  • 50,943
  • 13
  • 104
  • 142
ioreskovic
  • 5,531
  • 5
  • 39
  • 70
  • 1
    Have you called connect first? There is also an onConnected listener that is called when a connection is established with the SIM Applet. – jim Jun 18 '14 at 13:08
  • The code never executes to that point, it crashes before that. – ioreskovic Jun 21 '14 at 19:49
  • Edit: I've made progress, but another obstacle appeared! – ioreskovic Jun 23 '14 at 11:23
  • @Lopina Did you make any progress on this? I'm in a similar situation where I just want to read the `EF-LOCI` 0x6F7E (28542), from a commercial MNO provided SIM card, an a stock Android. – not2qubit Oct 29 '14 at 19:05

1 Answers1

4

The error

java.lang.SecurityException: Access Control Enforcer: access denied: EF_DIR not found!!

is quite clear. The Open Mobiel API implementation on the S3's stock firmware requires a PKCS#15 file structure (Access Control File System, ARF) to be present on the secure element (UICC). (Instead of an Access Control Applet (ARA) as introduced by the GlobalPlatform Secure Element Access Control specification.)

So you would need a file system that looks something like this (see this for an example and see the GlobalPlatform Secure Element Access Control specification for further reference) to be present on the UICC:

MF (3F00)
|- EF DIR (2F00) --> shall reference PKCS-15
|
|- DF PKCS-15
|
|- ODF --> shall reference DODF
|- DODF --> shall reference EF ACMain
|- EF ACMain --> shall reference EF ACRules
|- EF ACRules --> shall reference EF ACConditions files
|- EF ACConditions1
|- ...
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
  • Hi Michael! Thank you for clarifying this a bit. However, there are still things that aren't clear for me. HOW exactly do you create a file system like that? Which tools to use to achieve that? Are there any real-world examples? I actually need a How-to PKCS#15 for Dummies here :( – ioreskovic Jun 24 '14 at 07:16
  • 1
    I assume this secure element is a UICC, right? In that case you would need to consult the UICC manufacturer's documentation (or in case you received the UICC through some mobile network operator, you would need to get in touch with them to add the necessary files for you). There's no such thing as a "simple" how-to for this. – Michael Roland Jun 24 '14 at 07:21
  • Hi @MichaelRoland, thanks for the answer, it has helped me. Do you know from which version of the OMAPI library it supports the Access Control Applet (ARA)? I have dived into the documentation but could hardly find anything (I saw just a single mention to ARA in v3.3 specs) – Burakito Sep 01 '20 at 15:40