Cette partie présente JavaCard et donne un exmple de programmation d'une application, serons abordés les sujets suivants concernant JavaCard:

Historique
En mars 1996, un petit groupe d'ingénieurs de Schlumberger au Texas ont souhaité simplifier la programmation des cartes à puces tout en préservant la sécurité des données. Presque immédiatement, ils ont analysé que ce problème avait déjà été posé par le chargement de code sur le World Wide Web. La solution avait été Java. Malheureusement vu la taille de la mémoire disponible sur une carte à puce seulement un sous-ensemble de Java pouvait être utilisé (la taille de la JVM (Java Virtual Machine) et du système de runtime ne devant pas dépasser 12 ko). C'est ainsi qu'est né JavaCard, le premier langage à objets adapté aux cartes à puces. Schlumberger et Gemplus sont les co-fondateurs du JavaCard Forum qui recommande des spécifications à JavaSoft (la division de Sun à qui appartient Java Card) en vue d'obtenir une standardisation du langage et il s'occupe aussi de la promotion des APIs (Application Programming Interface) JavaCard pour qu'il devienne la plate-forme standard de développement des applications pour les smart cards.

Architecture
La carte est basée sur un interpréteur de bytecode java


On retrouve donc la machine virtuelle java (JVM) au dessus du système d'exploitation. Comme pour les ordinateurs, chaque carte d'architecture devra avoir sa propre machine virtuelle. La machine virtuelle JavaCard est identique à celle de Java mais est découpée en deux parties : une sur la carte, l'autre hors carte ("Java Card Converter").
Il est donc nécessaire de pré-compiler les applications avant de les charger sur la carte :

La figure ci dessous présente le cycle de développement d'une application JavaCard.

.

La programmation s'effectue sur n'importe quel environement de programmation dans lequel on constitue des fichiers avec pour extension "java". On les compile ensuite afin de fournir le bytecode. Ce bytecode passe ensuite dans la machine virtuelle "hors carte" qui est découpée en 3 modules ayant chacun un rôle précis :

  • Le Vérifieur de ByteCode
    • Il utilise le vérifieur de Bytecode Java "classique"
    • Il contrôle le sous-ensemble JavaCard (langage + API)
  • Le Convertisseur en trois phases
    • Préparation : initialise les structures de données de la JCVM
    • Optimisation : ajuste l'espace mémoire, remplace certains InvokeVirtual par des InvokeStatic, etc.
    • Edition de liens : résout les références symboliques à des classes déjà présentes dans la carte (via "image" de la carte).
  • Le Signeur
    • Il valide le passage par le vérificateur et le convertisseur par une signature vérifée par la carte au moment du chargement.

Le programme fournit alors des fichiers ".cap" qui peuvent être chargés dans la carte.

JavaCard par rapport à Java
The minimum system requirement is 16 kilobytes of read-only memory (ROM), 8 kilobytes of EEPROM, and 256 bytes of random access memory (RAM).
La configuration minimum pour faire fonctionner JavaCard est une carte de 16 ko de ROM, 8 ko d'EEPROM et 256 octets de RAM. Il était donc impératif de réduire l'API Java afin de pouvoir loger la JVM sur la carte.

