在三星Galaxy S3上设置SEEK的Android应用程序

4

首先介绍一下背景:

我正在尝试做一个Android应用程序的概念验证,检查是否可以向SIM卡应用发送一些APDU命令并处理响应。

我使用SEEK for Android作为Open Mobile API的参考实现。

该应用程序应该在三星Galaxy S3智能手机上运行,该手机配备了Open Mobile API,如此处所述。

我不被允许使用自定义ROM,也不能对Android源代码进行任何修改。

到目前为止,我已经完成了以下工作:

  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

这是我正在使用的粗略代码模板:

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();
    }

}

我认为我的SIM卡在应用程序访问方面设置有误,但由于这部分不是我的领域,我不知道该怎么做才能解决这个问题。我在谷歌群组上遇到了与我类似的讨论,但我不确定如何解释它。非常感谢您的帮助!

1
你先调用了connect方法吗?同时,当与SIM应用建立连接时,也会调用onConnected监听器。 - jim
代码从未执行到那一点,它在那之前崩溃了。 - ioreskovic
我取得了进展,但又遇到了另一个障碍! - ioreskovic
@Lopina,你在这方面有进展吗?我也处于类似的情况中,只是想从商业MNO提供的SIM卡上读取EF-LOCI 0x6F7E(28542),并使用原始Android系统。 - not2qubit
1个回答

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

非常清楚。S3原始固件上的Open Mobile API实现需要在安全元素(UICC)上存在PKCS#15文件结构(访问控制文件系统,ARF),而不是全球平台安全元素访问控制规范引入的访问控制Applet(ARA)。因此,您需要一个类似于以下文件系统(请参见此处的示例,并参考全球平台安全元素访问控制规范以获取更多参考)存在于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
|- ...

嗨,迈克尔!感谢您稍微澄清了一下。但是,仍然有些事情对我来说不是很清楚。您是如何创建这样的文件系统的?使用哪些工具可以实现它?是否有任何实际示例?我其实需要一个针对 PKCS#15 的白痴指南 :( - ioreskovic
1
我假设这个安全元件是一个UICC,对吗?如果是这样,您需要查阅UICC制造商的文档(或者如果您通过某个移动网络运营商收到了UICC,则需要与他们联系以为您添加必要的文件)。这方面没有所谓的“简单”操作指南。 - Michael Roland
嗨@MichaelRoland,感谢您的答案,它对我很有帮助。您知道OMAPI库从哪个版本开始支持访问控制应用程序(ARA)吗?我已经深入研究了文档,但几乎找不到任何信息(我只在v3.3规范中看到了一次提到ARA)。 - Burakito

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接