MokaByte Numero  42  - Giugno 2000
 
De La Rue 1.0
Un esempio di 
Javacard classica
 II parte
di 
Roberto Fabbrica
Una implementazione di JavaCard molto interessante
 

La JavaCard GalactIC 1.0, prodotta da De La Rue, rappresenta piuttosto bene la maggior parte delle JavaCard disponibili dalla seconda metà dell’anno 1999. Il formato adottato è quello standard delle SmartCard, le risorse disponibili sono nella media rispetto ai prodotti degli altri fornitori e gli strumenti forniti a corredo permettono di affrontare tutte le problematiche legate all’installazione e all’uso delle JavaCard Applet.

Nell’articolo precedente sono state descritte le caratteristiche tecniche della JavaCard GalactIC 1.0, gli strumenti forniti dal produttore per l’installazione ed il test di JavaCard Applet e le principali caratteristiche tecniche del dispositivo.

 In quest’articolo saranno trattati il sistema operativo della JavaCard GalactIC 1.0, le particolarità dei comandi APDU proprie di questo dispositivo e l’interfaccia fornita per l’accesso alla JavaCard dal Personal Computer cui sono collegate.

 Per la corretta interpretazione di quest’articolo si consiglia vivamente la lettura dei precedenti articoli pubblicati dall’autore su MokaByte (numeri di Gennaio 2000, Febbraio 2000, Marzo 2000 e Aprile 2000), oltre naturalmente alla prima parte di quest’articolo. Alcuni dei concetti trattati in questa sede necessitano, infatti, di conoscenze sul campo delle JavaCard.
 

JavaCard Galactic 1.0
In questa seconda parte dell’articolo tratteremo inizialmente il sistema operativo della JavaCard GalactIC 1.0. I compiti del sistema operativo implementato su questa JavaCard sono fondamentalmente quelli di fornire supporto al JCRE e di fornire tutte le istruzioni necessarie alla configurazione della carta stessa.

 Il sistema operativo implementato sulle JavaCard GalactIC permette la comunicazione della carta con il lettore tramite un opportuno protocollo e fornisce una serie d’istruzioni per la configurazione di servizio della carta. Notare che buona parte del sistema operativo è implementata da una JavaCard Applet particolare, detta Basic Card Domain (dominio della carta). Questa JavaCard Applet è la prima ad essere caricata sulla carta (tramite apposite istruzioni) ed è quella che fornisce tutti i comandi riportati in questo paragrafo. Esistono delle procedure apposite per intervenire sul dominio di una carta, che permettono, per esempio, la sostituzione dello stesso con un nuovo dominio. Queste informazioni sono purtroppo mantenute riservate da De La Rue, poiché l’opportunità di intervenire sulla carta a questo livello permetterebbe in maniera molto semplice la clonazione delle carte e quindi dell’utilizzo non autorizzato delle tecnologie sviluppate dall’azienda.

 Di seguito sono riportate informazioni sulle istruzioni, definite di sistema operativo, accessibili dagli sviluppatori. Queste istruzioni sono utilizzabili tramite appositi comandi APDU. I dettagli sulla sintassi di questi comandi e sulle risposte restituite dalla carta sono reperibili nel manuale del sistema operativo del kit GalactIC ver. 1.0 di De La Rue. In questo paragrafo si privilegiano invece le informazioni relative alle scelte seguite a livello concettuale dai progettisti del sistema operativo.

