[DNFM0071] 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;
DNFM0071(1)

猜你喜欢

转载自blog.csdn.net/hanjing_csdn/article/details/79324539