MokaByte Numero  39  - Marzo 2000
 
Ambiente Java Card
Informazioni avanzate
II parte
di 
Roberto Fabbrica
Prosegue il viaggio nel mondo 
embedded controllato da Java

L’ambiente JavaCard, pur fornendo tutte le funzionalità necessarie all’utilizzo di codice Java e alla gestione degli oggetti, presenta alcune importanti differenze e limitazioni rispetto agli ambienti Java per workstation, dovute principalmente alla destinazione d’uso delle SmartCard e alle ridotte risorse disponibili. La conoscenza di queste caratteristiche è necessaria, sia al progettista sia allo sviluppatore, per realizzare qualsiasi applicazione JavaCard

Introduzione
Per comprendere correttamente gli argomenti trattati in quest’articolo, è consigliabile conoscere i concetti base relativi all’ambiente JavaCard. Questi possono essere facilmente acquisiti leggendo l’articolo “JAVACARD: TECNOLOGIA JAVA PER LE SMARTCARD”, scritto dallo stesso autore di quest’articolo, e pubblicato da MokaByte nel numero 37 (gennaio 2000). E’ altresì consigliabile aver letto la prima parte dell’articolo, pubblicata da MokaByte nel numero 38 (febbraio 2000).
Nella prima parte dell’articolo, pubblicata il mese scorso, sono state trattate le limitazioni e le principali estensioni dell’ambiente JavaCard rispetto all’ambiente Java per workstation. In questa seconda parte, viene inizialmente introdotto un esempio delle estensioni dedicate alle particolari funzionalità di cui deve essere dotata una SmartCard: la gestione dei PIN (Personal Identification Number).
Viene inoltre introdotto il concetto di APDU (Application Protocol Data Unit), cioè l’unità base di comunicazione utilizzata per far interagire l’entità esterna di controllo (solitamente una workstation o un microcontrollore dedicato) con una SmartCard. Si noti che questo concetto è completamente ereditato dalle SmartCard e che è standardizzato dalla normativa ISO 7816. Saranno discusse anche le procedure da utilizzare per accedere ai comandi APDU ricevuti dalla JavaCard e quelle da utilizzare per restituire le risposte APDU all’entità esterna.
Al termine di questa seconda parte, vengono infine riportate le conclusioni relative all’intero articolo (prima e seconda parte).
 

Informazioni avanzate sul'ambiente Java Card 
In questa seconda parte dell’articolo viene, inizialmente, descritta l’implementazione dei meccanismi di gestione dei PIN, necessaria per proteggere i servizi contenuti sulla JavaCard. Più precisamente, un PIN è un codice alfanumerico utilizzato per proteggere da accessi non autorizzati i servizi caricati su una JavaCard Applet. Tale codice alfanumerico deve essere custodito dal proprietario della JavaCard e da lui mantenuto segreto. Nel caso in cui il proprietario della JavaCard Applet smarrisca il dispositivo o qualche malintenzionato se ne impossessi fraudolentemente, questo non può essere in grado di utilizzare i servizi della JavaCard, poiché non conosce il PIN necessario ad utilizzarli.
Le classi più importanti messe a disposizione dal Framework per la gestione dei PIN sono la classe astratta PIN e la classe OwnerPIN, ambedue contenute nel package javacard.framework. La prima delle due classi rappresenta la superlcasse (astratta) di tutte le classi di gestione dei PIN e non è utilizzabile direttamente. La seconda rappresenta la classe degli oggetti destinati a fornire supporto per la protezione della JavaCard da accessi da parte di entità diverse dal proprietario. Notare che il Framework fornisce un’ulteriore classe destinata alla gestione della protezione tramite PIN, la classe ProxyPIN, contenuta nello stesso package delle precedenti. Quest’ultima classe viene utilizzata per distribuire una stessa istanza della classe OwnerPIN fra più JavaCard Applet. Per ulteriori informazioni su questa classe si consulti [Snm97c].
Per essere efficaci contro gli attacchi esaustivi, i PIN della classe OwnerPIN fanno uso di un contatore che tiene traccia del numero di tentativi di accesso falliti e di un numero massimo di tentativi. Una volta superato questo numero, la JavaCard non autorizza l’accesso neanche dopo la specificazione del PIN corretto. Questo stato degli oggetti OwnerPIN è definito stato di block, l’operazione di ripristino è invece definita unblocking. E’ compito del programmatore implementare i meccanismi adatti per il recupero della piena funzionalità della JavaCard.
Il passaggio del PIN dall’applicazione esterna alla JavaCard avviene secondo le modalità preferite dallo sviluppatore. Il metodo consigliato è comunque quello di inserire il byte array contenente il PIN in testa al byte array contenente i dati del comando relativo all’operazione da proteggere. La lunghezza del PIN può quindi essere specificata fra i parametri del comando, o non specificata per niente nel caso in cui si intenda utilizzare PIN a lunghezza fissa.
Non esistendo altri dispositivi di input/output, la comunicazione fra la JavaCard e l’esterno avviene tramite opportuni segnali elettrici sull’interfaccia di comunicazione. Per la comunicazione viene utilizzato un apposito protocollo, corrispondente allo standard ISO 7816, basato sul concetto di APDU (Application Protocol Data Unit). Questo concetto è particolarmente importante in quanto gli APDU sono visibili a livello del codice Java sia dalla parte della JavaCard Applet, sia dalla parte dell’applicazione esterna di controllo. I comandi APDU inviati dall’applicazione esterna di controllo alla JavaCard Applet prendono il nome di APDU di comando. Quelli restituiti, come risposta, dalla JavaCard Applet all’applicazione esterna di controllo, prendono invece il nome di APDU di risposta. Di seguito verrà analizzata la sintassi di ambedue le tipologie.