Ecco l’elenco delle istruzioni di sistema operativo accessibili dal programmatore su JavaCard GalactIC ver. 1.0 tramite comandi APDU:
 

  • ERASE ALL APPLETS: questo comando permette di cancellare tutte le JavaCard Applet caricate sulla carta, escluso il dominio della carta;
  • GET RESPONSE: questo comando permette il reperimento dei dati restituiti dalla carta quando il comando APDU che li ha richiesti è un qualsiasi comando di tipo 4 o un comando di tipo 2 con un’errata indicazione della lunghezza della risposta attesa;
  • SELECT: questo comando permette di selezionare la JavaCard Applet da rendere attiva. Se la JavaCard Applet specificata non esiste sulla carta, l’APDU corrispondente è inviato alla JavaCard Applet correntemente attiva;
  • GET DATA: questo comando permette di ottenere dalla carta le informazioni impostate dal costruttore, quali per esempio il tipo di chip e le informazioni sul contenuto della ROM;
  • INITIALIZE UPDATE: questo comando permette l’inizializzazione di una sessione di comunicazione con l’entità esterna, per permettere il caricamento di JavaCard Applet sulla carta. Questo comando si fonda sull’autenticazione della carta nei confronti dell’entità esterna e genera le chiavi MAC (per la firma delle JavaCard Applet in ingresso sulla carta) ed ENC (per la cifratura delle JavaCard Applet in ingresso sulla carta), da usare per la sessione corrente. Notare che, come sarà spiegato più avanti, le chiavi di sessione sono generate indipendentemente dall’entità esterna e dalla JavaCard durante lo scambio di dati che avviene durante l’esecuzione di questo comando. In questo modo l’entità esterna può caricare JavaCard Applet sulla carta firmandoli con la chiave MAC e cifrandoli con la chiave ENC e la JavaCard è in grado di verificare se l’entità esterna è autorizzata verificando la cifratura e la firma.


Particolarmente interessante è il metodo con cui l’entità esterna e la JavaCard creano le chiavi di sessione MAC ed ENC, senza scambiarle esplicitamente ed in maniera tale da permettere l’autorizzazione all’entità esterna all’installazione di nuove JavaCard Applet. Questa è la procedura seguita:
 

  1. L’entità esterna genera un numero casuale e lo invia alla carta tramite il comando APDU stesso;
  2. La JavaCard genera un numero casuale al suo interno, lo congiunge con quello ricevuto dall’entità esterna e, tramite questo numero e le sue chiavi MAC ed ENC private (mantenute all’interno della carta), genera le chiavi di MAC ed ENC di sessione;
  3. La JavaCard restituisce come risposta il numero casuale ricevuto dall’entità esterna cifrato secondo la chiave MAC di sessione e il numero casuale precedentemente generato al suo interno;
  4. L’entità esterna, una volta ricevuto il crittogramma ed il numero casuale generato all’interno della carta, provvede al calcolo delle chiavi di sessione MAC ed ENC (per questo deve conoscere le chiavi private MAC ed ENC contenute all’interno della carta) e all’autenticazione della carta (tramite verifica del crittogramma ricevuto, ottenuto dal numero casuale inviato precedentemente dall’entità esterna cifrato secondo la chiave MAC di sessione).


Tutte le operazioni di cifratura e di firma sono realizzate tramite l’algoritmo triple DES. I crittogrammi hanno lunghezza pari a 64 bit, le chiavi MAC ed ENC di sessione hanno lunghezza pari a 64 bit, le chiavi MAC ed ENC private (contenute all’interno della carta) hanno invece lunghezza pari a 128 bit.

Il procedimento seguito dalla JavaCard e dall’entità esterna, per il calcolo delle chiavi MAC ed ENC di sessione, può essere schematizzato come mostrato in figura 1.

