L’interfaccia smartcard con STM32

Una libreria sviluppata da STmicroelectronics che semplifica l’uso delle smartcard ISO 7816 con i microcontrollori della famiglia STM32.

Lo sviluppo del firmware di un apparato host in grado di utilizzare una smartcard richiede di soddisfare diversi standard d’interfaccia al livello fisico ed al livello di collegamento dati. Avvalendoci della libreria smartcard sviluppata da STMicroelectronics, possiamo trascurare i dettagli dei protocolli di comunicazione di basso livello focalizzandoci  sull’applicazione. Inoltre, l’uso del modulo USART della MCU STM32 in una particolare modalità smartcard, semplifica ulteriomente sia il firmware che la realizzazione dell’hardware d’interfaccia. Esula dallo scopo di questo articolo la trattazione della programmazione lato device, cioè di applicazioni che girano sulla smartcard. A questo proposito, esistono diversi framework per lo sviluppo, tra cui javacard sviluppato da Sun che permette di realizzare applicazioni indipendenti dalla particolare implementazione della smartcard.

L’interfaccia smartcard degli  STM32

La famiglia STM32 è l’ultima nata delle famiglie di microcontrollori di ST Microelectronics. All’epoca della sua uscita (metà 2007) ha rappresentato una delle prime implementazioni del nuovo core ARM Cortex-M3 in una MCU. Questo core a 32 bit RISC è stato progettato in funzione del mercato dei sistemi embedded (ST è stata partner nella progettazione) ed è caratterizzato dall’uso di un set d’istruzioni, denominato Thumb-2, che permette un utilizzo particolarmente efficiente della memoria programma. Con questo set d’istruzioni è infatti possibile combinare istruzioni a 16 e 32 bit nel codice in maniera trasparente, permettendo così di aumentare sia la densità che la velocità di esecuzione dello stesso. La velocità di clock massima della MCU è di 72 MHz e l’architettura Harvard con pipeline a 3 stadi della CPU permette di ottenere un throughput massimo di 1.25 DMIPS/MHz. La gestione degli interrupt, è particolarmente curata ed ottimizzata in funzione dell’uso di un RTOS, con bassi tempi di latenza (minimo 6 cicli). La memoria programma di tipo Flash ha una dimensione massima di 512 KB mentre la memoria RAM arriva a 64 KB. Vasta la dotazione di periferiche: oltre alle solite USART, I2C, SPI, PWM, troviamo su alcuni modelli un’interfaccia SDIO per schede SD/MMC, inoltre, un’interfaccia I2S (audio digitale) ed un modulo USB device.

L’interfaccia smartcard

L’interfaccia USART degli STM32 è particolare in quanto è in grado di gestire in hardware la comunicazione con una smartcard. Il protocollo di comunicazione asincrono usato dalle smartcard è definito dallo standard ISO 7816-3 e richiede  il seguente settaggio dell’USART:

➤ 8 bit di dati;

➤ 1 bit di parità;

➤ 0.5 o 1.5 bit di stop.

Un’ulteriore particolarità è data dal fatto che viene utilizzato il  solo terminale USART_TX per l’I/O, che risulta quindi di tipo half duplex, mentre il  terminale USART_CK fornisce il clock alla smartcard. Il  segnale di clock è usato dalla smartcard sia per derivare (con opportuni calcoli che vedremo)  il baud rate della comunicazione seriale, sia come clock della CPU integrata nella stessa, se presente. La connessione alla smartcard può avvenire tramite un circuito d’interfaccia come l’ST8024 che si occupa di fornire  i segnali di controllo nonchè di protezione per l’alimentazione della card. Nella tabella 1 sono riportati i pin utilizzati dalla MCU e dalla smartcard.

Tabella 1: connessioni tra STM32 e smartcard

Tabella 1: connessioni tra STM32 e smartcard

Per il  corretto settaggio dei pin della MCU, si può fare riferimento al codice della libreria smartcard. è anche possibile utilizzare una scheda di sviluppo già configurata per l’uso di una smartcard. Un esempio è la scheda STM3210B-EVAL prodotta da ST, che comprende il circuito d’interfaccia ST8024. La libreria Smartcard è stata sviluppata proprio con questa scheda.

