JavaCard Shareable Interface

From
Jump to navigation Jump to search

Auf einer JavaCard können mehrere Applets installiert werden. Die JavaCard-Laufzeitumgebung isoliert diese Applets voneinander. Dies bedeutet, dass ein Applet keinen Zugriff auf Objekte anderer Applets hat, es sei denn, das jeweilige Applet gewährt diesen Zugriff explizit. In diesem Projekt wird dargestellt, wie ein solcher Zugriff über Applet-Grenzen hinweg funktioniert.

Hierfür kommen Shareable Interfaces zum Einsatz. In einem solchen Interface werden Methoden definiert, die von einem Applet aufgerufen werden können, selbst wenn das Objekt, das dieses Interface implementiert, Teil eines anderen Applets ist. Ein solches Objekt wird als Shareable Interface Object (SIO) bezeichnet.

Die primäre Quelle für dieses Projekt ist die Java Card Runtime Environment Specification 3.0.5 [1], Kapitel 6 „Applet Isolation and Object Sharing“. Insbesondere wird in Abschnitt 6.2.4 „Shareable Interfaces“ die Funktionsweise allgemein beschrieben. Der Quellcode für dieses Projekt ist in der Gitlab-Instanz des CMS zu finden. [2]

Implementation

Zur Überprüfung der Funktionsweise von Shareable Interfaces werden folgende Programme definiert:

  • ShareableInterface.java enthält ein Interface mit einer Methodendefinition
  • Implementation.java implementiert das Shareable-Interface
  • ServerApplet.java hält ein Objekt der implementierenden Klasse
  • ClientApplet.java ruft die Methode an dem Objekt des Server-Applets

Ziel dieses Projekts ist die Demonstration von Shareable Interfaces in JavaCard. Um den Fokus auf das Wesentliche zu legen, wird die Funktionalität bewusst einfach gehalten: Das Interface definiert die Methode incrementAndGet, die keine Argumente erwartet und einen Wert vom Typ short zurückgibt. Die Implementation-Klasse implementiert diese Methode, indem es eine auf 0 initialisierte Zählvariable hält, diese inkrementiert und den neuen Wert zurückgibt. Das Server-Applet hält ein Objekt dieser Klasse. Das Client-Applet ruft die Methode bei Erhalt einer APDU auf.

Definition des Shareable-Interface

Zunächst wurde in ShareableInterface.java ein Shareable-Interface definiert. Ein Shareable-Interface ist ein Interface welches javacard.framework.Shareable erweitert. Es befindet sich im eigenen Package service.

package service;

import javacard.framework.Shareable;

public interface ShareableInterface extends Shareable {
    short incrementAndGet();
}

Implementation des Shareable-Interface

Die Klasse Implementation implementiert das Shareable-Interface. Sie hält eine private Zählvariable, die im Konstruktor auf 0 initialisiert wird. Die Methode incrementAndGet inkrementiert diese Variable und gibt den neuen Wert zurück.

package server;

import service.ShareableInterface;

public class Implementation implements ShareableInterface {

    private short counter;

    Implementation() {
        counter = 0;
    }

    public short incrementAndGet() {
        counter++;
        return counter;
    }
}

Server-Applet erstellt Objekt der Implementation-Klasse

Im Konstruktor wird eine Instanz der implementierenden Klasse erstellt; dieses Objekt fungiert als Shareable Interface Object, da die Klasse dieses Objekts das Shareable-Interface implementiert. Da APDUs von diesem Applet nicht verarbeitet werden sollen, gibt die process-Methode stets ein Statuswort ungleich 0x9000 zurück.

package server;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;

public class ServerApplet extends Applet {

    private Implementation shareableInterfaceObject;

    private ServerApplet() {
        shareableInterfaceObject = new Implementation();
        register();
    }

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

    public void process(APDU apdu) {
        ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
    }
}

Der Zugriff auf die Interface-Methode incrementAndGet ist derzeit noch auf das Server-Applet beschränkt. Dieses Applet wird in einem späteren Schritt erweitert; zunächst wird jedoch das Client-Applet implementiert.

Client-Applet erhält ein Shareable Interface Object

Um Zugriff auf das Shareable Interface Object des Server-Applets zu erhalten, wird zunächst eine Variable sio vom Typ ShareableInterface deklariert. Diese Variable wird initialisiert, sobald das Client-Applet die erste APDU empfängt. Dazu ruft das Applet javacard.framework.JCSystem.getAppletShareableInterfaceObject auf und übergibt dabei den Application Identifier (AID) des Server-Applets.

package client;

import javacard.framework.AID;
import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import service.ShareableInterface;

public class ClientApplet extends Applet {

    private ShareableInterface sio; // shareable interface object

    private final AID SERVER_AID = new AID(
        new byte[]{(byte)0xF1, (byte)0xF2, (byte)0xF3, (byte)0xF4, (byte)0xF5, 0x08, 0x01},
        (short)0, (byte)7
    );

    private ClientApplet() {
        register();
    }

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

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

        if (sio == null) {
            sio = (ShareableInterface)JCSystem.getAppletShareableInterfaceObject(SERVER_AID, (byte)0);
            if (sio == null) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); }
        }

        short value = sio.incrementAndGet();

        byte[] buffer = apdu.getBuffer();
        buffer[0] = (byte)(value >> 8);
        buffer[1] = (byte)value;

        apdu.setOutgoingAndSend((short)0, (short)2);
    }
}