XXX_figura1_XXX
Figura 1 – Calcolo delle chiavi di sessione.

  • EXTERNAL AUTHENTICATE: questo comando permette l’autenticazione dell’entità esterna che sta operando sulla carta. Questa autenticazione ha validità limitata alla durata della sessione. L’autenticazione ha successo solamente se la carta riconosce il crittogramma ricevuto dall’entità esterna come la cifratura tramite la chiave MAC di sessione del numero casuale generato e restituito dalla carta durante l’esecuzione del comando INITIALIZE UPDATE di inizio sessione. Una volta che l’entità esterna si è verificata, questa ha accesso ai comandi di caricamento delle JavaCard Applet tramite comandi senza cifratura e firma dei dati. Tramite l’autenticazione esterna, l’entità esterna acquisisce inoltre la capacità di modificare le chiavi interne alla JavaCard (ENC o MAC) e la capacità di attivare la JavaCard (cioè permetterne il funzionamento);
  • INSTALL: questo comando permette di caricare una JavaCard Applet sulla carta, ed è eseguibile solo se preceduto da un comando di INITIALIZE UPDATE. Se l’entità esterna non si è autenticata tramite un comando di EXTERNAL AUTHENTICATE, il comando APDU deve necessariamente prevedere la firma dei dati tramite la chiave MAC di sessione e la cifratura dei dati tramite la chiave ENC di sessione. In caso contrario, i dati possono essere inviati direttamente in chiaro;
  • LOAD APPLET: questo comando permette il trasferimento di un blocco di una JavaCard Applet, ed è eseguibile solo se preceduto da un comando di INITIALIZE UPDATE. I dati sono sempre inviati in chiaro;
  • PUT KEY: questo comando permette la sostituzione di una delle chiavi private (ENC o MAC) contenute all’interno della carta, ed è eseguibile solo se preceduto da un comando di EXTERNAL AUTHENTICATE. La chiave da sostituire è sempre inviata cifrata tramite la chiave ENC di sessione;
  • SET STATUS: questo comando permette l’attivazione della JavaCard, cioè gli permette di processare APDU tramite le JavaCard Applet in essa caricate. Questo comando può essere eseguito solo se preceduto da un comando di EXTERNAL AUTHENTICATE.


Per ulteriori informazioni si consulti [Dlr98b].

 Terminata l’analisi del sistema operativo della JavaCard GalactIC 1.0, conviene analizzare brevemente alcune caratteristiche avanzate sui comandi APDU adottati da questo dispositivo. Le JavaCard GalactIC ver. 1.0 utilizzano, infatti, una formattazione dei comandi APDU leggermente differente da quella definita dalle norme ISO 7816 parte 4. Inoltre, questa parte dell’articolo risulta molto utile per capire come reperire i risultati dalle JavaCard.

La formattazione richiesta ai comandi APDU, sia per quanto riguarda la loro creazione all’esterno per l’invio alla JavaCard, sia per quanto riguarda la loro disponibilità a livello di JavaCard Applet, differisce da quella definita dalle norme ISO 7816 parte 4 per questi dettagli:
 

  • I comandi APDU di tipo 1, costituiti dal solo header di 4 byte, non sono accettati. Questi devono essere modificati aggiungendo in coda un’ulteriore byte di valore nullo (0x00), come mostrato in figura 2.



Figura  2 – GalactIC APDU di tipo 1

  • I comandi APDU di tipo 4, costituiti da un header di 4 byte, un byte che specifica la lunghezza dei dati, i byte costituenti la parte dati e un byte finale che specifica la lunghezza della risposta attesa, non sono accettati. Questi devono essere modificati eliminando l’ultimo byte in coda, come mostrato in figura 3.



fig. 3 – GalactIC APDU di tipo 4

I rimanenti comandi APDU (di tipo 2 e di tipo 3), così come la risposta restituita, rispettano invece le specifiche delle norme ISO 7816 parte 4.

Queste JavaCard necessitano anche della gestione esplicita, da parte dello sviluppatore, del recupero dall’esterno dei dati di risposta risultato di comandi APDU di tipo 2 e di tipo 4. 

La necessità di reperire esplicitamente i dati di risposta per i comandi APDU di tipo 2 inviati alla carta si presenta quando la lunghezza della risposta attesa (indicata nel comando APDU e denominata Le) non è uguale alle lunghezza della risposta effettiva restituita dalla JavaCard correntemente selezionata. Questo può avvenire fondamentalmente per due motivi: la lunghezza della risposta attesa è sconosciuta (per cui nell’APDU di tipo 2 si utilizza una lunghezza Le uguale a zero, cioè lunghezza indefinita), oppure la lunghezza indicata Le è errata (per qualche motivo la JavaCard Applet correntemente selezionata risponde con una lunghezza diversa da quella attesa). In questa situazione, il sistema operativo della carta risponde con uno stato che indica quale situazione si è verificata e la lunghezza esatta della risposta, lasciando al programmatore il compito di reperire il risultato. Di seguito sono riportate le possibili risposte che sono fornite dal sistema operativo:
 

  • Se la lunghezza dei dati di risposta attesi specificata nel comando APDU è minore della lunghezza dei dati di risposta restituiti effettivamente dalla JavaCard Applet, il sistema operativo della carta restituisce all’esterno uno stato di errore 0x6CLL esadecimale (wrong length con indicazione, 0xLL, della lunghezza corretta);
  • Se la lunghezza dei dati di risposta attesi specificata nel comando APDU è maggiore della lunghezza dei dati di risposta effettivamente restituiti dalla JavaCard Applet, il sistema operativo della carta restituisce all’esterno uno stato di errore 0x61LL esadecimale (correct execution con indicazione, 0xLL, della lunghezza corretta);