Un APDU di comando è una sequenza di byte contenente le istruzioni inviabili dall’applicazione esterna alla JavaCard e gli eventuali dati associati a queste istruzioni. La struttura degli APDU di comando è definita dallo standard ISO 7816 parte 4. La struttura generale di un APDU di comando è quella rappresentata nella figura 1.
 
 

fig. 1 – APDU di comando

Ogni APDU di comando può essere suddiviso in due parti, un header ed una parte dati, come mostrato nelle figure 2 e 3.
 

fig. 2 – Header

 
fig. 3 – Parte dati

 

L’header è composto da quattro byte: il CLA (byte di classe), l’INS (byte di istruzione), il P1 (primo byte del parametro) ed il P2 (secondo byte del parametro). Il byte di classe codifica, secondo lo standard ISO 7816 parte 4, la classe dell’istruzione. Il byte di istruzione codifica, sempre secondo lo standard ISO 7816 parte 4, l’istruzione che la JavaCard deve eseguire. Il primo ed il secondo byte del parametro codificano invece il parametro a 16 bit relativo all’istruzione.
La parte dati degli APDU di comando serve per comunicare alla JavaCard Applet destinataria dell’istruzione eventuali dati. Questa parte dati è a lunghezza variabile e può anche non essere presente. 
Per chiarire le caratteristiche di questa parte degli APDU di comando conviene suddividere gli APDU di comando in quattro gruppi in funzione del tipo di scambio di informazioni con la JavaCard Applet:
 

  • APDU di comando di tipo 1: si tratta di APDU di comando che non inviano dati alla JavaCard e che non si aspettano dati in risposta. In questo caso la parte dati è completamente mancante, come mostrato nella figura 4.
fig. 4 – APDU di comando di tipo 1
  • APDU di comando di tipo 2: si tratta di APDU di comando che non inviano dati alla JavaCard ma che richiedono dati in risposta. In questo caso la parte dati prevede l’utilizzo del byte Le per specificare la lunghezza della risposta attesa. Notare che né il byte Lc né la parte DATA sono presenti in APDU di questo tipo, come mostrato nella figura 5.
fig. 5 – APDU di comando di tipo 2

 
 
  • APDU di comando di tipo 3: si tratta di APDU di comando che inviano dati alla JavaCard ma che non si aspettano dati in risposta. In questo caso la parte dati prevede l’utilizzo del byte Lc per contenere la lunghezza della parte dati dell’APDU di comando. La parte DATA contiene i dati di comando. Notare che nessun byte Le è presente in coda all’APDU di comando, come mostrato nella figura 6.

 
fig. 6 – APDU di comando di tipo 3

 
 
 
 
 
  • APDU di comando di tipo 4: si tratta di APDU di comando che inviano dati di comando alla JavaCard e che richiedono anche dati di risposta. In questo caso la parte dati prevede l’utilizzo del byte Lc per contenere la lunghezza della parte dati dell’APDU di comando, della parte DATA per contenere i dati di comando e del byte Le per specificare la lunghezza della risposta attesa (notare che se Le contiene il valore 0 significa che la lunghezza della risposta è indefinita, cioè la risposta può essere di lunghezza qualsiasi), come mostrato nella figura 7.

 
fig. 7 – APDU di comando di tipo 4