Lo standard smartcard ISO 7816

Lo standard ISO 7816 definisce le specifiche per l’utilizzo delle smartcard cosiddette “con contatti”, come ad esempio le card GSM dei telefoni cellulari. Le parti principali dello standard sono:

Part 1: caratteristiche fisiche;

Part 2: disposizione dei contatti;

Part 3: segnali elettrici e protocolli di trasmissione;

■  Part 3 Amendment 2: revisione del PTS (Protocol Type Selection);

Part 4: comandi per l’interscambio dei dati e la sicurezza;

Part 5: registrazione degli application providers - convenzioni sui nomi.

Nel seguito vedremo in particolare gli standard 7816-3 e 7816-4.

ISO  7816-3: segnali  elettrici e protocolli di trasmissione

Lo standard ISO 7816-3 definisce  il protocollo di comunicazione tra il master (il reader, nel nostro caso il sistema  STM32) e lo slave (la smartcard). La comunicazione è iniziata dal reader cui segue il responso da parte della smartcard. Per inizializzare la comunicazione è necessario eseguire in una prima fase la cosiddetta procedura di reset: normalmente infatti la smartcard non è connessa stabilmente con il reader e risulta quindi indispensabile usare delle opportune precauzioni hardware e software per portare la card in uno stato consistente.  I sistemi hardware sono rappresentati da un interruttore incorporato nel connettore d’inserzione della card e dal circuito d’interfaccia del reader: una volta che la card è inserita correttamente è alimentata e viene iniziata dal reader la sequenza di reset vera e propria. All’inter no della procedura di reset la smartcard segnala al reader la propria inizializzazione mediante l’invio della sequenza ATR (Answer To Reset). Questa sequenza è costituita da un numero variabile di caratteri (da 2 a 33). Nel caso più comune, come nell’esempio d’applicazione che vedremo, i caratteri sono, nell’ordine, i seguenti:

➤ TS (initial character), obbligatorio: indicala convenzione di bit signaling, cioé se nelle trasmissioni successive si dovrà intendere un valore H come 1 (direct convention) o 0 (inverse convention). Inoltre nel primo caso i caratteri  si intenderanno trasmessi lsb first, al contrario nella inverse convention. TS è utilizzato anche come segnale di sincronizzazione  e per derivare il baud rate iniziale della smartcard.

➤ T0 (format character), obbligatorio: indica la presenza o meno di ulteriori caratteri di configurazione TA1, TB1, TC1, TD1 ed il numero di altri eventuali caratteri dal significato proprietario (denominati historical characters).

➤ TA1, TB1, TC1, TD1 (interface  characters), opzionali: sono usati per indicare i parametri del protocollo di comunicazione. In particolare,  il carattere TA1 è usato per determinare  il baud rate della comunicazione, mentre il carattere  TD1 indica il tipo di protocollo (T)  della comunicazione stessa.

Vediamo nello specifico la codifica dei caratteri TA1 e TD1. Il baud rate della comunicazione è espresso da due tipi di formule, a seconda che la smartcard sia provvista di clock interno o esterno (fs): avremo

➤ clock interno: bit rate = (1/D)*(1/9600) s;

➤ clock esterno: bit rate = (1/D)*(F/fs) s

dove il fattore F è derivato dai 4 msb del carattere TA1 (F1), mentre  il fattore D è derivato dai 4 lsb di TA1 (D1). Il valore effettivo di F e di D è ricavato usando i valori F1 e D1 come indici di due tabelle con valori standard (si veda il codice dell’esempio).

Il bit time è definito come ETU (Elementary Time Unit): si noti che la comunicazione iniziale durante l’ATR è garantita dal fatto che di default si assegna all’ETU un valore pari a 372/f, con f compresa tra 1 e 5 MHz. In pratica si sceglie f in modo che risulti: ETU = 372/f = 1/9600, da cui una velocità di 9600 baud. I 4 lsb del carattere TD1 indicano il protocollo di comunicazione,  i valori più comuni sono:

➤ T=0: comunicazione asincrona half duplex per singoli byte;

➤ T=1: comunicazione asincrona half duplex a blocchi di byte.

ISO 7816-4: comandi per l’interscambio dei dati

Lo standard ISO 7816-4 definisce dei protocolli di livello link e dei protocolli applicativi di livello superiore. Il  protocollo di livello link T=0 (o T0) in particolare, fornisce un canale di comunicazione affidabile mediante  il controllo di parità sui singoli caratteri trasmessi. Il reader e la smartcard si scambiano delle unità di dati che a livello link sono denominate TPDU (Transmission Protocol Data Unit) mentre a livello applicativo sono dette APDU (Application Protocol Data Unit). Poiché, nel caso che ci interessa del protocollo T=0, le APDU sono sovrapponibili alle TPDU, tratteremo le sole APDU. Ciò anche perché le TPDU sono trattate in maniera automatica dalla libreria. Notiamo inoltre che il controllo di parità e l’eventuale ritrasmissione dei dati è gestita tramite funzioni della libreria. Lo standard ISO 7816-3 definisce due API di livello applicativo:

➤ File system: fornisce un insieme d’istruzioni per selezionare, leggere e scrivere file contenuti nella smartcard.

➤ Security: istruzioni che permettono un mutua identificazione tra reader e smartcard e l’eventuale crittografia dei dati scambiati. Vedremo degli esempi di istruzioni di queste API quando esporremo le caratteristiche della libreria e l’applicazione demo. Le APDU scambiate tra reader e Smartcard sono di due tipi:

Command APDU: generate dal reader come richiesta verso la smartcard;

➤ Response APDU: generate dalla smartcard come risposta.

La command APDU, rappresentata in alto nella figura 1, è costituita da un header e da un body. L’header è formato dai campi seguenti:

➤ CLA: classe applicativa che specifica un certo set di comandi;

➤ INS: un’istruzione specifica del set di comandi;

➤ P1: 1° parametro dell’istruzione;

➤ P2: 2° parametro dell’istruzione.

Il body della APDU è costituito dai campi seguenti:

➤ Lc: numero di byte del campo dati trasmesso dal reader.

➤ Data: campo dati.

➤ Le: numero massimo di byte dei dati attesi in risposta da parte della smartcard. In funzione del tipo di comando possono mancare alcuni o tutti i campi del body. La response APDU, rappresentata in basso nella figura 1, è invece costituita da un body e da un trailer.

Figura 1: campi delle command e response APDU.

Figura 1: campi delle command e response APDU.

Il body è costituito dal campo Dati da restituire al reader, mentre il trailer è formato dai seguenti campi:

➤ SW1: indica il successo dell’operazione o la categoria dell’errore;

➤ SW2 (opzionale): codice d’errore/successo specifico per ogni istruzione.

Il  campo body manca se la Smartcard non deve restituire dei dati al reader. Nella tabella 2 sono riportati i valori del campo INS per le API File system e Security.

Tabella 2: istruzioni delle API File System e Security

Tabella 2: istruzioni delle API File System e Security

Vediamo un esempio di selezione del file root del file system di una smartcard, la command APDU avrà i valori seguenti:

CLA: set proprietario = 0xA0

INS: Select File = 0xA4

PW1 = 0x00

PW2 = 0x00

Lc = 0x02

Data: identificativo file = 0x3F00

Le = 0x00

La response APDU, in caso di successo avrà i campi seguenti

Data: -

SW1: successo = 0x90

SW2: nessuna info aggiuntiva = 0x00

La libreria ST per smartcard