Naturalmente, se la lunghezza dei dati di risposta attesi specificata nel comando APDU è uguale alla lunghezza dei dati di risposta restituiti effettivamente dalla JavaCard Applet, il sistema operativo della carta restituisce immediatamente all’esterno i dati di risposta e lo stato di corretta esecuzione 0x9000 esadecimale.

Il procedimento da seguire per reperire i dati di risposta nel caso in cui sia stato restituito all’esterno uno degli stati 0x61LL esadecimale o 0x6CLL esadecimale differisce in funzione dello stato ritornato:
 

  • Se è restituito uno stato 0x61LL, dove 0xLL indica la lunghezza effettiva in esadecimale della risposta, è necessario utilizzare un comando di GET RESPONSE con specificata la lunghezza esatta. Questo comando è il comando APDU di sistema operativo rappresentato in figura 4.



Figura 4 – Comando APDU GET RESPONSE

  • Se è restituito uno stato 0x6CLL, dove 0xLL indica la lunghezza effettiva in esadecimale della risposta, è necessario ripetere l’invio del comando APDU con specificata la lunghezza esatta. In altre parole è necessario sostituire la lunghezza errata specificata con quella corretta restituita nello stato.


 Per quanto riguarda invece i comandi APDU di tipo 4, il sistema operativo della JavaCard restituisce all’esterno sempre lo stato 0x61LL. Di conseguenza, per ricevere i dati di risposta, è sempre necessario utilizzare un comando di GET RESPONSE con specificata la lunghezza effettiva della risposta ottenibile dallo stato, in maniera del tutto analoga a quanto detto precedentemente per i comandi APDU di tipo 2 con lunghezza della risposta attesa superiore alla lunghezza effettiva della risposta fornita dalla JavaCard.

Di seguito è infine trattata l’API che permette di gestire la JavaCard GalactIC 1.0 dal PC a cui questa è collegata. Questa è particolarmente importante poiché è l’unica interfaccia disponibile allo sviluppatore di applicazioni basate su JavaCard per accedere al dispositivo. 

Per permettere la comunicazione di applicazioni o applet scritte in Java con il CAD, e quindi con la JavaCard GalactIC, è messa a disposizione dei programmatori una classe contenente un insieme di metodi appositi. Questa classe, contenuta nel file Reader.class, è distribuita assieme al software fornito con il kit di sviluppo.

In realtà, nel CD contenente il software del kit GalactIC ver. 1.0, sono contenute due classi ottimizzate rispettivamente per gli ambienti di sviluppo visuali Microsoft e Symantec, mentre la classe utilizzabile con il JDK 1.2 di JavaSoft (SUN) deve essere richiesta al supporto tecnico di De La Rue.