JavaCard se caractérise donc par rapport à Java par les caractéristiques suivantes :

  • Pas de chargement dynamique de classes
    • L'allocation dynamique d'objets (new) est supportée mais pas de ramasse miette (garbage collector) ni de désallocation explicite (c'est à dire que la mémoire allouée ne peut pas être récupérée).La méthode finalize() n'est pas supportée.
  • Types de base
    • byte (8bits), short (16 bits), int (32 bits), boolean
    • Pas de types char (ni de classe String), double, float et long
    • Pas de classes Boolean, Byte, Class, Integer etc...
  • Les objets de base disponibles sont
    • java.lang.Object
    • java.lang.Throwable
  • Les tableaux sont limités
    • Ils ne peuvent avoir qu'une dimension
    • les éléments supportés sont uniquement les types de bases supportés par JavaCard
    • La taille maximum est de 2^15 éléments
  • Le mécanisme d'héritage est semblable à java, on conserve donc
    • La surcharge de méthodes, les méthodes abstraites et les interfaces
    • L'invocation de méthodes dynamique
    • L'utilisation des mots clés instanceof, super et this
  • Pas de threads
    • Pas de classe Thread, pas de fonctionnalités de synchronisation des threads ( synchronised, wait...)
    • Toute application javacard est donc monothread
  • Sécurité
    • Notions de paquetages et opérateurs de portée identiques à java (protected, private et public)
    • Pas de classe SecurityManager, la politique de sécurité est directement implémentée dans la machine virtuelle
  • Mécanismes d'exceptions supportés
    • Les exceptions peuvent être définies (extends Throwable), propagées (throw) et interceptées (catch).
    • Les classes Trowable, Exception et Error sont supportées et certaines de leurs sous classes (dans java.lang)
  • Méthodes natives (natives)
    • Supporté pour les classes de base (masquées)
    • Optionnelles pour les classes chargées
    • Atomicité
    • La mise à jour des champs doit être atomique
    • Modèle transactionnel : beginTransaction( ), commitTransaction( ) et abortTransaction( )

Les concepts de programmation
Une approche traditionnelle du fonctionnement de la carte à puce est représentée par la figure ci-dessous :

La carte communique avec le terminal via des commandes/réponses APDU (voir norme) traitées directement par le masque de la carte. Ce dernier lit, écrit et met à jour les données contenues dans l'EEPROM.
L'approche JavaCard est différente :

L'application cliente envoit toujours des commandes APDU mais ce sont les applets Java présentes sur la carte qui les traitent. Les applets quand à elles sont exécutées par le JCRE (Java Card Runtime Environment ou Envirronement d'exéction JavaCard) via l'API JavaCard. Ceci permet donc d'adapter la carte aux applications clientes en lui chargeant l'applet correspondante.

L'API JavaCard
Elle contient un package principal pour programmer une applet carte, des extensions et des API utilitaires.

  • Package principal : javacard.framework
    • Il définit les classes AID, APDU, Applet, ISO, PIN, JCSystem, Util
    • Plus des classes d'execption
  • Extensions
    • javacardx.framework : permet la gestion des fichiers selon la norme ISO 7816-4
    • javacardx.crypto : assure la gestion des clés publiques et privées, la génération de nombre aléatoires, implémente des fonctions de chiffrement et de hashage optimisées...
  • Les API utilitaires
    • public final class JCSystem : cette classe contient les méthodes statiques pour interagir avec le JCRE
      • Gestion des transactions (1 seul niveau)
      • Gestion du partage d'objets entre applets
    • public class Util : cette classe contient des méthodes statiques utiles optimisées pour la carte
      • Copie, comparaison de tableaux de bytes
      • Création de short à partir de byte
    • public final class AID
      • Encapsule des identifiants d'applications carte conformes à la norme ISO 7816-5
    • public class ISO7816
      • Champs statiques de constantes conformes aux normes ISO 7816-3 et 4
    • public abstract class PIN
      • Représentation d'un code secret (tableau d’octets)
      • attribut OwnerPIN : code secret pouvant être mis à jour

L'Applet carte
L'applet carte est un programme serveur de la javaCard, une applet est sélectionné par le terminal par un APDU de sélection. Cette sélection est faite en fonction de l'ID de l'applet qui doit être unique (représenté par la classe AID signifiant Applet ID).
Une applet a les propriétés suivantes :

  • Une fois qu'elle est installée dans la carte, elle est toujours disponible
  • L'applet doit hériter de la classe javacard.framework.Applet
  • Elle doit implémenter les méthodes qui intéragissent avec le JCRE : install( ), select( ), deselect( ), et process( )

Définition des méthodes publiques qu'elle doit obligatoirement implémenter :

  • public void install( APDU apdu )
    • Appelée (une fois) par le JCRE quand l'applet est chargée dans la carte
    • Doit s'enregistrer auprès du JCRE (méthode register( ))
  • public boolean select( )
    • Appelée par le JCRE quand un APDU de sélection est reçu et désigne cette applet
    • Rend l'applet active
  • public void process( APDU apdu )
    • Appelée par le JCRE quand un APDU de commande est reçu pour cette applet (doit être active)
  • public void deselect( )
    • Appelée par le JCRE pour désélectionner l'applet courante

Comment une applet gère les APDU ?

L'unité de traitement de base d'une applet est un objet de type javacard.framework.APDU qui est transmis par le JCRE à la réception d'un APDU de commande par la carte (en provenance du terminal). La méthode process( ) de l'applet courant est alors appelée.

