Cartes à puce et OpenCard Framework

Le développeur Java précédentLa colonne «Cartes à puce: une introduction» a donné un aperçu général des cartes à puce et de leur fonctionnement. Il comprenait une section sur les normes des cartes à puce, présentant le concept d'OpenCard. Comme décrit dans le premier article, OpenCard est une norme ouverte qui assure l'interopérabilité des applications de cartes à puce entre les NC, les terminaux de point de vente, les ordinateurs de bureau, les ordinateurs portables, les décodeurs et les PDA. OpenCard peut fournir des applications de cartes à puce Java 100% pures. Les applications de carte à puce ne sont souvent pas pures car elles communiquent avec un périphérique externe ou utilisent des bibliothèques sur le client. Dans cet article, nous fournirons deux implémentations à deux lecteurs de cartes différents, montrant comment vous ajouteriez la prise en charge des lecteurs de cartes à OpenCard. Nous espérons que les ports pour Litronic, Gemplus, Schlumberger, Bull, Toshiba et SCM seront bientôt disponibles, compliments d'OpenCard etJavaWorld .

introduction

Pour utiliser une carte à puce, vous devez être capable de lire la carte et de communiquer avec elle à l'aide d'une application. OpenCard fournit un cadre pour cela en définissant des interfaces qui doivent être implémentées. Le framework OpenCard définit plusieurs de ces interfaces. Une fois ces interfaces implémentées, vous pouvez utiliser d'autres services dans les couches supérieures de l'API. Par exemple, avec un lecteur correctement interfacé, OpenCard peut démarrer un agent Java card chaque fois que la carte est insérée. L'agent de carte peut alors communiquer avec des applications sur la carte à puce via le terminal de carte dans le cadre d'une session.

Cet article vous apprendra comment interfacer les terminaux de cartes avec OpenCard. Les prochains articles discuteront de la manière d'écrire un agent. Une petite application de test, qui obtient la chaîne ATR (Answer to Reset) est fournie. L'ATR est fondamental pour les cartes à puce. Nous prendrons le kit de développement OpenCard et expliquerons les implémentations pour deux lecteurs de carte à puce différents en utilisant l'interface de terminal de carte. Les techniques décrites dans l'article pour la mise sous tension des lecteurs, le démarrage des sessions de cartes et l'utilisation des unités de données de protocole et des unités de données de protocole d'application peuvent être réutilisées pour la plupart des lecteurs du marché.

Bien qu'il ne soit pas nécessaire d'utiliser OpenCard pour créer des applications de cartes à puce Java 100% pures, sans cela, les développeurs sont obligés d'utiliser des interfaces maison pour les cartes à puce. (Pour une explication détaillée de ce que signifie vraiment 100% pur, consultez la section Ressources.) OpenCard fournit également aux développeurs une interface avec PC / SC (une interface d'application de carte à puce développée par Microsoft et d'autres pour communiquer avec des cartes à puce basées sur Win32 plates-formes pour PC) pour l'utilisation d'appareils existants sur les plates-formes Win32. Continuez à lire et apprenez à utiliser les cartes à puce avec votre navigateur.

Architecture OpenCard: un aperçu

OpenCard fournit une architecture pour développer des applications en Java qui utilisent des cartes à puce ou d'autres périphériques compatibles ISO 7816 sur différentes plates-formes cibles telles que Windows, les ordinateurs du réseau, les stations de travail Unix, les Webtops, les décodeurs, etc. OpenCard Framework fournit une interface de programmation d'application (API), qui vous permet d'enregistrer des cartes, de rechercher des cartes dans les lecteurs et éventuellement de faire démarrer des agents Java lorsque des cartes sont insérées dans le lecteur. L'architecture d'OpenCard est illustrée à la figure 1.

L'architecture d'OpenCard Framework est constituée des CardTerminal, des CardAgent, des agents et / ou des applications qui interagissent avec ces composants. OpenCard se compose de quatre packages Java avec le préfixe opencard :

  1. application
  2. io
  3. agent
  4. Terminal

Le package terminal dans OpenCard

Les packages opencard.application et opencard.io fournissent l'API de haut niveau utilisée par le développeur de l'application. Les services nécessaires à l'API de haut niveau sont exécutés par des classes dans les packages opencard.agent et opencard.terminal . Le package opencard.agent fait abstraction des fonctionnalités de la carte à puce via le CardAgent. Le package opencard.terminal fait abstraction des terminaux de cartes (également appelés lecteurs de cartes ). Comprendre la structure du package opencard.terminal est nécessaire pour comprendre les exemples d'implémentations de terminaux de cartes fournis dans cet article.