La libreria Smartcard sviluppata da ST è costituita dai file smartcard.h e smartcard.c. Nella libreria sono contenute le definizioni delle costanti e dei tipi utilizzati dalle Smartcard, le funzioni che si occupano di gestire  il livello link ed applicativo oltre al livello fisico. Il livello fisico si avvale dell’interfaccia USART dell’STM32 configurata in modalità smartcard. È utilizzato  il solo protocollo T=0 per il livello link, mentre per il  livello fisico è gestita solo la direct convention (bit H=1, lsb first). Le funzioni pubbliche della libreria sono le seguenti:

➤ SC_Handler;

➤ SC_PTSConfig;

➤ SC_PowerCmd;

➤ SC_Reset;

➤ SC_ParityErrorHandler.

Vediamo le caratteristiche di queste funzioni.

SC_Handler

La funzione SC_Handler è la più complessa da usare ed è quella che ci permette di inviare una command APDU alla Smartcard e di ricevere in risposta un response APDU. Oltre a ciò gestisce anche gli stati della Smartcard, perciò è usata ad esempio nella fase di inizializzazione della stessa (sequenza ATR). Il prototipo di questa funzione è il seguente:

void SC_Handler(SC_State *SCState,
 SC_ADPU_Commands *SC_ADPU, SC_AD-
 PU_Responce *SC_Response)

Il parametro  SCState è un puntatore ad un enum che contiene gli stati in cui si può trovare la Smartcard:

typedef enum {
 SC_POWER_ON = 0x00,
 SC_RESET_LOW = 0x01,
 SC_RESET_HIGH = 0x02,
 SC_ACTIVE = 0x03,
 SC_ACTIVE_ON_T0 = 0x04,
 SC_POWER_OFF = 0x05
 } SC_State;

la funzione SC_Handler infatti implementa una macchina a stati per gestire le varie fasi dell’attivazione e della comunicazione tra reader e smartcard. Il parametro SC_APDU è un puntatore ad una struttura che contiene i parametri  del comando:

typedef struct {
 SC_Header Header;
 SC_Body Body;
 } SC_ADPU_Commands;

Il campo Header è a sua volta una struttura così definita:

typedef struct {
 u8 CLA;  /* Command class */
 u8 INS;  /* Operation code */
 u8 P1; /* Selection Mode */
 u8 P2;  /* Selection Option */
 } SC_Header;

il significato  dei cui campi è stato trattato nel paragrafo dedicato alle command APDU.  Il campo Body conterrà i dati della APDU

typedef struct {
 u8 LC;  /* Data field length */
 u8 Data[LCmax]; /* Command parameters *
 u8 LE;   /* Expected length of data to be returned */
 } SC_Body;

anche in questo caso facciamo riferimento al paragrafo dedicato alle command APDU per il significato  dei campi. Il terzo parametro della funzione SC_Handler, SC_Response, è un puntatore ad una struttura definita come:

typedef struct {
 u8 Data[LCmax];  /* Data returned from the card */
 u8 SW1;  /* Command Processing status */
 u8 SW2;  /* Command Processing qualification */
 } SC_ADPU_Responce;

i cui campi sono quelli che abbiamo visto nella descrizione della response APDU.

SC_PTSConfig

La funzione SC_PTSConfig è usata per eseguire la procedura PTS (Protocol Type Selection) per selezionare  il baud rate della comunicazione tra reader e smartcard e selezionare  il protocollo di link (nel nostro caso sempre T=0). Il  prototipo della funzione è il seguente: void SC_PTSConfig(void)
Questa funzione va richiamata subito dopo l’esecuzione della sequenza ATR: ne vedremo un esempio d’uso nel programma demo.

SC_PowerCmd

La funzione SC_PowerCmd è usata per comandare l’alimentazione della Smartcard. L’esecuzione di questa funzione cambia lo stato del pin CMDVCC dell’STM32. Il prototipo è:

void SC_PowerCmd
 (FunctionalState NewState);

Il parametro  NewState  può assumere  il valore ENABLE per alimentare la card, DISABLE per disattivarla.

SC_Reset

Il prototipo della funzione è:

void SC_Reset
 (BitAction ResetState);

Questa funzione è usata per attivare il pin RST della Smartcard (ResetState = Bit_SET) o per disattivarlo (ResetState = Bit_RESET).

