JavaCard——共享接口對象

本文介紹Java平臺中的共享接口對象機制。Java卡平臺中提供這套機制的目的主要是:一個應用可以穿透防火牆來調用其他應用提供的功能。

首先我們來認識幾個概念:

1. 共享接口

javacard.framework.shareable接口是所有共享接口的基類,在每個共享接口中,都將定義一些共享接口方法,實現了這些接口方法的對象可以不受應用防火牆的限制,被不同上下文的應用程序訪問其實現的共享接口方法,即,儘管實現共享接口方法的對象和調用共享接口方法的對象屬於不同的執行上下文,但仍可完成對共享接口方法的調用。任何類都可以通過實現共享接口中定義的接口方法來實現共享接口。一個類可實現多個共享接口。

2. 共享接口對象

實現了共享接口的類的對象實例,稱爲共享接口對象(Shareable Interface Object, SIO)。共享接口對象作爲一個通用Java智能卡對象,對象中聲明的方法或數據域在應用防火牆的保護下,可以被同一上下文的其他方法所訪問。但若在不同上下文的方法調用中,只有共享接口方法纔可越過防火牆被其他 Applet 調用,而共享接口對象中的其他方法將被禁止調用。

3. 對象共享流程(如何在應用程序中使用這套機制)

假設有服務器應用 A 和客戶應用 B,他們屬於不同的執行上下文,且客戶應用需要服務器應用提供某些服務支持,那麼其運行流程如下:

 

 

(1) 若服務器應用 A 要爲其他應用提供某一服務,首先服務器應用 A 需定義一個擴展自 javacard.framework.fhareable 的共享接口,並在共享接口中定義將要被其他應用所訪問的共享接口方法。

(2) 在服務器應用 A 中定義一個實現了上述共享接口的類 C,類 C 需對共享接口中定義的方法給出具體實現。該類中也可以定義其他方法和域,但只有共享接口中定義的方法才能被其他應用所訪問,其他方法和域則被應用防火牆保護(應該是被卡外虛擬機的語法規則保護,但這個地方作爲卡內虛擬機也要進行保護,否則會有安全漏洞,例如:客戶端應用獲取了共享接口對象sio,強行將其轉換爲原有類型,然後調用其非共享接口)。

(3) 若要實現對象共享,服務器應用 A 先要創建一個類 C 的對象實例 O。由於 O 屬於服務器應用 A,因此應用防火牆允許服務器應用 A 訪問 O 中的域和方法。

(4) 若客戶應用 B 要調用服務器應用 A 中的某個方法,客戶應用首先要調用Java卡平臺提供的API——JCSystem.getAppletShareableInterfaceObject()方法,向 JCRE 請求服務器應用 A 定義的共享接口對象。JCSystem.getAppletShareableInterfaceObject()方法會遍歷卡內應用列表以找到相應的共享接口對象。

(5) JCRE 接到請求後,查找內部的應用的註冊表,若找到服務器應用 A,則 JCRE 調用服務器應用 A 的 getShareableInterfaceObject()方法來獲取服務器應用 A 的共享接口對象 O 的引用。

(6) 服務器端應用A在接到JCRE的請求後,服務器端應用A將返回對象O的一個引用給客戶應用B。

(7) 客戶端應用B在收到服務器端應用A的對象引用後,將該對象引用轉換爲共享接口類型,並將它作爲服務器端應用A的共享接口對象存儲起來。在得到此對象接口對象(SIO)後,客戶端應用B可通過調用此SIO中的共享接口方法來請求服務器應用A的相應服務。

實例: 

Server:

//===========================================================
// MyShareable.java
//===========================================================

package Server;
import javacard.framework.APDU;
import javacard.framework.Shareable;

/**
 * 定義共享接口。服務器應用想要提供哪些功能給其他應用,就在這個接口裏定義相應的方法。
 */
public interface MyShareable extends Shareable
{
    public abstract void m1(APDU apdu, short bytesRead);
};

//===========================================================
// ServerApplet.java
//===========================================================

package Server;
import javacard.framework.*;

/**
 * 服務器應用,因爲這個類實現了MyShareable共享接口。
 */
public class ServerApplet extends Applet implements MyShareable
{
    //構造函數
    protected ServerApplet(byte bArray[], short bOffset, byte bLength)
    {
        register();
    }