Notare che la classificazione degli APDU di comando, necessaria per poterne identificare correttamente il contenuto, è a carico del produttore della carta per i metodi generali e a carico del programmatore per le istruzioni indirizzate alle JavaCard Applet. Notare infine che la codifica dei byte CLA, INS, P1 e P2, nonché della parte dati, non è standardizzata. In altre parole, l’APDU di comando utilizzato per eseguire, per esempio, la cancellazione di tutte le JavaCard Applet presenti su una JavaCard di un produttore, è generalmente diverso da quello che compie la stessa azione su una JavaCard di un altro produttore. Per le informazioni relative ai dettagli degli APDU di comando utilizzabili si consiglia di consultare la documentazione relativa alla JavaCard che si intende utilizzare.
Un APDU di risposta è invece una sequenza di byte contenente gli eventuali dati di risposta e la Status Word restituita dalla JavaCard a seguito dell’invio di un APDU di comando. La struttura degli APDU di risposta ed il loro contenuto sono definiti dallo standard ISO 7816 parte 4. La struttura generale di un APDU di risposta è quella rappresentata dalla figura 8.
 
 

fig. 8 – APDU di risposta

La prima parte dell’APDU di risposta non è obbligatoria: la JavaCard può anche non restituire dati. L’ultima parte è invece presente in qualsiasi APDU di risposta e contiene la Status Word. Quest’ultima è una parola a 16 bit che informa l’entità esterna del risultato dell’esecuzione dell’ultimo APDU di comando inviato alla JavaCard. In caso di esecuzione corretta, la JavaCard restituisce una Status Word apposita per indicare questa situazione: si tratta della Status Word 9000 esadecimale. Per l’elenco ed il significato dei possibili valori delle Status Word si rimanda alla documentazione ISO 7816 parte 4 (poiché la maggior parte delle Status Word di risposta è standardizzata) e alla documentazione che accompagna la JavaCard che si intende utilizzare.
Come già accennato precedentemente, il concetto di APDU è visibile a livello di codice sia dal lato applicazione di controllo sia dal lato JavaCard Applet. Di seguito viene indicato come fare riferimento agli APDU di comando ricevuti e come restituire APDU di risposta dalla JavaCard Applet. Purtroppo, dal lato applicazione di controllo, è solitamente possibile inviare APDU di comando e interpretare APDU di risposta unicamente tramite metodi proprietari di apposite classi di interfaccia. Per capire come eseguire questo tipo di operazioni è quindi necessario consultare la documentazione fornita con il CAD che si intende utilizzare. Come si ricorderà, il metodo process( ) di una JavaCard Applet è richiamato dal JCRE ogni volta che questo riceve un APDU di comando dall’entità esterna. Tale APDU di comando è passato per parametro al metodo process( ) sotto forma di un oggetto di classe javacard.framework.APDU. Questo oggetto rappresenta il vertice di tutta l’attività di comunicazione con l’esterno, resa possibile dai metodi disponibili. Di seguito è riportato l’elenco dei metodi principali dell’oggetto APDU, utilizzabili all’interno di process( ) per implementare il funzionamento voluto della JavaCard Applet. Notare che l’ordine in cui sono riportati questi metodi rispecchia il loro utilizzo generale all’interno del metodo process( ), cioè apertura del buffer APDU, lettura dell’header e dei dati ed invio dei risultati. Naturalmente questi metodi non devono essere tutti utilizzati all’interno del metodo process( ), solo quelli necessari all’esecuzione delle operazioni che interessano vanno presi in considerazione.

  • getBuffer( ): questo metodo permette di ottenere un riferimento al buffer che contiene le informazioni relative all’APDU corrente. Questo buffer, spesso detto buffer APDU, si presenta come un array di byte da cui è possibile leggere ogni parte dell’APDU di comando e su cui è anche possibile scrivere gli eventuali dati di risposta richiesti. Questo buffer ha una lunghezza dipendente dalla piattaforma JavaCard utilizzata, la lunghezza minima garantita è in ogni caso di 37 byte;
  • setIncomingAndReceive( ): questo metodo permette di informare il JCRE che la JavaCard Applet intende leggere dati dal buffer APDU. Quando questo metodo è eseguito sono letti nel buffer quanti più dati possibili dall’APDU di comando corrente;
  • receiveBytes( ): questo metodo permette di leggere i dati contenuti all’interno del buffer APDU. E’ possibile specificare l’offset da cui iniziare la lettura tramite opportune costanti, in questo modo è possibile leggere ogni parte dell’APDU di comando (byte dell’header compresi). Può essere utilizzato anche per leggere una quantità di dati non contenibile in un unico buffer APDU;
  • setOutgoing( ): questo metodo permette di informare il JCRE che la JavaCard Applet intende restituire dati tramite il buffer APDU;
  • setOutgoingLength( ): questo metodo permette di informare il JCRE della lunghezza del messaggio da restituire (che in ogni caso deve essere inferiore alla lunghezza specificata da Le, cioè la lunghezza attesa specificata nell’APDU di comando inviato dall’entità esterna);
  • sendBytes( ): questo metodo permette di inviare, scrivendoli sul buffer APDU, dati di risposta verso il CAD. Può essere utilizzato anche quando è necessario inviare una quantità di dati non contenibile in un unico buffer APDU;
  • setOutgoingAndSend( ): questo metodo implementa in un’unica istruzione le istruzioni setOutgoing( ), setOutgoingLength( ) e sendBytes( ). Può essere utilizzato solo quando la risposta è di lunghezza inferiore alla lunghezza massima del buffer APDU;
  • wait( ): questo metodo permette di segnalare al CAD di non eseguire il timeout per l’operazione corrente. Queste serve ad evitare che operazioni temporalmente lunghe portino il CAD al timeout.