Un terminal de carte fait abstraction du dispositif utilisé dans un système informatique pour communiquer avec une carte à puce. Le paquet opencard.terminal contient des classes pour représenter le matériel du terminal de carte, pour interagir avec l'utilisateur et pour gérer les ressources du terminal de carte. Tous les lecteurs n'ont pas ces capacités. Lors de la mise en œuvre d'un lecteur qui n'a pas de saisie au clavier, nous utiliserons l'extension UserInteractionHandler.

Représentation du terminal de carte

Chaque terminal de carte est représenté par une instance de classe CardTerminalqui définit le terminal de carte abstrait compatible OpenCard. Un terminal de carte peut avoir un ou plusieurs emplacements pour cartes à puce et éventuellement un écran et un clavier ou un clavier NIP. Les emplacements d'un terminal de carte sont représentés par des instances de la classe abstraite Slot, qui propose des méthodes pour attendre qu'une carte soit insérée, pour communiquer avec la carte et pour l'éjecter (si possible).

Interaction de l'utilisateur

L'utilisation d'une carte à puce nécessite une interaction avec l'utilisateur - pour la vérification du titulaire de la carte. L'interface UserInteractionfournit cette fonctionnalité. Il fournit des méthodes pour écrire un message sur l'écran et recevoir des entrées de l'utilisateur. Les terminaux de cartes qui ne prennent pas en charge toutes les fonctionnalités d'interaction utilisateur peuvent utiliser le UserInteractionHandler, qui implémente a en UserInteractiontant qu'interface utilisateur graphique basée sur la boîte à outils de fenêtrage abstrait (AWT).

La gestion des ressources

Les cartes et les lecteurs de cartes nécessitent une gestion des ressources afin que les agents puissent bénéficier du niveau de contrôle d'accès dont ils ont besoin. La gestion des ressources prévoit le partage des terminaux à cartes et des cartes insérées dans ceux-ci entre les agents du système. Par exemple, supposons que vous utilisez votre carte à puce pour signer un document en même temps qu'un message électronique de haute priorité qui doit être décodé à l'aide de votre carte à puce arrive. La gestion des ressources arbitre l'accès au CardTerminalport et au port correct.

La gestion des ressources pour les terminaux à cartes est réalisée par la CardTerminalRegistryclasse OpenCard. Il n'existe qu'une seule instance de CardTerminalRegistry: le registre de terminaux à cartes à l'échelle du système. Le registre des terminaux de cartes à l'échelle du système garde la trace des terminaux de cartes installés dans le système. Peut être configuré dans le registre terminal de carte de propriétés sur le démarrage du système ou dynamique à travers registeret unregisterméthodes pour ajouter ou supprimer dynamiquement les terminaux de carte à partir du Registre.

Lors de l'enregistrement d'un terminal à carte, il CardTerminalFactoryest nécessaire de créer une instance de la classe d'implémentation correspondante pour le terminal à carte. La fabrique de terminaux de cartes utilise le nom de type et le type de connecteur du terminal de cartes pour déterminer la CardTerminalclasse à créer. Le concept de fabrique de terminaux à cartes permet à un fabricant de terminaux à cartes de définir un mappage entre les noms de types conviviaux et le nom de classe.

Exemple d'implémentation: terminal de carte IBM

Dans cette section, nous décrirons l'intégration du terminal de carte IBM 5948 dans OpenCard. Le terminal de carte IBM 5948 possède un emplacement pour cartes à puce, un écran LCD et un clavier NIP. Il est connecté au poste de travail ou au PC via un port série. Plus d'informations sur ce lecteur sont disponibles dans le

Ressources

section.

Pour accéder à un terminal de carte à partir de OpenCard, une mise en œuvre pour les deux classes abstraites CardTerminalet Slotdoivent être fournis. Ceux-ci ont été nommés IBM5948CardTerminalet IBM5948Slot, respectivement. De plus, un CardTerminalFactorynom approprié IBMCardTerminalFactoryest nécessaire. L'implémentation du terminal se compose du package com.ibm.zurich.smartcard.terminal.ibm5948 . La figure 2 décrit les relations d'héritage entre les classes d' opencard.terminal , les classes Java et l'implémentation du terminal. Le diagramme de classes contient également une classe IBM5948Driver, qui n'implémente aucune classe abstraite d'OpenCard mais sert d'interface Java à la bibliothèque de pilotes de terminal écrite en C.

