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:
- I've downloaded Android API lvl 18 with Open Mobile API and Open Mobile API packages.
- I've created a sample application that should try to access an applet on my SIM card, as described here.
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.
I have org.simalliance.openmobileapi.jar as dependency:
I have the permission:
<uses-permission android:name="org.simalliance.openmobileapi.SMARTCARD"/>
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!