    //安裝函數
    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new ServerApplet(bArray, bOffset, bLength);
    }

    //APDU命令處理函數
    public void process(APDU apdu) { }

    //客戶端對象就是通過這個方法來獲取共享對象的
    public Shareable getShareableInterfaceObject(AID serverAID, byte param)
    {
        return this;
    }

    //實現的共享接口中的方法。
    //將接收到的數據原樣發送到卡外。
    public void m1(APDU apdu, short bytesRead)
    {
        byte echoBytes[] = new byte[256];
        byte buffer[] = apdu.getBuffer();
        short echoOffset = (short)0;
        while (bytesRead > 0)
        {
            Util.arrayCopyNonAtomic(buffer,
            ISO7816.OFFSET_CDATA,
            echoBytes, 
            echoOffset,
            bytesRead);
            echoOffset += bytesRead;
            bytesRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
        }

        apdu.setOutgoing();
        apdu.setOutgoingLength((short)(echoOffset + 5));

        //發送APDU頭
        apdu.sendBytes((short)0, (short)5);
        //發送數據
        apdu.sendBytesLong(echoBytes, (short)0, echoOffset);
    }
}

Client:

//===========================================================
//ClientApplet.java
//===========================================================

package Client;
import Server.MyShareable;
import javacard.framework.*;

public class ClientApplet extends Applet
{
    private final static byte CLA_JCRE_TEST = (byte)0x80;
    private final static byte INS_DO_TESTS = (byte)0x20;
    private AID serverAID;

    protected ClientApplet(byte bArray[], short bOffset, byte bLength)
    {
        register();
    }

    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new ClientApplet(bArray, bOffset, bLength);
    }

    public void process(APDU apdu)
    {
        byte buffer[] = apdu.getBuffer();
        MyShareable sio = null;

        if ((buffer[ISO7816.OFFSET_CLA] != CLA_JCRE_TEST) &&
            (buffer[ISO7816.OFFSET_CLA] != ISO7816.CLA_ISO7816))
        {
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        }

        short bytesRead = apdu.setIncomingAndReceive();

        switch (buffer[ISO7816.OFFSET_INS])
        {
        case ISO7816.INS_SELECT:
            //verify that the AIDs match
            if (!JCSystem.getAID().equals(buffer, ISO7816.OFFSET_CDATA, buffer[ISO7816.OFFSET_LC]))
            {
                ISOException.throwIt(ISO7816.SW_APPLET_SELECT_FAILED);
            }
            //server AID bytes
            buffer[(short)(ISO7816.OFFSET_CDATA + buffer[ISO7816.OFFSET_LC] - (short)2)]--;
            serverAID = new AID(buffer, (short)ISO7816.OFFSET_CDATA, buffer[ISO7816.OFFSET_LC]);
            break;
        case INS_DO_TESTS:
            switch(buffer[ISO7816.OFFSET_CDATA])
            {
            //置垃圾回收標識
            case 0:
                try
                {
                    if (javacard.framework.JCSystem.isObjectDeletionSupported())
                    {
                        javacard.framework.JCSystem.requestObjectDeletion();
                    }
                }
                catch(Throwable t)
                {
                }
                break;
            //調用共享接口方法
            case 1:
                sio = (MyShareable)JCSystem.getAppletShareableInterfaceObject(serverAID, (byte)0);
                sio.m1(apdu, bytesRead);
                break;
            }
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }
}

測試腳本:

//下載ServerApplet
RESET
AUTH
80 e6 02 00 1d 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 01 01 08 a0 00 00 00 03 00 00 00 00 00 00

80 e8 00 00 ef c4 82 01 5b 01 00 21 de ca ff ed 02 02 06 00 01 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 01 01 06 53 65 72 76 65 72 02 00 21 00 21 00 21 00 14 00 15 00 2e 00 1e 00 68 00 0a 00 0f 00 05 00 9e 03 b3 00 00 00 00 00 00 02 01 00 04 00 15 02 00 01 07 a0 00 00 00 62 00 01 03 01 07 a0 00 00 00 62 01 01 03 00 14 01 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 01 81 00 0c 06 00 1e 00 00 c1 81 02 42 81 03 00 ff 00 05 04 00 00 00 1b ff ff 00 18 00 1f 81 02 00 00 02 01 08 07 00 68 00 01 40 18 8c 00 00 18 8b 00 01 7a 04 30 8f 00 02 18 1d 1e 8c 00 03 7a 00 20 7a 01 30 18 77 05 33 11 01 00 90 0b 2e 19 8b 00 04 28 04 03 29 05 70 19 15 04 08 1b 16 05 1e 8d 00 09 3b 16 05 1e 41 29 05 19 08 8b 00 0a 31 1e 64 e8 19 8b 00 05