Notare inoltre che la classe Reader.class è in realtà l’interfaccia verso due DLL di sistema che implementano la comunicazione con il lettore: nel caso di installazione di una nuova versione della Reader.class è necessario quindi provvedere manualmente alla copia delle DLL fornite insieme alla classe nella directory di sistema di Windows per permettere un corretto funzionamento della classe.

 I metodi contenuti nella classe permettono di gestire la connessione con il lettore, di accendere o spegnere il lettore (e quindi la carta eventualmente contenuta) e di controllare la comunicazione. Di seguito è riportato l’elenco di questi metodi corredati da una breve descrizione. Per ulteriori informazioni si rimanda alla documentazione fornita da De La Rue.
 

  • boolean open(String connectionName)

  • uesto metodo permette di aprire una connessione logica con il lettore. Deve essere specificato come parametro il nome logico di una connessione (costituito, generalmente, da due lettere seguite da due cifre). Il nome logico di una connessione può essere impostato dal pannello di controllo di Windows durante la configurazione del lettore;
     
  • boolean isCardPresent()

  • questo metodo permette di verificare la presenza di una carta pronta a ricevere comandi all’interno del lettore. L’effettiva presenza di una carta pronta a ricevere comandi deve comunque essere verificata chiamando, subito dopo questo metodo, il metodo numberOfBytesRead(): se viene restituito 0 allora nessuna carta è presente o pronta a ricevere comandi, se viene restituito 1 allora è presente una carta in grado di ricevere comandi;
  • boolean powerOn(byte[] abAtr, int iAtr)

  • questo metodo permette di accendere il lettore, cioè di alimentare la carta. Questo metodo restituisce i byte di Answer To Reset, cioè di risposta al reset della carta che avviene durante la salita dell’alimentazione, nel byte array abAtr passato per parametro. Notare che il parametro iAtr viene utilizzato esclusivamente per indicare la lunghezza del byte array passato per parametro, l’informazione sul numero di byte restituiti nel byte array deve essere ottenuta eseguendo il metodo numberOfBytesRead();
     
  • boolean setGlobalTimeout(int iTimeout)

  • questo metodo permette di impostare, tramite il parametro iTimeout, il numero di secondi relativi al timeout del metodo transmit(byte[], int, byte[], int), cioè il numero di secondi da attendere, dopo la trasmissione di un comando, prima di lanciare un errore di mancata risposta da parte della carta;
     
  • boolean transmit(byte[] abSend, int iSend, byte[] abReceive, int iReceive)

  • questo metodo permette di inviare un comando APDU alla carta e di ricevere la risposta (eventuali dati di ritorno e stato di ritorno). I primi due parametri (abSend e iSend) specificano rispettivamente il byte array contenente il comando APDU da inviare alla carta e la lunghezza di questo comando. I successivi due parametri (abReceive e iReceive) specificano il byte array in cui memorizzare la risposta restituita dalla carta e la lunghezza di questo byte array. Notare che il parametro iReceive viene utilizzato esclusivamente per indicare la lunghezza del byte array abReceive passato per parametro, l’informazione sul numero di byte restituiti nel byte array deve essere ottenuta eseguendo il metodo numberOfBytesRead();
     
  • boolean powerOff()

  • questo metodo permette di spegnere il lettore, cioè di togliere alimentazione alla carta;
     
  • boolean close( )

  • questo metodo permette di chiudere una connessione logica precedentemente aperta tramite il metodo open(String).


Come si può facilmente notare, tutti i metodi descritti finora restituiscono un valore booleano. Il significato di questo valore è il seguente: se viene restituito true significa che l’esecuzione del metodo è andata a buon fine, mentre se viene restituito false significa che il metodo non è stato eseguito correttamente. In quest’ultimo caso, viene messo a disposizione del programmatore un metodo apposito che permette di ricavare lo stato di errore che si è presentato:

- int lastErrorCode( ): questo metodo permette di ricavare lo stato di errore che si è presentato nell’esecuzione dell’ultimo metodo che ha restituito un valore booleano false. Per l’interpretazione dello stato di errore, di lunghezza pari ad un byte, consultare [Dlr98c].