SC_ParityErrorHandler

Il prototipo della funzione è il seguente: void SC_ParityErrorHandler(void);
Questa funzione è usata per reinviare un byte non ricevuto correttamente dalla smartcard. Il controllo di parità eseguito su ogni carattere determina infatti un comportamento diverso a seconda che il carattere sia inviato dal reader o dalla smartcard. Nel caso in cui la smartcard rilevi un errore di parità sul carattere inviato dal reader, porrà bassa la linea di I/O durante il bit di stop: questo evento viene intercettato via hardware causando l’attivazione di una routine di interrupt all’interno della quale sarà richiamata la funzione SC_ParityErrorHandler() in modo da ritrasmettere l’ultimo carattere (è contenuto in una variabile globale).

L’applicazione demo

La libreria smartcard comprende una demo che dimostra l’uso delle funzioni della stessa. Nella directory Smartcard_AN\projects sono presenti tre progetti per poter compilare  il codice con diversi ambienti di sviluppo

➤ EWARM di IAR (www.iar.com);

➤ RIDE di Raisonance (www.raisonance.com);

➤ RVMDK di Keil (www.keil.com).

In figura 2 possiamo vedere il progetto caricato nell’IDE di Raisonance L’applicazione demo esegue alcune operazioni sul file system di una card GSM. Ogni card GSM contiene nel suo file system, secondo lo standard ETSI GSM 11.11, almeno i file seguenti:

Master Root, radice del file system: identificativo 0X3F00;

GSMDir, directory: identificativo 0x7F20;

Telecom, directory: identificativo 0x7F10;

ICCID, numero di identificazione della card, nella directory Master: identificativo 0x2FE2, lunghezza 10 Byte;

IMSI (International Mobile Subscriber Identity), nella directory GSMDir: identificativo 0x6F07, lunghezza 9 Byte. Questo file ha un accesso sicuro che richiede l’uso del PIN1 (o CHV1).

Una breve spiegazione sul file system di una smartcard: è una struttura gerarchica costituita da tre categorie di file:

Master File (MF): radice del file system;

Dedicated File (DF): è l’equivalente di una directory;

Elementary  File (EF): è un file di dati.

Gli EF a loro volta sono suddivise in due categorie:

Transparent: file non strutturati (binari);

Record-oriented: file organizzati in record, di lunghezza fissa o variabile.

Figura 2: il progetto della demo in Raisonance RIDE.

Figura 2: il progetto della demo in Raisonance RIDE.

La file system API delle Smartcard  definisce un insieme di operazioni sui file: selezione, lettura, scrittura, ecc. Ogni file è identificato da un identificativo esadecimale, che nel caso di alcuni file è definito dagli standard. Il Master File ad esempio ha sempre l’identificativo 0x3F00. È anche possibile identificare i file tramite una stringa: lo standard ISO 7816-5 si occupa delle regole di denominazione dei file. Vediamo quali sono le operazioni principali eseguite nella demo. Non appena la card viene inserita nell’apposito connettore, l’MCU esegue la sequenza ATR:

 

SCState = SC_POWER_ON;
 SC_ADPU.Header.CLA = 0x00;
 SC_ADPU.Header.INS = SC_GET_A2R;
 SC_ADPU.Header.P1 = 0x00;
 SC_ADPU.Header.P2 = 0x00; SC_ADPU.Body.LC = 0x00;
 while(SCState != SC_ACTIVE_ON_T0)
 {

SC_Handler(&SCState, &SC_ADPU,
 &SC_Responce);
 }