80 e8 80 01 70 3b 19 16 05 08 41 8b 00 06 19 03 08 8b 00 07 19 1b 03 16 05 8b 00 08 7a 08 00 0a 00 00 00 00 00 00 00 00 00 00 0a 00 05 01 00 02 00 00 05 00 2e 00 0b 06 81 03 00 03 81 03 01 01 00 05 00 06 00 00 01 03 81 0a 01 03 81 0a 07 03 81 0a 09 03 81 0a 04 03 81 0a 05 06 81 10 02 03 81 0a 03 09 00 0f 00 00 00 0b 05 04 06 06 14 11 0c 08 09 06 08

//安裝ServerApplet
80 e6 0c 00 39 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 01 01 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 01 81 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 01 81 01 00 02 c9 00 00
if SW is_not "9000" goto failure


//下載ClientApplet
RESET
AUTH
80 e6 02 00 1d 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 02 01 08 a0 00 00 00 03 00 00 00 00 00 00

80 e8 00 00 ef c4 82 01 cc 01 00 21 de ca ff ed 02 02 04 00 01 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 02 01 06 43 6c 69 65 6e 74 02 00 21 00 21 00 21 00 14 00 28 00 46 00 0e 00 bc 00 0a 00 19 00 00 00 78 02 c6 00 00 00 00 00 00 03 01 00 04 00 28 03 03 01 07 a0 00 00 00 62 01 01 00 01 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 01 01 00 01 07 a0 00 00 00 62 00 01 03 00 14 01 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 02 81 00 14 06 00 0e 00 00 00 80 03 01 00 01 07 01 00 00 00 20 07 00 bc 01 00 91 80 08 00 9b 00 04 01 40 18 8c 00 0c 18 8b 00 01 7a 04 30 8f 00 02 18 1d 1e 8c 00 03 7a 07 24 19 8b 00 05 2d 01 2e 1a 03 25 10 80 6a 0d 1a 03 25 60 08 11 6e 00 8d 00 06 19 8b 00 07 29 04 1a 04 25 75 00 71 00 02 ff a4 00 0d

80 e8 80 01 e1 00 20 00 3f 8d 00 08 1a 08 1a 07 25 8b 00 09 61 08 11 69 99 8d 00 06 1a 08 1a 07 25 41 05 43 3e 25 04 43 5b 38 18 8f 00 0a 3d 1a 08 1a 07 25 8c 00 0b 87 00 70 3a 1a 08 25 73 00 2d 00 00 00 01 00 0b 00 19 8d 00 0d 60 27 8d 00 0e 70 22 28 05 70 1e ad 00 03 8d 00 0f 94 00 00 10 2e 1b 19 16 04 8e 03 00 10 00 70 08 11 6d 00 8d 00 06 7a 08 00 0a 00 00 00 00 00 00 00 00 00 00 05 00 46 00 11 02 00 02 00 03 80 03 01 01 00 02 00 06 00 00 09 01 82 01 00 03 80 0a 01 06 80 07 01 03 80 0a 06 06 80 08 03 03 80 06 02 01 80 06 00 06 80 06 00 06 80 03 00 06 80 08 11 06 80 08 12 06 80 08 04 01 81 00 00 09 00 19 00 02 80 20 00 13 07 06 04 06 06 07 15 04 15 08 08 12 09 15 05 0c 04 09 09

//安裝ClientApplet
80 e6 0c 00 39 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 02 01 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 02 81 10 a0 00 00 00 62 03 01 0a 01 01 02 01 04 07 02 81 01 00 02 c9 00 00
if SW is_not "9000" goto failure

RESET

//選擇ClientApplet
0x00 0xA4 0x04 0x00 0x10 0xA0 0x00 0x00 0x00 0x62 0x03 0x01 0x0A 0x01 0x01 0x02 0x01 0x04 0x07 0x02 0x81 0x7F;

//調用ServerApplet實例的共享接口方法
0x80 0x20 0x00 0x00 0x01 0x01;

//設置垃圾回收標誌
0x80 0x20 0x00 0x00 0x01 0x00;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章