La classe javacard.framework.APDU :

  • Est compatible avec le format de messages ISO 7816-4
  • Cache les caractéristiques des protocoles de communication bas niveau (T=0 et T=1).
  • Encapsule les échanges de messages APDUs (commandes et réponses) dans un buffer d'entrées/sorties

La lecture et l'écriture dans le buffer d'APDU se déroule comme le montre le diagramme de séquence ci dessous :

Le rôle d'une applet est d'une part de maintenir son propre état, gérer ses champs, créer des objets et les référencer pour travailler. D'autre part elle réponds à des commandes APDUs (méthode process( ) ) avec des réponses APDUs.
Pour concevoir une applet on doit effectuer les étapes suivantes :

  • Créer les objets de base à l'installation, initialiser les champs
    • Implémentation de la méthode install( )
  • Définir les APDUs traités par la méthode process( )
    • Implémentation d'un analyseur de commandes
    • Utilisation des champs et objets de l'applet
  • Définir les traitements à la sélection et à la désélection (méthodes select( ) et deselect( ) )

L'application Cliente (Application terminal)
L'application cliente se trouve sur le terminal qui dialogue avec la carte :

  • Elle implémente les classes du terminal (avec JDK)
  • Elle communique avec le serveur (applet carte), pour cela elle s'ocuupe de
    • l'établissement de la liaison : envoi d’un APDU de sélection avec l’AID de l’applet (standardisé)
    • l'invocation de services de l’applet, c'est à dire :
      • le codage et l'envoi d’APDUs de commande conformes à ceux traités par l’applet
      • la réception et décodage des APDUs de réponse retournés par l’applet

Il n'existe pas d’API standard de communication avec la carte, on peut utiliser une des API fournit pas différents constructeurs. Cependant une API est en cours de standardisation.
Le diagramme de séquence ci dessous indique les communications entre l'application cliente avec la carte :

Construction d'une application Java Card
Une application carte s'effectue en trois étapes :

  • Ecriture du code dans la carte (application serveur = applet Java Card) : Il implémente les services.
  • Installation de l'applet dans les cartes : Ceci permet d'initialiser les services.
  • Le code dans le terminal (application cliente) : Il invoque les services implémentés dans l'applet.

On prendra l'exemple d'une application qui incrémente/décrémente appelée tout naturellement "Compteur".

Programmation de l'application Serveur (applet JavaCard)
On définit tout d'abord les caractéristiques de l'applet :

  • État de l'applet
    • Maintient une valeur entière positive ou nulle (pas d'objets)
  • Installation : création de l'objet Applet
    • Initialisation de la valeur du compteur
    • Enregistrement auprès du JCRE
  • Opérations
    • Lecture : retourne la valeur du compteur
    • Incrémentation/décrémentation : ajoute/soustrait un montant au compteur et retourne la nouvelle valeur du compteur
  • Sélection et désélection
    • Aucun traitement

Ensuite on définit les APDUs traités par l'applet :

  • int lire( )
    • Commande : AA 01 XX XX 00 04
    • Réponse : RV3 RV2 RV1 RV0 90 00
  • int incrementer( int )
    • Commande : AA 02 XX XX 04 AM3 AM2 AM1 AM0 04
    • Réponse : RV3 RV2 RV1 RV0 90 00
  • int decrementer( int ) : idem mais INS=03

Programmation de la classe Applet :

On donne l'exemple de la programmation de l'opération de décrémentation :

Installation de l'applet Java Card
On compile, convertit et on charge l'applet de façon sécurisé
dans la cartes (on utilise JavaCard IDE). On appelle ensuite la méthode install( ) de l'applet.

Programmation de l'application Client
Comme il n'existe pas d'API de communication standard, on utilisera celle fournie par Gemplus
On utilise le package
com.gemplus.gcr, que l'on présente rapidemment, le package intègre les classes suivantes :

  • La classe Ifd (Interface Device)
    • Elle représente le lecteur
    • Elle gère les canaux de communication avec le lecteur
    • On a des sous-classe pour chaque mode de communication
  • Classe Icc (Integrated Circuit Card)
    • Elle représente la carte
    • Elle gère la connexion à la carte
    • Elle gère l’échange d’APDUs avec la carte par la méthode ApduResponse exchangeApdu(ApduCommand command) throws GcrException
  • Classe GcrException (et sous-classes) pour les erreurs de communication

On code donc le client carte pour la liaison :

Puis on code la décrémentation