Quando la funzione SC_Handler ritorna
SCState = SC_ACTIVE_ON_T0
significa che la procedura ATR è andata a buon fine e la Smartcard è pronta a ricevere comandi tramite il protocollo T=0. Successivamente viene eseguita la procedura PTS per selezionare  il baud rate della comunicazione  (il protocollo è solo T=0):
SC_PTSConfig();
Questa funzione invia alla smartcard dei caratteri di configurazione, in particolare il carattere denominato PTS1 è pari al carattere TA1 ricevuto dalla Smartcard durante la sequenza ATR, nell’esempio: PTS1 = 0x95 da cui F1=9-> F=512, dalla tabella F_Table[ ] e D1=5-> D=16, dalla tabella D_Table[ ] (in smartcard.c – si veda la figura 2). Utilizzando l’Eq.1 otteniamo allora: baud rate = (1/D)*(F/fs) = (1/16)*(512/3600000) = 112500 baud essendo nel caso della demo fs = 3.6 MHz. La lettura del file ICCID contenuto nella Master root, avviene come segue:
1) si seleziona la Master root inviando una command APDU del tipo Select File

 

SC_ADPU.Header.CLA = SC_CLA_GSM11;
 SC_ADPU.Header.INS = SC_SELECT_FILE;
 SC_ADPU.Header.P1 = 0x00; SC_ADPU.Header.P2 = 0x00;
 SC_ADPU.Body.LC = 0x02;

SC_ADPU.Body.Data[0] = 0x3F; //ID MF
 SC_ADPU.Body.Data[1] = 0x00; while(i < LCmax) {
 SC_ADPU.Body.Data[i++] = 0;
 }
 SC_ADPU.Body.LE = 0;
 // esegue la command APDU
 SC_Handler(&SCState, &SC_ADPU,
 &SC_Responce);

Si noti l’uso di CLA = SC_CLA_GSM11 per selezionare  il set di istruzioni riconosciuto dalla card GSM.
2) Si seleziona  il file ICCID inviando una APDU del tipo Select File

 

SC_ADPU.Header.CLA = SC_CLA_GSM11;
 SC_ADPU.Header.INS = SC_SELECT_FILE;
 SC_ADPU.Header.P1 = 0x00;
 SC_ADPU.Header.P2 = 0x00;
 SC_ADPU.Body.LC = 0x02;
 SC_ADPU.Body.Data[0] = 0x2F;
 // ID ICCID SC_ADPU.Body.Data[1] = 0xE2;

while(i < LCmax) {
 SC_ADPU.Body.Data[i++] = 0
 }
 SC_ADPU.Body.LE = 0;
 // esegue la command APDU
 SC_Handler(&SCState, &SC_ADPU,
 &SC_Responce);

3) Il contenuto del file ICCID può ora essere letto tramite una APDU del tipo Read Binary:

SC_ADPU.Header.CLA = SC_CLA_GSM11;
 SC_ADPU.Header.INS = SC_READ_BINARY;
 SC_ADPU.Header.P1 = 0x00;
 SC_ADPU.Header.P2 = 0x00;
 SC_ADPU.Body.LC = 0x00;
 SC_ADPU.Body.LE = 10;
 // esegue la command APDU
 SC_Handler(&SCState, &SC_ADPU,
 &SC_Responce);

Si noti il campo LE = 10 pari alla lunghezza (nota) del file ICCID: il contenuto del file sarà disponibile nel campo Data della struttura SC_Responce. La lettura del contenuto del file IMSI è analoga: la differenza principale è dovuta al fatto che, poiché si tratta di un file protetto, prima della APDU Read Binary sarà necessario eseguire la verifica del CHV1 tramite una APDU del tipo Verify:

SC_ADPU.Header.CLA = SC_CLA_GSM11;
 SC_ADPU.Header.INS = SC_VERIFY;
 SC_ADPU.Header.P1 = 0x00;
 SC_ADPU.Header.P2 = 0x01;
 SC_ADPU.Body.LC = 0x08;
 // CHV1 da verificare
 for(i = 0; i < SC_ADPU.Body.LC; i++)

{

SC_ADPU.Body.Data[i] = CHV1[i];

}

while(i < LCmax) { SC_ADPU.Body.Data[i++] = 0; {

SC_ADPU.Body.LE = 0;

}

SC_ADPU.Body.LE = 0;

// esegue la command APDU

SC_Handler(&SCState, &SC_ADPU,

&SC_Responce);

 

 

 

Scrivi un commento

EOS-Academy