Conclusioni
Nella prima e seconda parte di questo articolo sono state descritte le caratteristiche peculiari dell’ambiente JavaCard, mantenendo il punto di vista dello sviluppatore di applicazioni Java per workstation. Questo, secondo il mio parere, è un ottimo modo per apprendere le caratteristiche avanzate dell’ambiente JavaCard. Come si è potuto notare, l’ambiente JavaCard fornisce una quantità di funzionalità estremamente potenti e flessibili, quali ad esempio la persistenza e la gestione delle transazioni. 
Purtroppo, sviluppando applicazioni reali, ci si rende immediatamente conto che esistono limiti non imputabili all’ambiente stesso, dovuti principalmente alla ridotta quantità di risorse disponibili. Se dall’analisi svolta finora appare, infatti, chiaro che non esistono limiti alla programmazione orientata agli oggetti, in pratica, dovendosi confrontare con pochi KByte di memoria non volatile e qualche centinaio di Byte di memoria volatile disponibili, ci si rende immediatamente conto dell’impossibilità di applicare completamente il paradigma della programmazione orientata agli oggetti. La strutturazione ad oggetti in ambiente Java richiede, infatti, un overhead di risorse che spesso il programmatore JavaCard non può permettersi, pena l’impossibilità di eseguire le applicazioni sviluppate a causa della mancata disponibilità di memoria. E’ per questo motivo, e non per le caratteristiche intrinseche dell’ambiente JavaCard, che spesso le JavaCard Applet vengono realizzate tramite un’unica classe, sfruttando in pratica solamente i principi della programmazione strutturata e non quelli della programmazione orientata agli oggetti. Ribadisco comunque che questo dipende dalle risorse disponibili e non dall’ambiente JavaCard: avendo a disposizione risorse sufficienti, qualunque vincolo in questo senso tende a scomparire, il che fa ben sperare per le generazioni di JavaCard che verranno in futuro.
Tenuto conto anche di quest’ultimo fattore, è possibile elencare alcune ulteriori regole che il progettista e lo sviluppatore JavaCard devono conoscere ed applicare per realizzare JavaCard Applet funzionanti:

  • Viste le ridotte disponibilità di risorse di memorizzazione e la non garanzia di presenza di un garbage collector, è consigliabile non creare nuovi oggetti secondo necessità ma creare ogni oggetto che si prevede di utilizzare in modo definitivo, mantenendo un riferimento ad esso. In questo modo è possibile utilizzare l’oggetto tante volte quanto serve. E’ anche consigliato l’utilizzo di classi static nei casi in cui queste possano fornire le funzionalità richieste;
  • Se è necessario l’utilizzo di codice che crea nuovi oggetti dinamicamente, è buona norma il contenere tutte le istruzioni di creazione all’interno di una transazione, perché una volta creato un oggetto non si può liberare la memoria che gli si è allocata (una eventuale interruzione delle operazioni durante la creazione di nuovi oggetti, ripresa in un secondo tempo, porterebbe a sprecare la memoria utilizzata dagli oggetti creati prima dell’interruzione);
  • Vista la ridotta disponibilità di memoria dedicabile al salvataggio del bytecode sulla JavaCard, si consiglia di ridurre al minimo il numero di accessi agli array, salvando in variabili locali i valori che si suppone dovranno essere utilizzati più volte. Questo permette di ottenere bytecode notevolmente più compatto, quindi di risparmiare memoria.

Bibliografia
Per approfondire i concetti trattati in questo articolo si consiglia la lettura dei seguenti documenti, tutti disponibili nel sito web di SUN dedicato a Java (www.javasoft.com):

[Snm97a]: SUN Microsystems, “Java Card 2.0 Language Subset and Virtual Machine Specification – Revision 1.0 Final”, 1997, www.javasoft.com

[Snm97b]: SUN MicroSystems, “Java Card 2.0 Programming Concepts – Revision 1.0 Final”, 1997, www.javasoft.com

[Snm97c]: SUN MicroSystems, “Java Card 2.0 Application Programming Interfaces – Revision 1.0 Final”, 1997, www.javasoft.com

[Snm98]: SUN MicroSystems, “Java Card Applet Developer’s Guide – Revision 1.12”, 1998, www.javasoft.com

Chi volesse mettersi in contatto con la redazione può farlo scrivendo a mokainfo@mokabyte.it