Server-Applet gibt dem Client-Applet Zugriff auf das Shareable Interface Object

Im nächsten Schritt wird das Server-Applet erweitert. Wenn das Client-Applet die Methode javacard.framework.JCSystem.getAppletShareableInterfaceObject aufruft, ruft die JavaCard-Laufzeitumgebung die Methode javacard.framework.Applet.getShareableInterfaceObject am Applet auf, dessen AID der Client als Argument übergeben hat. In diesem Fall handelt es sich um das Server-Applet. Da das Server-Applet die Applet-Klasse erweitert, erbt es diese Methode und muss sie daher überschreiben. Das Server-Applet wird folglich um die folgende Methode ergänzt:

import javacard.framework.AID;
import javacard.framework.Shareable;

    // ...

    private final AID ALLOWED_CLIENT_AID = new AID(
        new byte[]{(byte) 0xf1, (byte) 0xf2, (byte) 0xf3, (byte) 0xf4, (byte) 0xf5, 0x09, 0x01},
        (short)0, (byte)7
    );

    // ...

    public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {
        if (clientAID.equals(ALLOWED_CLIENT_AID)) {
            return shareableInterfaceObject;
        }
        return null;
    }

In dieser Methode übergibt die JavaCard-Laufzeitumgebung die AID des anfragenden Applets als Argument. Wir prüfen, ob es sich um die AID unseres Client-Applets handelt. Stimmt diese überein, geben wir eine Referenz auf das Shareable Interface Object zurück. Weicht die AID ab, lehnen wir die Anfrage durch Rückgabe von null ab. Auf diese Weise lässt sich der Zugriff auf ein Shareable-Interface auf bestimmte Applets beschränken.

Client-Applet verwendet das Shareable-Interface

Im Client-Applet können nach dem Erhalt und der Speicherung des Shareable Interface Object in der Variablen sio alle vom Interface definierten Methoden aufgerufen werden. Dadurch lässt sich die Zählvariable des Server-Applets inkrementieren und der zurückgegebene Wert als Inhalt der Antwort-APDU verwenden.

Bauen, Installieren, und Testen

Dieses Projekt nutzt das Build-System Ant. Die Datei build.xml dient als Build-Skript und ermöglicht das Kompilieren des Projekts, die Installation der Applets auf einer JavaCard sowie die Ausführung von Tests.

Der Build-Prozess wird durch den Befehl ant build oder einfach ant gestartet und verläuft wie folgt: Die drei Java-Quelldateien werden mittels javac in Class-Dateien übersetzt. Das Shareable-Interface wird anschließend in eine für JavaCards ladbare CAP-Datei konvertiert. Da im Target build-shareable-interface die Export-Option aktiviert ist, wird zudem eine Export-Datei generiert. Diese ist für die Erstellung der Server- und Client-Applets erforderlich und wird in den Targets build-server-applet sowie build-client-applet über das Import-Tag referenziert. Für jedes dieser Applets entsteht eine separate CAP-Datei. Der Build-Prozess benötigt das JavaCard SDK [3] sowie Ant-JavaCard [4], welche durch das Skript automatisch in das Build-Verzeichnis heruntergeladen werden.

Die Installation der Applets auf einer JavaCard erfolgt mit dem Befehl ant install. Hierfür wird das Tool GlobalPlatformPro [5] verwendet, das vorab vom Build-Skript heruntergeladen wird. Da die CAP-Datei des Shareable-Interfaces kein Applet, sondern ein reines Library-Package enthält, wird diese nicht mit der Option --install, sondern ausschließlich mit --load auf die Karte geladen.

Mit ant test wird ein Test kompiliert und ausgeführt. Der Testcode befindet sich in der Datei Test.java. Dabei wird zunächst das Client-Applet auf der JavaCard selektiert und zwei APDU-Befehle an dieses gesendet, um zu verifizieren, ob die vom Shareable-Interface bereitgestellte Methode erfolgreich ausgeführt werden kann.

Die Applets können abschließend mit dem Befehl ant uninstall von der Karte entfernt werden, und die Build-Verzeichnisse mit ant clean gelöscht werden.

Alternative Architekturen

Shareable-Interface im gleichen Package wie das Server-Applet

Befinden sich das Shareable-Interface, das Server-Applet und die implementierende Klasse im selben Package, entfällt die Erstellung einer CAP-Datei für das Interface. In diesem Fall sind im Build-Skript die Targets build-shareable-interface und install-shareable-interface zu entfernen. Bei den verbleibenden Targets, die von den entfernten Targets abhängen, ist die Abhängigkeit auf das Target zu ändern, von dem das entfernte Target abhängig war. Dem Target build-server-applet ist der Export-Parameter hinzuzufügen und der Import-Parameter zu entfernen. Beim uninstall-Target ist die AID des Shared-Interfaces zu entfernen.

Kein Server-Applet

Die Verwendung von Shareable-Interfaces ist nur erforderlich, wenn ein Applet auf Objekte eines anderen Applets zugreifen muss. Hat man hingegen nur eine Klasse, die Funktionen für Java-Card-Applets bereitstellen soll, dann kann diese einfach so als Library-CAP-Datei kompiliert und auf die Karte geladen werden, d.h. im Build-Skript ohne Applet- dafür mit Export-Tag, und mit der Option --load statt --install beim Installieren. Die Applets können diese Klasse anschließend nutzen.

Referenzen