We assume that the terminal is already connected to the workstation or PC, and that the serial port is configured to work with the terminal. In the following section, we describe the design and implementation of the driver, the terminal, the slot, and the card terminal factory. The configuration of the card terminal registry also is provided.

The card terminal driver

The card terminal is shipped with a driver that is available as a dynamic link library (DLL). The DLL has a C API that offers the functions CT_init, CT_data, and CT_close:

  • The function CT_init is used to open a connection to a card terminal that is connected to a certain serial port. After the connection has been established, protocol data units (PDU) can be exchanged with the card terminal and APUs can be exchanged with the smart card that is plugged into the slot of the terminal via the CT_data function.

  • The CT_data call is used to send one PDU and retrieve the response from the terminal or the smart card, respectively.

  • The CT_close function is used to close the connection to the card terminal and release any resources.

Success or failure of all three API calls is indicated by the return code.

The Java API

Similar to the C API, we define a Java API for the card terminal driver. The Java API for the card terminal consists of class IBM5948Driver, which has native methods calling the C API. We decided to implement as much functionality as possible in Java and have only some "glue" code written in C. In fact, the parameters of the ctInit and ctClose method are just passed on to the respective C API function. Since arrays are organized differently in C and Java, they need to be handled by calls to the Java Native Interface (JNI) API of the virtual machine. The native methods return the return code of the C API. The implementation of the ctData method is shown below:

JNIEXPORT jint JNICALL Java_com_ibm_zurich_smartcard_terminal_ibm5948_IBM5948Driver_ctData(JNIEnv *env, jobject that, jbyte destination, jbyteArray command, jint commandLength, jbyteArray response, jint responseMax) { short rc; unsigned char sad = HOST; unsigned char dad = destination; unsigned short responseLength = (unsigned short)responseMax; unsigned char *commandArray; unsigned char *responseArray; jclass cls = (*env)->GetObjectClass(env, that); jfieldID fid; jint ctn; fid = (*env)->GetFieldID(env, cls, "ctNumber", "I"); if(fid == NULL) { return(CT_ERR_HTSI); } ctn = (*env)->GetIntField(env, that, fid); commandArray = (unsigned char *) (*env)->GetByteArrayElements(env, command, 0); responseArray = (unsigned char *) (*env)->GetByteArrayElements(env, response, 0); rc = CT_DATA(ctn, &dad, &sad, commandLength, commandArray, &responseLength, responseArray); (*env)->ReleaseByteArrayElements(env, command, (signed char *)commandArray, 0); (*env)->ReleaseByteArrayElements(env, response, (signed char *)responseArray, 0); fid = (*env)->GetFieldID(env, cls, "responseLength", "I"); if(fid == NULL) { return(CT_ERR_HTSI); } (*env)->SetIntField(env, that, fid, responseLength); return rc; } 

The native methods described above mimic the C API in Java. The reason for this was to have as little C code to maintain as possible. On top of the native methods, which are private, the methods init, data, and close are implemented. They call the native methods and throw an exception if the return code indicates an error. In the case of the data method, the response byte array is returned upon a successful completion of the native method call. The example below shows the data method:

synchronized byte[] data(byte destination, byte[] pdu) throws CardTerminalException { int rc = ctData(destination, pdu, pdu.length, response, response.length); if (rc == CT_OK) { byte[] result = new byte[responseLength]; System.arraycopy(response, 0, result, 0, responseLength); return result; } else throw new CardTerminalException(rc2String(rc)); } 

In order to keep memory management inside Java, a buffer response for the answer from the terminal is allocated once and passed on to the native code. Since the C API is not re-entrant, the methods of IBM5948Driver must be declared synchronized.

Implementing the card terminal

Le terminal de carte est contrôlé en soumettant les PDU de contrôle à la méthode de données du IBM5948Driver. Le format des PDU de contrôle est conforme à la norme ISO 7816-4. Cela nous permet de déployer une classe opencard.agent.CommandPDUpour construire les PDU et opencard.agent.ResponsePDUgérer les réponses.

La IBM5948CardTerminalclasse étend la classe CardTerminal. Le constructeur initialise la super classe et instancie le pilote. Ensuite, il instancie la baie pour contenir les emplacements et instancie une instance de IBM5948Slotpour représenter le seul emplacement du terminal de carte IBM 5948.