Vale la pena sottolineare, per evitare eventuali fraintendimenti, che nell’uso del metodo transmit(byte[], int, byte[], int) la restituzione di uno stato di errore da parte della carta non genera la restituzione di un errore da parte del metodo. Questa situazione equivale, infatti, ad una corretta esecuzione del metodo con restituzione da parte della carta dello stato di errore nel byte array contenente i dati di risposta.

 L’ultimo metodo messo a disposizione dalla classe è quello che permette di ricavare il numero di byte letti durante l’esecuzione di uno dei metodi che attendono la restituzione di risultati (powerOn(byte[], int) e transmit(byte[], int, byte[], int). Questo metodo è il seguente:

- int numberOfBytesRead( ): questo metodo permette di ricavare il numero di byte letti dalla carta dall’ultimo metodo eseguito. Notare che, come già detto precedentemente, viene anche utilizzato di seguito al metodo isCardPresent( ) per verificare la presenza all’interno del lettore di una carta in grado di accettare comandi.

 Per ulteriori informazioni sulla classe Reader si rimanda a [Dlr98a].
 
 
 

Conclusioni
La JavaCard GalactIC 1.0, come già detto nella prima parte dell’articolo, è sicuramente un dispositivo che rappresenta piuttosto bene l’insieme della JavaCard disponibili fino alla fine dell’anno scorso, e continua a rappresentare un buon metro di paragone per le JavaCard dell’ultima generazione attualmente disponibili.

In questa seconda parte dell’articolo, leggermente più avanzata della precedente, si sono toccati argomenti che permettono di capire meglio il funzionamento di una JavaCard. Tali argomenti, se correttamente interpretati, permettono di apprendere alcune nozioni spesso ignorate nelle trattazioni teoriche, che portano sovente a notevoli risparmi di tempo in fase di progettazione e realizzazione di applicazioni basate su JavaCard. Proprio per questo sono convinto che siano gli strumenti come questo quelli più adeguati ai novizi per iniziare la realizzazione di applicazioni reali.

Un ultimo appunto riguarda gli strumenti forniti con la JavaCard GalactIC 1.0. Sia gli strumenti per la gestione del dispositivo che quelli per l’interfaccia con l’applicazione esterna di controllo forniscono allo sviluppatore un’interfaccia di livello piuttosto basso. Se da un lato questo richiede un maggior sforzo in termini di progettazione, codifica e debug, dall’altro permette una notevole libertà di implementazione. Questo fa sì che dispositivi come questo siano da preferirsi in tutte quelle applicazioni delle JavaCard che escono dai canoni delle classiche applicazioni SmartCard.
 
 
 

BIBLIOGRAFIA
Le informazioni riportate in questo articolo possono essere approfondite leggendo i documenti elencati di seguito. Questa documentazione non è purtroppo disponibile in linea, poiché distribuita esclusivamente insieme al kit JavaCard GalactIC 1.0. Per ulteriori informazioni è comunque possibile consultare il sito web del produttore all’indirizzo www.delarue.com.

[Dlr98a]: De La Rue Cartes et Systèmes, “GalactIC Version 1 - Smart Card Reader Java API”, 1998, Manual references: PE 993-097 / 12NC: 4311 240 26342, www.delarue.com

[Dlr98b]: De La Rue Cartes et Systèmes, “GalactIC Version 1 – Operating System”, 1998, Manual references: PE 993-100 / 12NC: 4311 240 26352, www.delarue.com
 

[Dlr98c]: De La Rue Cartes et Systèmes, “GalactIC Version 1 – User Manual”, 1998, Manual references: PE: 993-099 / 12NCT: 4311 240 26362, www.delarue.com
 
 
 


Roberto Fabbrica, nato a Ravenna il 28 dicembre 1972, è laureato in Ingegneria Informatica alla Facoltà di Ingegneria dell’Università di Bologna dal 1999. Attualmente lavora come libero professionista, fornendo consulenze come analista programmatore in Visual Basic ed esperto SQL ad una software house bolognese e collaborando al progetto e all’implementazione di applicazioni Java web oriented presso il DEIS (Dipartimento di Elettronica, Informatica e Sistemistica) della Facoltà di Ingegneria dell’Università di Bologna, sede di Cesena.
 


Si informa  che la società De La Rue Card Systems è stata acquisita dal Gruppo Charles Froncoise Oberthur lo scorso Ottobre assumendo il nuovo nome di OBERTHUR CARD SYSTEMS. A seguito di tale acquisizione tutti i prodotti smart card di De La Rue sono stati integrati nella gamma smart card di Oberthur mantendo per entrambi i nomi commerciali. Quindi GalactIC compare come la smart card basata su tecnologia Java di Oberthur Card Systems, la cui versione è stata aggiornata recentemente a 2.1. 
Per ulteriori informazioni si invita alla consultazione del sito web http://www.oberthurcs.com/.
 
Chi volesse mettersi in contatto con la redazione può farlo scrivendo a mokainfo@mokabyte.it