JavaCard: How can an applet's instance call a

2020-02-09 19:34发布

Consider a Java Card Classic applet with multiple instances that need to share some data in a byte[] variable (e.g. persistent mutable, that is EEPROM/Flash), containing information common to all instances.

A static byte[] variable would be a perfect fit, but these happen to be prohibited by validation rules imposed on me (I'm told: as a catch-all way to demonstrate that un-instantiating an instance frees what it allocated on instantiation).

This would be solved if a slave instance could call one of the applet's method in the context of a master instance (perhaps initially identified by AID, or/and/then in some other way). How can this be done? Any example?


Update: the code in this other question is next to doing what I want shares objects, but does not seem to call a method in the context of another instance.

1条回答
家丑人穷心不美
2楼-- · 2020-02-09 20:01

A tested example, as promised:

package nl.owlstead.javacard.sharedarray;

import javacard.framework.*;

/**
 * The master and slave AID should only differ in the last byte; the master should end with the 'm' ASCII character.
 * This applet is for demonstration purposes only.
 * 
 * @author owlstead@stackoverflow
 */
public class SharingApplet extends Applet {

    public interface SharedArray extends Shareable {
        public byte[] getSharedArray();
    }

    public static class SharedArrayImpl implements SharedArray {
        private byte[] sharedArray;

        public SharedArrayImpl(final byte[] arrayToShare) {
            this.sharedArray = arrayToShare;
        }

        public byte[] getSharedArray() {
            return sharedArray;
        }
    }

    private static final short MAX_AID_SIZE = 16;
    private static final short START = 0;
    private static final byte SHARABLE_PARAM = 0;
    private static final byte PARAM_SHARED_ARRAY = 0;

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        final byte aidLength = bArray[bOffset++];
        final byte lastAIDByte = bArray[(short) (bOffset + aidLength - 1)];
        final boolean isMaster = lastAIDByte == 'm';
        final SharingApplet applet = new SharingApplet(isMaster);
        applet.register(bArray, bOffset, aidLength);
        applet.setMasterAID();
    }

    // if null, it is not the master
    private final SharedArray sharedArray;
    private AID masterAID;

    public SharingApplet(final boolean isMaster) {
        if (isMaster) {
            final byte[] sa = new byte[] { 'm' };
            sharedArray = new SharedArrayImpl(sa);
        } else {
            sharedArray = null;
        }
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }

        byte[] buf = apdu.getBuffer();
        switch (buf[ISO7816.OFFSET_INS]) {
        case (byte) 0x00: {
            final SharedArray theSharedArray;
            if (sharedArray == null) {
                theSharedArray = (SharedArray) JCSystem.getAppletShareableInterfaceObject(masterAID, SHARABLE_PARAM);
            } else {
                theSharedArray = sharedArray;
            }
            final byte[] sa = theSharedArray.getSharedArray();
            Util.arrayCopy(sa, START, buf, START, (short) sa.length);
            apdu.setOutgoingAndSend(START, (short) sa.length);
            break;
        }
        case (byte) 0x02: {
            final SharedArray theSharedArray;
            if (sharedArray == null) {
                theSharedArray = (SharedArray) JCSystem.getAppletShareableInterfaceObject(masterAID, SHARABLE_PARAM);
                final byte[] sa = theSharedArray.getSharedArray();
                sa[START] = 's';
            } else {
                theSharedArray = sharedArray;
                final byte[] sa = theSharedArray.getSharedArray();
                sa[START] = 'm';
            }
            break;
        }
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    private void setMasterAID() {
        final byte[] workspace = new byte[MAX_AID_SIZE];
        final AID slaveOrMasterAID = JCSystem.getAID();
        final byte aidLength = slaveOrMasterAID.getBytes(workspace, START);
        workspace[(short) (aidLength - 1)] = 'm';
        this.masterAID = new AID(workspace, START, aidLength);
    }

    public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {
        if (sharedArray == null || parameter != PARAM_SHARED_ARRAY) {
            return null;
        }
        return sharedArray;
    }
}
查看更多
登录 后发表回答