Progetto e sviluppo di una PKI per la firma digitale
Transcript
Progetto e sviluppo di una PKI per la firma digitale
UNIVERSITA’ POLITECNICA DELLE MARCHE Facoltà di INGEGNERIA Corso di Laurea in Ingegneria Elettronica Dipartimento di Elettronica, Intelligenza Artificiale e Telecomunicazioni PROGETTO E SVILUPPO DI UNA PKI PER LA FIRMA D IGITALE BASATA SU SMART C ARD IN AMBITO SANITARIO Relatore Tesi di laurea di Chiar.mo Prof. Aldo Franco Dragoni Matteo Liuti Correlatore Chiar.mo Prof. Paolo Puliti Anno Accademico 2004/2005 Indice Indice Struttura della tesi....................................................................................... 1 Capitolo 1. INTRODUZIONE .................................................................... 3 1.1 Lo sviluppo dei sistemi informatici ................................................................ 4 1.2 Il problema della sicurezza ............................................................................ 4 1.3 La sicurezza nella Pubblica Amministrazione ............................................. 6 Capitolo 2. CRITTOGRAFIA .................................................................... 9 2.1 Concetti base di crittografia .......................................................................... 10 2.2 Crittografia Simmetrica................................................................................. 12 2.2.1 Cifratura a blocchi e a flusso. ............................................................... 14 Algoritmi a blocchi ........................................................................................... 14 Algoritmi a flusso.............................................................................................. 16 2.2.2 I principali algoritmi di cifratura simmetrica....................................... 17 Data Encryption Standard (DES)..................................................................... 18 Triple DES (TDES) ........................................................................................... 19 Advanced Encryption Standard (AES) ............................................................. 19 International Data Encryption Algorithm (IDEA) ........................................... 20 RC2 e RC4 ........................................................................................................ 21 2.3 Crittografia asimmetrica ............................................................................... 21 Algoritmi a chiave di cifratura pubblica .......................................................... 23 Algoritmi a chiave di decifratura pubblica ...................................................... 24 Uso combinato delle due tecniche .................................................................... 25 2.3.1 I principali algoritmi di cifratura asimmetrica..................................... 27 Rivest Shamir Adelman (RSA) .......................................................................... 28 Digital Signature Algorithm (DSA) ................................................................. 29 2.4 Considerazioni generali sulla sicurezza degli algoritmi crittografici......... 30 2.5 Funzione di Hash ............................................................................................ 32 2.6 Firma Digitale ................................................................................................. 34 2.6.1 Aspetti legali della firma digitale........................................................... 37 I Indice Capitolo 3. PUBLIC KEY INFRASTRUCTURE...................................41 3.1 Introduzione ....................................................................................................42 3.2 Il certificato a chiave pubblica.......................................................................43 3.2.1 Ciclo di vita di un certificato..................................................................45 3.2.2 Revoca di un certificato..........................................................................46 3.3 Certification Authority e Registration Authority ........................................48 3.3.1 Modello di fiducia...................................................................................48 3.3.2 Tipologie di collegamenti fra Autorità di Certificazione ......................49 Modello reticolare.............................................................................................50 Modello ad albero .............................................................................................52 Modelli a struttura ibrida .................................................................................53 3.3.3 3.4 Catene di certificazione ..........................................................................54 Standard...........................................................................................................57 3.4.1 Standard X.509 per i certificati a chiave pubblica ................................57 3.4.2 Standard PKCS.......................................................................................60 Capitolo 4. SMART CARD.......................................................................63 4.1 Aspetto di una Smart Card ............................................................................64 4.2 Architettura interna........................................................................................65 4.3 Tipi di Smart Card..........................................................................................66 4.4 Standard...........................................................................................................67 4.4.1 Standard ISO/IEC 7816 .........................................................................67 ISO/IEC 7816-1: Caratteristiche fisiche...........................................................69 ISO/IEC 7816-2: Dimensione e locazione dei contatti .....................................70 ISO/IEC 7816-3: Segnali elettrici e protocolli di trasmissione ........................71 4.4.2 Altri standard..........................................................................................73 4.4.3 Abstract Syntax Notation .......................................................................74 4.5 Funzionamento di una Smart Card...............................................................76 4.5.1 Sequenze di attivazione e disattivazione ................................................76 4.5.2 Sistema operativo....................................................................................78 4.5.3 File system ..............................................................................................79 4.5.4 Protocolli di trasmissione.......................................................................82 Protocollo T=0..................................................................................................82 Protocollo T=1..................................................................................................84 4.5.5 Application Protocol Data Unit .............................................................86 II Indice 4.6 Interfaccia con le applicazioni ....................................................................... 88 4.6.1 PC/SC ..................................................................................................... 89 4.6.2 Open Card Framework .......................................................................... 90 4.6.3 Confronto tra OCF e PC/SC.................................................................. 92 4.6.4 Java Card ............................................................................................... 93 4.7 PKCS#11.......................................................................................................... 96 4.7.1 Caratteristiche tecnologiche .................................................................. 97 4.7.2 Sessioni................................................................................................... 98 Sessioni R/O...................................................................................................... 99 Sessioni R/W ................................................................................................... 100 Eventi di sessione............................................................................................ 100 4.7.3 Oggetti .................................................................................................. 101 Oggetti “Data”............................................................................................... 103 Oggetti “Key”................................................................................................. 103 Oggetti “Certificate”...................................................................................... 104 4.7.4 Considerazioni sulla sicurezza ............................................................ 105 4.7.5 Provider di sicurezza IAIK................................................................... 106 Capitolo 5. REALIZZAZIONE DEL PROGETTO............................. 109 5.1 Descrizione generale del progetto ............................................................... 110 5.1.2 5.2 Applicazione all’ambito sanitario........................................................ 112 Implementazione........................................................................................... 114 5.2.1 Strumenti utilizzati ............................................................................... 114 5.2.2 Installazione del Provider IAIK........................................................... 115 5.2.3 Software prodotto ................................................................................. 117 Software di inizializzazione ............................................................................ 118 Software di firma ............................................................................................ 122 Tool di gestione della smart card ................................................................... 125 Capitolo 6. CONCLUSIONI E SVILUPPI FUTURI ........................... 129 Appendice. CODICE JAVA................................................................... 133 Bibliografia .............................................................................................. 163 Ringraziamenti....................................................................................... 165 III Struttura della tesi Struttura della tesi Ogni capitolo della tesi riguarda un argomento chiave del progetto sviluppato. In questo lavoro hanno particolare importanza i concetti di crittografia, infrastrutture a chiave pubblica e smart card. Per ognuno di essi viene fornita prima una descrizione generale delle nozioni di base, andando poi ad approfondire i concetti più importanti e inerenti al progetto. Il primo capitolo fornisce una visione breve e introduttiva dell’evoluzione dei sistemi informatici e dei problemi di sicurezza ad essa legati, con uno sguardo al settore della Pubblica Amministrazione. Il secondo capitolo descrive le tecniche crittografiche simmetriche ed asimmetriche, necessarie per comprendere l’argomento più importante di questo lavoro che è la firma digitale. Di essa si spiegherà il funzionamento ed il suo valore legale. Il terzo capitolo si occupa dell’infrastruttura a chiave pubblica (Public Key Infrastructure) fornendone una descrizione strutturale e funzionale e introducendo gli standard di base. Il quarto capitolo è dedicato interamente alle Smart Card, alla loro architettura, al loro funzionamento ed ai loro requisiti in termini di normative e standard. Presenta anche una sezione che descrive il modo con cui un’applicazione può interagire con la smart card servendosi di un apposito provider di sicurezza. Il quinto capitolo descrive il lavoro che ho realizzato in collaborazione con la ASUR zona 7 della regione Marche. Verrà fornita prima una presentazione generale per poi andare in dettaglio sui vari aspetti del progetto e sulle scelte fatte. Nel capitolo sesto sono espresse alcune considerazioni personali sul lavoro svolto e vengono proposti dei possibili punti di sviluppo. Infine l’appendice contiene il listato del software prodotto. 1 Struttura della tesi 2 Introduzione Capitolo 1. INTRODUZIONE 3 Capitolo 1 1.1 Lo sviluppo dei sistemi informatici Lo sviluppo dei sistemi informatici negli ultimi anni ha compiuto passi da gigante, sia per quanto riguarda la continua nascita di nuove tecnologie, sia per la sempre più ampia possibilità di accesso a queste nuove conoscenze. Indubbiamente un notevole contributo a questa diffusione deriva dall’enorme successo di Internet. Dal suo predecessore ARPANET (nato nel 1969 dalla collaborazione tra alcune università degli Stati Uniti1) e soprattutto dall’introduzione del World Wide Web (nel 1992 da parte del CERN) e del protocollo HTTP con il quale i server Web comunicano tra loro, si è verificata una vera e propria rivoluzione che ha reso alla portata di tutti risorse che prima erano inaccessibili. La facilità di acceso e di uso del Web, unita alla possibilità di offrire contenuti in modo immediato, consente ai singoli e alle aziende di rendere massima l’efficienza e la chiarezza delle comunicazioni. Con gli anni questa sempre maggiore diffusione ha reso internet una necessità, portando enormi vantaggi ma anche una notevole quantità di rischi. 1.2 Il problema della sicurezza E’ perfettamente intuibile come la facilità di accesso ad un qualunque sistema favorisca l’accesso anche da parte di persone che non hanno intenzioni del tutto benevole. Sono sempre più frequenti infatti i cosiddetti “crimini informatici” ad opera di soggetti che penetrano nei sistemi per visualizzare, modificare o addirittura cancellare informazioni sensibili, o con il semplice intento di recare danno al sistema. Le tecniche di accesso sono diverse e vanno dal “social engineering”, allo “sniffing”, allo “scan” e così via. Le conseguenze di questi crimini possono essere disastrose, specialmente se il sistema in questione è quello di una grande azienda. 1 Per la nascita di ARPANET hanno collaborato l’Università dello Utah, l’Università di California e lo Stanford Research Institute, finanziati dal progetto “Advanced Research Projects Agency” del governo degli Stati Uniti. 4 Introduzione Il problema della sicurezza dei sistemi informatici è quindi un argomento molto importante che deve essere sempre considerato (nelle giuste misure2) qualunque sia il sistema di cui si disponga. In questo scenario ci vengono in aiuto diversi strumenti come la crittografia, la firma digitale, le PKI e le Smart Card che impareremo a conoscere nel corso di questa trattazione. Da quanto detto si delineano due aspetti su cui è opportuno intervenire: • controllo degli accessi al sistema; • protezione dei dati sensibili. Il primo punto coinvolge il problema dell’autenticazione, cioè del riconoscimento di chi accede al sistema. Si possono individuare, a tal proposito, tre livelli di sicurezza: • Autenticazione ad un fattore: basata su qualcosa che l’utente sa. E’ il caso di una coppia di login costituita da nome utente e password. • Autenticazione a due fattori: basata su qualcosa che l’utente sa e qualcosa che l’utente ha. E’ il caso che esamineremo di una smart card con PIN di autenticazione. • Autenticazione a tre fattori: basata su qualcosa che l’utente sa, qualcosa che l’utente ha ed una caratteristica unica dell’utente. E’ il caso di sistemi che integrano funzionalità di controllo biometriche come impronte digitali, cornea o altro. Per quanto riguarda la protezione dei dati sensibili, questa avviene mediante l’impiego di particolari funzioni crittografiche. La crittografia è una tecnica che ci consente di proteggere i nostri dati rendendoli incomprensibili a chiunque, a meno che non abbia la chiave giusta per decifrarli. In questo modo anche se un messaggio che viaggia in rete venisse intercettato da un soggetto male intenzionato, egli non potrebbe mai sapere che cosa tale messaggio in realtà contiene. Questo permette di garantire la segretezza di una comunicazione, in quanto solo chi è in possesso della chiave di decifratura può interpretare correttamente il messaggio. 2 Si tenga sempre presente che il livello di sicurezza di un sistema deve essere proporzionale all’importanza delle informazioni che si intende proteggere. 5 Capitolo 1 Livelli di sicurezza ancora più elevati si raggiungono con la crittografia asimmetrica che impiega due chiavi (una pubblica e una privata) per effettuare le operazioni di cifratura e decifratura. La crittografia (nello specifico la quella asimmetrica) trova impiego (ed anzi è alla base) del processo di firma digitale. Questa ha lo stesso ruolo della firma autografa su documento cartaceo3, cioè serve a garantire l’autenticità del documento, ossia la corretta identità del mittente. In generale, quando si allega la firma digitale ad un documento informatico si garantisce l’autenticità dell’autore e l’integrità della trasmissione, cioè il fatto che nessuno abbia modificato il documento dopo l’invio. L’impiego di queste tecniche richiede una struttura capace di gestire correttamente l’uso delle chiavi pubbliche di crittografia (tramite l’utilizzo di appositi certificati4) e in grado di fornire i protocolli di comunicazione e le regole base per offrire i servizi crittografici. La struttura in questione prende il nome di Public Key Infrastructure (PKI). Una PKI offre un elevato livello di sicurezza finché le chiavi pubbliche e private vengono gestite correttamente, da qui l’esigenza di trovare un mezzo che ci consenta di custodire la nostra chiave privata in estrema sicurezza, ma anche di poterla portare sempre con noi. Il problema trova soluzione con l’impiego delle Smart Card, cioè schede capaci non solo di contenere dati al loro interno, ma anche di elaborarli5. 1.3 Da La sicurezza nella Pubblica Amministrazione qualche anno a questa parte il settore della Pubblica Amministrazione sta attraversando una crescente informatizzazione dei servizi. L’obiettivo principale è quello di creare servizi on-line, orientati alle necessità dei cittadini e delle imprese e capaci di rendere più semplice e rapida ogni interazione con le Pubbliche Amministrazioni. Inoltre si intende eliminare gradualmente la documentazione cartacea sostituendola con documenti 3 Per una descrizione più dettagliata sugli aspetti legali della firma digitale si rimanda al paragrafo §2.6.1. I certificati a chiave pubblica, appunto. 5 Da cui appunto il nome di scheda intelligente. 4 6 Introduzione informatici usufruendo delle citate tecniche di crittografia e firma digitale. I vantaggi che ne scaturiscono sono molto rilevanti: si va da una maggiore efficienza e velocità dei servizi, ad un più facile accesso ai servizi stessi, ad una migliore archiviazione delle informazioni, alla possibilità di effettuare ricerche più veloci e più mirate, alla possibilità di consultare sedi diverse indipendentemente dalla loro posizione geografica. Un progetto sicuramente ambizioso ma necessario per stare al passo con il continuo sviluppo tecnologico. Abbiamo già parlato dei rischi che comporta l’apertura di un qualsiasi sistema informatico alla rete telematica, e nel caso delle Pubbliche Amministrazioni è di particolare importanza il problema della non divulgazione dei dati sensibili degli utenti. Questo si traduce nella necessità di realizzare un sistema di comunicazione in grado di garantire la riservatezza e la segretezza dei dati scambiati. Un apposito ente governativo, il CNIPA (Centro Nazionale per l’Informatica nella Pubblica Amministrazione6), ha il preciso obiettivo di dare supporto alla Pubblica Amministrazione nell’utilizzo efficace dell’informatica per migliorare la qualità dei servizi e contenere i costi dell’azione amministrativa. Diversi progetti sono stati sviluppati ed alcuni sono già operativi a livello regionale, come ad esempio il progetto “ESCAPE7” (Electronic Signature in Care Activities for Paper Elimination) della regione Veneto, “CRS-SISS8” (Carta Regionale dei Servizi – Sistema Informativo Socio-Sanitario) della regione Lombardia, “SUT9” (Sportello Unico del Territorio) e “Progetto People10” della regione Marche. A livello nazionale invece esistono due progetti che riguardano la Carta di Identità Elettronica (CIE) e la Carta Nazionale dei Servizi (CNS) per l’autenticazione dell’individuo e l’accesso ai servizi delle pubbliche amministrazioni. La CIE è stata emessa dai comuni in sostituzione della carta d’identità tradizionale. Essa adotta una smart card ibrida (cioè che presenta, oltre al 6 www.cnipa.gov.it www.progettiescape.it 8 www.crs.lombardia.it 9 www.sportellounico.marche.it 10 www.progettopeople.it 7 7 Capitolo 1 microchip, anche una banda ottica) e i dati del titolare (compresa la foto) sono impressi in modo visibile sul supporto fisico della scheda e memorizzati sia all’interno del chip che della banda ottica. Questa doppia tecnologia da garanzie sulla sicurezza dei dati e consente il riconoscimento in rete del titolare. La carta d’identità elettronica è stata individuata come strumento di semplificazione del rapporto tra Pubblica Amministrazione e cittadini, cercando di salvaguardare diversi obiettivi, tra i quali: • maggiore sicurezza nel processo di identificazione ai fini di polizia; • utilizzo quale strumento di identificazione in rete per l’accesso ai servizi telematici; • completa interoperabilità su tutto il territorio nazionale. Per quanto riguarda la Carta Nazionale dei Servizi, invece, questa definisce uno standard per favorire la convergenza degli strumenti di identificazione digitale. La CNS, progettata parallelamente alla CIE, ha il fine di anticipare le funzioni di accesso ai servizi in rete e rappresenta il punto di riferimento per l’emissione di carte multiservizi. Mediante questa carta, infatti, è possibile ottenere servizi sanitari, fiscali, usufruire di sistemi di pagamento bancari e postali e utilizzare la firma digitale. 8 Crittografia Capitolo 2. CRITTOGRAFIA 9 Capitolo 2 2.1 Concetti base di crittografia La crittografia è la disciplina che studia la trasformazione di dati allo scopo di nascondere il loro contenuto semantico, impedire il loro utilizzo non autorizzato, o impedire qualsiasi loro modifica non rilevabile11. Il termine deriva dal greco crypto che significa “nascondere” e graphein che significa “scrivere”, infatti la crittografia è stata definita anche come la scienza della scrittura segreta12. Parallelamente alla crittografia si sviluppa un’altra disciplina che prende il nome di crittoanalisi e si occupa di recuperare il contenuto di un messaggio cifrato senza disporre delle informazioni necessarie alla decifratura. Ambedue le discipline sono governate da una branca della matematica che va sotto il nome di crittologia. La crittografia è stata sempre presente nella storia dell’uomo, anche se in forme diverse. Il più semplice esempio risale ai tempi di Giulio Cesare che nella sua corrispondenza scambiava l’ordine delle lettere spostandole di quattro verso destra in modo che la A risultasse la D e così via. Figura 1. Esempio di cifrario di sostituzione monoalfabetica impiegato da Giulio Cesare. E’ una tecnica molto semplice di cifrario di sostituzione monoalfabetica che risulta completamente inefficace una volta noto l’algoritmo utilizzato. L’evoluzione delle tecniche crittografiche ha avuto una svolta proprio quando si è deciso di rendere pubblici gli algoritmi di cifratura e decifratura dei messaggi, legando la capacità di leggerne correttamente il contenuto ad una ulteriore informazione che è appunto la chiave di decifratura. Da qui nascono le moderne tecniche di crittografia come la crittografia simmetrica e quella 11 12 Bruce Schneider: “Applied Cryptography Second Edition: protocols, algorithms and source code in C” Jonathan Knudsen: “Java Cryptography”. 10 Crittografia asimmetrica che vedremo approfonditamente nei prossimi paragrafi. I vantaggi che questo nuovo modo di pensare ha portato sono molti: • la pubblicazione degli algoritmi rende possibile il loro studio da parte dei crittoanalisti di tutto il mondo consentendo di scoprirne eventuali debolezze; • come conseguenza del punto precedente si hanno nuovi algoritmi sempre più sicuri; • si rendono molto più accessibili le tecniche di protezione dati anche ad aziende che non dispongono di personale specializzato. Grazie a queste nuove tecniche un sistema crittografico è in grado di garantire i seguenti requisiti: • Autenticazione d’identità: verifica dell’identità di una o entrambe le parti coinvolte in una comunicazione; • Integrità dei dati: il documento trasmesso deve contenere tutte le informazioni in esso presenti sin dalla redazione, con la possibilità di verificare le eventuali alterazioni, intenzionali o meno, che i dati possono aver subito attraversando un canale insicuro; • Autenticità dei dati: verifica dell’effettiva identità del mittente; • Non ripudio: impossibilità, da parte sia del mittente che del destinatario, di negare l’avvenuto scambio di dati. Nel seguito del capitolo andremo a studiare le principali tecniche di crittografia simmetrica e asimmetrica, analizzandone il principio di funzionamento, i pregi e i difetti. Verranno inoltre fornite delle brevi indicazioni sugli algoritmi che queste tecniche adottano, focalizzando maggiormente l’attenzione sull’algoritmo RSA, in quanto è forse il più conosciuto ed è quello impiegato nello sviluppo di questo progetto. Negli esempi e negli schemi che verranno riportati si farà spesso riferimento ad un ipotetico scambio di dati tra un “Mittente” e un “Destinatario”. La situazione si presenta in questo modo: 11 Capitolo 2 Mittente Messaggio in chiaro Messaggio cifrato Cifratura Chiave Canale di trasmissione Destinatario Messaggio in chiaro Chiave Decifratura Messaggio cifrato Figura 2. Schema di principio di una comunicazione cifrata tra due entità Il messaggio originale (messaggio in chiaro) viene opportunamente cifrato con una apposita chiave. Il risultante messaggio cifrato sarà spedito sul canale di trasmissione e giungerà al destinatario che effettuerà le operazioni di decifratura per recuperare il contenuto originale del messaggio. Lungo il canale il messaggio è visibile a tutti, ma questo non compromette la sicurezza della comunicazione in quanto, essendo cifrato, solo chi è in possesso dell’apposita chiave è in grado di comprenderne il contenuto. 2.2 Crittografia Simmetrica La crittografia simmetrica, detta anche a chiave segreta, utilizza algoritmi che impiegano un’unica chiave sia per le operazioni di cifratura sia per quelle di decifratura13. Il mittente e il destinatario devono essere in possesso della stesa chiave per fare in modo che l’intera operazione abbia successo. L’uso di una chiave diversa comporterebbe l’impossibilità di recuperare le informazioni dal messaggio cifrato e, di conseguenza, la necessità di ripetere la trasmissione. La sicurezza è garantita fintantoché la chiave rimane a conoscenza solo dei due interlocutori e segreta ad ogni altro14. 13 14 Da qui il nome di crittografia simmetrica. Da qui il nome di crittografia a chiave segreta. 12 Crittografia Lo schema di funzionamento è il seguente: Mittente Messaggio in chiaro Messaggio cifrato Cifratura Chiave Canale sicuro Canale insicuro Destinatario Messaggio in chiaro Decifratura Messaggio cifrato Figura 3. Schema di funzionamento di una comunicazione cifrata con tecnica simmetrica. Come si può vedere il funzionamento è molto simile allo schema di crittografia di base introdotto precedentemente. Si può notare però l’impiego di due canali di trasmissione: un canale sicuro15 riservato alla chiave segreta ed un canale insicuro in cui viene spedito il messaggio cifrato. Il mittente e il destinatario devono innanzitutto concordare in segreto la chiave da utilizzare per la cifratura e decifratura, il mittente quindi, prima dell’invio del messaggio, genera la chiave segreta e la spedisce al destinatario attraverso un canale sicuro. Il difetto principale di questa tecnica sta proprio in questo scambio, in quanto, anche se si adotta un canale sicuro, c’è sempre il rischio che le informazioni vengano intercettate e, poiché l’informazione che sta viaggiando in rete è proprio la chiave segreta, la sua intercettazione comprometterebbe la sicurezza di tutta la comunicazione. In questo caso infatti verrebbe meno non solo il requisito di segretezza, ma anche quelli di integrità del messaggio ed autenticazione del mittente. Se una terza parte infatti riuscisse ad entrare in possesso della chiave segreta, potrebbe intercettare il messaggio cifrato, modificarlo e cifrarlo di nuovo, senza che il destinatario si accorga di nulla. Un altro svantaggio della crittografia simmetrica riguarda il fatto che ogni utente deve disporre di una chiave diversa per ogni altro utente con cui intenda 15 Ad esempio un canale SSL. 13 Capitolo 2 comunicare. Questo rappresenta un problema tanto più serio quanto più il numero di utenti è elevato. Per avere un riscontro pratico si pensi che in un generico sistema di n utenti ci si troverebbe a dover gestire un numero di chiavi segrete pari a: n ⋅ (n − 1) . 2 2.2.1 Cifratura a blocchi e a flusso. Gli algoritmi impiegati nella crittografia simmetrica si possono distinguere in due categorie: • algoritmi a blocchi: l’operazione di cifratura o decifratura viene effettuata su gruppi di bit (o byte, o parole) detti appunto blocchi; • algoritmi a flusso: l’operazione di cifratura o decifratura viene effettuata sui singoli bit (o byte, o parole). Algoritmi a blocchi Il messaggio da cifrare (o decifrare) viene suddiviso in blocchi di lunghezza prefissata (solitamente 64 bit) e l’algoritmo viene applicato ad ognuno di questo blocchi singolarmente. E’ necessario che il messaggio abbia lunghezza esattamente multipla della dimensione del blocco altrimenti si verifica un errore nell’applicazione dell’algoritmo. Per evitare questo problema si prevede il riempimento dell’ultimo blocco con opportuni caratteri di allineamento. Questo procedimento è noto come “pad” ed in figura è riportato l’esempio di un messaggio suddiviso in n blocchi in cui al blocco n-esimo sono stati aggiunti i caratteri di riempimento (parte tratteggiata). 14 Crittografia Blocco 1 Blocco 2 ….. Blocco 3 Blocco n-1 Blocco n Figura 4. Esempio di suddivisione in blocchi di un messaggio e applicazione dei caratteri di riempimento (tratteggio). Esistono diversi modi per eseguire l’operazione di “pad” a seconda dei diversi tipi di dato. Di seguito vengono brevemente descritti quelli più comuni: • il più semplice di tutti non fa altro che aggiungere zeri fino al raggiungimento della lunghezza stabilita per il blocco; • se i dati sono binari si integra il blocco con bit che sono l’opposto degli ultimi bit costituenti il messaggio; • nel caso di caratteri ASCII si usano byte di riempimento casuali specificando nell’ultimo byte il carattere ASCII corrispondente al numero di byte aggiunti; • un’ultima tecnica impiega anch’essa bit di riempimento casuali, ma negli ultimi tre bit vengono indicati il numero di bit originali (quindi non aggiunti) che costituiscono l’ultimo blocco. Un difetto di questa tecnica si incontra quando il messaggio è esattamente multiplo della dimensione del blocco (ad esempio 64 bit) e quindi non si necessiterebbe di alcun tipo di padding. In questo caso si dovrà aggiungere un ulteriore blocco con 61 bit random e gli ultimi tre nulli. Citiamo ora i più comuni algoritmi a blocchi: • Electronic Codebook (ECB): è il metodo più semplice in cui il risultato dell’operazione dipende solo dal valore della chiave. In questo modo, fissata una chiave K, un certo blocco B al quale viene applicato l’algoritmo darà come risultato sempre lo stesso blocco B’. Questa caratteristica di univocità del risultato apre la strada all’elaborazione parallela, in cui diversi blocchi del messaggio possono essere trasformati in modo indipendente (anche da più calcolatori) ottenendo lo stesso risultato di una elaborazione singola ma a tutto vantaggio della velocità di esecuzione. L’altra faccia della medaglia riguarda il fatto che un crittoanalista (o peggio un hacker che sia entrato in possesso della 15 Capitolo 2 chiave segreta) può risalire dal messaggio cifrato a quello originale tramite un attacco a forza bruta, ovvero cifrando diversi messaggi fino a che non ottiene la stessa sequenza cifrata16. • Cipher Block Chaining (CBC): questa tecnica prevede che ciascun blocco in chiaro venga messo in XOR con in blocco cifrato precedente e poi ulteriormente cifrato con la chiave segreta. Questo modo di procedere fa si che il risultato dell’operazione ad ogni blocco dipenda non solo dalla chiave utilizzata, ma anche dalla cifratura di tutti i blocchi precedenti. Diventa così impossibile effettuare un attacco a forza bruta su un blocco n-esimo del messaggio senza conoscere anche i precedenti, in quanto non è più detto che due blocchi uguali, cifrati con la stessa chiave, diano lo stesso risultato. Rimane il fatto però che due messaggi identici saranno cifrati in modo identico. Per evitare ciò viene allora inserito in testa ad ogni blocco da cifrare un vettore di inizializzazione, che non è altro che un blocco casuale di dati. • Cipher Feedback (CFB): i blocchi vengono “incatenati” in modo molto simile a quello della tecnica precedente. In questo caso però ogni blocco cifrato viene messo in XOR con il corrente blocco in chiaro spezzettato in segmenti più piccoli. La cifratura elementare di un blocco viene quindi effettuata su gruppi di 4 o 8 bit alla volta man mano che questi giungono al cifratore. L’idea è quella di elaborare i dati non appena divengono disponibili invece di aspettare che un blocco sia del tutto completato. Algoritmi a flusso Negli algoritmi simmetrici a flusso il messaggio in chiaro si presenta in ingresso come un stream (un flusso, appunto) di dati e l’operazione di cifratura (o decifratura) viene effettuata su ogni singolo bit (o byte) di ingresso. Più in dettaglio questi algoritmi fanno uso di un generatore di bit che, a seconda della chiave fornita, è in grado di produrre una sequenza di bit 16 Si intende in questo tipo di attacco che la terza persona (crittoanalista o hacker che sia) sia a conoscenza della chiave segreta e comunque la buona riuscita dell’attacco richiede tempi lunghissimi (tanto più lunghi quanto più è grande il blocco). 16 Crittografia apparentemente casuale17. Nell’effettiva operazione di cifratura i dati in ingresso vengono messi in XOR con i dati provenienti dal generatore. In questo modo non si verifica mai che due messaggi identici, cifrati con la stessa chiave, diano origine a due messaggi cifrati uguali. Gli algoritmi a flusso a loro volta si possono dividere in due categorie: • Algoritmi autosincronizzanti: in questo tipo di algoritmi il generatore di numeri casuali prende in ingresso, ad ogni passo, anche un certo numero di bit cifrati precedentemente. Quindi, comunque sia fissata una chiave, uno stesso bit (o byte) potrà essere cifrato ogni volta in modo diverso a seconda delle precedenti informazioni elaborate dal flusso in ingresso. • Algoritmi sincroni: in questi algoritmi il flusso di bit generati è completamente indipendente dal flusso di dati in ingresso. Questo comporta il vantaggio di ridurre la propagazione degli errori: si pensi ad esempio ad un canale di trasmissione rumoroso in cui si verifica un errore su un bit durante l’invio del messaggio cifrato. In ricezione il decifratore sbaglierà, ovviamente, il bit incriminato, ma questo errore non si ripercuoterà su altri bit, in quanto non c’è la dipendenza dagli stati precedenti (come invece avviene nel caso degli algoritmi autosincronizzanti). 2.2.2 I principali algoritmi di cifratura simmetrica Verranno ora presentati alcuni tra i più noti algoritmi impiegati nella crittografia simmetrica. Per ognuno di essi si illustreranno i concetti base riguardanti il loro funzionamento e si effettueranno delle brevi considerazioni sulla loro sicurezza. 17 Tale sequenza di bit pseudocasuali è il risultato di complesse operazioni aritmetiche che si basano sui parametri costituenti la chiave. Di fatto risulta (quasi) impossibile prevedere la sequenza generata senza conoscere la chiave. 17 Capitolo 2 Data Encryption Standard (DES) Il Data Encryption Standard (DES) venne adottato dal governo degli Stati Uniti nel 1977 come standard per la crittografia simmetrica. E’ stato sviluppato dalla IBM come evoluzione di un altro algoritmo, Lucifer, risalente ai primi anni ‘70. Sebbene la sua validità dovesse essere programmata di 5 o 10 anni, il DES è rimasto un riferimento per molti anni a seguire18. L’algoritmo che utilizza, il DEA (Data Encryption Algorithm), rientra nella classe dei codici a blocchi ed è utilizzabile con tutti i modelli visti precedentemente. Ogni blocco ha la dimensione di 64 bit. Più in dettaglio il DES impiega blocchi di 64 bit ed utilizza chiavi di cifratura di 64 bit suddivise in 8 sottoblocchi di 8 bit ciascuno. L’ultimo bit di ogni sottoblocco è di controllo, di conseguenza è come se avessimo a che fare con una chiave a 56 bit. Durante la cifratura il blocco di testo in chiaro viene innanzitutto trasposto e poi diviso in una metà destra e una metà sinistra di 32 bit ciascuna. In seguito, ad ognuna di queste metà, vengono applicate 16 passate (dette round) tramite una funzione che opera trasposizioni e sostituzioni mediante apposite sottochiavi19. Durante ogni round l’output della metà sinistra diventa l’input della destra e viceversa. Dopo il completamento di tutti i round i due sottoblocchi vengono riuniti e il risultato permutato per invertire la trasposizione iniziale. L’operazione di decifratura avviene in modo del tutto analogo, con la sola accortezza di assegnare le sottochiavi in ordine inverso a quello utilizzato durante la cifratura. Questo algoritmo, che potrebbe a prima vista sembrare molto cavilloso, in realtà sfrutta operazioni molto semplici come trasposizione, sostituzione e XOR di bit. Nonostante abbia resistito anche più del dovuto come standard, il DES non è considerato un algoritmo molto sicuro ed è utilizzato per la cifratura di dati relativamente importanti. Il difetto maggiore è il limitato spazio delle chiavi (keyspace20) di cui dispone che è pari a 256. Esistono inoltre delle 18 Già nei primi anni 90 non era più considerato abbastanza sicuro e nel 1998 è stato violato per la prima volta. 19 Le sottochiavi vengono ricavate dividendo i bit effettivi che costituiscono la chiave in due sottoblocchi di 28 bit ciascuno. Ad ogni round questi semiblocchi vengono sciatati verso sinistra dando origine alle sottochiavi. 20 Per keyspace si intende l’insieme di tutte le chiavi, diverse l’una dall’altra, ricavabili come combinazione di n bit (dove n rappresenta la dimensione della chiave). 18 Crittografia perplessità riguardanti la sua sicurezza derivanti dal ruolo che ha avuto l’NSA21 nel validare l’algoritmo. In particolare si contesta la scelta di ridurre la dimensione delle chiavi da 128 bit a 64 bit, dando adito a congetture sulla robustezza di DES. Triple DES (TDES) Una evoluzione del DES può essere considerata il triplo-DES (noto anche come DESede), così denominato in quanto utilizza tre chiavi indipendenti in tre diversi passaggi. Ci sono molte varianti del TDES, di seguito ne illustreremo due tra le più comuni. La prima impiega sue chiavi K1 e K2 di 56 bit ciascuna raddoppiando così l’effettiva lunghezza della chiave (che ora è di 112 bit) ed incrementando il keypsace di un fattore 256. Ogni blocco di 64 bit viene prima cifrato con la prima chiave (K1), poi decifrato con la seconda (K2), poi di nuovo cifrato ancora con la prima chiave (K1). Questo modo di procedere rende TDES un algoritmo molto più sicuro del precedente. Una particolarità riguarda il fatto che se le due chiavi K1 e K2 risultassero uguali, allora l’applicazione di questo algoritmo porterebbe un risultato identico all’applicazione dell’algoritmo DES. Un’altra versione di TDES sfrutta tre chiavi diverse e indipendenti da 56 bit ciascuna, con un effettivo keyspace di 168 bit. Ogni blocco viene cifrato per tre volte, ogni volta con una chiave diversa. E’ sicuramente un algoritmo più complesso e più costoso (soprattutto in termini di tempo) dei precedenti, ma è anche il più sicuro. Advanced Encryption Standard (AES) E’ un algoritmo di cifratura a blocchi, noto anche come algoritmo di Rijndael22, sviluppato dai crittografi belgi Joan Daemen e Vincent Rijmen. E stato adottato dalla National Institute of Standards and Technology (NIST) e dalla US Federal Information Processing Standard (FIPS) nel novembre 2001. 21 22 National Security Agency Più propriamente AES è una particolare implementazione dell’algoritmo Rijndael. 19 Capitolo 2 Ogni blocco ha dimensione fissa di 128 bit e possono essere impiegate chiavi di 128, 192 o anche 256 bit. AES opera su delle matrici chiamate stati. Con 128 bit in input (ovvero le dimensioni di un blocco) ogni stato è composto da 4 righe e 4 colonne di 32 bit ciascuna, cioè matrici di 4x4 byte. Durante la cifratura, ad ogni fase (round), vengono eseguite le operazioni sostituzione, spostamento, combinazione lineare dei byte ed inoltre ogni byte viene combinato in XOR con una chiave di sessione calcolata dal gestore delle chiavi. Questo algoritmo presenta molti vantaggi, primo fra tutti la possibilità di impiego di chiavi di lunghezza diversa e comunque tale da garantire un ottimo livello di sicurezza. Si pensi che, secondo l’NSA, la dimensione di una chiave impiegata per cifrare dati Top Secret deve essere di 192 o 256 bit. Inoltre AES è di facile implementazione sia hardware che software e le sue richieste di risorse sono limitate. Questo lo rende applicabile a qualsiasi tipo di strumento capace di eseguire operazioni crittografiche ed è un grosso incentivo per la sua diffusione. International Data Encryption Algorithm (IDEA) IDEA è nato nel 1991 sotto il nome di IPES (Improved Proposed Encryption Standard) ideato dai crittologi Xuejja Lai e James L. Massey. E’ anch’esso un algoritmo a blocchi di 64 bit ed è applicabile a tutti i modelli di cifratura a blocchi. Utilizza chiavi a 128 bit e l’operazione di cifratura comporta una divisione del blocco in chiaro in quattro sottoblocchi di 16 bit. Ognuno subisce otto round di trasformazioni durante le quali vengono eseguite le operazioni di XOR dei bit, addizione e moltiplicazione modulare. Nell’ultimo round i quattro sottoblocchi vengono concatenati per produrre il blocco cifrato. Durante gli otto round sono coinvolte nelle operazioni 52 chiavi diverse (sei per ogni round) che vengono ricavate dividendo la chiave iniziale in otto stringhe di 16 bit che costituiscono le prime otto chiavi. In seguito i 128 bit della chiave originale vengono shiftati di 25 bit a sinistra ottenendo una nuova sequenza che verrà ancora divisa in otto stringhe a 16 bit per ricavare altre otto sottochiavi. Iterando il procedimento si ricavano tutte le 52 sottochiavi. 20 Crittografia L’operazione di decifratura è identica eccezion fatta per il modo con cui vengono ricavate le sottochiavi. Offre un buon grado di sicurezza, al livello del TDES23 ed il suo utilizzo per scopi non commerciali è libero. RC2 e RC4 Questi algoritmi sono stati sviluppati dalla RSA Data Security Inc. e l’ideatore è Ron Rivest24. Sono algoritmi applicabili sia nella cifratura a blocchi che in quella a flusso. In particolare RC2 opera una tripla cifratura, come nel caso TDES, ma risulta molto più veloce. La caratteristica dei due algoritmi è che utilizzano chiavi di lunghezza arbitraria come seme per un generatore di numeri pseudo-casuali che vengono messi in XOR con i dati da cifrare. Sono giudicati algoritmi sicuri, ma il loro libero utilizzo è limitato a sole chiavi di lunghezza non superiore di 40 bit. 2.3 Crittografia asimmetrica Nel 1976 Whitfield Diffie e Martin Hellmann, due crittologi americani, pubblicarono uno scritto in cui, ipotizzando di poter disporre di un cifrario asimmetrico, dimostravano la fattibilità di sistemi crittografici di nuovo tipo mediante il concetto di chiavi pubbliche. Un sistema di questo tipo si sarebbe servito di due chiavi distinte, l’una l’inverso dell’altra, con le seguenti caratteristiche: • complementari: se una chiave è usata per cifrare l’altra deve essere usata per decifrare e viceversa; • indipendenti: la conoscenza di una chiave non deve consentire di risalire all’altra chiave. Di fatto è stato il punto di inizio dal quale si sono poi sviluppate tutte le tecniche che vedremo nel corso della trattazione. 23 24 Alcuni crittologi sostengono sia migliore IDEA, altri invece sostengono il contrario. Da cui il nome RC: Ron’s Code (o Rivest’s Code). 21 Capitolo 2 La crittografia asimmetrica, detta anche crittografia a chiave pubblica, prevede l’utilizzo di due chiavi diverse per le operazioni di cifratura e decifratura. Una di queste chiavi deve rimanere nota al solo possessore, che quindi è l’unica persona in grado di utilizzarla. Tale chiave è detta chiave privata. L’altra chiave invece può essere resa liberamente nota ed è utilizzabile da qualsiasi utente necessiti il suo impiego in una comunicazione. Tale chiave è detta chiave pubblica. Le due chiavi sono legate matematicamente tra loro, ma costruite in modo che sia impossibile risalire alla chiave privata partendo da quella pubblica. La distribuzione delle chiavi pubbliche avviene tramite l’utilizzo di appositi certificati, detti certificati a chiave pubblica, ed è affidata ad una entità detta Autorità di Certificazione. Questi concetti verranno ripresi ed approfonditi nel capitolo successivo riguardante l’infrastruttura a chiave pubblica, per ora ci basta sapere che un certificato è un mezzo tramite il quale vengono rese note le chiavi pubbliche di un particolare utente, e l’Autorità di Certificazione ci garantisce che quella chiave appartiene effettivamente all’utente in questione. Nella crittografia asimmetrica un messaggio cifrato con una delle due chiavi della coppia può essere decifrato solo con la chiave ad essa associata. L’ordine di utilizzo delle chiavi è arbitrario ai fini della corretta decifratura, quindi è possibile cifrare un messaggio con la propria chiave privata e decifrarlo con quella pubblica, oppure cifrare con la chiave pubblica e decifrare con quella privata. In ambedue i casi si è capaci di risalire correttamente al messaggio originale, ciò che cambia riguarda alcuni requisiti di sicurezza che vedremo tra poco. Proprio sulla base dell’arbitrarietà di utilizzo delle chiavi è possibile dividere gli algoritmi asimmetrici in due categorie: • algoritmi a chiave di cifratura pubblica: impiegano la chiave pubblica in cifratura e quella privata in decifratura; • algoritmi a chiave di decifratura pubblica: impiegano la chiave privata in cifratura e quella pubblica in decifratura. 22 Crittografia Algoritmi a chiave di cifratura pubblica Il funzionamento di questo tipo di algoritmi asimmetrici è illustrato nello schema seguente in cui si considera l’esempio di una comunicazione tra un generico “Mittente” ed un altrettanto generico “Destinatario”. Si indicano con KprivD e KpubD rispettivamente le chiavi privata e pubblica del destinatario. Mittente Messaggio in chiaro Messaggio cifrato Cifratura KpubD Canale insicuro KpubD KprivD Destinatario Messaggio in chiaro Decifratura Messaggio cifrato Figura 5. Schema di funzionamento di un algoritmo a chiave di cifratura pubblica. E’ opportuno fare una considerazione prima di proseguire. Nello schema viene raffigurato l’invio della chiave pubblica dal destinatario al mittente (la freccia tratteggiata). Questa rappresentazione vuole solo indicare che la chiave pubblica che si utilizza appartiene effettivamente al destinatario, e che il mittente, in qualche modo, ne viene in possesso. Il modo in cui questo avviene è stato citato ad inizio capitolo e verrà approfondito nella prossima sezione. Il funzionamento dei questo schema è molto semplice e ricorda quello a cifratura simmetrica, eccezion fatta per la distinzione tra chiave pubblica e privata. Il Mittente cifra il messaggio in chiaro con la chiave pubblica del Destinatario, quest’ultimo riceve il messaggio cifrato e, tramite l’utilizzo della propria chiave privata, riesce a risalire al messaggio originale. Ricordiamo che l’impiego di una qualsiasi altra chiave nella decifratura darebbe un risultato del tutto senza senso e, di conseguenza, l’impossibilità da parte del destinatario di conoscere il messaggio originale. Questa caratteristica dell’algoritmo, unita alla fondamentale proprietà di uso esclusivo delle chiavi 23 Capitolo 2 private da parte dei soli possessori, garantisce un importante requisito di sicurezza: la segretezza della comunicazione. Infatti il Mittente, utilizzando la chiave pubblica del Destinatario, sa che quel messaggio potrà essere decifrato solo dall’effettivo possessore della chiave associata. Anche se il cifrato venisse intercettato da una terza entità (ricordiamo che si fa uso di un canale insicuro) questa non sarà capace di comprenderne il significato. Il difetto di questo schema sta nel fatto che il Destinatario non può essere sicuro dell’effettiva identità del mittente, in quanto chiunque può procurarsi la sua chiave pubblica e spedirgli dei messaggi cifrati. Algoritmi a chiave di decifratura pubblica Lo schema di funzionamento è illustrato nella figura seguente in cui con KprivM e KpubM si intendono rispettivamente le chiavi privata e pubblica del mittente. Anche in questo caso valgono le considerazioni dell’esempio precedente riguardanti lo scambio della chiave pubblica tra i due interlocutori. 24 Crittografia Mittente Messaggio in chiaro Messaggio cifrato Cifratura KprivM KpubM Canale insicuro KpubM Destinatario Messaggio in chiaro Decifratura Messaggio cifrato Figura 6. Schema di funzionamento di un algoritmo a chiave di decifratura pubblica. Il Mittente cifra il messaggio in chiaro con la propria chiave privata ed il Destinatario utilizza la chiave pubblica del Mittente per decifrare il messaggio. In questo modo, se il destinatario riesce a recuperare correttamente il messaggio originale, vuol dire che questo è stato cifrato con la chiave privata associata a quella pubblica che ha utilizzato nella decifratura, e solo una persona ha la facoltà di usufruire di detta chiave privata: il Mittente. In altre parole il destinatario è sicuro dell’effettiva identità del mittente, viene cioè garantito con questo schema un altro requisito di sicurezza fondamentale: l’autenticazione d’identità. Dall’altra parte però viene meno la caratteristica di segretezza (tipica del caso precedente) in quanto chiunque può venire a conoscenza della chiave pubblica del mittente e quindi chiunque è in grado di decifrare il messaggio. Questo tipo di cifratura trova largo impiego nei sistemi che fanno uso della firma digitale, come vedremo più avanti nel corso del capitolo. Uso combinato delle due tecniche Abbiamo visto come i due schemi di cifratura asimmetrica riescano a garantire alternativamente la segretezza della comunicazione e l’autenticazione del mittente. Sono però queste due caratteristiche troppo importanti che devono 25 Capitolo 2 essere presenti contemporaneamente in una comunicazione crittografata. Si può allora pensare di adottare contemporaneamente i due schemi in modo combinato così da poter raggiungere un livello di sicurezza ancora maggiore. Il risultato dell’impiego delle due tecniche è riportato nel seguente schema: Mittente Text T’ Cifratura KprivM Cipher Cifratura KpubD Canale insicuro Destinatario Text T’ Decifratura Cipher Decifratura KpubM KprivD Figura 7. Schema di utilizzo della cifratura asimmetrica per l’invio di un messaggio autenticato e segreto. Con “Text” si vuole indicare il messaggio in chiaro, “T’” rappresenta un messaggio cifrato intermedio diverso da quello finale che viene spedito al mittente e che è invece indicato con “Cipher”. Per quanto riguarda le chiavi si ha la stessa nomenclatura dei casi precedenti. Avvengono due successive operazioni di cifratura: • prima il Mittente cifra il messaggio in chiaro con la propria chiave privata ottenendo un messaggio intermedio T’; • poi T’ viene ancora cifrato con la chiave pubblica del Destinatario ottenendo il messaggio cifrato finale (Cipher). In ricezione il Destinatario andrà a decifrare il messaggio prima impiegando la sua chiave privata e poi quella pubblica del Mittente. 26 Crittografia In realtà, in cifratura, l’ordine di utilizzo delle due chiavi è arbitrario, ma deve essere noto, in quanto chi riceve il messaggio dovrà eseguire la decifratura impiegando le chiavi in ordine inverso. In termini di sicurezza l’utilizzo della chiave privata del mittente garantisce la proprietà di autenticazione del messaggio, mentre l’impiego della chiave privata del destinatario garantisce la segretezza della trasmissione. Un’ultima considerazione riguarda l’incremento del numero delle chiavi all’aumentare del numero di utenti che vogliono comunicare tra loro. Questo problema era particolarmente sentito nella crittografia simmetrica in cui si aveva un incremento quadratico delle chiavi. Nella crittografia asimmetrica non è invece necessario che un utente crei una chiave diversa per ogni comunicazione con un altro utente. Ognuno infatti dispone di una propria coppia di chiavi ed utilizza sempre questa coppia per comunicare con qualsiasi altro utente. In questo modo si ha un incremento lineare del numero di chiavi in funzione del numero di utenti. Nella realtà lo schema appena descritto non è molto utilizzato perché piuttosto complesso. Non è raro invece l’utilizzo di tecniche miste che uniscono la semplicità della crittografia simmetrica con la sicurezza di quella asimmetrica. L’esempio più immediato riguarda la tecnica impiegata nel protocollo SSL25 in cui, nella comunicazione tra due entità, viene creata “al volo” una chiave segreta, detta chiave di sessione, per cifrare il messaggio. La chiave a sua volta viene cifrata con la chiave pubblica del destinatario ed allegata al messaggio stesso. 2.3.1 I principali algoritmi di cifratura asimmetrica La crittografia asimmetrica consente di cifrare solo blocchi di dati di dimensione fissa. E’ infatti impossibile cifrare i dati in ingresso bit a bit come avveniva negli algoritmi simmetrici a flusso. Possiamo quindi dire che la crittografia asimmetrica lavora solo su blocchi di bit. 25 “Secure Socket Layer”, chiamato nelle sue ultime versioni con il nome di “Transport Layer Security” (TLS). 27 Capitolo 2 In questo paragrafo verranno introdotti alcuni tra i più noti algoritmi di crittografia asimmetrica, andando ad esaminare più in dettaglio solo uno tra questi, l’algoritmo RSA, che, oltre ad essere forse il più famoso, è quello impiegato in questo progetto di firma digitale. Rivest Shamir Adelman (RSA) L’algoritmo RSA è stato sviluppato da Ron Rivest, Adi Shamir e Len Adelman26. Descritto per la prima volta nel 1977 è stato poi brevettato nel 1983 negli Stati Uniti dal MIT27. Si basa sul problema matematico della fattorizzazione di un numero, che consiste nel trovare quei numeri primi che, moltiplicati tra loro, forniscono il numero dato. E’ questo un problema tanto più complesso quanto più è grande il numero iniziale. Forniamo ora una breve descrizione dell’algoritmo. Per generare la coppia di chiavi si eseguono queste operazioni: 1. si scelgono due numeri primi p e q abbastanza grandi da garantire un adeguato livello di sicurezza; 2. si calcola il prodotto n = p ⋅ q (detto modulo); 3. si sceglie un numero e (detto esponente pubblico) che sia più piccolo e primo rispetto a ( p − 1) ⋅ (q − 1) ; 4. si calcola un numero d (detto esponente privato) tale che: (e ⋅ d ) ⋅ mod[( p − 1) ⋅ (q − 1)] = 1 ; 5. la coppia (n, e ) costituisce la chiave pubblica, mentre la coppia (n, d ) costituisce la chiave privata. A questo punto le chiavi sono state create ed i fattori p e q possono essere distrutti (anche se in realtà vengono mantenuti all’interno della chiave privata). Due chiavi create in questo modo sono chiaramente legate tra loro (dal fattore n) e inoltre per calcolare d da e (e quindi la chiave privata a partire da quella pubblica) non basta conoscere n, ma serve anche il prodotto ( p − 1) ⋅ (q − 1) . In ogni caso è un’operazione molto costosa in termini di tempo, soprattutto se n è grande. 26 27 Il nome RSA è infatti acronimo dei loro cognomi. Massachusetts Institute of Technology. 28 Crittografia L’operazione di cifratura avviene nel seguente modo: 1. l’utente si procura la chiave pubblica del destinatario (n, e ) ; 2. il messaggio in chiaro m viene cifrato attraverso l’operazione c = m e mod(n ) , in cui “c” indica il messaggio cifrato. L’operazione di decifratura prevede che l’utente, con la propria chiave privata (n, d ) , compia la seguente operazione: m = c d mod(n ) . L’algoritmo permette anche di invertire l’ordine di utilizzo delle chiavi, cioè è possibile cifrare con la chiave privata e decifrare con quella pubblica. In ogni caso il procedimento restituisce il messaggio originale solo se le chiavi utilizzate nella cifratura e nella decifratura appartengono alla stessa coppia, e sono quindi legate dal fattore n secondo la relazione descritta nel punto 4. Da questa breve presentazione nasce però un dubbio sulla sicurezza dell’algoritmo, in quanto si basa sull’assunzione che il calcolo di e c mod(n ) (con n numero composto di cui non si conoscono i fattori) sia computazionalmente intrattabile28. Il dubbio nasce dal fatto che questa assunzione non è mai stata dimostrata! Digital Signature Algorithm (DSA) L’algoritmo DSA, proposto nel 1991 dal NIST per l’utilizzo nell’ambito dello standard DSS (Digital Signature Standard), è stato progettato appositamente per la realizzazione di firme digitali. Il procedimento di cifratura infatti prevede anche l’utilizzo di una funzione di Hash29 (nello specifico la funzione SHA) ed apposite operazioni di verifica della firma. Esso si basa sulla difficoltà di risoluzione del problema del logaritmo discreto. In linea teorica sarebbe possibile ricavare la chiave privata calcolando il logaritmo discreto di quella pubblica. Nella realtà però questa operazione è impraticabile a causa della grandezza dei numeri in gioco. Tale algoritmo però non viene molto utilizzato in quanto esistono algoritmi ritenuti molto più sicuri. 28 29 Nota come “assunzione RSA”. La funzione di Hash sarà illustrata tra poco in questo stesso capitolo. 29 Capitolo 2 2.4 Considerazioni generali sulla sicurezza degli algoritmi crittografici Ogni algoritmo crittografico viene studiato dai crittoanalisti per valutarne l’effettiva robustezza a vari tipi di attacchi e quindi misurarne la sicurezza. Nel corso di tutto il capitolo sono stati presentati molti algoritmi diversi tra loro, ognuno con determinate caratteristiche che lo rendevano più o meno sicuro di un altro. Come detto ad inizio capitolo, però, l’evoluzione crittografica più importante si è verificata quando è stato abbandonato il principio di security by obscurity secondo il quale un sistema (in questo caso un particolare algoritmo crittografico) risulta sicuro fintantoché rimane segreto alle persone non autorizzate ad accedervi, in quanto, non conoscendolo, non sono in grado di violarlo. Ad esso si è sostituito il concetto, che è diventato un fondamento della crittografia moderna, secondo il quale la sicurezza di un sistema crittografico dipende esclusivamente dalla conoscenza della chiave. Tutti gli algoritmi introdotti nei paragrafi dedicati alla crittografia simmetrica e asimmetrica sono infatti di dominio pubblico ed il loro funzionamento è noto a chiunque, eppure questo non costituisce una minaccia alla loro sicurezza, anzi, al contrario, è un incentivo al loro sviluppo, in quanto è più facile scoprirne difetti e debolezze e quindi porvi rimedio. Ciononostante la chiave non è altro che una sequenza di bit generata in modo più o meno casuale che, in linea teorica, può sempre essere ricavata. Esistono infatti dei metodi di ricerca esaustiva che consentono di risalire alla chiave utilizzata nella cifratura provando ad applicare l’algoritmo ad un testo cifrato, impiegando chiavi sempre diverse, fino a che non si ottiene un risultato sensato. Questo modo di procedere è noto come “attacco a forza bruta” (brute force attack). Il successo di questo tipo di attacchi dipende dal numero massimo di tentativi che possono essere fatti, ovvero dal numero massimo di chiavi che quel particolare algoritmo può accettare, cioè dal keyspace. Per darci un’idea di quanto influisca la lunghezza della chiave in un attacco a forza bruta si può considerare l’esempio riportato in tabella che indica 30 Crittografia i tempi necessari al completamento dell’attacco variando le dimensioni della chiave, sotto l’ipotesi di poter effettuare un milione di tentativi al secondo. Lunghezza della chiave Dimensioni del keyspace Tempo di ricerca 32 bit 4,29*109 1,2 ore 40 bit 1,1*1012 13 giorni 48 bit 56 bit 64 bit 2,81*10 14 8,9 anni 7,21*10 16 2.300 anni 1,84*10 19 580.000 anni Tabella 1. Tempo di ricerca necessario per un attacco a forza bruta nell’ipotesi che si possano effettuare un milione di tentativi al secondo. Ancora una volta la sicurezza del sistema è legata solo alla chiave ed in particolare ad una sua caratteristica che è la lunghezza. Si può decidere di scegliere una chiave talmente lunga da rendere materialmente impossibile un attacco a forza bruta30, questo però comporterebbe anche una notevole riduzione delle prestazioni del nostro sistema, in quanto una chiave più lunga richiederebbe calcoli più complessi e quindi un rallentamento delle operazioni di cifratura e decifratura. Occorre quindi trovare un giusto compromesso tra il grado di sicurezza che si vuole raggiungere e la velocità di esecuzione richiesta31. In generale, quando si vuole realizzare un sistema di sicurezza, bisogna sempre tenere presente che tipo di dati si stanno proteggendo. Il livello di sicurezza del sistema deve essere tanto più alto quanto più sono sensibili le informazioni in gioco. In quest’ottica è opportuno seguire due linee guida: • il costo32 richiesto per violare l’algoritmo deve essere superiore al valore dei dati protetti; • il tempo richiesto per violare l’algoritmo deve risultare superiore al tempo per cui i dati cifrati devono rimanere segreti. 30 Si intende con le tecnologie attualmente disponibili. In futuro un aumento delle capacità di calcolo o una nuova tecnica di crittoanalisi potrebbe ridurre drasticamente i tempi necessari al recupero della chiave. 31 Si pensi in particolare al caso della Smart Card che sono dispositivi estremamente sicuri, ma con limitatissime risorse di calcolo. 32 Si intende “costo” non solo in senso monetario, ma anche in termini di risorse e tempo impiegati. 31 Capitolo 2 Sotto queste ipotesi, qualsiasi tentativo di attacco, anche se andasse a buon fine, non comporterebbe alcun vantaggio al soggetto attaccante. 2.5 Funzione di Hash La funzione di Hash è un processo di trasformazione dei bit, che si differenzia dagli algoritmi crittografici finora trattati. Un qualsiasi messaggio elaborato tramite funzione di Hash restituisce una stringa di bit di lunghezza fissa (solitamente 128 o 160 bit), detta message digest (impronta digitale). Tale impronta rappresenta una sorta di riassunto, o sintesi matematica, del messaggio. Andiamo ora ad enunciare le proprietà che caratterizzano la funzione di Hash e che la rendono “crittograficamente sicura” : • è applicabile a qualsiasi sequenza di dati di qualsiasi tipo e dimensione; • il risultato della sua applicazione è una stringa di bit di dimensione fissa (128 o 160bit) indipendente dalla dimensione del messaggio originale; • la variazione di un solo bit del messaggio originale comporta la variazione dell’intero digest; • è una funzione a senso unico (one way), cioè risulta impossibile risalire al messaggio originale partendo dal digest; • è una funzione senza collisioni (collision free), nel senso che è impossibile trovare due messaggi diversi tra loro che restituiscano lo stesso digest. E’ necessario a questo punto fare una precisazione. Negli ultimi due punti si è utilizzato il termine “impossibile”. Questo in realtà non è del tutto corretto, sarebbe più opportuno parlare di “bassa probabilità” piuttosto che di “impossibilità”. Come abbiamo detto, la funzione di Hash restituisce sempre una sequenza di lunghezza fissa indipendentemente dal tipo e dalla dimensione del messaggio originale. In termini più precisi si può dire che la funzione di Hash realizza una applicazione non iniettiva che ha come dominio uno spazio a dimensione infinita (che rappresenta l’insieme di tutti i messaggi in chiaro di 32 Crittografia qualsiasi lunghezza) e come codominio uno spazio a dimensione finita (che rappresenta l’insieme di tutti i possibili digest di lunghezza prefissata). Figura 8. Rappresentazione della funzione di Hash come applicazione dall’insieme infinito V dei messaggi in chiaro all’insieme finito W di tutti i possibili digest di lunghezza prefissata. Di fatto effettua una compressione dello spazio, per questo motivo prima è stata utilizzata l’espressione di “riassunto matematico” per definire l’impronta di un messaggio. Risulta però matematicamente impossibile (e questa volta il termine è impiegato correttamente) che ad ogni elemento del dominio corrisponda un unico elemento del codominio! La matematica comunque ci assicura anche che la probabilità che a due elementi distinti del dominio corrisponda uno stesso elemento del condominio è, se pur diversa da zero, estremamente bassa. In senso pratico non si sono ancora trovati due messaggi diversi che abbiano lo stesso digest. Da questa considerazione si può ritenere ragionevole l’assunto che la funzione di Hash risulti crittograficamente sicura, cioè a senso unico e priva di collisioni. Una conseguenza immediata di quest’ultima proprietà è che può risultare altrettanto ragionevole dire che “due messaggi che presentato lo stesso digest sono uguali tra loro”. Questa è una definizione particolarmente interessante in quanto ci permette di utilizzare la funzione di Hash ogniqualvolta ci interessi confrontare due messaggi tra loro per verificarne l’uguaglianza. Essendo i 33 Capitolo 2 messaggi di dimensioni arbitrarie, infatti, risulta sicuramente più comodo eseguire il confronto direttamente sui digest che sono a lunghezza fissa. Questa tecnica apre la strada ad una delle più importanti applicazioni della funzione di Hash: la firma digitale. Prima di concludere il paragrafo facciamo una veloce panoramica sugli algoritmi che la funzione di Hash utilizza: • MD5 (Message Digest 5): è un algoritmo sviluppato dai laboratori RSA che fornisce digest di 128 bit; • SHA (Secure Hash Algorithm): chiamato anche Secure Hash Standard (SHS) è un algoritmo pubblicato dal Governo degli Stati Uniti che produce digest di 160 bit; • SHA-1: è la versione migliorata del precedente algoritmo. Produce anch’esso digest di 160 bit, ma, a differenza del suo predecessore, l’SHA-1 non è stato ancora violato. 2.6 Firma Digitale Si è già discusso sulla tendenza, da parte di enti pubblici e privati, ad eliminare (o quantomeno ridurre) la documentazione cartacea e favorire quella digitale, evidenziando i vantaggi che questo comporterebbe in termini di: • migliore gestione degli archivi; • più efficienza nei servizi; • minor costo; • realizzazione di sistemi sicuri che garantiscano: autenticazione d’identità, integrità dei dati, autenticità dei dati, non ripudio. La firma digitale rende possibile tutto questo in quanto, lo dice la parola stessa, consente la firma di documenti direttamente in formato digitale. Questo processo deve essere ovviamente regolamentato da opportune normative giuridiche che garantiscano adeguati livelli di sicurezza, ma di queste ci occuperemo nel prossimo paragrafo. La firma digitale è una tecnologia matematico-informatica che consente la creazione e la gestione di documenti informatici sicuri, ovvero documenti dei 34 Crittografia quali sia possibile attribuirne la provenienza soggettiva e verificarne l’integrità del contenuto dal momento della loro formazione. Alla base del processo di firma digitale troviamo due concetti già noti, che sono la crittografia asimmetrica e la funzione di Hash. In particolare, della crittografia asimmetrica, si sfrutta l’algoritmo a chiave di decifratura pubblica secondo il quale un documento viene cifrato con la chiave privata del mittente consentendo sempre la sua piena identificazione. La funzione di Hash invece ci consente di rendere la cifratura più semplice e veloce, in quanto non viene cifrato il documento originale, ma bensì la sua impronta (digest) che sappiamo essere di lunghezza fissa. Vediamo ora come si realizza la firma digitale di un qualsiasi documento informatico: Mittente Text Digest Hash Cifratura Firma KprivM Text + Firma Figura 9. Processo di firma digitale di un documento informatico. Il processo prevede tre stadi principali: • generazione del digest: il messaggio originale (Text) viene elaborato mediante la funzione di Hash ottendo così la sua impronta (Digest); • generazione della firma: il digest viene cifrato con la chiave privata del mittente (KpriM); • apposizione della firma: al messaggio in chiaro si allega la firma precedentemente ottenuta (ed eventualmente il certificato contenente la chiave pubblica di decifratura). 35 Capitolo 2 Il documento firmato così ottenuto viene inviato al destinatario che, a sua volta, dovrà eseguire dei controlli per assicurarsi della validità della firma. Le operazioni che compie sono riportate nel seguente schema: Hash Text Digest Destinatario Text + Firma Confronto Firma Decifratura Digest presunto KpubM Figura 10. Processo di verifica della firma digitale. Il processo di verifica della firma digitale prevede i seguenti stadi: • il documento firmato viene diviso nella parte di documento in chiaro ed in quella relativa alla firma e le due parti vengono elaborate separatamente; • il documento in chiaro viene sottoposto alla funzione di Hash e se ne calcola il digest; • la firma viene decifrata con la chiave pubblica del mittente (recuperata dal certificato relativo al mittente stesso) ottenendo così il “digest presunto”, ovvero l’impronta del documento originale al momento della firma; • i due digest vengono tra loro confrontati e a questo punto ci sono due possiblità: o i digest risultano uguali: allora la firma è valida ed il documento è integro; o i digest sono diversi: significa che il documento ha subito delle modifiche (dolose o accidentali) dal momento in cui è stato firmato dal mittente a quello in cui è stato ricevuto dal destinatario. La firma digitale così ottenuta lega l’entità, che detiene l’uso esclusivo della chiave privata, ai dati, tramite l’impiego del digest. Infatti ogni firma, anche se apposta con la stesa chiave privata, è unica e diversa in relazione ad un diverso documento. 36 Crittografia Questo tipo di firma offre tutte le garanzie di sicurezza di una normale firma autografa, portando in più due vantaggi fondamentali: • è più difficile da falsificare: in quanto si dovrebbe entrare in possesso della chiave privata del mittente; • garantisce l’integrità del documento: la modifica anche di un solo bit del documento comporta la variazione dell’intero digest. Prima di discutere gli aspetti legali vorrei puntualizzare un aspetto che è passato un po’ in secondo piano per dare maggiore risalto ai processi di firma e verifica. Da quanto detto il documento firmato, costituito dal testo in chiaro con allegata la firma, viene spedito al destinatario su un canale telematico. E’ opportuno precisare che in questa operazione vengono utilizzati canali di comunicazione sicuri (come ad esempio SSL) e quindi in rete viaggiano sempre messaggi cifrati. In questo modo rimane garantita la segretezza della trasmissione. Inoltre non è necessario che il documento e la sua firma si trovino sullo stesso supporto digitale, le due parti possono anche essere separate e spedite su canali diversi senza che per questo venga meno il legame esistente fra di esse33. 2.6.1 Aspetti legali della firma digitale La sicurezza di una operazione giuridica, cioè la possibilità di dimostrarne efficacemente l’esistenza e il contenuto, deriva dal poter disporre di una documentazione sicura, ossia non alterabile o che mantenga traccia delle eventuali alterazioni. Oggi la funzione di mezzo probatorio è assolta fondamentalmente dai documenti cartacei, tuttavia l’impiego sempre più frequente delle nuove tecnologie ha fatto sorgere l’esigenza di riconoscere uno status giuridico ai documenti su supporto informatico e la loro validità ai fini probatori. A questo 33 Con l’accortezza che il destinatario disponga di un sistema in grado di riconoscere e recuperare le due parti. 37 Capitolo 2 scopo devono essere garantiti i requisiti fondamentali di integrità, non modificabilità e autenticazione. Nel caso del tradizionale supporto cartaceo questo è possibile grazie all’inscindibilità fisica tra contenuto (il testo del documento) e contenitore (il foglio di carta) e all’apposizione della sottoscrizione autografa. Diversamente, nel caso dei documenti informatici, il medesimo contenuto è facilmente riproducibile su diversi contenitori, ed ogni copia risulta esattamente identica all’originale. Grazie alle elaborazioni previste nel processo di firma digitale è possibile rendere il documento informatico altrettanto sicuro garantendo tutti i requisiti necessari. La legislazione italiana è stata tra le prime a livello mondiale a dettare una disciplina organica in materia di firma digitale e documento informatico. L’introduzione nel nostro ordinamento dell’istituto della firma digitale è avvenuto in modo progressivo. Il primo passo risale alle normativa del 15 marzo 1997 noto come “Legge Bassanini” in materia di riforma della Pubblica Amministrazione e di semplificazione amministrativa. Esso testualmente disponeva che “gli atti, dati e documenti formati dalla pubblica amministrazione e dai privati con strumenti informatici o telematici, i contratti stipulati nelle medesime forme, nonché la loro archiviazione e trasmissione con strumenti informatici, sono validi e rilevanti a tutti gli effetti di legge”. In attuazione da quanto previsto da tale norma il 10 novembre 1997 è stato emesso il decreto legge n.513 contenente i criteri e le modalità per la formazione, l’archiviazione e la trasmissione di documenti con strumenti informatici e telematici. In seguito, l’8 febbraio 1999, fu emanato un successivo decreto recante le regole tecniche per la formazione, la trasmissione, la duplicazione, la riproduzione e la validazione, anche temporale, dei documenti informatici. Successivamente l’Autorità per l’Informatica nella Pubblica Amministrazione34 ha elaborato uno schema di Testo Unico delle disposizioni legislative e regolamentari in materia di documentazione amministrativa, applicabile per la parte relativa ai documenti informatici e alla firma digitale 34 Oggi CNIPA: Centro Nazionale per l’Informatica nella Pubblica Amministrazione. 38 Crittografia anche nei rapporti tra privati. Tale testo è stato approvato definitivamente il 6 ottobre 200 ed è entrato in vigore il 28 dicembre dello stesso anno. Questa serie di normative ha sancito la totale equiparazione della firma digitale alla sottoscrizione autografa e del documento informatico firmato digitalmente alla scrittura privata, purché conforme alle disposizioni del Testo Unico. 39 Capitolo 2 40 Public Key Infrastructure Capitolo 3. PUBLIC KEY INFRASTRUCTURE 41 Capitolo 3 3.1 Introduzione Nel capitolo precedente si è discusso il funzionamento di alcune tecniche crittografiche e si sono fatte delle considerazioni sulla loro sicurezza. In particolare abbiamo visto che le applicazioni di firma digitale utilizzano algoritmi crittografici asimmetrici e che la sicurezza di questi algoritmi è legata esclusivamente alla segretezza della chiave privata. Di questo ovviamente si deve occupare l’utente stesso cercando di divulgare il meno possibile le informazioni riguardanti la sua chiave privata e soprattutto evitando di delegarne l’uso a terzi. Si consiglia l’utente di dotarsi di apposite Smart Card che rendono il compito più semplice. Questo però non basta per garantire del tutto la sicurezza del sistema. La firma digitale lega infatti un documento non al suo autore, ma alla chiave privata impiegata nell’operazione di cifratura. Si ha quindi bisogno di una entità che ci assicuri che quella chiave appartiene ad una certa persona. Inoltre un sistema informatico che faccia uso della firma digitale, per essere completamente funzionante, deve poter gestire in modo corretto lo scambio e la divulgazione delle chiavi pubbliche. Si introduce così il concetto di infrastruttura a chiave pubblica35, in cui un’autorità fidata si preoccupa di identificare e autenticare tutti gli utenti che vogliano usufruire dei suoi servizi e garantisce inoltre l’appartenenza di una chiave pubblica ad uno specifico utente mediante l’emanazione di un certificato. Si può definire una PKI come un insieme di hardware, software, risorse umane, protocolli, regole e procedure necessarie per fornire supporto all’utilizzo su larga scala dei sistemi di crittografia asimmetrici. Prima di procedere alla descrizione di una PKI ritengo opportuno spiegare il meccanismo di gestione delle chiavi pubbliche. Il prossimo paragrafo, infatti, introdurrà il concetto di certificato a chiave pubblica, che verrà poi ripreso nella parte dedicata agli standard. 35 PKI: Public Key Infrastructure 42 Public Key Infrastructure 3.2 Il certificato a chiave pubblica Un certificato a chiave pubblica è un documento informatico che associa una chiave pubblica ad un soggetto. In esso dovranno quindi essere scritti alcuni dati necessari all’identificazione del soggetto stesso. Per risultare valido, un certificato deve essere firmato da una apposita entità (l’Autorità di Certificazione) che garantisca l’effettiva appartenenza della chiave pubblica al soggetto in questione. Un certificato a chiave pubblica deve quindi contenere: • Informazioni varie sul formato del certificato; • Subject: dati identificativi del soggetto; • Chiave pubblica del soggetto e informazioni relative (algoritmo di cifratura utilizzato, impieghi previsti e altro); • Periodo di validità del certificato; • Issuer: dati identificativi dell’emettitore del certificato; • Signature: un digest delle informazioni precedenti cifrato con la chiave privata dell’emettitore. In pratica un utente (soggetto) si rivolge ad una Autorità di Certificazione per farsi rilasciare il certificato a chiave pubblica. In una comunicazione tra due entità il mittente appone la firma sul documento originale ed invia il documento firmato ed il certificato. Il destinatario deve verificare l’attendibilità del certificato prima ancora di verificare la firma. Deve quindi decifrare la signature con la chiave pubblica dell’issuer ottenendo un digest presunto da confrontare con il digest ricavato da tutti gli altri campi del certificato elaborati con la funzione di Hash. Se il confronto ha esito positivo allora il certificato è valido e si procede alla verifica della firma. Le figure sottostanti mostrano i processi di firma e verifica di un certificato: 43 Capitolo 3 Root CA private key Root certificate enc Data Root CA public key digest hash Signature Subject certificate enc Data digest hash Subject public key Signature Figura 11. Firma del certificato da parte di un soggetto e di una Autorità di Certificazione. Root CA certificate Data Root CA public key Signature dec Presumed digest Subject certificate Data hash digest Subject public key =? Ok Signature Figura 12. Verifica di un certificato a chiave pubblica. L’impiego dei certificati a chiave pubblica non è comunque obbligatorio. Nel Testo Unico36 si afferma che l’attività di certificazione è necessaria solo ove si vogliano conseguire gli effetti di “validità e rilevanza a tutti gli effetti di legge”. E’ del tutto lecito infatti scambiarsi documenti con la tecnica delle chiavi asimmetriche senza ricorrere all’uso dei certificati, ad esempio nel caso in cui si dispone di una rete di piccole dimensioni in cui ci si scambiano dati non troppo riservati e quindi si può tollerare un livello di sicurezza meno restrittivo. 36 Vedi paragrafo § 2.6.1 “Aspetti legali della firma digitale”. 44 Public Key Infrastructure La certificazione diventa necessaria quando si desidera che il documento acquisti pieno valore probatorio. In ultimo si può fare un’osservazione sul fatto che un certificato a chiave pubblica lega una chiave pubblica ad una certa persona (che abbiamo chiamato soggetto). In realtà eravamo partiti dall’esigenza di legare la chiave privata al soggetto in questione. Una PKI in realtà non può gestire le chiavi private (per evidenti motivi di sicurezza), ma abbiamo visto il legame matematico forte che associa indissolubilmente le chiavi pubblica e privata. Un certificato quindi lega un soggetto ad una coppia di chiavi, fornendosi della sola informazione di cui può disporre, che è la chiave pubblica. 3.2.1 Ciclo di vita di un certificato L’emissione effettiva di un certificato elettronico da parte di una Autorità di Certificazione a favore di un utente finale deve essere preceduta da una fase di registrazione dell’utente stesso. Attraverso il processo di registrazione l’utente richiedente il servizio di certificazione si identifica presso l’autorità preposta al servizio di registrazione. Le credenziali che in questa fase l’utente deve sottoporre all’Autorità di Registrazione dipendono fortemente dalle modalità e procedure di registrazione definita nell’ambito di una politica di sicurezza. Il processo di registrazione stabilisce una relazione iniziale tra utente finale e Autorità di Certificazione. L’utente finale, una volta attestata l’autenticità della sua identità, viene registrato nel dominio di fiducia gestito dalla CA. L’obiettivo di primaria importanza del processo di registrazione è quindi quello di garantire che la chiave pubblica, di cui un certo utente finale richiede la certificazione, appartenga effettivamente al nome del richiedente. Terminata la fase di registrazione, l’utente può richiedere l’emissione di un certificato elettronico. La procedura di generazione di un certificato elettronico consiste dei seguenti passaggi: • L’utente finale sottopone all’Autorità di Certificazione le informazioni da certificare. 45 Capitolo 3 • L’Autorità di Certificazione può verificare l’accuratezza delle informazioni presentate in accordo a politiche e standard applicabili. • L’Autorità di Certificazione firma le informazioni generando il certificato a chiave pubblica e lo inserisce in un database pubblico. Solitamente la CA archivia una copia del certificato anche sul suo database privato. Ogni operazione di generazione dei certificati elettronici viene registrata su un archivio di registrazione dati. Ogni certificato elettronico generato ha una validità temporale limitata, al termine della quale va sostituito. Il periodo di validità di un certificato, in assenza di compromissioni o di usi illeciti, garantisce l’utente che deve utilizzare tale certificato che la chiave pubblica possa essere utilizzata per lo scopo per cui è stata generata e che l’associazione tra la chiave pubblica e le altre informazioni contenute nel certificato sia ancora valida. 3.2.2 Revoca di un certificato L’operazione di revoca di un certificato costituisce una fase molto critica della gestione del ciclo di vita dei certificati. Un certificato elettronico deve essere revocato in presenza di almeno una delle seguenti condizioni: • Compromissione rilevata, o semplicemente sospettata, della chiave privata corrispondente alla chiave pubblica contenuta nel certificato. • Cambiamento di una qualsiasi delle informazioni contenute nel certificato elettronico o delle condizioni iniziali di registrazione. La revoca del certificato elettronico è effettuata dalla Autorità di Certificazione e generalmente viene avviata su richiesta dello stesso utente finale. In questo caso, data la criticità e le implicazioni dell’operazione di revoca, è indispensabile predisporre un sistema di autenticazione della richiesta di revoca. Ogniqualvolta un certificato viene revocato, tutti gli utenti appartenenti alla stessa infrastruttura devono essere informati dell’avvenuta revoca. Il meccanismo più comunemente utilizzato per la notifica su larga scala di avvenute revoche fa uso della cosiddetta lista di revoca dei certificati (CRL: 46 Public Key Infrastructure Certificate Revocation List). La gestione di tali liste è delegata alla Certification Authority. Nell’ambito del dominio amministrato ogni CA pubblica periodicamente una struttura dati contenente l’elenco dei certificati revocati, ossia una lista firmata digitalmente dalla CA che riporta i certificati revocati, la data temporale in cui è avvenuta la revoca ed eventualmente il motivo della revoca. Di seguito è schematizzato il formato di una lista di revoca dei certificato conforme allo standard X509. Figura 13. Formato di una CRL secondo lo standard X509. Le liste di revoca giocano un ruolo di fondamentale importanza in tutti i processi crittografici, in quanto devono essere consultate sia in fase di cifratura, sia in fase di verifica della firma. Infatti, prima di cifrare un messaggio, va verificato che la chiave pubblica che si deve usare per la cifratura appartenga ad un certificato valido. Analogo discorso vale per la verifica della firma, poiché una firma può essere ritenuta valida solo se il certificato del firmatario, oltre ad essere autentico ed integro, non è stato revocato. 47 Capitolo 3 3.3 Certification Authority e Registration Authority Le principali entità che costituiscono una PKI sono: • Certification Authority (CA): o Autorità di Certificazione (già menzionata in precedenza) è l’entità che rilascia i certificati. Una CA garantisce per un certo numero di utenti o per altre Autorità di Certificazione. E’ un punto molto critico della struttura in quanto la compromissione di una CA (ad esempio la venuta a conoscenza della sua chiave privata da parte di terzi) potrebbe compromettere la sicurezza dell’intera PKI. E’ quindi opportuno che sia l’hardware che il software che hanno accesso diretto alla chiave privata della CA si trovino su una macchina off-line. • Registration Authority (RA): o Autorità di Registrazione, è l’entità che si occupa della creazione delle chiavi, della distribuzione dei certificati, di assegnare gli identificativi (alias) ai client, di archiviare chiavi e certificati, di generare e gestire le richieste di certificato e altro ancora. In pratica svolge tutte quelle funzioni che servono per interfacciare l’utente con l’Autorità di Certificazione. 3.3.1 Modello di fiducia Abbiamo appena detto che una Autorità di Certificazione garantisce per un certo numero di utenti o, eventualmente, per altre Autorità di Certificazione. Questo significa che ogni utente che appartiene ad una certa AC è a conoscenza delle chiavi pubbliche di tutti gli utenti appartenenti alla stessa AC e può quindi verificare la firma di ognuno di essi. Nel caso fossero coinvolti gli utenti di diverse AC, è necessario che le AC in questione emettano degli appositi certificati (detti cross certificate) che consentano ad ogni utente di fidarsi della AC esterna. La modalità con cui l’utente arriva a fidarsi di un certificato emesso da una AC a lui sconosciuta, partendo dalla fiducia che egli ripone in una singola 48 Public Key Infrastructure AC a lui nota, viene indicata come modello di fiducia (Trust Model) dell’infrastruttura. Più precisamente un modello di fiducia specifica in che modo si può porre fiducia nell’asserzione che un utente remoto sia effettivamente chi dice di essere (autenticazione) e che abbia effettivamente i diritti di accesso al servizio o informazione che sta richiedendo (autorizzazione). Quindi il modello di fiducia si pone alla base dell’infrastruttura a chiave pubblica, specificando quali procedure riescono a garantire il corretto funzionamento dei servizi di sicurezza offerti dall’infrastruttura stessa. Un esempio di modello di fiducia è il cosiddetto web of trust (rete di fiducia) utilizzato dal programma di cifratura PGP. In questo particolare modello non si fa ricorso ad Autorità di Certificazione centralizzate, ma sono gli utenti stessi a certificarsi reciprocamente le chiavi di cui possono garantire la provenienza, firmandole. Tale meccanismo si basa sul presupposto che un utente firmi la chiave pubblica altrui solo quando ha la certezza sull’identità del suo titolare. Nessuno però può assicurare che venga firmata una chiave pubblica sulla quale non sono stati esercitati accurati controlli. Questo modello, anche se del tutto funzionale, non ha validità giuridica in quanto ritenuto poco sicuro. Esistono comunque altri modelli, e li vedremo nel prossimo paragrafo, che prevedono strutture reticolari o strutture gerarchiche ad albero, e che hanno maggiore valenza legale. 3.3.2 Tipologie di collegamenti fra Autorità di Certificazione In genere una PKI è composta da diversi Certificatori37 ognuno dei quali garantisce per un certo numero di utenti. Nasce però un problema quando un utente che si riferisce ad una CA riceve un messaggio da un altro utente che fa riferimento ad un’altra CA. Non conoscendo quest’ultima l’utente non è in grado di identificare il mittente, quindi cade un fondamentale requisito di sicurezza. Da qui la necessità di far interagire tra loro le varie CA. 37 Nel “Testo Unico” dell’AIPA il nome di “Certification Authority” è stato tradotto in “Certificatore”, anche se risulta di uso più comune la traduzione letterale “Autorità di Certificazione”. I due termini indicano comunque la stessa entità ed in questo testo sono utilizzati in modo del tutto equivalente. 49 Capitolo 3 Esistono due modelli principali di collegamento fra Autorità di Certificazione: • Modello reticolare: ogni CA nasce come autorità locale di cui si fidano tutti e solo gli utenti appartenenti ad essa. • Modello ad albero: prevede una CA globale di cui tutti si fidano, che distribuisce opportunamente le sue mansioni ad altre CA locali, ognuna facente capo ad una comunità ristretta di utenti o ad altre CA ancora più localizzate. Modello reticolare La figura sottostante indica un esempio di PKI composta da quattro Autorità di Certificazione ognuna facente capo a tre utenti. Figura 14. PKI strutturata secondo il modello reticolare. L’interoperabilità tra Autorità di Certificazione diverse è ottenuta mediante accordi fra le AC stesse. Si supponga che l’utente U11 riceva un messaggio firmato dall’utente U32 e ne voglia quindi verificare la firma. L’Autorità cui U11 fa riferimento (AC1) non possiede la chiave di U32, quindi non è in grado di fornirla direttamente. E’ allora necessario che AC1 si metta in contatto con AC2 chiedendogli la chiave di U32. 50 Public Key Infrastructure In particolare, nella comunicazione tra le due Autorità di Certificazione, AC1 verifica in primo luogo che AC2 adotti politiche di sicurezza uguali, o comunque che garantiscano un livello di sicurezza almeno pari a quello garantito dalle proprie politiche, in seguito AC1 rilascia un certificato, detto cross certificate, che: • garantisce che una chiave certificata da AC2 è valida; • contiene la chiave di verifica dei certificati di AC2. Tale certificato, una volta reso noto a tutti gli utenti appartenenti ad AC1, permette loro di fidarsi di una chiave certificata da AC2. E’ proprio grazie a questi cross certificate che un’Autorità di Certificazione ripone la sua fiducia su un’altra AC. Di fatto un utente può verificare la firma di un qualsiasi altro utente la cui AC abbia instaurato un cross certificate con la propria. Bisogna notare che questo modello prevede che, agli occhi di un utente, sia sempre la propria Autorità di Certificazione a garantire l’autenticità delle firma delle altre AC, in linea con un modello di distribuzione della fiducia che prevede che ogni entità si fidi soltanto della AC di appartenenza. Il rilascio dei cross certificate però presenta aspetti problematici. Prima di rilasciare un cross certificate una Autorità di Certificazione deve assicurarsi che l’altra AC garantisca un livello di sicurezza almeno pari a quello da lei offerto. Questo in realtà non capita mai, perché le AC fanno riferimento a realtà ambientali diverse fra loro e probabilmente anche di diversi paesi, quindi soggette a specifiche politiche di sicurezza. Quello che in effetti è il vantaggio di una struttura reticolare, cioè collegare diverse AC indipendenti fra loro, senza creare un sistema centralizzato, si rivela un’arma a doppio taglio, in quanto proprio questa indipendenza può manifestarsi come un limite alle possibilità di comunicazione tra gli utenti. In generale il livello di sicurezza di una Autorità di Certificazione, di conseguenza l’affidabilità dei certificati da essa rilasciati, risulta determinato dai seguenti fattori: • gli algoritmi crittografici impiegati nei processi di firma digitale; • le politiche di accesso agli elaboratori adottate; • il software utilizzato; 51 Capitolo 3 • le procedure per l’identificazione e l’autenticazione preliminare degli utenti. Modello ad albero Facendo uso delle stesse convenzioni del caso precedente, riportiamo l’esempio di una PKI composta da quattro Autorità di Certificazione strutturata secondo il modello ad albero. Figura 15. PKI strutturata secondo il modello ad albero. Nel modello ad albero esiste un’unica Autorità di Certificazione globale della quale tutti gli utenti dell’infrastruttura di fidano. Ogni utente però non interagisce direttamente con essa, ma con altre AC, ciascuna locale ad una comunità ristretta di utenti. Questo modello prevede che le AC siano distribuite gerarchicamente, secondo una struttura ad albero, in cui ogni livello corrisponde ad una Autorità di Certificazione con un ruolo diverso all’interno dell’infrastruttura. Ogni AC garantisce per tutti i livelli ad essa sottostanti firmando i certificati a chiave pubblica con la propria chiave privata. La AC globale, che è all’apice della gerarchia, garantisce per se stessa con un certificato autofirmato. 52 Public Key Infrastructure Si può definire il modello ad albero come un caso particolare del modello reticolare, considerando i certificati che legano le AC “padre” con le AC “figlie” dei veri e propri cross certificate. Ciò che distingue i due modelli è il fatto che normalmente una AC padre rilascia un cross certificate per ogni AC figlia, mentre non è necessario il procedimento inverso, cioè che le AC figlie rilascino un cross certificate per la AC padre. Questo perché la struttura ad albero è accentrata ed il possesso della chiave pubblica della AC radice permette la verifica di qualsiasi certificato rilasciato da qualsiasi altra AC dell’albero. Un utente infatti, per verificare il certificato emesso da un’altra AC, deve risalire la gerarchia dell’albero verificando tutti i cross certificate che portano alla radice. Questo tipo di collegamento tende a minimizzare il problema delle diverse politiche di sicurezza adottate da ogni AC. La AC globale infatti ha anche il compito di dettare delle linee di sicurezza alle quali tutte le AC facenti parte dell’albero devono attenersi. Nelle applicazioni pratiche, le PKI con effetti legali impiegano un modello ad albero che si sviluppa su due livelli, con il livello superiore di emanazione Statale o pubblica che certifica le autorità inferiori, normalmente private. Modelli a struttura ibrida In questo caso si hanno più infrastrutture ad albero che, per necessità di cooperazione, si riuniscono in un’unica rete di AC secondo le modalità del modello infrastrutturale a rete. Soltanto le AC radice devono rilasciarsi mutuamente dei cross certificate, e questo garantisce l’interoperabilità fra tutte le AC appartenenti agli alberi le cui radici si sono mutuamente certificate. La situazione finale è simile a quella di una rete di AC, ma con una differenza sostanziale: ogni utente continua a fidarsi soltanto della AC radice dell’albero contenente la sua AC locale di appartenenza. Una struttura ibrida di questo tipo è quella destinata a formarsi in una realtà di ampiezza continentale o mondiale, in cui ogni stato sviluppa una infrastruttura nazionale gerarchica indipendentemente dagli altri, poi, se le varie infrastrutture sono compatibili tra loro, una serie di certificazioni mutue riesce a garantire l’interoperabilità fra di esse. 53 Capitolo 3 3.3.3 Catene di certificazione In uno scenario costituito da una molteplicità di Autorità di Certificazione su larga scala, strutturate secondo un certo modello organizzativo, non è pensabile che ogni utente abbia diretta conoscenza della chiavi pubbliche di ogni potenziale interlocutore, sottoforma di certificato elettronico, o delle chiavi pubbliche delle corrispondenti Autorità di Certificazione competenti. Occorre quindi disporre di un meccanismo corretto di ritrovamento dei certificati elettronici degli interlocutori appartenenti a domini di sicurezza esterni. Il modello generale su cui si basano tutti i sistemi di distribuzione su larga scala della chiavi pubbliche sottoforma di certificati elettronici, utilizza le cosiddette catene di certificazione, anche note come cammini di certificazione. Il problema del ritrovamento di un cammino di certificazione consiste sostanzialmente nel trovare, se esiste, un cammino di certificazione che permetta di verificare l’autenticità di un certificato elettronico di uno specifico utente remoto, a partire da un insieme di chiavi pubbliche, assunte come radici del cammino, delle quali si ha la diretta e sicura conoscenza. La risoluzione del problema quindi assume per date certe condizioni iniziali: tali condizioni iniziali si identificano nella conoscenza di chiavi di specifiche autorità di certificazione già note, e che quindi già dispongono della nostra fiducia. La figura sottostante mostra un esempio di catena di certificazione, costituita da tre certificati, in una ipotetica comunicazione tra Alice e Bob appartenenti a due CA diverse. 54 Public Key Infrastructure Figura 16. Esempio di catena di certificazione. La presenza del certificato 1 garantisce Alice sull’autenticità della chiave pubblica dell’autorità di certificazione B; Alice può quindi utilizzare la chiave pubblica di B per verificare l’autenticità del certificato 2. La presenza del certificato 2 garantisce ora Alice sull’autenticità della chiave pubblica dell’autorità di certificazione C; ora Alice può utilizzare la chiave pubblica dell’autorità di certificazione C per verificare l’autenticità del certificato 3 e quindi della chiave pubblica di Bob. Se fosse venuto a mancare il certificato 2 Alice non avrebbe potuto verificare l’autenticità del certificato elettronico di Bob e conseguentemente avviare con Bob una comunicazione sicura. Il cammino che si percorre all’interno di una catena di certificazione riflette il modello strutturale che costituisce la PKI. L’esempio precedente è riconducibile ad un modello reticolare in cui il certificato 1 ed il certificato 2 costituiscono due cross certificate che legano rispettivamente l’autorità di certificazione A con B, e l’autorità di certificazione B con C. In un modello ad albero si avrebbe uno schema molto simile, nel quale i cross certificate legano le autorità di certificazione padre con le figlie. La differenza risiede nel certificato all’apice della catena, che rappresenta l’autorità di certificazione radice. Tale certificato infatti è autofirmato, in quanto la CA 55 Capitolo 3 radice garantisce per se stessa, quindi i campi “subject” e “issuer” del certificato rappresentano la stessa entità. Riportiamo di seguito l’esempio di un cammino di certificazione che si potrebbe trovare in una infrastruttura che utilizza un modello ad albero. L’autorità di certificazione A è la CA radice. Figura 17. Esempio di catena di certificazione in una struttura ad albero. 56 Public Key Infrastructure 3.4 Standard Questo paragrafo descrive brevemente gli standard in vigore che disciplinano i certificati a chiave pubblica e le PKI. Questi standard riguardano molti campi tra cui il formato con cui i dati devono essere contenuti in un certificato, le regole di implementazione degli algoritmi crittografici, le regole di utilizzo di hardware crittografici e altro ancora. 3.4.1 Standard X.509 per i certificati a chiave pubblica Lo standard ormai diffusamente riconosciuto di definizione del formato dei certificati è quello descritto nelle specifiche ITU X.50938, corrispondenti alle specifiche ISO/IEC 9594-839. Tale standard è giunto alla terza versione (X.509v3), dopo che le due precedenti versioni si erano dimostrate insufficienti a risolvere certe problematiche. Vediamo da quali campi è composto un certificato: • Version: indica la versione del formato del certificato. • Serial Number: è un codice numerico che identifica univocamente il certificato. • Signature Algorithm: specifica l’algoritmo utilizzato dalla CA per firmare il certificato. • Issuer X.500 Name: indica il nome della CA (secondo lo standard di naming X.500). • Validity Period: specifica la data e l’ora di inizio validità e fine validità del certificato. • Subject X.500 Name: nome del possessore del certificato. • Subject Public Key Information: contiene il valore della chiave pubblica del possessore del certificato e l’algoritmo con cui tale chiave viene usata. 38 International Telecommunication Unit. International Standard Organization / International Electrotechnical Commission. 39 57 Capitolo 3 • Issuer Unique Identifier: è una stringa di bit aggiuntivi, opzionale, usata nel caso in cui nella struttura ad albero ci siano due CA. • Subject Unique Identifier: stringa opzionale di bit usata nel caso di omonimia tra due membri di una stessa CA. • CA Signature: è la firma digitale della CA sul certificato. Nella terza versione dello standard è stato aggiunto un ulteriore campo: Standard Extention. Questo campo è suddiviso in tre sottoinsiemi: l’identificatore del tipo di estensione, un indicatore di criticità e il valore effettivo dell’estensione. L’indicatore di criticità facilita l’interoperabilità tra sistemi che non utilizzano certificati con determinate estensioni e sistemi che, invece, interpretano tutte le estensioni definite a livello di standard. Tale indicatore è semplicemente un flag che indica se l’estensione è critica o non critica; nell’ultimo caso il sistema che deve elaborare il certificato può eventualmente ignorare l’estensione in questione se non è in grado di interpretarla. Le estensioni standard definite nei certificati X.509v3 si dividono in quattro gruppi: • Estensioni contenenti informazioni sulla chiave pubblica che specificano il tipo di utilizzo per cui è stata emessa una certa chiave. • Estensioni contenenti informazioni aggiuntive relative alla CA e all’utente possessore del certificato. • Estensioni contenenti informazioni sulle politiche di emissione e sulle finalità di utilizzo dei certificati. • Estensioni contenenti informazioni sui vincoli di spazio di nomi o di politica da imporre durante il ritrovamento o la verifica di un certificato appartenente ad un dominio di fiducia esterno. Vediamo di seguito un esempio di certificato X.509 v3. 58 Public Key Infrastructure Figura 18. Esempio di certificato X.509v3. Per avere un’idea di come si presenta nella pratica un certificato a chiave pubblica conforme allo standard X.509 riportiamo di seguito l’esempio di un certificato (autofirmato) rilasciato dall’Autorità di Certificazione della BNL (BNL Multiservizi)40. Version: V3 Subject: CN=Proxy Locale Multiservizi, OU=Certification Service Provider, O=Multiservizi S.p.A., L=Roma, ST=rm, C=IT Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5 Key: SunJSSE RSA public key: public exponent: 010001 modulus: d5d04894 9b80aca4 1fb8228b cc319e8f 4dd956f3 a010e5f2 d42bbe13 2ad8ce46 a53c044c eb8e4073 ebe42ff5 04263dde 44ade1c9 5a4d19ac 31da9390 c2f50ccd Validity: [From: Fri Feb 18 11:46:14 CET 2000, To: Mon Feb 15 11:46:14 CET 2010] Issuer: CN=Proxy Locale Multiservizi, OU=Certification Service Provider, O=Multiservizi S.p.A., L=Roma, ST=rm, C=IT SerialNumber: [ 01] Certificate Extensions: 1 [1]: ObjectId: 2.16.840.1.113730.1.13 Criticality=false Extension unknown: DER encoded OCTET string = 0000: 04 25 16 23 45 6D 69 73 73 69 6F 6E 65 20 63 65 0010: 72 74 69 66 69 63 61 74 69 20 70 65 72 20 4D 4C 40 .%.#Emissione ce rtificati per ML Questo certificato è in dotazione con il software di installazione del lettore di Smart Card “GemPC410” della Gemplus utilizzato nello sviluppo di questo lavoro. 59 Capitolo 3 0020: 53 20 50 72 6F 78 79 Algorithm: [SHA1withRSA] Signature: 0000: 63 05 15 93 DE 7D 2B 0010: 2C 90 34 CB 29 0F 71 0020: 28 0A 28 71 C3 97 AB 0030: B3 F2 66 42 C5 06 E7 S Proxy 55 EE BF 03 5B C6 32 DB C0 85 47 7F 77 08 DC 25 42 A0 B3 4E 2E 10 1E 0C C4 7A 12 B2 95 E7 1B 16 D5 4A 47 E9 c.....+U[.wB.... ,.4.).q......z.J (.(q....2G.....G ..fB......%N.... 3.4.2 Standard PKCS PKCS è l’acronimo di Public Key Cryptography Standard e rappresenta una famiglia di standard rilasciati dalla RSA Laboratories41, con lo scopo di accelerare lo sviluppo e l’impiego delle tecniche di crittografia asimmetrica. Pubblicati per la prima volta nel 1991, queste specifiche sono presto diventate un punto di riferimento per il settore. Ogni specifica riguarda uno o più aspetti legati al mondo della crittografia e della sicurezza. Questo standard si articola in quindici normative che definiscono gli algoritmi di crittografia, la sintassi e le interfacce per l’utilizzo di vari strumenti crittografici. Di seguito ne riportiamo una breve descrizione42: • PKCS#1: RSA Cryptography Standard. Definisce le linee guida per l’implementazione dell’algoritmo RSA sui calcolatori digitali. • PKCS#3: Diffie-Hellman Key Agreement Standard. Standard per l’implementazione dell’algoritmo di key agreement Diffie-Hellman. • PKCS#5: Password-Based Criptography Standard. Raccomandazioni per l’implementazione della cifratura basata su password. • PKCS#6: Extended-Certificate Sysntax Standard. Propone una sintassi ASN.1 che estende quella dei certificati X.509. • PKCS#7: Cryptographic Message Syntax Standard. Sintassi generale per i dati crittografati. Su questo formato si basa ad esempio il protocollo di posta elettronica S/MIME e molti altri formati di interscambio per le informazioni di identificazione personale. 41 42 www.rsasecurity.com/rsalabs/ Le specifiche PKCS#2 e PKCS#4 sono state incorporate nel PKCS#1. 60 Public Key Infrastructure • PKCS#8: Private-Key Information Syntax Standard. Sintassi ASN.1 per le informazioni relative ad una chiave privata, e descrizione della sintassi per la chiavi private cifrate. • PKCS#9: Selected Attribute Types. Definisce i tipi ASN.1 degli attributi usati in PKCS#6, PKCS#7, PKCS#8 e PKCS#10. • PKCS#10: Certification Request Syntax Standard. Descrive una sintassi per la richiesta di firma di un certificato. • PKCS#11: Cryptographic Token Interface Standard. Specifica una API (Cryptoki) per i dispositivi in grado di eseguire operazioni crittografiche e trattare le informazioni relative (chiavi e certificati). È lo standard de facto per l’interoperabilità tra i diversi modelli e tipi di HSM (Hardware Security Module). Definisce un modello ad oggetti del token indipendente dall’hardware sottostante e dalla piattaforma operativa. • PKCS#12: Personal Information Excange Syntax Standard. Specifica un formato portabile per la memorizzazione o il trasporto di informazioni personali, come chiavi private, certificati e altro. È il formato utilizzato nei browser più comuni per l’importazione e l’esportazione di chiavi e certificati (Netscape/Mozilla, Internet Explorer, Opera, Konqueror). • PKCS#13: Elliptic Curve Cryptografy Standard. Standard ancora in fase di sviluppo, che specifica molti aspetti della crittografia basata sulla teoria delle curve ellittiche. • PKCS#15: Cryptographic Token Information Format Standard. Propone un modello generalizzato per l’accesso alle smart card e ai token crittografici, al fine di favorire maggiormente l’interoperabilità tra l’hardware dei diversi vendor. 61 Capitolo 3 62 Smart Card Capitolo 4. SMART CARD 63 Capitolo 4 4.1 Aspetto di una Smart Card Le Smart Card sono schede del tutto simili, nella forma, a quelle che si utilizzano per telefonare o per le operazioni bancarie (carte di credito). Sono infatti delle tessere di plastica capaci di contenere dati al loro interno. La caratteristica che distingue le Smart Card dalle altre schede però, sta nel fatto che esse contengono un processore in grado di dotarle di una certa “intelligenza” (da cui appunto il nome di “scheda intelligente”), che consente non solo la semplice memorizzazione dei dati, ma anche la loro elaborazione. Secondo lo standard ISO vengono definite “Integrated Circuit Card” (ICC, ovvero “schede a circuito integrato”). La figura sottostante da un’idea di come viene inserito il microchip all’interno della tessera. Figura 19. Applicazione del chip sulla scheda. In pratica questo processore consente di eseguire operazioni sui dati direttamente all’interno della card. E’ questa una proprietà da non sottovalutare in quanto fornisce un enorme contributo alla sicurezza. Infatti le operazioni che si svolgono sulla scheda riguardano soprattutto dati sensibili (dati personali del possessore della carta, certificati a chiave pubblica, chiavi private…) e più questi rimangono legati alla scheda, maggiore è il livello di sicurezza. Ma vediamo ora più in dettaglio come è fatta una Smart Card. 64 Smart Card 4.2 Architettura interna Abbiamo già detto che una Smart Card possiede al suo interno un processore, ma questo da solo non basta per eseguire le operazioni menzionate. Ecco come è composta schematicamente una Smart Card: Figura 20. Architettura interna di una Smart Card. • CPU: è il processore centrale, di tipo CISC a 8, 16 o 32 bit e con un clock di 3,5 o 5 MHz; • ROM: è una memoria di sola lettura le cui dimensioni variano da 2 a 64 KByte e contiene il sistema operativo della scheda; • PROM: è una memoria molto piccola (32 o 64 Byte) che contiene il numero seriale della scheda; • EEPROM: ha una capacità di circa 128 KByte e contiene informazioni relative a dati e applicazioni (è la memoria di massa); • RAM: memoria di lavoro volatile, varia tra 128 e 1024 Byte; • Sottosistema I/O: è l’interfaccia per lo scambio dati con l’esterno. 65 Capitolo 4 Come si può vedere la struttura di una Smart Card è molto simile a quella di un normale computer. Alcune schede possono presentare delle variazioni allo schema descritto (che è da ritenersi una struttura base di riferimento) a seconda delle funzioni cui sono destinate. Un esempio che ci riguarda molto da vicino è dato proprio dalle schede crittografiche. Gli algoritmi che queste devono eseguire sono molto complessi quindi necessitano di un ulteriore processore chiamato appunto coprocessore crittografico. Altri esempi si possono avere nel campo della biometria in cui i dati relativi al riconoscimento dell’impronta digitale, o della retina, o di qualunque altra caratteristica biometrica, sono molto ingombranti quindi necessitano di una espansione di memoria realizzata ad esempio con una banda ottica (che può arrivare a contenere diversi MByte). 4.3 Tipi di Smart Card E’ opportuno a questo punto spendere qualche parola in più sui diversi tipi di Smart Card. La prima distinzione che si può fare riguarda la presenza o meno del microchip, abbiamo allora: • Schede di memorizzazione (memory card): non hanno al loro interno un processore, ma solo un dispositivo di memorizzazione (ad es. banda magnetica). Consentono la memorizzazione e il recupero dati. Potrebbero contenere anche una logica di sicurezza per l’accesso ai dati (autenticazione); • Schede con processore (ICC): contengono un microchip che consente di memorizzare, recuperare e manipolare i dati. Alcune di esse presentano anche un coprocessore di supporto per le operazioni più complesse (schede crittografiche). Un’altra classificazione delle Smart Card può essere fatta in base al loro modo di comunicare con il mondo esterno, si hanno quindi: • Smart Card con contatti: si accede alla scheda per mezzo di contatti posti sulla superficie della tessera; 66 Smart Card • Smart Card senza contatti: presentano un dispositivo capace di trasmettere e ricevere onde elettromagnetiche utilizzate per scambiare i dati. 4.4 Standard Le Smart Card, anche se diverse nell’architettura, devono rispettare alcuni standard riguardanti le loro caratteristiche fisiche, i protocolli di comunicazione, i comandi etc. Due enti in particolare (International Standard Organization43 e International Electrotechnical Commission44) si sono proposti di sviluppare una serie di requisiti di riferimento per i produttori di Smart Card. I produttori, dal lato loro, hanno tutto l’interesse a rispettare tali requisiti, in quanto questo garantisce l’interoperabilità, cioè la possibilità di utilizzare schede diverse su di uno stesso hardware (o software), e quindi facilita la diffusione delle schede. In questo paragrafo verranno illustrati alcuni standard, con particolare attenzione allo standard ISO/IEC. 4.4.1 Standard ISO/IEC 7816 Tutte le caratteristiche fondamentali di una Smart Card sono esposte nella normativa ISO/IEC 7816 che comprende le seguenti sezioni: ISO/IEC 7816-1: Physical characteristics; ISO/IEC 7816-2: Dimensions and location of the contacts; ISO/IEC 7816-3: Electronic signals and transmission protocols; ISO/IEC 7816-4: Inter-industry commands for interchange; ISO/IEC 7816-5: Numbering system and application identifiers; ISO/IEC 7816-6: 43 44 Inter-industry data elements; www.iso.org. www.iec.ch 67 registration procedure for Capitolo 4 ISO/IEC 7816-7: Inter-industry commands for Structured Card Query Language; ISO/IEC 7816-8: Security related inter-industry commands; ISO/IEC 7816-9: Enhanced inter-industry commands; ISO/IEC 7816-10: Electronic signals answer to reset for synchronous card; ISO/IEC 7816-11: Card structure and enhanced functions for multi-application use; ISO/IEC 7816-15: Cryptographic information application. Questi standard sono in continua evoluzione a seguito dell’uscita di nuove tecnologie o dell’impiego di particolari soluzioni nate come proprietarie (dall’iniziativa di un produttore) e poi sviluppatesi fino a diventare di uso comune. Gli standard forniscono delle linee guida da seguire quando si ha a che fare con le Smart Card. Tuttavia ogni produttore è consigliato a seguire tali requisiti, ma non obbligato, per questo non è raro imbattersi in particolari schede che implementano funzioni non inerenti agli standard descritti (soprattutto nel campo della crittografia), ma che un produttore ha ritenuto opportuno implementare come migliore soluzione per un determinato impiego. E’ comunque il buon senso a suggerirci di trovare un compromesso tra rispetto degli standard e libera iniziativa a soluzioni proprietarie. Si pensi a cosa succederebbe se, ad esempio, ognuno producesse schede di differente forma e con diversi protocolli di comunicazione! Si verrebbe a creare il caos più assoluto! Senza dimenticarci di una proprietà fondamentale come l’interoperabilità che sarebbe completamente persa. Per questo è necessario attenersi ad alcuni riferimenti comuni a tutti, e sono proprio quelli che troviamo nelle prime tre sezioni dello standard ISO/IEC 7816. Di fatto, una scheda dichiarata conforme al suddetto standard risulta conforme almeno alle prime tre sezioni. 68 Smart Card ISO/IEC 7816-1: Caratteristiche fisiche Questo standard definisce le caratteristiche fisiche di una Smart Card, in particolare: • le sue dimensioni: Figura 21. Dimensioni di una Smart Card secondo lo standard ISO/IEC 7816-1. • il valore minimo di radiazione ultravioletta che la scheda deve sopportare, stimato al livello medio di radiazione ambientale; • il valore minimo di esposizione ai raggi X che non provochi danni alla scheda, stimato ad una energia media corrispondente alla quantità cumulativa annuale; • il profilo della superficie dei contatti: la differenza tra il livello dei contatti e quello della superficie della scheda deve essere minore di 0,1 mm; • la resistenza alle sollecitazioni meccaniche sia della scheda che dei contatti: questi non devono essere danneggiati dalla pressione provocata da una sfera di acciaio del diametro di 1,5 mm alla quale è applicata una forza di 1,5 N; • la resistenza elettrica tra i contatti: non deve essere superiore a 0,5 Ω per valori di corrente compresi tra 50 µA e 300 mA; • il valore minimo di campo magnetico statico che la scheda deve sopportare; 69 Capitolo 4 • la resistenza a scariche elettrostatiche: il chip non deve subire danni se sottoposto ad una scarica elettrica di 1500 V provenienti da una capacità di 100 pF attraverso una resistenza di 1500 Ω; • i limiti massimi di flessione della scheda: deve resistere ad una deformazione di 2 cm dal lato lungo, o di 1 cm dal lato corto, con una periodicità di 30 flessioni al minuto. ISO/IEC 7816-2: Dimensione e locazione dei contatti Questa sezione si occupa di definire le dimensioni fisiche, la locazione e l’assegnamento dei contatti del chip sulla carta. In figura è riportato lo schema dei contatti esterni del microcontroller previsti dallo standard, la loro disposizione sulla tessera plastificata e la dimensione dei contatti stessi. Figura 22. Posizione e dimensione dei contatti sulla Smart Card. 70 Smart Card Figura 23. Assegnazione dei contatti. • VCC. Tensione continua di alimentazione, 3 o 5V; • RST. Linea di reset; • CLK. Segnale di clock del microcontroller. Lo spazio esiguo non permette alle smart card di disporre di un’alimentazione interna, e il segnale di clock deve essere fornito dall’interfaccia esterna (IFD: Interface Device o CAD: Card Acceptance Device); • GND. Riferimento di massa per le tensioni applicate; • VPP. Alcune smart card hanno bisogno, in fase di programmazione, di una tensione continua supplementare, fornita su questa linea. • I/O. Linea per l’input/output seriale. I contatti C4 e C8 non sono collegati, e sono riservati ad usi futuri (Reserved for Future Use). ISO/IEC 7816-3: Segnali elettrici e protocolli di trasmissione Questo standard descrive i segnali elettrici e i protocolli di trasmissione utilizzati nelle Smart Card. In particolare vengono date indicazioni sui livelli delle tensioni e correnti riguardanti tutti i segnali introdotti precedentemente, nonché sui tempi di salita e discesa e sulle capacità parassite. Di seguito sono riportate solo le specifiche su alcuni segnali, tra i quali quelli fondamentali di alimentazione e clock, il reset che verrà discusso ulteriormente 71 Capitolo 4 più avanti, e l'I/O. Viene tralasciato Vpp il cui utilizzo è opzionale e interessa più il programmatore della scheda che non l'utente finale. Symbol Conditions Minimum Maximum Unit Vih Either (1) Iih max = +/- 500uA 2 VCC V Iih max = +/- 50uA 0.7 VCC VCC (3) V Vil Iil max = 1mA 0 0.8 V Voh Either (2) Iol max = +/- 100uA 2.4 VCC V Iol max = +/- 20uA 3.8 VCC V Vol Iol max = 1mA 0 0.4 V tr, tf Cin = 30pF; Cout = 30pF 1 us (1) For the interface device, take into account both conditions. (2) It is assumed that a pull up resistor is used in the interface device (recommended value 20k Ohm. (3) The voltage on I/O shall remain between 0.3V and VCC+0.3V. Figura 24. Caratteristiche elettriche di I/O sotto normali condizioni operative. Symbol Conditions Either (1) Vih Minimum Maximum Unit IIih max = +/- 200uA 2.4 VCC (2) V Iih max = +/- 20uA 0.7*VCC VCC (2) V Iih max = +/- 10uA VCC-0.7 VCC (2) V 0 (2) 0.5 V Iol max = +/- 100uA 2.4 VCC V Iol max = +/- 20uA 3.8 VCC V Vil Iil max = +/-200 uA Voh Either (2) tr, tf Cin = 30pF 9% of the with a max:0.5us (1) For the interface device, take into account (2) The voltage on CLK shall remain between 0.3V and Vcc+0.3V. three period conditions. Figura 25. Caratteristiche elettriche di CLK sotto normali condizioni operative. Symbol Conditions Minimum Maximum Unit Vih Either (1) IIih max = +/- 200uA 4 VCC (2) V Iih max = +/- 20uA VCC-0.7 VCC (2) V Vil Iil max = +/-200 uA 0 (2) 0.6 V (1) For the interface device, take into account (2) The voltage on RST shall remain between 0.3V and VCC+0.3V. both conditions. Figura 26. Caratteristiche elettriche di RST sotto normali condizioni operative. 72 Smart Card Symbol Minimum Maximum Unit Vcc 4.75 5.25 V 200 mA Icc Figura 27. Caratteristiche elettriche di Vcc sotto normali condizioni operative. Inoltre in questo standard sono definite anche le sequenze di attivazione e il comportamento del microcontroller al segnale di reset. Sono infine definiti due protocolli half-dupex asincroni di trasferimento dei dati chiamati T=0 e T=1. Questi ultimi concetti saranno ripresi ed analizzati più in dettaglio nel paragrafo riguardante il funzionamento di una Smart Card. 4.4.2 Altri standard Abbiamo visto come le prime tre sezioni dello standard ISO/IEC 7816 definiscano i requisiti che regolamentano le caratteristiche fisiche, i protocolli di comunicazione e il funzionamento di basso livello della Smart Card. Salendo di un livello troviamo il set di comandi di cui dispone la scheda. Una sua definizione viene data nella parte quarta dello standard precedente, tuttavia i comandi disponibili sono legati alle operazioni che la scheda è destinata a compiere, quindi è possibile trovare diversi set di comandi per diversi campi applicativi, ognuno comunque regolato da un opportuno standard. Di seguito sono riportati gli standard principali relativi ai set di comandi: • ISO/IEC 7816-4. Fornisce indicazioni riguardanti: o il contenuto dei messaggi (sia di comando che di risposta) inviati dal lettore alla scheda e viceversa; o la struttura dei file e dei dati interni alla scheda; o i metodi di accesso a file e dati nella scheda; o i metodi di secure messaging; o i metodi di accesso agli algoritmi presenti nella scheda (senza occuparsi di descrivere tali algoritmi). 73 Capitolo 4 • EMV (Europay, Mastercard, Visa). È uno standard industriale che definisce comandi specifici per le transazioni finanziarie. Non è uno standard internazionale, ma costituisce comunque un riferimento per il settore. • GSM 11.11. Costituisce lo standard per le applicazioni legate alla telefonia mobile. • CEN EN 1546. Standard che definisce comandi specifici per applicazioni di moneta elettronica (electronic purse). 4.4.3 Abstract Syntax Notation L’Abstract Syntax Notation (ASN) è il metodo più usato per strutturare i dati nelle smart card e trova particolare applicazione nelle schede crittografiche. Rispetta gli standard internazionali ISO/IEC 8824 relativi alla sintassi e ISO/IEC 8825 per quanto riguarda le regole di codifica. Ambedue sono inerenti alle raccomandazioni X.409 del CCITT. La struttura dati ASN.1 è una struttura flessibile, cioè vengono specificati di volta in volta il tipo di dato che si sta trasmettendo e la sua lunghezza. Gli sviluppatori di questo standard hanno preferito evitare strutture fisse in quanto potrebbero risultare incompatibili con eventuali sviluppi futuri comportando così costi aggiuntivi di adattamento. Di seguito è riportato un esempio di struttura dati che rispetta le Basic Encoding Rules (BER) dello standard ASN.1 e nota con il nome di struttura TLV. TAG LENGTH VALUE 1 o 2 byte da 1 a 3 byte n byte Figura 28. Struttura dati TLV dello standard ASN.1. 74 Smart Card E’ composta da tre campi: • Tag: è un’etichetta che identifica il dato e ne specifica il tipo; • Length: specifica la lunghezza del dato. La codifica di questo campo è definita nelle Distinguished Encoding Rules (DER) che sono un sottoinsieme delle BER. • Value: rappresenta il dato vero e proprio. Vediamo ora più in dettaglio il campo Tag. I due bit più significativi selezionano un tipo (o classe) di dato presente nel campo Value tra i quattro disponibili: • universal (00): rappresenta un dato generico; • application (01): specifica un dato che appartiene ad una applicazione o ad uno standard; • context-specific (10); • private (11). Le ultime due classi si riferiscono a dati di applicazioni non standardizzate. Il bit successivo specifica se l’oggetto in questione è una primitiva o un constructed (se è stato creato da altri oggetti). I rimanenti bit (cinque se il campo tag fosse di un solo byte, più altri otto se il campo fosse lungo due byte) codificano l’effettiva etichetta scelta dall’utente per identificare il dato. MSB 0 1 classe 2 3 4 constr. 5 6 7 LSB etichetta Figura 29. Significato dei bit costituenti il campo TAG. Questo tipo di struttura ha il vantaggio di essere semplice, flessibile e permette di scambiare qualsiasi tipo di dato. Per contro potrebbe comportare un elevato costo di gestione nel caso in cui il campo Value fosse di pochi byte, in quanto si avrebbero più byte impiegati per descrivere il dato (nei campi T e L) rispetto a quelli costituenti il dato vero e proprio (campo V). 75 Capitolo 4 4.5 Funzionamento di una Smart Card In questo paragrafo verranno ripresi i concetti, già citati nella descrizione dello standard ISO/IEC 7816-3, relativi alle sequenze di attivazione e disattivazione della scheda e ai protocolli di trasmissione che essa utilizza. Inoltre verranno brevemente descritti anche il sistema operativo impiegato dalla scheda e la struttura del file system per la gestione dei dati. Infine si illustreranno anche i concetti base del protocollo APDU. 4.5.1 Sequenze di attivazione e disattivazione Lo scambio dei dati tra smart card e interfacce esterne è regolato da una procedura descritta dettagliatamente nella terza sezione della normativa ISO/IEC 7816, nella quale il segnale applicato alla linea di reset (RST) gioca un ruolo fondamentale. La sequenza di attivazione è la seguente: • mantenere RST basso; • applicare Vcc; • mettere il contatto I/O in modalità ricezione; • applicare, se previsto, la tensione Vpp; • applicare un segnale di clock stabile (CLK). La figura seguente mostra l’andamento temporale dei segnali appena descritti. 76 Smart Card GND VCC CLK RST ATR I/O t Inserimento smart card Stabilizzazione contatti Figura 30. Sequenza di attivazione. Con RST a livello basso, il microcontroller è nello stato di reset. Dopo un certo numero di cicli di clock, RST viene portato a livello alto. La smart card inizia la comunicazione in un intervallo di tempo compreso tra 400 e 40.000 cicli di clock, inviando sulla linea seriale una trama chiamata ATR (Answer To Reset), che include informazioni relative ai protocolli di trasmissione supportatati, all’identificazione del tipo di smart card, dell’hardware on-board e del sistema operativo, varie informazioni aggiuntive (historical characters) che possono anche essere inserite dal produttore della carta e infine da un checksum di controllo. Con l’ATR è possibile identificare univocamente il modello di smart card con il quale l’IFD sta comunicando. Se nell’ATR la card dichiara di supportare più di un protocollo di comunicazione (ad esempio sia T=0 che T=1), l’IFD invia una trama detta PTS request (Protocol Type Selection). Dopo la risposta della card (PTS response) sarà selezionato uno tra i protocolli negoziabili, e inizierà la comunicazione vera e propria. 77 Capitolo 4 La sequenza di disattivazione è la seguente: • abbassare il livello di RST; • abbassare CLK; • scollegare Vpp; • abbassare I/O; • disattivare l’alimentazione Vcc. 4.5.2 Sistema operativo L’elaborazione dei comandi, la gestione del file system e molte altre caratteristiche delle smart card dipendono dal particolare sistema operativo cablato in ROM, che pilota le operazioni del microcontroller. In un certo senso possiamo pensare ad una smart card come ad una scatola nera alla quale inviamo dei comandi e dalla quale riceviamo delle risposte. Sebbene chiamare Sistema Operativo i pochi Kbyte cablati nelle ROM delle smart card potrebbe sembrare fuorviante, per rendersi conto dell’ alto grado di sviluppo al quale si è arrivati è sufficiente pensare al fatto che molti tra i sistemi operativi per smart card permettono di incorporare interpreti per linguaggi di alto livello come Basic o Java. Lo sviluppo di un Sistema Operativo per una Smart Card è diverso da quello che si avrebbe in un computer tradizionale, in quanto sono diverse le condizioni ambientali (in cui il SO è inserito) e le condizioni di utilizzo. In una smart card si ha a disposizione pochissima memoria (nell’ordine dei Kbyte), non è presente alcuna interfaccia utente ed infine sono ottimizzate per garantire la massima sicurezza dei programmi, durante la loro esecuzione, e dei dati, durante il loro accesso o elaborazione. Queste condizioni sono molto restrittive e rendono necessario lo sviluppo di un sistema specifico che, pur avendo affinità di base con i normali sistemi operativi, deve per forza differenziarsi da essi. 78 Smart Card Le dimensioni di un sistema operativo per smart card dipendono dalle caratteristiche e dalle funzioni della scheda. In generale si va dai 3 KB di sistemi per singole applicazioni, ai 30 KB per smart card multiapplicazione. I compiti principali che un sistema operativo per smart card deve assolvere sono: • trasferimento dei dati dalla smart card verso l’esterno e dall’esterno verso la smart card; • controllo dell’esecuzione dei comandi; • gestione dei file; • gestione ed esecuzione di algoritmi crittografici (per smart card crittografiche). 4.5.3 File system Molti dei comandi dello standard ISO/IEC 7816-4 sono rivolti alla gestione del file system. Una smart card consente solo l’utilizzo di strutture standardizzate di file. I dati sono organizzati secondo la gerarchia ad albero illustrata nella figura seguente. MF DF EF … … … … … … Figura 31. Struttura gerarchica del file system di una smart card. 79 Capitolo 4 I file si dividono principalmente in due categorie: • Dedicated File (DF): è un contenitore di file (directory) che può avere al suo interno degli EF o anche altri DF di livello inferiore. Il DF radice è chiamato Master File (MF) e rappresenta la directory root del file system. Non esistono limitazioni al livello di profondità dei DF (eccetto la limitazione di spazio). Nelle schede multiapplicazione si tende a creare una directory (e quindi un DF) per ogni applicazione. • Elementary File (EF): contengono i dati utili per le applicazioni. Si dividono a loro volta in: o Internal EF: contengono dati che utilizza il sistema operativo (ad esempio dati del SO stesso, di una applicazione, chiavi segrete o codice programma). L’accesso a questi file è protetto. o Working EF: contengono dati utili per le applicazioni esterne, cioè dati che sono destinati ad un utilizzo al di fuori della scheda. La figura sottostante mostra una schematizzazione dei vari tipi di file. File Directory Data MF EF Internal EF DF Working EF Figura 32. Tipi di file presenti in una smart card. I dati all’interno degli EF possono essere organizzati secondo una di queste quattro strutture predefinite: 80 Smart Card • Transparent. Ci si riferisce con questo termine ad una sequenza binaria non strutturata, alla quale si può accedere in lettura o scrittura per singoli byte o per blocchi; • Linear Fixed. I dati sono organizzati in record di lunghezza fissa: ogni file può contenerne al massimo 254. Questa struttura permette operazioni di lettura/scrittura di un numero intero di record. La lunghezza di ogni record può essere al massimo di 254 byte; • Linear Variable. Come per la struttura linear fixed, l’unità minima di lettura/scrittura è il record, fino ad un massimo di 254 per ogni file. La dimensione dei record è variabile (da un minimo di un byte fino ad un massimo di 254 byte), e ogni record ha un campo supplementare che ne indica la lunghezza. La tipica applicazione di una struttura simile è una rubrica telefonica, nella quale i nomi e i numeri di telefono non hanno lunghezza fissa: usare allo stesso scopo una struttura linear fixed è possibile, ma non efficiente in termini di gestione dello spazio in memoria; • Cyclic. È basata sulla struttura linear fixed (dimensione massima di un record 254 byte), ma ha in più un puntatore che indica l’ultimo record che è stato scritto. Raggiunto l’ultimo record, il puntatore indirizzerà i successivi accessi al primo record della struttura (lista ciclica). Anche in questa struttura il massimo numero di record memorizzabile è 254. Ognuno dei file appena introdotti, oltre a contenere i dati, deve anche fornire alcune informazioni sul suo formato. Tutte le informazioni riguardanti il file sono contenute sul file stesso attraverso una struttura di questo tipo: Header Body Figura 33. Struttura interna di un file. 81 File Capitolo 4 Un file è costituito da una intestazione (header) che contiene informazioni sulla struttura del file e sulle condizioni di accesso. Questa punta al corpo del file (body) che contiene i dati veri e propri. Per motivi di sicurezza solo il sistema operativo può accedere all’intestazione del file, mentre all’utente (o a qualsiasi applicazione esterna) sarà proposto solo il corpo del file. Per questo l’header e il body sono contenuti in due pagine diverse della memoria, in quanto, in caso contrario, si potrebbero sfruttare dei trucchi per accedere all’header e cambiare le condizioni di accesso al file. Ogni file, infine, può essere selezionato usando un opportuno identificatore (FID: File Identifier), cioè un campo di due byte che contiene il nome del file (in esadecimale45). L’utilizzo di alcuni di questi identificatori è riservato, come ad esempio FID “3F00” che è associato al master file, oppure FID “FFFF” riservato ad applicazioni future. Analogamente esiste anche un identificatore per le applicazioni chiamato Application Identifier (AID). 4.5.4 Protocolli di trasmissione Attualmente le smart card utilizzano due protocolli di trasmissione denominati T=0 e T=1. Sono due protocolli per comunicazioni seriali asincrone di tipo half duplex. Per il futuro sono previsti anche altri tipi di protocolli, come ad esempio il T=2 che sarà in grado di gestire comunicazioni full duplex, ma sono ancora in fase di sviluppo. Protocollo T=0 Il protocollo T=0 è forse il più comune, anche perché largamente impiegato nello standard GSM. Si tratta di un protocollo di comunicazione byteoriented, nel quale ogni unità di trasmissione è preceduta da un bit di start a 45 La smart card impiega un modo di indirizzamento codificato in esadecimale in quanto, non esistendo alcuna interfaccia utente, tali indirizzi devono essere compresi solo dai programmi. 82 Smart Card livello basso e seguito da un bit di parità e da un livello alto della durata di due bit (guard time) che segnala la fine della trasmissione. start bit n data byte n parity bit n start bit n+1 guard time Figura 34. Esempio di un byte dati e bit di controllo del protocollo T=0. T=0 adotta un modello di comunicazione master-slave, nel quale il segnale di comando è sempre generato dall’IFD (master) e il segnale di risposta dalla smart card (slave). I dati scambiati tra IFD e smart card sono organizzati in trame chiamate TPDU (Transmission Protocol Data Unit). La trama di comando inviata dall’IFD alla smart card ha sempre la seguente struttura. CLA INS P1 P2 P3 Figura 35. Trama di comando T=0. Nella trama di comando distinguiamo i seguenti campi: • CLA. Classe dell’istruzione. • INS. Codice dell’istruzione. • P1, P2. Parametri dell’istruzione. • P3. Lunghezza dell’eventuale blocco di dati seguente. Dopo ogni comando il protocollo prevede l’invio da parte della smart card, di un codice di risposta (ACK). A seconda del tipo di istruzione selezionata dalla trama di comando, ad ACK segue la trasmissione dei dati da o 83 Capitolo 4 per la smart card. Se viene rilevato un errore di parità su un byte del blocco trasmesso, il ricevente (IFD o smart card) abbassa il livello della linea I/O prima che termini il guard time, forzando la ripetizione della trasmissione dell’intera trama. La comunicazione termina con due byte di stato inviati dalla smart card all’IFD (SW1 e SW2), che contengono gli eventuali codici di errore. Il valore 0x9000 segnala il successo dell’operazione. Il controllo di parità può rilevare solo errori sul singolo bit; inoltre, se durante il trasferimento dall’IFD alla card di una sequenza di lunghezza P3, viene perso un byte, si incorre nello stallo (deadlock) della card, che si può sbloccare solo riattivando la linea RST. La probabilità che si verifichino errori di questo tipo è comunque molto bassa. T=0 si colloca tra il primo (livello fisico) e il secondo (data link) livello dello stack ISO/OSI, poiché interviene sia sull’elaborazione del singolo byte (introducendo i bit di parità), che nella definizione dell’intera trama. La mancata separazione dei layer rende T=0 poco adatto al trattamento di dati cifrati, per i quali è preferibile che i blocchi trasmessi siano trattati direttamente dai livelli sorgente e destinazione, lasciando ai layer intermedi il solo compito di inserire le intestazioni che gli competono. T=0 garantisce un buon transfer rate medio46, e la larga diffusione sul mercato, unita alla semplicità della realizzazione, lo rendono una soluzione ancora molto praticata, sebbene in rapida obsolescenza. Protocollo T=1 T=1 è un protocollo block-oriented più complesso e articolato di T=0, classificabile al livello data-link dello stack ISO/OSI. La differenza fondamentale con T=0 è che l’unità minima di trasmissione è una sequenza di byte di lunghezza variabile (block o frame). T=1 si appoggia su un protocollo del livello fisico simile a T=0, ma senza controllo di parità. Il controllo degli errori viene effettuato sull’intero blocco dei dati scambiati tra smart card e IFD, realizzando in questo modo la separazione dei layer e rendendo T=1 più adatto per il trasporto di dati cifrati. 46 Il valore del transfer rate dipende dalla frequenza di clock del microcontroller e da altri parametri in gioco. 84 Smart Card La comunicazione inizia dopo la ricezione dell’ATR da parte dell’IFD, oppure dopo un eventuale PTS andato a buon fine. La struttura di un blocco è illustrata qui sotto. Information field Epilogue field node address NAD protocol control byte PCB Prologue field length LEN APDU EDC 1 byte 1 byte 1 byte 0... 254 byte 1... 2 byte Figura 36. Struttura di un blocco T=1. Il campo NAD permette di controllare la tensione Vpp (2 bit) e di codificare indirizzi logici di sorgente e destinazione dei dati (ognuno su 3 bit). PCB codifica varie informazioni sulla gestione del protocollo. LEN codifica la lunghezza in byte del campo successivo. Il valore 0xFF per questo campo è riservato per future estensioni. Il campo APDU (Application Protocol Data Unit) contiene i dati da o per il livello applicativo. EDC (Error Detection Code) contiene un codice di correzione degli errori calcolato sui campi precedenti, selezionabile via ATR tra un codice di ridondanza ciclica (CRC) o longitudinale (LRC). A parità di condizioni generali (frequenza di clock e altri parametri) l’analisi delle prestazioni indica che i transfer rate ottenibili con T=0 e con T=1 sono molto simili. T=1 dispone di un meccanismo di rilevazione e correzione degli errori più affidabile e, come abbiamo visto, realizza una separazione tra i livelli preferibile in determinate circostanze (secure messaging). Dall’altro lato, T=1 richiede una programmazione più complessa e un buffer sulla scheda di dimensioni in media quattro volte maggiori rispetto al buffer sufficiente per T=0 (300 byte contro 1100). 85 Capitolo 4 4.5.5 Application Protocol Data Unit Le strutture dati APDU (Application Protocol Data Unit) definite nello standard ISO/IEC 7816-4 contengono sia i comandi provenienti dal livello applicativo e destinati alla smart card, sia le risposte che quest’ultima restituisce ai livelli superiori dopo aver elaborato i dati in ingresso. Le APDU sono quindi distinte in due classi: command APDU e response APDU. La struttura più generale di un APDU di comando è la seguente. CLA INS P1 P2 Lc header Data Le body Figura 37. APDU di comando. I primi quattro campi sono lunghi ciascuno un byte e costituiscono l’intestazione (header); i restanti tre (body) sono opzionali e di lunghezza variabile. CLA identifica lo specifico set di comandi che si sta usando: ad esempio un valore 0xA0 per CLA identifica il set di comandi dello standard GSM 11.11. Ai comandi ISO è assegnato il range 0x0X (dove X è una qualsiasi cifra esadecimale), mentre i valori di CLA appartenenti al range 0x8X e 0x9X sono riservati per i comandi proprietari definiti dal costruttore della card. INS contiene la codifica dell’istruzione. Per motivi di compatibilità con i protocolli di trasferimento dati sottostanti (T=0 e T=1) sono vietate le configurazioni con INS pari, e i range 0x6X e 0x9X. I byte seguenti dell’intestazione (P1 e P2) possono assumere qualsiasi valore, e vengono usati per fornire maggiori informazioni sull’istruzione codificata in INS (sono i parametri del comando). Il corpo dell’istruzione può mancare del tutto o essere presente solo parzialmente, dando luogo a quattro possibili configurazioni significative per un APDU di comando. 86 Smart Card a) header b) header Le c) header Lc data d) header Lc data Le Figura 38. Possibili configurazioni di una APDU di comando. I campi Lc e Le hanno lunghezza variabile da uno a tre byte, e codificano rispettivamente la lunghezza in byte del successivo campo dati, e il numero di byte che ci si aspetta in risposta dalla smart card. Il campo data contiene gli eventuali dati che la card dovrà processare. La struttura dell’APDU di risposta è la seguente. Data SW1 SW2 Figura 39. APDU di risposta. Il campo Data è opzionale, con lunghezza pari al valore del campo Le del comando che ha richiesto la risposta, e naturalmente contiene il risultato dell’elaborazione della smart card. I due campi SW1 e SW2 sono obbligatori e contengono i codici di stato (Status Word) della smart card. Valori pari a 0x61XX o 0x9000 identificano l’assenza di errori o di condizioni anomale, mentre altri valori, così come specificato nello standard, si riferiscono ad errori o situazioni eccezionali. Come si può notare, la struttura descritta è molto simile a quella definita nel protocollo di trasferimento T=0: la corrispondenza con i TPDU è definita caso per caso nella normativa. Ad esempio, per una command APDU con il solo header il campo P3 del TPDU è impostato a 0x00. Nel caso del protocollo T=1, le APDU vengono mappate nel campo information senza alcun cambiamento. 87 Capitolo 4 La figura seguente mostra l’integrazione tra i protocolli di trasmissione descritti nel paragrafo precedente e i comandi del livello applicativo: nel blocco Card si può identificare il sottosistema di I/O, e in APDU Processor il sistema operativo/CPU. Application Command Funzioni specifiche della card Response Command Reader (T=0 / T=1) Command Card Response Response APDU Processor Figura 40. Schema di una comunicazione tra una applicazione e la smart card. 4.6 Interfaccia con le applicazioni Abbiamo visto in che modo una smart card comunica con il proprio lettore, attraverso i protocolli T=0 o T=1, e con le applicazioni, attraverso le APDU di comando e di risposta. In questo paragrafo andremo a descrivere più in dettaglio la struttura dell’interfaccia tra la smart card e le applicazioni che richiedono i suoi servizi. Verranno illustrate e discusse tre principali architetture: PC/SC, Open Card Framework e Java Card. 88 Smart Card 4.6.1 PC/SC Il progetto PC/SC è centralizzato sull’interoperabilità tra smart card e card terminal e la cooperazione tra card terminal e personal computer. Si struttura in otto parti che ricoprono tutte le specifiche: dalle caratteristiche fisiche della smart card e del suo lettore fino al livello applicazione. Figura 41. Architettura PC/SC. 89 Capitolo 4 Part 1. Fornisce una descrizione introduttiva dell’architettura PC/SC. Part 2. Specifica le caratteristiche fisiche della scheda (ICC) e del lettore (IFD) e da indicazioni sulle regole di gestione degli errori. Part 3. Specifica le caratteristiche dell’interfaccia tra lettore e PC in modo da rendere il sistema indipendente dal dispositivo fisico. La parte 3 e la parte 2 (quindi l’IFD e l’IFD Handler) costituiscono quello che viene chiamato Interface Device Subsystem. Part 4. Descrive le linee guida per lo sviluppo di protocolli interni relativi all’interfaccia descritta nella parte 3. Part 5. Definisce il componente base dell’architettura PC/SC: l’ICC Resource Manager. Esso si occupa di gestire le richieste provenienti dalle applicazioni e smistarle ai diversi lettori di schede, nonché regolare gli accessi multipli ad una stessa risorsa. Part 6. Specifica le due interfacce primarie usate dall’applicazione: • ICC Service Provider: contiene una classe che mantiene il contesto della comunicazione con la smart card (necessaria nel caso di accessi multipli). In più può anche fornire primitive per l’accesso ai file della scheda o per le operazioni di autenticazione. • Crypto Service Provider: specifica le primitive per le operazioni crittografiche quali generazione e gestione delle chiavi, firma digitale, funzioni di hash e altre ancora. Part 7. Contiene consigli per il programmatore sull’utilizzo di questa interfaccia. Part 8. Contiene consigli su come gestire l’identificazione, l’autenticazione e la memorizzazione sicura dei dati. 4.6.2 Open Card Framework Lo scopo che gli sviluppatori di OCF hanno voluto raggiungere è quello di realizzare un’interfaccia di alto livello tra la smart card e le applicazioni il più possibile universale in termini sia di tipologie di schede adottabili, sia di diversi tipi di computer o sistemi operativi. Tale progetto è stato sviluppato con tecnologia Java sfruttando i vantaggi di una struttura orientata agli oggetti. 90 Smart Card L’Open Card Framework è strutturato in questo modo: Figura 42. Architettura OCF. Nel livello più alto c’è l’applicazione (application developer) che vuole comunicare con la smart card. Il Card Issuer è responsabile dell’application management layer che si occupa di eseguire e far coesistere più applicazioni in una stessa card. Può accadere che un’applicazione richieda una funzione specifica di una determinata smart card (ad esempio una funzione crittografica), in questo caso, se si dispone di una JavaCard la funzione viene eseguita come applet all’interno della card stessa, altrimenti la funzione deve essere fornita dall’interfaccia OCF tramite il Card Service. Esso contiene tutte le informazioni riguardanti il sistema operativo e le funzioni supportate dalla scheda. Nel livello più basso troviamo il Card Terminal che interfaccia direttamente con l’hardware (è una classe che astrae il lettore della scheda). L’Open Card Framework Core contiene cinque oggetti: CardServiceScheduler, SmartCard (che non è il dispositivo fisico ma una sua 91 Capitolo 4 astrazione), CardID e i due registri: CardServiceRegistry e CardTerminalRegistry. Quando viene inserita una smart card nel lettore per prima cosa vengono creati gli oggetti SmartCard e CardID che identificano il tipo di scheda. Il CardServiceFactory contiene le informazioni riguardanti i servizi offerti da una smart card. Quando un’applicazione richiede un certo servizio ad una determinata scheda il CardServiceRegistry chiama tutti i CardServiceFactory relativi al CardID dell’oggetto SmartCard finché non viene creato un appropriato oggetto CardService. In modo analogo, quando si inserisce la smart card (e dopo l’avvenuta identificazione), il CardTerminalRegistry chiama tutti i CardTerminalFactory relativi al CardID dell’oggetto SmartCard finché non viene creato l’oggetto CardTerminal opportuno. Per fare in modo che OCF funzioni con diverse smart card, ognuna di esse deve disporre del relativo CardTerminal. 4.6.3 Confronto tra OCF e PC/SC La prima differenza sta nella struttura architetturale delle due soluzioni. OCF segue maggiormente una filosofia ad oggetti accentrata principalmente sui servizi offerti dalla smart card, PC/SC invece è meno orientato agli oggetti e tiene più in considerazione i dispositivi fisici che sono appunto personal computer e smart card. Un immediato riscontro di questo diverso approccio lo si può trovare analizzando il CardTerminal di OCF che non fornisce specifiche sul suo funzionamento di basso livello, cosa che invece avviene (e in modo molto dettagliato) sia nell’IFD che nell’IFD Handler di PC/SC. Una differenza più forte si evidenzia nell’ambito delle applicazioni crittografiche. PC/SC presenta un componente dedicato a questo tipo di funzioni: il Crypto Service Provider, cosa che invece viene a mancare nell’altra struttura. Per questo si può dire che PC/SC è più orientato verso la crittografia rispetto ad OCF. Le due soluzioni comunque hanno anche molte cose in comune, come è facile aspettarsi da due progetti che, nonostante seguano strade diverse, si 92 Smart Card pongono lo stesso obiettivo. Ci sono infatti alcuni componenti che offrono funzionalità simili (e a volte equivalenti). E’ il caso dell’”ICC Service Provider” di PC/SC e del “CardService” di OCF; oppure l’”Interface Device Subsystem” di PC/SC e il “CardTerminal” di OCF. In definitiva, sia OCF che PC/SC offrono, in un modo o nell’altro, una valida interfaccia che garantisce tutti i servizi offerti dalla scheda e richiesti dalle applicazioni. Forse la differenza più importante riguarda il loro campo di utilizzo. OCF infatti, essendo strutturato ad oggetti e sviluppato in Java, può essere utilizzato in modo indipendente dal sistema operativo che il personal computer supporta, mentre PC/SC è strettamente legato a Microsoft Windows. Dall’altra parte PC/SC è in grado di interfacciarsi con qualsiasi linguaggio di programmazione, mentre OCF è ristretto al campo delle applicazioni Java. 4.6.4 Java Card Una Java Card è un particolare tipo si smart card che consente l’utilizzo, all’interno della scheda stessa, del linguaggio di programmazione Java, così da poterne sfruttare le caratteristiche di sicurezza, robustezza e compatibilità con vari sistemi operativi. La Java Card contiene una versione rivista della Java Virtual Machine chiamata Java Card Virtual Machine (JCVM) che interagisce col sistema operativo della smart card. Questa, in pratica, implementa tutte le funzioni che la smart card deve offrire e le rende disponibili sottoforma di applet. La JCVM in realtà contiene un sottoinsieme di tutte le classi costituenti il linguaggio Java a causa delle forti limitazioni di spazio e potenza di calcolo presenti in una smart card. L’insieme delle classi caricate nella Java Card costituisce l’interfaccia (API) con le funzioni della scheda ed è chiamata Java Card Framework. Questa è composta da quattro package: • javacard.framework: è il package più importante e fornisce la struttura base del linguaggio Java. Deve essere in ogni Java Card; • javacardx.framework: contiene le classi per la gestione dei file; 93 Capitolo 4 • javacardx.crypto: implementa le funzioni crittografiche; • javacardx.cryptoEnc: fornisce i metodi di cifratura. Il primo è essenziale ed è installato su tutte le Java Card, mentre gli altri tre sono delle estensioni (opzionali) che vengono installate appositamente dal costruttore. Sul secondo package è bene fare una precisazione: in effetti una Java Card non include un file system vero e proprio, ma la gestione dei file è affidata ad apposite applet (contenute appunto in questo pacchetto). Queste applet ovviamente rispettano lo standard ISO/IEC 7816-4 riguardante la sintassi e la struttura dei file. Meritano una nota particolare i due ultimi pacchetti. La poca memoria disponibile in una smart card rende impossibile (o comunque molto lenta) l’esecuzione di algoritmi crittografici complessi programmati in Java, per questo nei due package sono contenute classi che riportano gli algoritmi in codice macchina nativo in modo da velocizzarne l’esecuzione. Non è stato possibile unificare tutte le funzioni crittografiche in un solo pacchetto a causa di alcune restrizioni legislative. Queste riguardano l’esportazione e l’utilizzo di funzioni crittografiche. L’uso della crittografia infatti non è consentito liberamente, ma è soggetto a leggi locali diverse da paese a paese. In particolare se si intende usare algoritmi crittografici per le sole operazioni di decifratura è sufficiente servirsi del pacchetto “javacardx.crypto”, mentre se si hanno anche esigenze di cifratura allora occorre implementare il pacchetto “javacardx.cryptoEnc”. In definitiva tutte le funzioni della Java Card vengono eseguite come applet all’interno della JCVM. Vediamo ora più in dettaglio l’iter da seguire per lo sviluppo e l’esecuzione di una applicazione destinata ad una Java Card. 94 Smart Card Figura 43. Processo di sviluppo di una applicazione per Java Card. Il procedimento è del tutto simile a quello impiegato per realizzare un qualsiasi software Java per computer: si parte dal codice sorgente e si compila per ottenere il bytecode. La differenza sta proprio nella Virtual Machine. La JCVM infatti è composta di due parti: • una Off-card VM che riceve il bytecode e vi esegue le varie operazioni di verifica (riguardanti il formato, la sintassi e, se presente, la firma). Questa inoltre crea un file CAP (Card Application File) da inviare all’altra parte della VM; • una On-card VM che riceve il file CAP e ne testa e interpreta il bytecode generando le istruzioni macchina per il processore della smart card. Una soluzione di questo tipo porta tutti i vantaggi che sono caratteristici del linguaggio Java, in particolare la robustezza, la sicurezza e l’indipendenza dall’hardware in uso. Con questa struttura è inoltre possibile eseguire più applet su una stessa Java Card garantendo comunque la loro indipendenza (attraverso un controller di accesso) e la sicurezza dei dati. Il problema più grande invece riguarda l’impiego di risorse. Nelle smart card la memoria disponibile è poca e va preziosamente custodita. Per una 95 Capitolo 4 stessa funzione l’impiego di una Java Card richiede maggiori risorse rispetto ad una smart card tradizionale. Questo si fa sentire maggiormente in applicazioni crittografiche, dove le esigenze di calcolo sono più elevate. Da quanto detto si può concludere che l’utilizzo di una Java Card può risultare vantaggioso fin quando si eseguono applicazioni “semplici” come ad esempio la gestione dei file (in pratica quando si utilizzano smart card per fini che esulano dalla crittografia, come ad esempio operazioni bancarie o telefoniche). Quando invece si entra nell’ambito crittografico si deve raggiungere un compromesso tra una maggiore sicurezza e indipendenza dall’hardware ed una minore capacità prestazionale dovuta appunto ad un impiego più massiccio di risorse. 4.7 PKCS#11 Abbiamo già introdotto (nel capitolo relativo alle infrastrutture a chiave pubblica) la famiglia di standard PKCS47 che regolamentano le condizioni di impiego di algoritmi crittografici asimmetrici. Analizzeremo ora in dettaglio una particolare sezione dello standard, denominata “PKCS#11: Cryptographic Token Interface Standard”. Questo standard specifica un’interfaccia per la programmazione di applicazioni (API), detta Cryptoki (Cryptographic Token Interface), per tutti quegli strumenti che contengono informazioni, o sono in grado di implementare funzioni, di tipo crittografico. Cryptoki segue un approccio basato sulla programmazione ad oggetti cercando di raggiungere l’obiettivo dell’indipendenza tecnologica e della condivisione di risorse presentando alle applicazioni una visione comune e di tipo logico del dispositivo crittografico che viene denominato cryptographic token. Lo standard specifica i tipi di dato e le funzioni disponibili per un’applicazione che richiede servizi crittografici. Cryptoki isola un’applicazione dai dettagli del dispositivo crittografico. L’applicazione non deve cambiare se vuole interfacciarsi con un nuovo tipo di periferica o se vuole girare sotto un 47 Vedi paragrafo § 3.4.2 “Standard PKCS”. 96 Smart Card altro ambiente, in altre parole l’applicazione diventa portabile e si garantisce la proprietà di interoperabilità. E’ importante precisare che non è necessario che tutti i dispositivi crittografici siano in grado di eseguire la totalità delle funzioni offerte dall’interfaccia. Il compito di cryptoki è quello di rendere disponibile un modo logico di programmare i dispositivi, di qualunque tipo essi siano. Per cui ognuno di essi, nella realtà, implementerà un sottoinsieme delle funzioni offerte da cryptoki. PKCS#11 non specifica i dettagli di programmazione, ma si limita a fornire una descrizione precisa dei tipi di dato e delle funzioni che possono essere utilizzati da uno sviluppatore di software per scrivere la propria applicazione. 4.7.1 Caratteristiche tecnologiche Il modello generale di cryptoki è illustrato nella seguente figura. Figura 44. Modello generale Cryptoki. 97 Capitolo 4 Il modello illustra i vari stadi di una comunicazione tra una o più applicazioni che richiedono operazioni crittografiche e uno o più dispositivi in grado di eseguire tali operazioni. L’applicazione non comunica direttamente con il dispositivo fisico, ma, tramite l’interfaccia cryptoki, accede ad un oggetto che rappresenta la sua astrazione logica: il Token. In particolare si possono evidenziare due oggetti: il Token, che astrae il dispositivo fisico in grado di svolgere operazioni crittografiche (ad esempio la smart card); e lo Slot, che astrae il dispositivo fisico di lettura. Questo modello rende tutti i dispositivi crittografici logicamente uguali, in modo che l’applicazione non debba interfacciarsi direttamente ai driver della periferica e ciò rende possibile l’interoperabilità. Cryptoki permette inoltre ad una o più applicazioni di accedere ad uno o più token. E’ capace infatti di gestire il funzionamento multisessione attraverso il blocco “Device Contention/Synchronization” che smista le richieste delle applicazioni ai rispettivi token. Cryptoki viene implementato tramite una libreria scritta in ANSI48 C alla quale l’applicazione si può collegare in modo diretto o dinamico. 4.7.2 Sessioni Cryptoki richiede che un’applicazione apra una o più sessioni con un token per guadagnare l’accesso agli oggetti ed alle funzioni del token stesso. Una sessione fornisce una connessione logica tra l’applicazione e il token, e può essere di due tipi: R/W (Read/Write) oppure R/O (Read/Only). Le denominazioni R/W e R/O si riferiscono agli oggetti del token, non a quelli della sessione. In entrambi i tipi di sessione, infatti, un’applicazione può creare, leggere, scrivere e distruggere oggetti sessione e leggere oggetti token. Solo in una sessione R/W è però consentito creare, modificare o distruggere oggetti token. 48 American National Standard for Programming Language. 98 Smart Card Una volta aperta la sessione l’applicazione ha accesso a tutti gli oggetti pubblici del token, per accedere a quelli privati è necessario autenticarsi tramite una procedura di login (nella quale bisogna fornire il PIN del token). Quando una sessione viene chiusa tutti gli oggetti creati al suo interno vengono distrutti, questo vale anche per oggetti che sono in uso da parte di altre sessioni. Cryptoki infatti supporta le operazioni multissessione, ma un particolare token permette solo un certo numero di sessioni aperte per ogni applicazione. Sessioni R/O Una sessione di sola lettura è costituita da due diversi stati. Figura 45. Stati di una sessione R/O. Quando la sessione viene aperta può trovarsi nello stato R/O Public Session se non è stata eseguita alcuna autenticazione, o nello stato R/O User Functions se l’utente è stato autenticato. Nel primo caso l’applicazione ha accesso in sola lettura agli oggetti token pubblici e in lettura e scrittura agli oggetti sessione pubblici. Nel secondo caso l’applicazione ha accesso in sola lettura a tutti gli oggetti del token (pubblici e privati) e in lettura e scrittura a tutti gli oggetti sessione (pubblici e privati). 99 Capitolo 4 Sessioni R/W Una sessione di lettura e scrittura è costituita da tre stati. Figura 46. Stati di una sessione R/W. Quando la sessione è aperta si può trovare nello stato R/W Public Session se non sono state eseguite autenticazioni, nello stato R/W User Functions se è stata eseguita una autenticazione, nello stato R/W SO Functions se è stato autenticato un utente di tipo SO (Security Officer: ha il compito di inizializzare il token impostando il PIN o manipolando alcuni oggetti pubblici). Nel primo caso l’applicazione ha accesso in lettura e scrittura a tutti gli oggetti pubblici. Nel secondo caso l’applicazione ha accesso in lettura e scrittura a tutti gli oggetti. Nell’ultimo caso l’applicazione ha accesso in lettura e scrittura ai soli oggetti pubblici del token. Eventi di sessione A seguito di particolari operazioni una sessione può cambiare il suo attuale stato. Gli eventi responsabili del cambiamento di stato di una sessione sono: 100 Smart Card • Log In SO: il Security Officer è stato autenticato dal token. • Log In User: il normal user è stato autenticato dal token. • Log Out: l’applicazione disconnette l’utente corrente (che sia SO o normal user). • Colse Session: l’applicazione chiude la sessione corrente o tutte le sessioni da lei aperte. • Device Removed: il token viene rimosso dal dispositivo di lettura. In Cryptoki tutte le sessioni che un’applicazione ha con un token devono avere lo stesso stato di autenticazione. Quando un’applicazione si autentica all’interno di un token tutte le sessioni di quell’applicazione diventano autenticate dal token stesso e se un’applicazione si disconnette da un token tutte le sessioni dell’applicazione vengono automaticamente chiuse. Le sessioni vengono gestite da un handle di sessione, che è un valore che identifica univocamente una sessione. Tale valore viene specificato alle funzioni per indicare loro su quale sessione devono agire. 4.7.3 Oggetti Un token è un dispositivo che contiene oggetti e può operare funzioni di tipo crittografico. Cryptoki definisce tre classi di oggetti: dati, certificati e chiavi. Un oggetto “dato” è specificato dall’applicazione, un oggetto “certificato” contiene un certificato digitale, un oggetto “chiave” contiene una chiave crittografica che può essere pubblica, privata o segreta. Ogni oggetto chiave possiede dei sottotipi che ne specificano l’utilizzo nei meccanismi49. La gerarchia degli oggetti è la seguente. 49 Nel testo tecnico “PKCS#11: Cryptographic Token Interface Standard” della RSA Laboratories, gli algoritmi crittografici vengono indicati con il nome di “mechanism” e di conseguenza tradotti in “meccanismi”. 101 Capitolo 4 Figura 47. Gerarchia degli oggetti definiti in cryptoki. Gli oggetti possono anche essere classificati in base al loro tempo di vita e alla loro visibilità, si possono quindi distinguere: • Oggetti token: sono visibili a tutte le applicazioni connesse al token che hanno un permesso sufficiente e permangono all’interno del token anche quando la sessione viene chiusa ed il token rimosso dallo slot. • Oggetti sessione: ogni volta che una sessione viene chiusa tutti gli oggetti creati dalla sessione vengono distrutti. In aggiunta tali oggetti sono visibili solo all’applicazione che li ha creati. Un’ulteriore classificazione può essere fatta in base ai requisiti di accesso, quindi troviamo: • Oggetti pubblici: un’applicazione non ha necessità di eseguire un login al token per vederli. • Oggetti privati: sono visibili solo a seguito di una avvenuto login. In generale un oggetto consiste in una serie di attributi, ognuno dei quali è caratterizzato da un determinato valore. Andiamo ora a vedere più da vicino le tre principali classi di oggetti definite da cryptoki. 102 Smart Card Oggetti “Data” Un oggetto Data contiene informazioni relative alle applicazioni ed è definito da cryptoki con i seguenti attributi: Data object Application Object ID Value Figura 48. Attributi di un oggetto Data. Oggetti “Key” Gli oggetti Key contengono chiavi di crittografia e autenticazione, che possono essere private, pubbliche o segrete. Key Key type Key ID Start Date End Date Derive Local Key Gen Mechanism Public Key Subject Trusted Encrypt Verify Verify Recover Wrap Private Key Subject Sensitive Decrypt Sign Sign Recover Unwrap Extractable Always Sensitive Never Extractable Secret Key Sensitive Encrypt Decrypt Sign Verify Wrap Unwrap Extractable Always Sensitive Never Extractable Figura 49. Gerarchia e attributi di un oggetto Key. 103 Capitolo 4 Oggetti “Certificate” Gli oggetti Certificate possono memorizzare certificati a chiave pubblica. Cryptoki specifica la modalità di accesso a questo tipo di oggetti, ma non attribuisce significati ed usi ai certificati. Certificate Certificate Type Trusted X.509 Public Key Certificate X.509 Attribute Certificate Subject Certificate ID Issuer Serial Number Value Owner Issuer Serial Number Attribute Types Value Figura 50. Gerarchia e attributi di un oggetto Certificate. In realtà cryptoki prevede anche altri tipi di oggetti, che forniscono informazioni aggiuntive riguardanti, ad esempio, le caratteristiche hardware del dispositivo e gli algoritmi crittografici supportati. La visione generale della gerarchia di alto livello degli oggetti definiti dallo standard cryptoki e di alcuni attributi ad essi associati è illustrata nella seguente figura. 104 Smart Card Figura 51. Gerarchia completa degli oggetti definiti nello standard cryptoki. 4.7.4 Considerazioni sulla sicurezza Come interfaccia ai dispositivi crittografici Cryptoki fornisce le basi per la sicurezza all’interno di un computer o di un sistema di comunicazione. Le due principali caratteristiche dell’interfaccia che facilitano tale compito sono: • L’accesso agli oggetti privati, le funzioni crittografiche e i certificati di un token richiede un PIN. Quindi il semplice possesso del dispositivo crittografico non è sufficiente per usarlo, è necessario anche conoscere il PIN di autenticazione. • Una protezione aggiuntiva per le chiavi private o segrete può essere garantita designandole come sensitive, cioè che non possono mai essere rivelate in chiaro al di fuori del token, oppure unextractable, ovvero non possono mai essere rivelate al di fuori del token neanche in forma criptata (anche se rimangono comunque utilizzabili). Ci si aspetta che l’accesso ad oggetti privati di tipo sensitive o unextractable risulti difficile all’infuori dell’interfaccia Cryptoki. Un dispositivo è solitamente dotato di un ambiente protetto (ad esempio una memoria protetta) 105 Capitolo 4 in cui memorizzare dati di questo tipo, alcuni dispositivi però non hanno questa possibilità, quindi devono proteggere i loro oggetti in altro modo. Una soluzione è quella di cifrare tali oggetti con una chiave speciale, detta master key, che viene ricavata dal PIN dell’utente. Sicuramente la crittografia è solo un elemento di sicurezza, e il token rappresenta solo un componente di un sistema, per cui la sicurezza deve essere intesa a livello globale. Mentre un token può essere considerato sicuro, bisogna allargare il campo di vista anche al sistema operativo che ospita l’applicazione che fa uso del token. E’ infatti possibile che altre applicazioni ostili intercettino informazioni riservate (come ad esempio il PIN del dispositivo) mentre queste sono gestite dal sistema operativo oppure attraversano un canale di comunicazione, con la conseguenza che l’applicazione pirata potrebbe far eseguire qualsiasi tipo di operazione al token. Da notare comunque che, in ognuno di questi spiacevoli casi, le chiavi marcate “sensitive” o “unextractable” non possono in alcun modo essere rilevate o modificate. Si può quindi concludere che Cryptoki non garantisce la sicurezza dell’intero sistema, ma fornisce una buona e solida base per lo sviluppo di applicazioni che fanno uso di dispositivi crittografici. 4.7.5 Provider di sicurezza IAIK Un provider di sicurezza è un software in grado di fornire la più ampia varietà di funzioni crittografiche e realizzare un’interfaccia per l’accesso al dispositivo crittografico. In questo lavoro è stata utilizzata un’implementazione dello standard PKCS#11 sviluppata dall’Institute for Applied Information Processing and Communications (IAIK) presso l’università austriaca “University of Technology” di Graz50. Il Provider IAIK fornisce un insieme di funzioni crittografiche accessibili mediante le API standard Java JCA (Java Cryptography Architecture) e JCE 50 http://www.iaik.tugraz.at/ 106 Smart Card (Java Cryptography Extention) e permette l’accesso al dispositivo fisico tramite una libreria conforme al descritto standard PKCS#11. La parte che si occupa di comunicare direttamente col il token prende il nome di Wrapper. La libreria fornita dal wrapper fa uso dei metodi nativi di Java JNI (Java Native Interface) che permettono alle applicazioni scritte in Java di usare le API Cryptoki (che, ricordiamo, sono scritte in C). Nella figura seguente è illustrata l’organizzazione dei livelli software coperti dal wrapper IAIK. Figura 52. Struttura dei livelli software del wrapper IAIK. Lo strato più basso è occupato dalla libreria dinamica di sistema fornita dal produttore del token, compilata per la piattaforma di destinazione, seguendo le direttive della specifica PKCS#11. Lo strato immediatamente superiore del wrapper è necessario per realizzare lo strato JNI che permette al codice Java di utilizzare funzioni C. Questo strato e quello ancora superiore devono quindi rispettare la convenzione dei nomi (name mangling) delle funzioni e dei metodi nativi prevista da JNI. Alla cima dello stack c’è il livello API, che è una struttura Object-Oriented con la quale si interfacciano le applicazioni. Il provider IAIK è dedicato all’uso di particolari dispositivi crittografici, come le smart card, e gli oggetti utilizzati durante l’esecuzione delle funzioni crittografiche vengono gestiti in modo specifico. Ad esempio gli oggetti “chiave” del provider PKCS#11 rappresentano chiavi contenute all’interno di un token e quindi non possono essere gestite come normali chiavi software. Infatti se un’applicazione richiede l’utilizzo di una chiave per un’operazione crittografica, il provider non trasferisce la chiave alla JVM, bensì invia il dato da elaborare 107 Capitolo 4 all’interno del token e chiede al token stesso di eseguire l’operazione prevista con la specifica chiave. In questo modo la chiave non esce mai al di fuori del token che contiene, oltre alla chiave stessa, anche l’implementazione dell’algoritmo necessario ad eseguire l’operazione direttamente dentro il token. Possiamo immaginare il token come una scatola nera all’esterno della quale vediamo entrare ed uscire dati in chiaro e dati cifrati, ma non possiamo in alcun modo vedere cosa avviene all’interno della scatola. 108 Realizzazione del progetto Capitolo 5. REALIZZAZIONE DEL PROGETTO 109 Capitolo 5 5.1 Descrizione generale del progetto Il lavoro che andrò ora a presentare è stato sviluppato in collaborazione con la ASUR zona 7 della regione Marche. Nel corso di questa tesi si è fatto spesso riferimento al settore della Pubblica Amministrazione e alla sua progressiva migrazione verso le tecnologie informatiche, allo scopo di trarre vantaggi sia per chi lavora (in termini di migliore gestione degli archivi e procedure più veloci), sia per l’utenza pubblica (garantendo più efficienza nei servizi e minori tempi di attesa). Proprio in quest’ottica va ad inserirsi questo progetto, del quale ora illustreremo le linee guida. L’obiettivo è quello di progettare un software che utilizzi le smart card per realizzare la firma digitale di documenti elettronici. Il campo di applicazione è appunto l’ambito sanitario, in cui un medico può inviare o richiedere dei referti ad un database (chiamato repository) per eventuali operazioni di teleconsulto o di second opinion. Il referto in questione, prima di essere spedito, dovrà essere firmato digitalmente, in modo da garantire i requisiti base di un sistema di sicurezza (autenticazione, integrità e riservatezza). Per il momento l’attenzione è rivolta ad un’utenza di soli medici, si prevede comunque che, una volta avviato il servizio, anche i pazienti possano disporre di una propria smart card. La prima decisione che si deve prendere riguarda il tipo di smart card da adottare. La scelta ricade su due possibili alternative: adottare una carta di impiego nazionale (come la CIE51); oppure adottare una soluzione propria. La prima scelta sembrerebbe più vantaggiosa, considerando che, in breve tempo, tutti saranno in possesso della carta di identità elettronica; inoltre c’è anche il vantaggio, non da poco, di poter usare una sola carta per più servizi. Seguire questa strada, però, si è rivelato presto difficoltoso a causa del fatto che la CIE non è ancora disponibile in tutti i comuni, inoltre c’è una mancanza di divulgazione di materiale, sia tecnico che pratico, relativo al suo funzionamento. Non rimane quindi che adottare una soluzione propria che preveda l’impiego di una smart card specifica per il servizio offerto. 51 Carta di Identità Elettronica. 110 Realizzazione del progetto Come si è detto, l’utenza prevista, sia attuale che futura, per questo progetto coinvolge sia i medici che i pazienti. Un campo di impiego così vasto richiede una particolare attenzione alla possibilità di utilizzo delle tecnologie informatiche proposte da parte di personale non specializzato. Si è cercato quindi di improntare il progetto verso la semplicità d’uso, continuando comunque a garantire tutti i servizi e i requisiti di sicurezza previsti. Si è scelto allora di “partire da zero” e seguire tutti i passi necessari alla realizzazione dell’infrastruttura per la firma digitale. Si prevede quindi che un utente (che si tratti, indifferentemente, di un medico o di un paziente) si procuri una smart card vuota, che dovrà essere inizializzata e resa utilizzabile per le operazioni di firma digitale. Il progetto, quindi, si compone di due parti principali: • Inizializzazione: è la fase in cui la smart card è resa operabile. Si deve dotare la scheda di una coppia di chiavi e di un certificato a chiave pubblica (nel formato X.509). Più precisamente vengono create, al suo interno, la coppia di chiavi asimmetriche e la richiesta di certificato da inviare alla Certification Authority. Quest’ultima firmerà un certificato X.509 che poi sarà memorizzato all’interno della smart card. • Firma: è la fase in cui si realizzano le operazioni legate alla firma digitale del documento elettronico. In particolare sarà possibile: cifrare il documento originale per ottenere la firma; decifrare un documento firmato; verificare la firma per testare l’integrità del documento. Il software di firma riceverà in ingresso direttamente il digest del documento originale, si dovrà quindi occupare di cifrarlo con la chiave privata presente nella smart card e restituire un oggetto che contenga il documento cifrato ed il certificato a chiave pubblica (che contiene la chiave di decifratura). Il fatto di avere come input un digest rende il software di firma utilizzabile con qualunque tipo di documento e, di conseguenza, in qualsiasi contesto. 111 Capitolo 5 5.1.2 Applicazione all’ambito sanitario Questo lavoro trova applicazione ad un altro progetto nato anch’esso dalla collaborazione tra l’Università Politecnica delle Marche e la ASUR Marche zona 7 di Ancona riguardante la delocalizzazione della refertazione diagnostica. Tale progetto, denominato MirO, si pone l’obiettivo di fornire un prodotto flessibile in grado di implementare un servizio di refertazione asincrono: cioè capace di separare, sia da un punto di vista temporale che spaziale, l’esecuzione di un esame dalla refertazione dello stesso. Lo scopo è quello di creare un’applicazione software completa in grado di gestire l’intero processo di telerefertazione e di teleconsulto. Figura 53. Posizione del progetto MiRo nel processo di telerefertazione e teleconsulto. Tale progetto intende realizzare una piattaforma orientata ai servizi che abbia le caratteristiche di flessibilità e semplicità. La sua architettura infatti è basata su standard diffusi e riconosciuti, come Internet, in modo da creare le basi per facilitare le applicazioni sia in ambito sanitario a livello di personale medico, che, in un prossimo futuro, direttamente ai cittadini. MiRo si basa sul concetto di evento. L’effettuazione di un esame presso un laboratorio (qualsiasi, di una qualunque struttura ospedaliera) e la 112 Realizzazione del progetto conseguente archiviazione del dato in forma digitale genera ciò che viene chiamato evento. L’evento, in realtà, non è il dato clinico vero e proprio, ma rappresenta una sorta di meta-dato-clinico del dato digitale prelevato in laboratorio. Esso consiste in una serie di informazioni che riguardano: l’unità erogante il dato, la data e l’ora dell’esame, la struttura che lo ha prodotto, il codice impegnativa, il link da dove si può scaricare il dato, lo stato e altro ancora. Ogni evento viene immagazzinato all’interno di un apposito raccoglitore, definito repository, che costituisce il core del sistema e che contiene la definizione del legame tra evento ed esame. Qualsiasi esame che può essere memorizzato in forma digitale può essere associato ad un evento, dotando quindi il progetto delle caratteristiche di flessibilità ed adattabilità. In figura è mostrata l’architettura generale di MiRo dove si notano i tre attori principali del sistema: Repository; Laboratories; Doctors. Figura 54. Architettura generale del progetto MiRo. Il cuore del sistema è rappresentato dal Repository centrale offerto da un’azienda o da un ente erogante (vedi ASUR), il quale si impegna nel corretto funzionamento dell’intero sistema di refertazione e nella manutenzione dello stesso. 113 Capitolo 5 A destra del repository troviamo il laboratorio, cioè la struttura che usufruisce del servizio per generare gli eventi dovuti all’acquisizione dei dati digitali di un esame clinico. A sinistra del repository si trova colui che scrive il referto, ossia il medico o un’equipe di medici specializzati, i quali pubblicano il proprio referto autenticandolo con la propria firma digitale. Proprio in quest’ultima parte si va a collocare il progetto di firma digitale che garantisce all’intero sistema le caratteristiche di: autenticazione d’identità; riservatezza dei dati trasmessi; integrità dei dati; non ripudio della comunicazione. Tutte queste proprietà sono alla base di un sistema sicuro e sono raggiunte tramite l’impiego delle tecniche di crittografia asimmetrica, delle infrastrutture a chiave pubblica e delle smart card. 5.2 Implementazione Verranno ora descritti gli aspetti pratici del lavoro svolto, a cominciare da un elenco degli strumenti che sono stati necessari per la sua realizzazione, per poi andare più in dettaglio sul software che è stato prodotto. Si è voluto analizzare meglio anche il provider di sicurezza IAIK (già introdotto nella sezione dedicata alle smart card52) in quanto elemento base per l’accesso alla scheda. 5.2.1 Strumenti utilizzati Gli strumenti software impiegati nel progetto sono: • Java 1.4.2 Standard Edition: è il kit di sviluppo Java; • Eclipse 3.1: editor per il software Java; • Provider IAIK: fornisce le funzioni crittografiche e l’interfaccia con la smart card; 52 Si veda il paragrafo § 4.7.5. 114 Realizzazione del progetto • OpenSSL 0.9.8: impiegato come Certification Authority temporanea per la creazione dei certificati X.509. Per quanto riguarda l’hardware: • Tutti i programmi sopra enunciati sono stati installati su di un Celeron con clock a 650 MHz, memoria RAM da 320 MB e sistema operativo Windows 2000 Professional. • Il lettore di smart card è un GemPC410 della GemPlus con collegamento seriale alla porta RS232. • Le smart card sono delle GemPlus GPK16 da 16KB. 5.2.2 Installazione del Provider IAIK Il Provider di sicurezza IAIK, sviluppato dalla “University of Technology” austriaca di Graz, è un software che fornisce un insieme di funzioni crittografiche, utilizzabili mediante le API standard JCE, ed un Wrapper che implementa il modulo PKCS#11 per interfacciare le smart card53. E’ un elemento essenziale necessario in tutte e tre le componenti software che verranno presentate, per questo si è ritenuto opportuno dedicargli particolare attenzione. L’installazione delle due parti del provider avviene in modo separato ed anche il loro utilizzo è diverso (come vedremo più avanti descrivendo il software di firma). La JCE fornita dal provider IAIK si installa molto semplicemente da programma inserendo la seguente riga di codice: Security.addProvider(new IAIK()); L’installazione del modulo PKCS#11 invece prevede due possibili alternative: una installazione statica ed una dinamica. Andremo ora a vedere brevemente i due procedimenti e le ragioni che hanno condotto a scegliere prima l’una poi l’altra versione. 53 Per informazioni più dettagliate si veda il paragrafo § 4.7 PKCS#11 e §4.7.5 Provider di sicurezza IAIK. 115 Capitolo 5 L’installazione statica prevede di aggiungere le seguenti librerie esterne al progetto: • iaikPkcs11Provider.jar: contiene le classi che costituiscono il provider; • iaikPkcs11Wrapper.jar: contiene le classi che costituiscono il wrapper; • iaik_jce.jar: contiene le funzioni crittografiche; • iaik_jce_full.jar: contiene alcune funzioni crittografiche aggiuntive (in realtà questa libreria è opzionale). Bisogna poi impostare le proprietà del provider aggiungendo i file “IAIKPkcs11.properties” e “IAIKPkcs11Global.properties” (contenuti all’interno del pacchetto “iaikPkcs11Provider.jar”) in una gerarchia di directory del tipo “iaik/pkcs/pkcs11/provider/” da inserire all’interno del classpath del progetto. Il primo file dovrà essere modificato andando a scegliere la corretta libreria DLL per il dispositivo di lettura che si sta utilizzando. Nel nostro caso il dispositivo è un GemPlus e la libreria è “gclib.dll” (fornita con il CD di installazione del lettore). Il secondo file invece deve essere anch’esso modificato aggiungendo la seguente riga: providerInstance.1=iaik/pkcs/pkcs11/provider/IAIKPkcs11.properties che indica alla prima istanza del provider di cercare le proprietà necessarie sul file “IAIKPkcs11.properties”. Si deve poi modificare il file “java.security” del Java Runtime Environment aggiungendo l’istanza del provider nel seguente modo: security.provider.6=iaik.pkcs.pkcs11.provider.IAIKPkcs11 Infine, per richiamare il provider da programma, basta scrivere la seguente riga di codice: pkcs11Provider = IAIKPkcs11.getProviderInstance(1); L’installazione dinamica necessita l’importazione delle stesse librerie del caso precedente, ma le proprietà del provider vengono impostate al runtime direttamente dal programma con il seguente codice: Properties providerProperties = new Properties(); providerProperties.put("PKCS11_NATIVE_MODULE", "gclib.dll"); pkcs11Provider = new IAIKPkcs11(providerProperties); Security.addProvider(pkcs11Provider); 116 Realizzazione del progetto Inizialmente si è scelto di eseguire una installazione statica del provider per motivi di robustezza, in quanto tutte le configurazioni impostate staticamente hanno sempre priorità maggiore di quelle impostate dinamicamente. Questa soluzione però pone molti limiti alla possibilità di interagire con diversi dispositivi hardware, in quanto, per ognuno di essi, bisognerebbe creare una istanza dedicata del provider con il relativo file di proprietà che seleziona la libreria DLL corretta. Si è preferito allora adottare l’opzione dinamica che assegna la libreria DLL al runtime, in questo modo si è più predisposti verso l’interoperabilità. Anche se, attualmente, il software prodotto è in grado di gestire un solo tipo di lettore, uno sviluppo futuro potrebbe eseguire al runtime sia il riconoscimento dell’hardware che l’assegnazione dell’apposita libreria. Sono state considerate anche soluzioni alternative al provider IAIK, che presenta delle limitazioni di utilizzo. Una di queste è Bouncy Castle54. Si tratta di un provider di sicurezza completamente gratuito capace di fornire tutte le funzioni crittografiche necessarie. Non è stato impiegato in questo progetto in quanto non implementa il modulo PKCS#11 per comunicare con le smart card. Una sua applicazione potrebbe riguardare la Certification Authority per la generazione dei certificati X.509. Una alternativa possibile, invece, sembra essere il provider della SUN fornito in dotazione con le ultime versioni del pacchetto Java. Questo infatti è gratuito (si tratta di software open source) ed implementa il modulo PKCS#11. 5.2.3 Software prodotto Il software sviluppato nel presente lavoro si compone di tre parti distinte: • Software di inizializzazione: si occupa di creare la coppia di chiavi e la richiesta di certificato sulla smart card e, successivamente, di inserire il certificato X.509 all’interno della scheda. 54 www.bouncycastle.org 117 Capitolo 5 • Software di firma: esegue le operazioni di cifratura necessarie per realizzare la firma digitale. • Tool di gestione della smart card: è uno strumento di uso generico capace di leggere e scrivere la smart card e gestire il keystore della scheda. Andremo ora ad analizzare questi programmi descrivendone il funzionamento e riportando anche alcuni esempi. Per maggior chiarezza si può fare riferimento al codice riportato in appendice. Software di inizializzazione Si è già discusso, nella descrizione generale del progetto, sulla scelta che è stata fatta di partire da smart card vuote e renderle utilizzabili per le operazioni di firma. Il software di inizializzazione ha proprio questo compito, ed in particolare si occupa di generare la coppia di chiavi e la richiesta di certificato all’interno della smart card, inviare la richiesta alla Certification Authority e registrare il certificato X.509, generato dalla CA, sulla smart card. Lo schema di funzionamento è il seguente: Generazione chiavi RSA Alias Generazione PKCS10 CSR Invio CSR alla CA CA off-line Inserimento su Smart Card Invio cert. X.509 Generazione certificato Figura 55. Schema di funzionamento del software di inizializzazione. 118 Realizzazione del progetto Si parte da un Alias che è una semplice stringa di caratteri che identifica univocamente il possessore della smart card. Si genera poi la coppia di chiavi RSA. Questa operazione avviene all’interno della smart card servendosi del provider IAIK per accedere ad essa ed alle sue funzioni. Si è utilizzato il metodo “KeyPairGenerator” del package “java.security” assegnando ad una sua istanza l’algoritmo RSA ed il nome del provider IAIK: KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", pkcs11Provider.getName()); Poi si sono elencate le specifiche delle chiavi pubblica e privata, in particolare si è resa la chiave privata “sensitive” e “unextractable” (in modo che non possa mai essere rivelata al di fuori della scheda, né in chiaro né in forma criptata) e si è scelta una lunghezza pari a 1024 bit. In questa fase si è utilizzato l’alias per assegnare la “label” alle chiavi. Tramite queste specifiche si è inizializzata l’istanza del precedente metodo di generazione e si è creata la coppia di chiavi: keyPairGen.initialize(keyPairSpec); KeyPair keyPair = keyPairGen.generateKeyPair(); Viene poi creata la richiesta di certificato nel formato standard PKCS#10. Anche questa operazione è eseguita all’interno della smart card, poiché la richiesta dovrà essere firmata con la chiave privata. Il metodo utilizzato, “CertificaRequest”, fa parte delle librerie del provider IAIK ed è impiegato in questo modo: iaik.pkcs.pkcs10.CertificateRequest request = new iaik.pkcs.pkcs10.CertificateRequest(keyPair.getPublic(), name); Riceve come parametri la chiave pubblica e “name”, che rappresenta il distinguished name secondo lo standard X.500. Tale richiesta è stata poi firmata con la chiave privata, impiegando l’algoritmo di hashing SHA-1: request.sign(iaik.asn1.structures.AlgorithmID.sha1WithRSAEncryption, keyPair.getPrivate(), pkcs11Provider.getName()); La richiesta così ottenuta viene codificata in BASE 64 (che serve a rappresentare una sequenza di byte in caratteri ASCII) ed inviata alla Certification Authority. Quest’ultima ha il compito di firmarla e creare un certificato valido nello standard X.509. All’interno di esso ci saranno quindi due 119 Capitolo 5 certificati a chiave pubblica: uno relativo al possessore della card e firmato dalla CA; l’altro relativo alla CA stessa ed autofirmato. Questo procedimento è stato messo in pratica servendosi del software OpenSSL. Il certificato è ottenuto nel formato PEM (Privacy-Enhanced Mail) che è una versione stampabile dello standard PKCS#7. L’ultima operazione riguarda la memorizzazione del certificato all’interno della smart card. Si tratta di aggiungere un elemento “key entry” al key store della scheda, con il seguente metodo: tokenKeyStore.setKeyEntry("alias", priK, null, chain); in cui “alias” è l’identificativo del possessore della scheda, “priK” è la chiave privata generata precedentemente, “null” è la password del key store, “chain” è la catena di certificazione estratta dal file PEM restituito dalla CA. Poiché viene utilizzata la chiave privata, anche questa operazione deve essere svolta all’interno della scheda servendosi del provider IAIK. A questo punto nella smart card sono presenti: la chiave privata ed il certificato a chiave pubblica relativi all’alias scelto. Quindi la scheda è ora utilizzabile per le operazioni di firma digitale. E’ importante sottolineare ancora una volta il fatto che tutte le operazioni che richiedono l’impiego della chiave privata vengono eseguite dentro la smart card. I metodi Java che necessitano di queste operazioni delegano al provider IAIK il compito di eseguirle, in quanto è l’unico che può avere accesso alla smart card. Per questo motivo bisogna sempre specificare il nome del provider nella creazione dell’istanza di un metodo crittografico. Riportiamo ora alcuni esempi per dare un’idea pratica di quanto descritto. Proponiamo in particolare la stampa della catena di certificazione: La catena presenta 2 certificati 1° elemento della catena: Version: 0 Serial number: 18 Signature algorithm: sha1WithRSAEncryption (1.2.840.113549.1.1.5) Issuer: [email protected],CN=JTelemed,OU=Soft,O=JTelemed,L=Ancona,ST=An,C=IT Valid not before: Fri Feb 03 11:00:23 CET 2006 not after: Sun Nov 23 11:00:23 CET 2008 Subject: CN=nome,OU=ou,O=o,L=l,ST=st,C=it SunJSSE RSA public key: 120 Realizzazione del progetto public exponent: 010001 modulus: b64c5f2e 547e0f70 d869824e 29a655da f6143851 35f1a722 b4e500cf be692586 b4dff5d9 7852a5b1 eaec11d4 241e4a0d f3af694e 20b64805 4248165e 12e43371 31f20f32 eda154b1 dca9cab7 6b92680d 18fd0c96 9161a793 ebc2bd8a 7f081c41 16ada19a fd5b5bad 521fb1aa b36807cd Certificate Fingerprint (MD5) : DD:01:3B:4B:9B:C0:37:F3:92:9B:F7:24:27:4F:F4:8A Certificate Fingerprint (SHA-1): CD:C0:43:7F:F7:EC:DC:E2:D1:AB:BE:7E:EC:66:81:5D:93:F1:27:DC 2° elemento della catena: Version: 0 Serial number: 1140969833 Signature algorithm: sha1WithRSAEncryption (1.2.840.113549.1.1.5) Issuer: CN=JTelemed,OU=Soft,O=JTelemed,L=Ancona,ST=An,C=IT Valid not before: Sun Feb 26 17:03:53 CET 2006 not after: Sat May 27 18:03:53 CEST 2006 Subject: CN=JTelemed,OU=Soft,O=JTelemed,L=Ancona,ST=An,C=IT SunJSSE RSA public key: public exponent: 010001 modulus: c911967d 40261662 2698b72c 322d0051 ba4e46f7 ca354315 1a41f447 b922c953 3f3e199d 16fa2736 0b87087b 1c89ca87 ccb8938e 9cbbfc22 7d05b2bd d6a1b0bd b659565e 9185af24 c06b1047 d79e632b 8dfef1b9 8108c2de 5b04c493 771240de fbeadec7 3a9d2217 255eda4e ad64f838 Certificate Fingerprint (MD5) : AF:73:A5:82:CB:66:BF:91:5A:2D:BC:2F:09:8A:22:3D Certificate Fingerprint (SHA-1): 5051471c 2170d913 6c9efc60 17f36601 80fd2058 65a9e773 d1a23fdd 05027f1d 1F:2C:64:91:B2:54:14:27:6B:1E:27:41:A4:BC:42:79:5C:C8:A2:9A Si può notare che il primo certificato ha come subject il DN (Distinguished Name) del possessore della smart card, e come issuer il DN della CA, mentre il secondo certificato è autofirmato e infatti i due campi indicano la stessa CA. Questa stessa catena di certificati è memorizzata su file in formato codificato e si presenta nel seguente modo: -----BEGIN CERTIFICATE----MIICQzCCAawCARIwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAklUMQswCQYD VQQIEwJBbjEPMA0GA1UEBxMGQW5jb25hMREwDwYDVQQKEwhKVGVsZW1lZDENMAsG A1UECxMEU29mdDERMA8GA1UEAxMISlRlbGVtZWQxIzAhBgkqhkiG9w0BCQEWFGp0 ZWxlbWVkQGp0ZWxlbWVkLml0MB4XDTA2MDIwMzEwMDAyM1oXDTA4MTEyMzEwMDAy M1owTjELMAkGA1UEBhMCaXQxCzAJBgNVBAgTAnN0MQowCAYDVQQHEwFsMQowCAYD VQQKEwFvMQswCQYDVQQLEwJvdTENMAsGA1UEAxMEbm9tZTCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEAtkxfLlR+D3DYaYJOKaZV2vYUOFE18acitOUAz1BRRxy+ aSWGtN/12XhSpbHq7BHUJB5KDfOvaU4gtkgFIXDZE0JIFl4S5DNxMfIPMu2hVLHc qcq3a5JoDRj9DJZsnvxgkWGnk+vCvYp/CBxBFq2hmv1bW61SH7Gqs2gHzRfzZgEC AwEAATANBgkqhkiG9w0BAQUFAAOBgQAnFmV86Cj7XU1M+iYINgq1A/FMnXDM/BZP 3LmKQ/rSdAJ+WjZH4gimrO3s4728Y01y6nCTX0fE5+V3lsbrJ7aIjTlHJCZUU5BH qXtJXmxoSrI9YG/TPMnrsDnFn9M3J0gEb6s7rbU8SQMWn99pBsIF58r1lWaQ4pSC d5NRUIoRGA== -----END CERTIFICATE---------BEGIN CERTIFICATE----- 121 Capitolo 5 MIICMjCCAZsCBEQB0WkwDQYJKoZIhvcNAQEFBQAwYDELMAkGA1UEBhMCSVQxCzAJ BgNVBAgTAkFuMQ8wDQYDVQQHEwZBbmNvbmExETAPBgNVBAoTCEpUZWxlbWVkMQ0w CwYDVQQLEwRTb2Z0MREwDwYDVQQDEwhKVGVsZW1lZDAeFw0wNjAyMjYxNjAzNTNa Fw0wNjA1MjcxNjAzNTNaMGAxCzAJBgNVBAYTAklUMQswCQYDVQQIEwJBbjEPMA0G A1UEBxMGQW5jb25hMREwDwYDVQQKEwhKVGVsZW1lZDENMAsGA1UECxMEU29mdDER MA8GA1UEAxMISlRlbGVtZWQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMkR ln1AJhZiJpi3LDItAFG6Tkb3yjVDFRpB9EeA/SBYuSLJUz8+GZ0W+ic2C4cIexyJ yofMuJOOnLv8ImWp53N9BbK91qGwvbZZVl6Rha8kwGsQR9eeYyuN/vG50aI/3YEI wt5bBMSTdxJA3vvq3sc6nSIXJV7aTq1k+DgFAn8dAgMBAAEwDQYJKoZIhvcNAQEF BQADgYEAef9V/kN/CBQEDn5o5Zd0/vsZy62Rdg3/Snn8oL9ew5Fv/gvOZrdecd0o LyV/quW+XqmmjPY+YcLHtupUJJpEfhAm06GImcojTt+3jCtjAb0iSocyAfOVIcWb ylgaNlmzaZPnuctITxh0FXDl7BfK7qzyQ0UJkg3ApCRSqeHIUqc= -----END CERTIFICATE----- Software di firma Il software di firma si compone principalmente di due classi: • Firma.java: è la classe che si occupa di eseguire le funzioni crittografiche relative alle operazioni di firma digitale. • DigestFirmato.java: è una classe che rappresenta il messaggio firmato e contiene due variabili: la firma (sottoforma di array di byte) ed il certificato X.509. Inoltre questa classe prevede anche due metodi (serializza e deserializza) che consentono il salvataggio su file ed il recupero dei due oggetti in forma serializzata. Il cuore di questo programma è la classe “Firma” che si compone di diversi metodi, tra i quali i più importanti sono: public DigestFirmato cifra(byte[] digest) che riceve come parametro il digest sottoforma di array di byte, lo invia alla smart card per la cifratura e ritorna una istanza dell’oggetto DigestFirmato; public byte[] decifra(DigestFirmato df) riceve come parametro una istanza di DigestFirmato, ne estrae il messaggio cifrato e il certificato X.509 ed esegue la decifratura. Ritorna l’array di byte risultato della decifratura; public void compara(byte arr1[], byte arr2[]) riceve due array di byte come parametri che rappresentano il digest originale e quello ricavato dalla decifratura. Ne esegue il confronto per verificare che il messaggio non sia stato modificato. 122 Realizzazione del progetto Questi metodi richiamano a loro volta altri metodi che si occupano, ad esempio, di verificare la presenza della smart card, richiedere il PIN di autenticazione per eseguire il login, verificare la validità temporale e le condizioni di uso del certificato, accedere alle chiavi pubblica e privata. Anche in questo caso andremo a commentare le più importanti righe di codice, in particolare quelle relative alle operazioni di cifratura e decifratura. In ambedue i casi è stato utilizzato il metodo “Cipher” della libreria “javax.crypto”. La cifratura necessita l’impiego della chiave privata, bisogna quindi specificare il modulo PKCS#11 del provider IAIK nell’istanza di cifratura: Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", pkcs11Provider.getName()); Il primo parametro specifica l’algoritmo di cifratura (RSA), il tipo di cifratura a blocchi (ECB) ed il tipo di riempimento (PKCS1Padding). In seguito si inizializza Cipher nella modalità di cifratura assegnando anche la chiave privata: c.init(Cipher.ENCRYPT_MODE, priK); Poi si esegue l’effettiva cifratura: cifrato = c.doFinal(digest); Una volta realizzata la firma si crea l’istanza dell’oggetto DigestFirmato assegnando sia la firma che il certificato: DigestFirmato df = new DigestFirmato(cifrato, x509); Durante la decifratura si compiono le stesse operazioni, ma è importante notare una differenza nel modo in cui viene creata l’istanza di Cipher. In questo caso non è richiesto l’impiego della chiave privata in quanto la decifratura avviene con la chiave pubblica. Inoltre tale chiave è estratta dal certificato recuperato dall’oggetto DigestFirmato, quindi, in realtà, non è necessaria neanche la smart card55. Per questo nell’istanziazione non si specifica il modulo PKCS#11 del provider IAIK, ma quella parte che fornisce solo la JCE e che è chiamata “IAIK”: Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "IAIK"); 55 Come in effetti dovrebbe essere. Si ricordi che il messaggio firmato è inviato su una rete pubblica e può raggiungere qualsiasi parte del mondo, e chi riceve il messaggio non può sicuramente disporre della stessa smart card di colui che lo ha inviato. 123 Capitolo 5 Ovviamente il modo di decifratura deve adottare le stesse proprietà impiegate nella cifratura (RSA/ECB/PKCS1Padding), altrimenti si incorrerebbe in un errore. In questa spiegazione è stato tralasciato il dettaglio di come viene gestita la chiave privata. Sappiamo già che il suo utilizzo è delegato esclusivamente al provider IAIK. Vogliamo ora precisare il fatto che, nell’operazione di firma, viene scelta la prima chiave trovata nel key store, senza selezionare un alias specifico. E’ stata scelta questa soluzione in quanto si prevede che nella scheda sia presente solo una coppia di chiavi. Sviluppi futuri potrebbero richiedere che una smart card contenga più coppie di chiavi, risulterebbe allora necessaria la richiesta dell’alias. Nella realizzazione di questo software, in realtà, è stata impiegata anche un’altra classe: Start.java. Questa serve a simulare il programma esterno che richiama i metodi delle classi “Firma” e “DigestFirmato”. Questa classe crea inizialmente un digest di esempio da una immagine presente su disco, poi richiama i metodi delle due classi precedentemente descritte per eseguire tutte le operazioni necessarie. Per eseguire la firma, allora, si scrive: Firma firma = new Firma(); DigestFirmato df = firma.cifra(digest); Per salvare la firma e il certificato su file: df.serializza("c:\\fileTesi\\FirmaSerialized"); Quando invece si vuole decifrare un messaggio firmato bisogna prima leggere il file ricevuto: DigestFirmato df = new DigestFirmato().deserializza("c:\\fileTesi\\FirmaSerialized"); poi si esegue la decifratura: Firma firma = new Firma(); byte[] decifrato = firma.decifra(df); Infine, per verificare che il messaggio sia integro, si confronta il digest iniziale con quello appena ricavato: firma.compara(decifrato, digest); 124 Realizzazione del progetto Tool di gestione della smart card Questo tool è uno strumento di uso generico che permette di eseguire sulla smart card alcune operazioni che potrebbero essere utili in termini di gestione, controllo e mantenimento del dispositivo. E’ dotato di una interfaccia a riga di comando, quindi permette di interagire direttamente con l’utente. L’utente, in questo caso, potrebbe essere l’amministratore del sistema oppure un tecnico specializzato che deve accedere alla smart card, ad esempio, per verificare se la procedura di inizializzazione è avvenuta correttamente, oppure in seguito a malfunzionamenti. Verrà ora proposta la stampa a schermo del menù principale di questo tool e saranno brevemente discusse tutte le operazioni consentite. IAIK JCE Provider for PKCS#11 operating with slot "GemPC410 0" of module "PKCS#11 Cryptoki" from PKCS#11 library "gclib.dll" Smart Card inserita. Scegli l'operazione che vuoi eseguire: 1. Leggi il contenuto della scheda 2. Scrivi un oggetto sulla scheda 3. Cancella un oggetto dalla scheda 4. Inserisci una key entry da un altro key store 5. Elimina una key entry dal key store della scheda -> La prima riga mostra alcune informazioni sul provider IAIK relative al lettore attualmente collegato e alla libreria cui fa riferimento. In seguito viene fatto un controllo per verificare che la smart card sia inserita, e quindi si elencano le operazioni possibili. Come si può vedere è possibile leggere, scrivere o cancellare gli oggetti della scheda e gestire il key store. Selezionando l’opzione 1 si esegue la lettura della smart card. Durante la procedura l’utente viene interrogato per indicare se vuole cercare un oggetto in particolare (fornendo la sua label), oppure se vuole leggere tutto il contenuto della scheda. Si richiede inoltre l’autenticazione tramite PIN per poter accedere alla parte privata della memoria. In caso di mancata autenticazione sarà possibile leggere solo il contenuto pubblico. Di seguito viene mostrato il video relativo all’esecuzione della lettura della smart card impiegata nel presente lavoro. 125 Capitolo 5 ---------------SESSION INFO----------------State: Read-Only User Session Device Error: 0x3039000 Read/Write Session: false Serial Session: true -----------END OF SESSION INFO-------------Trovati 3 oggetti. Oggetto 1: Object Class: <Attribute not present> --------------------------------------------Oggetto 2: Object Class: Certificate Token: true Private: false Modifiable: true Label: alias Certificate Type: X.509 Public Key Trusted: <Attribute not present> Subject (DER, hex): 304e310b3009060355040613026974310b3009060355040813027374310a3008060355 040713016c310a3008060355040a13016f310b3009060355040b13026f75310d300b06 0355040313046e6f6d65 ID (hex): 0d7591bf774bb2432f047dac969aba268d2ad2b5 Issuer (DER, hex): 308185310b3009060355040613024954310b300906035504081302416e310f300d0603 5504071306416e636f6e613111300f060355040a13084a54656c656d6564310d300b06 0355040b1304536f66743111300f060355040313084a54656c656d6564312330210609 2a864886f70d01090116146a74656c656d6564406a74656c656d65642e6974 Serial Number (DER, hex): 12 Value (BER, hex): 30820243308201ac020112300d06092a864886f70d0101050500308185310b30090603 55040613024954310b300906035504081302416e310f300d06035504071306416e636f 6e613111300f060355040a13084a54656c656d6564310d300b060355040b1304536f66 743111300f060355040313084a54656c656d65643123302106092a864886f70d010901 16146a74656c656d6564406a74656c656d65642e6974301e170d303630323033313030 3032335a170d3038313132333130303032335a304e310b300906035504061302697431 0b3009060355040813027374310a3008060355040713016c310a3008060355040a1301 6f310b3009060355040b13026f75310d300b060355040313046e6f6d6530819f300d06 092a864886f70d010101050003818d0030818902818100b64c5f2e547e0f70d869824e 29a655daf614385135f1a722b4e500cf5051471cbe692586b4dff5d97852a5b1eaec11 d4241e4a0df3af694e20b648052170d9134248165e12e4337131f20f32eda154b1dca9 cab76b92680d18fd0c966c9efc609161a793ebc2bd8a7f081c4116ada19afd5b5bad52 1fb1aab36807cd17f366010203010001300d06092a864886f70d010105050003818100 2716657ce828fb5d4d4cfa2608360ab503f14c9d70ccfc164fdcb98a43fad274027e5a 3647e208a6acedece3bdbc634d72ea70935f47c4e7e57796c6eb27b6888d3947242654 539047a97b495e6c684ab23d606fd33cc9ebb039c59fd3372748046fab3badb53c4903 169fdf6906c205e7caf5956690e29482779351508a1118 --------------------------------------------Oggetto 3: Object Class: Private Key Token: true Private: true Modifiable: true Label: alias Key Type: RSA ID: 0d7591bf774bb2432f047dac969aba268d2ad2b5 Start Date: <NULL_PTR> End Date: <NULL_PTR> Derive: false Local: false 126 Realizzazione del progetto Key Generation Mechanism: <Attribute not present> Subject (DER, hex): <NULL_PTR> Sensitive: true Secondary Authentication: <Attribute not present> Secondary Authentication PIN Flags: <Attribute not present> Decrypt: true Sign: true Sign Recover: false Unwrap: true Extractable: false Always Sensitive: true Never Extractable: true Modulus (hex): b64c5f2e547e0f70d869824e29a655daf614385135f1a722b4e500cf5051471cbe6925 86b4dff5d97852a5b1eaec11d4241e4a0df3af694e20b648052170d9134248165e12e4 337131f20f32eda154b1dca9cab76b92680d18fd0c966c9efc609161a793ebc2bd8a7f 081c4116ada19afd5b5bad521fb1aab36807cd17f36601 Public Exponent (hex): 010001 Private Exponent (hex): <Value is sensitive> Prime 1 (hex): <Value is sensitive> Prime 2 (hex): <Value is sensitive> Exponent 1 (hex): <Value is sensitive> Exponent 2 (hex): <Value is sensitive> Coefficient (hex): <Value is sensitive> --------------------------------------------Tralasciando le informazioni (comunque fornite durante l’esecuzione del programma) relative al lettore e alla scheda stessa, vengono riportare le informazioni sulla sessione creata, che è di tipo Read-Only, e sull’effettivo contenuto della scheda. In questo caso è stato fornito il PIN di autenticazione, quindi è possibile leggere sia il contenuto pubblico che quello privato. Si possono distinguere gli oggetti “certificato” e “chiave” relativi allo stesso alias. Da notare che nella chiave privata compaiono le informazioni impostate nella fase di generazione (in particolare “sensitive” e “unextractable”), ma non sono visibili le informazioni riservate (riguardanti gli esponenti). Il primo oggetto elencato, di cui non è definita la classe di appartenenza, è in realtà un oggetto che contiene informazioni relative alle chiavi appena create, ma che servono più alla smart card stessa che non all’utente, per questo non vengono esplicitate. Questo oggetto, comunque, viene sempre creato ogni volta che si genera una nuova coppia di chiavi. Le operazioni di scrittura e cancellazione sono molto simili a quella appena descritta, quindi si eviterà di riportare delle schermate di esempio. La differenza principale sta nel fatto che questa volta bisogna accedere alla scheda con una sessione di tipo Read-Write, quindi è obbligatorio fornire il PIN 127 Capitolo 5 di autenticazione. Brevemente, durante la scrittura si dovranno fornire: il percorso del file che si vuole copiare sulla scheda e la label che si vuole assegnare a tale file. Durante la cancellazione, invece, si leggeranno gli oggetti presenti nella scheda e, per ognuno, sarà chiesto di confermare la cancellazione. La quarta operazione consente di aggiungere un elemento al key store interno della smart card importandolo da un key store esterno. Questa operazione è servita nel corso dello sviluppo del software per eseguire alcune prove. Il suo impiego è più didattico che altro. A livello pratico non ha senso generare una chiave con un dispositivo esterno per poi inserirla sulla smart card, in quanto cade fin dal principio la caratteristica di non poter conoscere la chiave al di fuori della scheda. Potrebbe essere utilizzato come test per verificare il funzionamento della scheda, evitando di dover generare una nuova chiave e interrogare una CA per avere un nuovo certificato. Il suo funzionamento viene descritto direttamente dalla stampa dell’esecuzione del programma, che risulta sufficientemente autoesplicativa. Scrivi il percorso del file in cui si trova il key store ->c:\fileTesi\.keystore Immettere la passphrase del key store ->password Il keystore contiene i seguenti alias: alias cacert cakey matteo Quale alias vuoi inserire nella scheda? ->matteo Se questo alias è protetto con una propria passphrase immetterla, altrimenti premere INVIO -> Inserisci il PIN della Smart Card: ->1234 chiave e certificato inseriti sulla scheda. Infine l’operazione di eliminazione di un elemento del key store è del tutto simile alla cancellazione di un comune oggetto dalla scheda. Verrà chiesto il PIN di autenticazione e saranno stampati tutti gli elementi del key store, consentendo all’utente la facoltà di scegliere, tra questi, quale eliminare. 128 Conclusioni e sviluppi futuri Capitolo 6. CONCLUSIONI E SVILUPPI FUTURI 129 Capitolo 6 In questo lavoro si è cercato di rendere disponibili le tecnologie informatiche, relative al campo della sicurezza, al sistema della pubblica amministrazione e, nello specifico, all’ambito sanitario. Lo scopo è quello di realizzare un sistema informatico che consenta di migliorare la velocità e l’efficienza dei servizi, migliorare la gestione degli archivi, ridurre le pratiche burocratiche cercando di sostituire il documento cartaceo con il documento elettronico. Tutto questo garantendo i requisiti di sicurezza previsti in un sistema informatico, che riguardano: l’autenticazione d’identità; la segretezza delle informazioni; l’integrità dei dati; il non ripudio di una comunicazione. Dopo una prima fase necessaria all’acquisizione dei concetti fondamentali che tali tecnologie impiegano (come crittografia, infrastrutture a chiave pubblica e smart card), ho iniziato ad informarmi su progetti già avviati riguardanti l’utilizzo delle smart card nella pubblica amministrazione e non solo56. Mi sono reso conto che già da qualche anno questa tecnologia sta trovando un utilizzo sempre più ampio, e sono molte anche le nuove proposte di progetto. Ho notato però che gran parte di questi progetti riguardano iniziative personali (di un ente o di una azienda) e sono limitati ad un campo di azione localizzato. Esistono in realtà anche dei progetti a livello nazionale (è il caso della CIE57 e della CNS58), che però non sono ancora completamente avviati e quindi in fase di sviluppo. Con questo progetto si intende raggiungere un ampio numero di utenti (che comprende sia medici che pazienti), è quindi necessario adottare una carta che sia disponibile a tutti già da subito. Questo mi ha portato a scegliere la soluzione di impiegare una smart card vuota (le smart card, ormai, si trovano facilmente in commercio) e renderla utilizzabile per le operazioni di firma digitale. Una prima fase del lavoro, quindi, prevede l’inizializzazione della carta, che si effettua creando al suo interno una coppia di chiavi ed associando ad essa un certificato a chiave pubblica. La seconda fase, invece, si occupa di realizzare e verificare la firma digitale del documento elettronico. 56 Alcuni di questi progetti sono citati nella parte introduttiva della tesi. Carta di Identità Elettronica. 58 Carta Nazionale dei Servizi. 57 130 Conclusioni e sviluppi futuri Durante lo sviluppo del lavoro è stato spesso utile accedere al contenuto della smart card per verificare la corretta esecuzione delle operazioni, questo ha portato all’implementazione di uno strumento ad interfaccia testuale che consente di leggere e scrivere il contenuto della scheda e permette inoltre di gestire il suo key store. Attualmente questo progetto è più improntato verso l’uso di queste tecniche da parte dei medici, si prevede però, una volta avviata una fase sperimentale, di ampliare l’utenza anche ai pazienti che usufruiscono dei servizi offerti dalla struttura sanitaria. In questo scenario si potrebbe considerare di nuovo l’idea di impiegare la CIE che, si presume, possa essere disponibile a tutti i cittadini, con il vantaggio di poter disporre di un’unica smart card per accedere a diversi servizi. Alcune considerazioni tecniche riguardano invece l’interoperabilità tra diverse smart card. Al momento è possibile gestire solo un tipo di scheda, ma il software è strutturato in modo da poter interagire con un dispositivo diverso semplicemente cambiando una libreria. Questa operazione viene eseguita in modo dinamico al runtime, si può allora prevedere di farla precedere da un software di riconoscimento del dispositivo che scelga l’opportuna libreria. Inoltre la smart card è momentaneamente dotata di una sola coppia di chiavi (che per l’impiego attuale è più che sufficiente). Uno sviluppo del sistema, però, (ed in particolare l’eventuale impiego della CIE) potrebbe richiedere la presenza di più coppie di chiavi, eventualmente anche per usi diversi. Sarebbe allora richiesto di selezionare la chiave voluta (tramite assegnazione dell’alias) e verificarne l’utilizzo (cosa che già avviene per la firma), prima di eseguire l’operazione. Un’ultima considerazione riguarda il provider di sicurezza IAIK il cui utilizzo non è completamente gratuito. Si può allora pensare, in linea con la logica open source, di adottare il provider SUN in dotazione con le ultime versioni del pacchetto Java, che è del tutto gratuito. Un’altra alternativa potrebbe essere l’implementazione di un provider proprio. Si tratterebbe di riscrivere le funzioni base utilizzando i metodi nativi Java per interfacciarsi alla libreria della smart card. Questa soluzione è stata già presa in considerazione ed alcune funzioni del wrapper sono già state realizzate. 131 Capitolo 6 132 Codice Java Appendice. CODICE JAVA 133 Appendice Inizializzazione.java package smart_card; import iaik.asn1.CodingException; import iaik.pkcs.pkcs11.Module; import iaik.pkcs.pkcs11.Session; import iaik.pkcs.pkcs11.Slot; import iaik.pkcs.pkcs11.Token; import iaik.pkcs.pkcs11.TokenException; import iaik.pkcs.pkcs11.objects.RSAPrivateKey; import iaik.pkcs.pkcs11.objects.RSAPublicKey; import iaik.pkcs.pkcs11.provider.IAIKPkcs11; import iaik.pkcs.pkcs11.provider.TokenManager; import iaik.pkcs.pkcs11.provider.keypairgenerators.PKCS11KeyPairGenerationSpe c; import iaik.pkcs.pkcs11.provider.spec.PKCS11Spec; import iaik.pkcs.pkcs11.wrapper.PKCS11Exception; import iaik.security.provider.IAIK; import iaik.utils.Util; import import import import import import import import import import import import import import import import import import import import import import import import java.io.BufferedReader; java.io.FileInputStream; java.io.FileWriter; java.io.IOException; java.io.InputStreamReader; java.security.InvalidAlgorithmParameterException; java.security.InvalidKeyException; java.security.KeyPair; java.security.KeyPairGenerator; java.security.KeyStore; java.security.KeyStoreException; java.security.NoSuchAlgorithmException; java.security.NoSuchProviderException; java.security.PrivateKey; java.security.SecureRandom; java.security.Security; java.security.SignatureException; java.security.UnrecoverableKeyException; java.security.cert.CertificateException; java.security.cert.CertificateFactory; java.security.cert.X509Certificate; java.util.Collection; java.util.Enumeration; java.util.Properties; import sun.misc.BASE64Encoder; /* * Questa classe genera la coppia di chiavi RSA e la * richiesta di certificato PKCS#10 all'interno della * smart card e successivamente inserisce il certificato * sul key store della scheda. */ public class Inizializzazione { private IAIKPkcs11 pkcs11Provider; private TokenManager tokenManager; private Module module; 134 Codice Java private Token token; String prompt = new String(); /* * Il costruttore si occupa di installare i provider necessari * e richiama il metodo di verifica della SC. */ public Inizializzazione() { prompt = "->"; Security.addProvider(new IAIK()); Properties providerProperties = new Properties(); providerProperties.put("PKCS11_NATIVE_MODULE", "gclib.dll"); pkcs11Provider = new IAIKPkcs11(providerProperties); Security.addProvider(pkcs11Provider); System.out.println(pkcs11Provider.getInfo()+"\n"); checkToken(); } /* * Verifica che la SC sia inserita. */ private void checkToken() { try { tokenManager = pkcs11Provider.getTokenManager(); module = tokenManager.getModule(); Slot[] slots = module.getSlotList( Module.SlotRequirement.TOKEN_PRESENT); if (slots.length == 0) { System.out.println("Smart Card non presente o non valida!"); System.exit(0); } System.out.println("Smart Card inserita.\n"); token = slots[0].getToken(); } catch(TokenException te) { System.err.println("Smart Card non presente o non valida!\n" + te); } } /* * Verifica se la SC necessita di un login * ed esegue il login. */ private void checkLogin(Session s) { try { if (token.getTokenInfo().isLoginRequired()) { if (token.getTokenInfo().isProtectedAuthenticationPath()) { System.out.println("Inserisci il PIN nella tastiera del tuo lettore Smart Card."); s.login(Session.UserType.USER, null); } else { System.out.println("Inserisci il PIN della Smart Card:"); System.out.print(prompt); BufferedReader input = new BufferedReader( new InputStreamReader(System.in)); String userPINString = input.readLine(); 135 Appendice if (userPINString.length() > 0) { try { s.login(Session.UserType.USER, userPINString.toCharArray()); } catch(PKCS11Exception pkcs11e) { System.out.println("PIN errato!"); System.exit(0); } } } } System.out.println(""); } catch (TokenException te) { System.err.println("Errore di comunicazione con la scheda!\n" + te); System.exit(0); } catch (IOException ioe) { System.err.println("Errore di lettura dell'input!\n" + ioe); } } /* * Gernera una coppia di chiavi sulla smart card, associandole * all'alias dato. */ public KeyPair generateKeyPair(String alias) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance( "RSA", pkcs11Provider.getName()); SecureRandom random = new SecureRandom(); byte[] seed = random.generateSeed(20); //imposto le proprietà della chiave privata RSAPrivateKey priK = new RSAPrivateKey(); priK.getSign().setBooleanValue(Boolean.TRUE); priK.getToken().setBooleanValue(Boolean.TRUE); priK.getPrivate().setBooleanValue(Boolean.TRUE); priK.getSensitive().setBooleanValue(Boolean.TRUE); priK.getExtractable().setBooleanValue(Boolean.FALSE); priK.getLabel().setCharArrayValue(alias.toCharArray()); priK.getId().setByteArrayValue(seed); //imposto le proprietà della chiave pubblica RSAPublicKey pubK = new RSAPublicKey(); pubK.getModulusBits().setLongValue(new Long(1024)); byte[] publicExponentBytes = {0x01, 0x00, 0x01}; pubK.getPublicExponent().setByteArrayValue(publicExponentBytes); pubK.getVerify().setBooleanValue(Boolean.TRUE); pubK.getToken().setBooleanValue(Boolean.TRUE); pubK.getPrivate().setBooleanValue(Boolean.FALSE); pubK.getLabel().setCharArrayValue(alias.toCharArray()); PKCS11KeyPairGenerationSpec keyPairSpec = new PKCS11KeyPairGenerationSpec(tokenManager, pubK, priK, PKCS11Spec.USE_READ_WRITE_SESSION, PKCS11Spec.USE_USER_SESSION); keyPairGen.initialize(keyPairSpec); KeyPair keyPair = keyPairGen.generateKeyPair(); return keyPair; } /* 136 Codice Java * Chiama i metodi per generare la coppia di chiavi e * la richiesta di certificato e gestisce le loro eccezioni. */ public byte[] getCertReq(String alias, String dn) { byte[] certReq = null; java.security.KeyPair keyPair; try { keyPair = generateKeyPair(alias); System.out.println("\n[CHIAVE PRIVATA]\n" + keyPair.getPrivate().toString()); System.out.println("\n[CHIAVE PUBBLICA]\n" + keyPair.getPublic().toString()); certReq = PKCS10CertificateRequest(dn, keyPair); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); System.out.println("Algoritmo mancante!"); } catch (NoSuchProviderException e) { e.printStackTrace(); System.out.println("Provider mancante!"); } catch (InvalidAlgorithmParameterException e) { e.printStackTrace(); System.out.println("Parametro dell'algoritmo non valido!"); } catch (InvalidKeyException e) { e.printStackTrace(); System.out.println("Chiave non valida!"); } catch (SignatureException e) { e.printStackTrace(); System.out.println("Errore nella firma della richiesta!"); } catch (CodingException e) { e.printStackTrace(); System.out.println("Codifica non valida!"); } return certReq; } /* * Genera una richiesta di certificato nel formato standard * PKCS#10. */ public byte[] PKCS10CertificateRequest(String dn, java.security.KeyPair keyPair) throws InvalidKeyException, NoSuchAlgorithmException, SignatureException, CodingException { javax.security.auth.x500.X500Principal x500Principal = new javax.security.auth.x500.X500Principal(dn); System.out.print(x500Principal.toString() + "\n"); iaik.asn1.structures.Name name = new iaik.asn1.structures.Name( x500Principal.getEncoded()); System.out.println(name.toString(true) + "\n"); iaik.pkcs.pkcs10.CertificateRequest request = new iaik.pkcs.pkcs10.CertificateRequest( keyPair.getPublic(), name); request.sign(iaik.asn1.structures.AlgorithmID.sha1WithRSAEncryption,ke yPair.getPrivate(), pkcs11Provider.getName()); System.out.println("\n[RICHIESTA DI CERTIFICATO]\n" + request.toString()); return request.toByteArray(); } 137 Appendice CSR /* * Prende il file inviato dalla CA come risposta alla PKCS#10 * e ne ricava la catena di certificazione, * poi aggiunge la key entry sulla SC. */ public void setX509Cert(String alias, String fileName) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { //crea la catena di certificati (chain) FileInputStream fis = new FileInputStream(fileName); CertificateFactory cf = CertificateFactory.getInstance("X.509"); Collection coll = cf.generateCertificates(fis); Object[] arr = coll.toArray(); iaik.x509.X509Certificate[] chain = new iaik.x509.X509Certificate[coll.size()]; System.out.println("\nLa catena presenta " + coll.size() + " certificati"); for (int j=0; j<coll.size(); j++) { if (arr[j] instanceof X509Certificate) { X509Certificate cert = (X509Certificate) arr[j]; chain[j] = new iaik.x509.X509Certificate(cert.getEncoded()); System.out.println((j+1) + "° elemento della catena:\n" + chain[j]); } } Util.arrangeCertificateChain(chain, false); //inserisce la nuova key entry sulla Smart Card KeyStore tokenKeyStore; tokenKeyStore = KeyStore.getInstance("PKCS11KeyStore"); if (tokenKeyStore == null) throw new NullPointerException("KeyStore is null"); tokenKeyStore.load(null, null); System.out.println("Keystore caricato"); Enumeration e = tokenKeyStore.aliases(); while (e.hasMoreElements()) { System.out.println("\t" + e.nextElement()); } PrivateKey priK = (PrivateKey) tokenKeyStore.getKey("alias", null); tokenKeyStore.setKeyEntry("alias", priK, null, chain); System.out.println("certificato caricato sulla scheda."); } /* * Stampa la catena di certificazione del dato alias * da smart card. */ private void printChain(String alias) { try { KeyStore tokenKeyStore = KeyStore.getInstance("PKCS11KeyStore"); if (tokenKeyStore == null) throw new NullPointerException("KeyStore is null"); tokenKeyStore.load(null, null); java.security.cert.Certificate[] chain = tokenKeyStore.getCertificateChain(alias); for (int i = 0; i < chain.length; i++) { 138 Codice Java System.out.println("[" + i + "° ELEMENTO DELLA CATENA]\n" + chain[i]); } System.out.println("[Verifica catena]"); if (chain.length > 1) { for (int i = 0; i < (chain.length - 1); i++) { chain[i].verify(chain[i + 1].getPublicKey()); } System.out.println("Catena verificata"); } else if (chain.length == 1) { System.out.println("Un solo elemento, niente da verificare."); } else if (chain.length == 0) { System.out.println("Catena non presente, controllare la carta per l'alias " + alias); } } catch (InvalidKeyException e) { e.printStackTrace(); System.out.println("Catena NON verificata"); } catch (CertificateException e) { e.printStackTrace(); System.out.println("Catena NON verificata"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); System.out.println("Algoritmo mancante"); } catch (NoSuchProviderException e) { e.printStackTrace(); System.out.println("Provider mancante"); } catch (SignatureException e) { e.printStackTrace(); System.out.println("Catena NON verificata"); } catch (KeyStoreException e) { e.printStackTrace(); System.out.println("Errore di comunicazione con la Smart Card!"); } catch (IOException e) { e.printStackTrace(); System.out.println("Errore nel caricamento del keystore!"); } } /* * Crea le richieste di certificato PKCS#10, * le codifica in BASE64 e le salva sul file "alias.csr". * Al suo interno richiama un metodo per la * generazione della coppia di chiavi. */ private void genReq() { byte[] csr = getCertReq("alias", "CN=nome,OU=ou,O=o,L=l,ST=st,C=it"); BASE64Encoder enc = new BASE64Encoder(); String richiesta = "-----BEGIN CERTIFICATE REQUEST-----\n".concat( enc.encode(csr).concat("\n-----END CERTIFICATE REQUEST-----\n")); System.out.println(richiesta + "\n"); System.out.println("Salvataggio della richiesta su file..."); try { FileWriter fw = new FileWriter("c:\\fileTesi\\alias.csr"); fw.write(richiesta); fw.close(); } catch (IOException e) { e.printStackTrace(); 139 Appendice System.out.println("Errore nel salvataggio della richiesta!"); } System.out.println("Salvato."); } /* * Imposta la catena di certificazione sulla smart card. */ private void setChain() { try { setX509Cert("alias", "c:\\fileTesi\\alias.pem"); } catch (CertificateException e) { e.printStackTrace(); System.out.println("Certificato non valido!"); } catch (KeyStoreException e) { e.printStackTrace(); System.out.println("keystore non valido!"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); System.out.println("Algoritmo non valido!"); } catch (UnrecoverableKeyException e) { e.printStackTrace(); System.out.println("Impossibile prelevare la chiave!"); } catch (IOException e) { e.printStackTrace(); System.out.println("Errore nel caricamento del keystore!"); } printChain("alias"); } public static void main(String[] args) { Inizializzazione sc = new Inizializzazione(); try { Session session = sc.token.openSession( Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RW_SESSION, null, null); sc.checkLogin(session); //sc.genReq(); //genera la CSR //sc.setChain(); //imposta il certificato sulla SC session.closeSession(); sc.module.finalize(null); } catch (TokenException e) { e.printStackTrace(); System.out.println("Errore nell'apertura o nella chiusura della sessione!"); } } } 140 Codice Java Firma.java package smart_card; import iaik.pkcs.pkcs11.Module; import iaik.pkcs.pkcs11.Session; import iaik.pkcs.pkcs11.Slot; import iaik.pkcs.pkcs11.Token; import iaik.pkcs.pkcs11.TokenException; import iaik.pkcs.pkcs11.provider.IAIKPkcs11; import iaik.pkcs.pkcs11.provider.TokenManager; import iaik.pkcs.pkcs11.wrapper.PKCS11Exception; import iaik.security.provider.IAIK; import import import import import import import import import import import import import import import import import import import import import java.io.BufferedReader; java.io.IOException; java.io.InputStreamReader; java.security.InvalidKeyException; java.security.KeyStore; java.security.KeyStoreException; java.security.NoSuchAlgorithmException; java.security.NoSuchProviderException; java.security.PrivateKey; java.security.PublicKey; java.security.Security; java.security.UnrecoverableKeyException; java.security.cert.Certificate; java.security.cert.CertificateException; java.security.cert.CertificateExpiredException; java.security.cert.CertificateNotYetValidException; java.security.cert.X509Certificate; java.util.Arrays; java.util.Date; java.util.Enumeration; java.util.Properties; import import import import javax.crypto.BadPaddingException; javax.crypto.Cipher; javax.crypto.IllegalBlockSizeException; javax.crypto.NoSuchPaddingException; /* * Questa classe contiene i metodi necessari per * eseguire la firma digitale, decifrarla e verificarla. */ public class Firma { private IAIKPkcs11 pkcs11Provider; private Module module; private Token token; private Session session; private PrivateKey priK; private PublicKey pubK; private X509Certificate x509; String prompt = new String(); /* * Il costruttore si occupa di installare i provider necessari. */ public Firma() { prompt = "->"; 141 Appendice Security.addProvider(new IAIK()); Properties providerProperties = new Properties(); providerProperties.put("PKCS11_NATIVE_MODULE", "gclib.dll"); pkcs11Provider = new IAIKPkcs11(providerProperties); Security.addProvider(pkcs11Provider); System.out.println(pkcs11Provider.getInfo()+"\n"); } /* * Verifica se la Smart Card è inserita, * chiama i metodi necessari ad eseguire la cifratura * e ritorna una istanza di "DigestFirmato" che contiene * il messaggio cifrato ed il certificato x509. */ public DigestFirmato cifra(byte[] digest) { checkToken(); try { session = token.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RO_SESSION, null, null); checkLogin(); } catch (TokenException te) { System.err.println("Errore nell'apertura della sessione!\n" + te); System.exit(0); } estraiChiavi(null); byte[] cifrato = null; if (verificaUsoFirma(x509)) { cifrato = eseguiCifra(digest); } else System.exit(0); DigestFirmato df = new DigestFirmato(cifrato, x509); try { session.closeSession(); module.finalize(null); } catch (TokenException te) { System.err.println("Errore nella chiusura della sessione!\n" + te); System.exit(0); } return df; } /* * Riceve una istanza di "DigestFirmato" dalla quale * recupera il messaggio cifrato e il certificato x509, * poi chiama il metodo di decifratura e ritorna il * messaggio decifrato come array di byte. */ public byte[] decifra(DigestFirmato df) { byte[] ricevuto = df.getFirma(); pubK = df.getCert().getPublicKey(); return eseguiDecifra(ricevuto); } /* * Verifica che la SC sia inserita. */ private void checkToken() { try { TokenManager tokenManager = pkcs11Provider.getTokenManager(); module = tokenManager.getModule(); Slot[] slots = module.getSlotList( 142 Codice Java Module.SlotRequirement.TOKEN_PRESENT); if (slots.length == 0) { System.out.println("Smart Card non presente o non valida!"); System.exit(0); } System.out.println("Smart Card inserita.\n"); token = slots[0].getToken(); } catch(TokenException te) { System.err.println("Smart Card non presente o non valida!\n" + te); } } /* * Verifica se la SC necessita di un login * ed esegue il login. */ private void checkLogin() { try { if (token.getTokenInfo().isLoginRequired()) { if (token.getTokenInfo().isProtectedAuthenticationPath()) { System.out.println("Inserisci il PIN nella tastiera del tuo lettore Smart Card."); session.login(Session.UserType.USER, null); } else { System.out.println("Inserisci il PIN della Smart Card:"); System.out.print(prompt); BufferedReader input = new BufferedReader( new InputStreamReader(System.in)); String userPINString = input.readLine(); if (userPINString.length() > 0) { try { session.login(Session.UserType.USER, userPINString.toCharArray()); } catch(PKCS11Exception pkcs11e) { System.out.println("PIN errato!"); System.exit(0); } } } } System.out.println(""); } catch (TokenException te) { System.err.println("Errore di comunicazione con la scheda!\n" + te); System.exit(0); } catch (IOException ioe) { System.err.println("Errore di lettura dell'input!\n" + ioe); } } /* * Preleva la chiave privata e il certificato * della prima key entry che trova sulla smart card. * Prende come parametro la password del key store. */ private void estraiChiavi(char[] pass) { try { 143 Appendice System.out.println("Prelevo le chiavi dalla Smart Card..."); KeyStore tokenKeyStore = KeyStore.getInstance("PKCS11KeyStore"); if (tokenKeyStore == null) throw new NullPointerException("KeyStore non trovato!"); tokenKeyStore.load(null, null); if (tokenKeyStore.size() == 0) { System.out.println("Il key store è vuoto!"); System.exit(0); } else { Enumeration aliases = tokenKeyStore.aliases(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement().toString(); System.out.println(alias); if (tokenKeyStore.isKeyEntry(alias)) { priK = (PrivateKey) tokenKeyStore.getKey(alias, pass); Certificate[] certs = tokenKeyStore.getCertificateChain(alias); if (certs == null || certs.length == 0) { x509 = (X509Certificate) tokenKeyStore.getCertificate(alias); } else { x509 = (X509Certificate) certs[0]; } break; } } if (x509 == null) { System.out.println("Certificato non trovato!"); System.exit(0); } else verificaCert(); } } catch (KeyStoreException kse) { System.err.println("Errore nell'accesso al key store!\n" + kse); System.exit(0); } catch (CertificateException ce) { System.err.println("Errore nel caricamento del key store!\n" + ce); System.exit(0); } catch (IOException ioe) { System.err.println("Errore nel caricamento del key store!\n" + ioe); System.exit(0); } catch (NoSuchAlgorithmException nsae) { System.err.println("Errore nell'estrazione della chiave privata: algoritmo sconosciuto!\n" + nsae); System.exit(0); } catch (UnrecoverableKeyException uke) { System.err.println("Errore nell'estrazione della chiave privata!\n" + uke); System.exit(0); } } /* * Verifica la validità temporale del certificato. */ private void verificaCert() { Date data = new Date(); try { x509.checkValidity(data); } catch (CertificateExpiredException cee) { 144 Codice Java System.err.println("Certificato scaduto!\n" + cee); System.exit(0); } catch (CertificateNotYetValidException cnyve) { System.err.println("Certificato nona ancora valido!\n" + cnyve); System.exit(0); } } /* * Esegue la cifratura del digest con l'algoritmo RSA. * Tale operazione avviene all'interno della Smart Card, * per questo è necessario assegnare il provider "pkcs11provider". */ private byte[] eseguiCifra(byte[] digest) { byte[] cifrato = null; try { System.out.println("\nCifratura in corso..."); Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", pkcs11Provider.getName()); c.init(Cipher.ENCRYPT_MODE, priK); cifrato = c.doFinal(digest); System.out.println("...cifratura eseguita."); } catch (NoSuchProviderException nspe) { System.err.println("Errore nella cifratura: provider sconosciuto!\n" + nspe); System.exit(0); } catch (NoSuchAlgorithmException nsae) { System.err.println("Errore nella cifratura: algoritmo sconosciuto!\n" + nsae); System.exit(0); } catch (NoSuchPaddingException nspe) { System.err.println("Errore nella cifratura: padding sconosciuto!\n" + nspe); System.exit(0); } catch (InvalidKeyException ike) { System.err.println("Errore nella cifratura: chiave privata non valida!\n" + ike); System.exit(0); } catch (IllegalStateException ise) { System.err.println("Errore nella cifratura: stato non valido!\n" + ise); System.exit(0); } catch (IllegalBlockSizeException ibse) { System.err.println("Errore nella cifratura: dimensione del blocco non valida!\n" + ibse); System.exit(0); } catch (BadPaddingException bpe) { System.err.println("Errore nella cifratura: problemi nel padding!\n" + bpe); System.exit(0); } return cifrato; } /* * Decifra il messaggio ottenendo di nuovo il digest. * Per la decifratura non è necessaria la Smart Card, * infatti viene assegnato il provider "IAIK". */ 145 Appendice private byte[] eseguiDecifra(byte[] cifrato) { byte[] decifrato = null; try { System.out.println("\nDecifratura in corso..."); Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "IAIK"); c.init(Cipher.DECRYPT_MODE, pubK); decifrato = c.doFinal(cifrato); System.out.println("...decifratura eseguita."); } catch (NoSuchProviderException nspe) { System.err.println("Errore nella decifratura: provider sconosciuto!\n" + nspe); System.exit(0); } catch (NoSuchAlgorithmException nsae) { System.err.println("Errore nella decifratura: algoritmo sconosciuto!\n" + nsae); System.exit(0); } catch (NoSuchPaddingException nspe) { System.err.println("Errore nella decifratura: padding sconosciuto!\n" + nspe); System.exit(0); } catch (InvalidKeyException ike) { System.err.println("Errore nella decifratura: chiave privata non valida!\n" + ike); System.exit(0); } catch (IllegalStateException ise) { System.err.println("Errore nella decifratura: stato non valido!\n" + ise); System.exit(0); } catch (IllegalBlockSizeException ibse) { System.err.println("Errore nella decifratura: dimensione del blocco non valida!\n" + ibse); System.exit(0); } catch (BadPaddingException bpe) { System.err.println("Errore nella decifratura: problemi nel padding!\n" + bpe); System.exit(0); } return decifrato; } /* * Confronta il digest iniziale con quello ricavato dalla * decifratura. */ public void compara(byte arr1[], byte arr2[]) { if (arr1.length!=0 & arr2.length!=0) { if (Arrays.equals(arr1, arr2)) System.out.println("\nI due digest coincidono."); else System.out.println("\nI digest sono diversi! Il messaggio è stato modificato!"); } else System.out.println("Uno dei due array è vuoto!"); } /* * Verifica che il certificato sia utilizzabile per le operazioni * di firma e cifratura. */ private boolean verificaUsoFirma(X509Certificate cert) { System.out.println("Verifico l'utilizzo delle chiavi..."); 146 Codice Java } } boolean[] uso = cert.getKeyUsage(); if (uso == null || uso[0] || uso[3]) { System.out.println("...operazione consentita."); return true; } else { System.out.println("...operazione non consentita!"); return false; } 147 Appendice DigestFirmato.java package smart_card; import import import import import import java.io.FileInputStream; java.io.FileOutputStream; java.io.IOException; java.io.ObjectInputStream; java.io.ObjectOutputStream; java.security.cert.X509Certificate; /* * Questa classe rappresenta il documento firmato che * viene inviato nella trasmissione. */ public class DigestFirmato { byte[] firma = null; X509Certificate x509cert; public DigestFirmato() { } public DigestFirmato(byte[] cifrato, X509Certificate x509) { this.firma = cifrato; this.x509cert = x509; } public byte[] getFirma() { return firma; } public X509Certificate getCert() { return x509cert; } + e); /* * Salva il messaggio cifrato e il certificato x509 su file * in forma serializzata. */ public void serializza(String filename) { try { System.out.println("\nSerializzazione..."); ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(filename)); oos.writeObject(firma); oos.writeObject(x509cert); oos.close(); System.out.println("messaggio spedito."); } catch(Exception e) { System.err.println("Errore nella serializzazione!\n" } } System.exit(0); /* * Recupera il messaggio cifrato e il certificato x509 da file * e ritorna una istanza di "DigestFirmato". */ 148 Codice Java public DigestFirmato deserializza(String filename) { DigestFirmato df = new DigestFirmato(); try { System.out.println("\nDeserializzazione..."); ObjectInputStream ois = new ObjectInputStream( new FileInputStream(filename)); df.firma = (byte[]) ois.readObject(); df.x509cert = (X509Certificate) ois.readObject(); System.out.println("messaggio ricevuto."); ois.close(); } catch(IOException ioe) { System.err.println("Errore nella deserializzazione!\n" + ioe); System.exit(0); } catch (ClassNotFoundException cnfe) { System.err.println("Dato non valido!\n" + cnfe); System.exit(0); } return df; } } 149 Appendice Start.java package smart_card; import import import import import import java.io.ByteArrayOutputStream; java.io.FileInputStream; java.io.FileNotFoundException; java.io.IOException; java.security.MessageDigest; java.security.NoSuchAlgorithmException; /* * Questa classe richiama i metodi di "Firma" e "DigestFirmato" * per eseguire le operazioni di cifratura e decifratura. */ public class Start { /* * Crea un Message Digest da un file utilizzando * l'algoritmo SHA-1 */ public byte[] creaDigest(String fileName) { byte[] digest = null; try { System.out.println("\nCreo il Message Digest dal file \"" + fileName + "\"..."); FileInputStream fis = new FileInputStream(fileName); ByteArrayOutputStream baos = new ByteArrayOutputStream(256); byte[] buffer = new byte[256]; int bytesRead; while ((bytesRead = fis.read(buffer)) >= 0) { baos.write(buffer, 0, bytesRead); } fis.close(); MessageDigest md = MessageDigest.getInstance("SHA1"); md.update(baos.toByteArray()); digest = md.digest(); } catch (FileNotFoundException fnfe) { System.err.println("Errore nella creazione del Digest: file non trovato!\n" + fnfe); System.exit(0); } catch (IOException ioe) { System.err.println("Errore nella lettura del file!\n" + ioe); System.exit(0); } catch (NoSuchAlgorithmException nsae) { System.err.println("Errore nella creazione del Digest: algoritmo sconosciuto!\n" + nsae); System.exit(0); } return digest; } public static void main(String[] args) { Start start = new Start(); byte[] digest = start.creaDigest("c:\\fileTesi\\immagine.jpg"); System.out.println("Digest:\n" + new String(digest)); 150 Codice Java Firma firma = new Firma(); //DigestFirmato df = firma.cifra(digest); //esegue la cifratura del digest //df.serializza("c:\\fileTesi\\FirmaSerialized"); //salva il digest cifrato e il cert x509 su file DigestFirmato df = new DigestFirmato().deserializza( "c:\\fileTesi\\FirmaSerialized"); //recupera le informazioni dal file byte[] decifrato = firma.decifra(df); //decifra il messaggio ottenendo di nuovo il digest firma.compara(decifrato, digest); //confronta i due digest } } 151 Appendice SmartCardHandler.java package smart_card; import import import import import import import import import import import iaik.pkcs.pkcs11.Module; iaik.pkcs.pkcs11.Session; iaik.pkcs.pkcs11.Slot; iaik.pkcs.pkcs11.Token; iaik.pkcs.pkcs11.TokenException; iaik.pkcs.pkcs11.objects.Data; iaik.pkcs.pkcs11.objects.Object; iaik.pkcs.pkcs11.provider.IAIKPkcs11; iaik.pkcs.pkcs11.provider.TokenManager; iaik.pkcs.pkcs11.wrapper.PKCS11Exception; iaik.security.provider.IAIK; import import import import import import import import import import import import import import import import java.io.BufferedReader; java.io.ByteArrayOutputStream; java.io.FileInputStream; java.io.FileNotFoundException; java.io.IOException; java.io.InputStream; java.io.InputStreamReader; java.security.KeyStore; java.security.KeyStoreException; java.security.PrivateKey; java.security.Security; java.security.cert.Certificate; java.util.Arrays; java.util.Enumeration; java.util.Hashtable; java.util.Properties; /* * Questo è un tool di gestione della Smart Card. * E' dotato di una interfaccia testuale ed * è in grado di leggere, scrivere e cancellare oggetti * all'interno della Smart Card. * Permette anche di gestire il key store della scheda * aggiungendo entries provenienti da altri key store * o cancellando quelle già presenti. */ public class SmartCardHandler { private IAIKPkcs11 pkcs11Provider; private Module module; private Slot[] slots; private Token token; String prompt = new String(); /* * Il costruttore si occupa di installare i provider * necessari e chiama il metodo iniziale. */ public SmartCardHandler() { prompt = "->"; Security.addProvider(new IAIK()); Properties providerProperties = new Properties(); providerProperties.put("PKCS11_NATIVE_MODULE", "gclib.dll"); 152 Codice Java } pkcs11Provider = new IAIKPkcs11(providerProperties); Security.addProvider(pkcs11Provider); System.out.println(pkcs11Provider.getInfo()+"\n"); checkToken(); mainFrame(); /* * Verifica che la SC sia inserita. * E' il primo metodo chiamato dal costruttore. */ private void checkToken() { try { TokenManager tokenManager = pkcs11Provider.getTokenManager(); module = tokenManager.getModule(); slots = module.getSlotList( Module.SlotRequirement.TOKEN_PRESENT); if (slots.length == 0) { System.out.println("Smart Card non presente o non valida!"); System.exit(0); } System.out.println("Smart Card inserita.\n"); token = slots[0].getToken(); } catch(TokenException te) { System.err.println("Smart Card non presente o non valida!\n" + te); } } /* * E' il menù principale in cui si sceglie l'operazione da eseguire. */ private void mainFrame() { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Scegli l'operazione che vuoi eseguire:"); System.out.println("\t1. Leggi il contenuto della scheda"); System.out.println("\t2. Scrivi un oggetto sulla scheda"); System.out.println("\t3. Cancella un oggetto dalla scheda"); System.out.println("\t4. Inserisci una key entry da un altro key store"); System.out.println("\t5. Elimina una key entry dal key store della scheda"); String op = new String(); try { do { System.out.print(prompt); op = in.readLine(); } while (!(op.equals("1") || op.equals("2") || op.equals("3") || op.equals("4") || op.equals("5"))); switch (Integer.parseInt(op)) { case 1: preparaLettura(); break; case 2: preparaScrittura(); break; case 3: preparaCancella(); 153 Appendice break; case 4: preparaInserisci(); break; case 5: eliminaKeyEntry(); break; } } catch (IOException ioe) { System.err.println("Errore di lettura dell'input da consolle!\n" + ioe); System.exit(0); } } /* * Raccoglie le informazioni necessarie per l'operazione * di lettura dalla scheda. */ private void preparaLettura() throws IOException { System.out.println("Scrivi il nome dell'oggetto che vuoi leggere."); System.out.println("(premi INVIO per leggere tutto il contenuto della scheda)"); System.out.print(prompt); BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); String leggi = in.readLine(); leggiSC(leggi); } /* * Raccoglie le informazioni necessarie per l'operazione * di scrittura sulla scheda. */ private void preparaScrittura() throws IOException { String[] scrivi = new String[2]; BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); do { System.out.println("Scrivi il nome del file che vuoi copiare sulla scheda"); System.out.print(prompt); scrivi[0] = in.readLine(); } while(scrivi[0].equals("")); do { System.out.println("Scrivi la label che vuoi assegnare all'oggetto"); System.out.print(prompt); scrivi[1] = in.readLine(); } while(scrivi[1].equals("")); scriviSC(scrivi); } /* * Raccoglie le informazioni necessarie per l'operazione * di cancellazione di un oggetto dalla scheda. */ private void preparaCancella() throws IOException { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Scrivi la label dell'oggetto che vuoi cancellare"); 154 Codice Java System.out.println("(premi INVIO se vuoi visualizzare tutti gli oggetti)"); System.out.print(prompt); String canc = in.readLine(); cancellaSC(canc); } /* * Raccoglie le informazioni necessarie per l'operazione * di inserimento di una nuova key entry * sul key store della scheda. */ public void preparaInserisci() throws IOException { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); String filename = new String(); do { System.out.println("Scrivi il percorso del file in cui si trova il key store"); System.out.print(prompt); filename = in.readLine(); } while (filename.equals("")); System.out.println("Immettere la passphrase del key store"); System.out.print(prompt); char[] pass = in.readLine().toCharArray(); KeyStore ks = caricaKeyStore(filename, pass); String alias = new String(); while (true) { do { System.out.println("Quale alias vuoi inserire nella scheda?"); System.out.print(prompt); alias = in.readLine(); } while (alias.equals("")); if (verificaAlias(alias, ks)) break; else System.out.println("Alias non valido!"); } System.out.println("Se questo alias è protetto con una propria passphrase immetterla, altrimenti premere INVIO"); System.out.print(prompt); String answer = in.readLine(); if (!(answer.equals(""))) pass = answer.toCharArray(); inserisci(alias, ks, pass); } /* * Carica il key store situato su disco all'indirizzo dato. */ private KeyStore caricaKeyStore(String filename, char[] pass) { KeyStore ks = null; try { ks = KeyStore.getInstance(KeyStore.getDefaultType()); FileInputStream fis = new FileInputStream(filename); ks.load(fis, pass); if (ks.size() != 0) { String elenco[] = new String[ks.size()]; Enumeration e = ks.aliases(); for (int i=0; i<ks.size(); i++) { elenco[i] = (String) e.nextElement(); } Arrays.sort(elenco); 155 Appendice System.out.println("Il keystore contiene i seguenti alias:"); for (int j=0; j<elenco.length; j++) { System.out.println("\t" + elenco[j]); } } else { System.out.println("Il keystore è vuoto!"); } } catch (FileNotFoundException fnfe) { System.err.println("File non trovato!\n" + fnfe); System.exit(0); } catch (Exception e) { System.err.println("Errore nel caricamento del key store!\n" + e); System.exit(0); } return ks; } /* * Inserisce la nuova key entry sulla Smart Card. * L'alias, il key store e la password ricevuti * si riferiscono al key store di origine (quello su disco). */ private void inserisci(String alias, KeyStore ks, char[] pass) { try { Session sess = openSession(1); checkLogin(sess); PrivateKey priK = (PrivateKey) ks.getKey(alias, pass); Certificate[] certs = ks.getCertificateChain(alias); KeyStore tokenKeyStore = KeyStore.getInstance("PKCS11KeyStore"); if (tokenKeyStore == null) throw new NullPointerException("KeyStore non trovato!"); tokenKeyStore.load(null, null); System.out.println("inserisco la key entry"); tokenKeyStore.setKeyEntry(alias, priK, null, certs); System.out.println("chiave e certificato inseriti sulla scheda."); closeSession(sess); } catch (Exception e) { System.err.println("Errore nell'operazione di inserimento!\n" + e); System.exit(0); } } /* * Legge il contenuto del key store della scheda e * chiede quale entry si vuole eliminare. */ public void eliminaKeyEntry() { try { Session sess = openSession(1); checkLogin(sess); KeyStore tokenKeyStore = KeyStore.getInstance("PKCS11KeyStore"); if (tokenKeyStore == null) throw new NullPointerException("KeyStore non trovato!"); tokenKeyStore.load(null, null); if (tokenKeyStore.size() == 0) { System.out.println("Il key store è vuoto!"); System.exit(0); 156 Codice Java } else { System.out.println("Il keystore contiene i seguenti elementi:"); Enumeration e = tokenKeyStore.aliases(); while (e.hasMoreElements()) { System.out.println("\t" + e.nextElement()); } BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); String alias = new String(); while (true) { do { System.out.println("Quale entry vuoi eliminare?"); System.out.println(prompt); alias = in.readLine(); } while (alias.equals("")); if (verificaAlias(alias, tokenKeyStore)) { tokenKeyStore.deleteEntry(alias); System.out.println("key entry eliminata!"); break; } else System.out.println("Alias non valido!"); } closeSession(sess); module.finalize(null); } } catch (TokenException te) { System.err.println("Errore nell'apertura o nella chiusura della sessione!\n" + te); System.exit(0); } catch (Exception e) { System.err.println("Errore nell'operazione di eliminazione!\n" + e); System.exit(0); } } /* * Ritorna true se l'alias dato appartiene al dato key store. */ public boolean verificaAlias(String alias, KeyStore ks) { boolean answer = false; try { Enumeration e = ks.aliases(); while (e.hasMoreElements()) { if (alias.equals(e.nextElement())) { answer = true; break; } } } catch (KeyStoreException kse) { System.err.println("Errore nella lettura del key store!\n" + kse); System.exit(0); } return answer; } /* * Stampa a video il contenuto della Smart Card. 157 Appendice * Il parametro "leggi" rappresenta la label dell'oggetto * da leggere. Se è NULL viene letto tutto il * contenuto della scheda. */ private void leggiSC(String leggi) { try { printSlotInfo(slots[0]); printTokenInfo(); Session sess = openSession(0); checkLogin(sess); printSessionInfo(sess); Object[] obj = readFromCard(leggi, sess); if (obj.length > 0) { System.out.println("\nTrovati " + obj.length + " oggetti."); for (int i=0; i<obj.length; i++) { System.out.println("Oggetto " + (i+1) + ": "); System.out.println(obj[i]); System.out.println("---------------------------------------------"); } System.out.println("---------------------------------------------"); } else { System.out.println("Nessun oggetto trovato sulla Smart Card."); } closeSession(sess); module.finalize(null); } catch (TokenException te) { System.err.println("Errore in lettura: impossibile comunicare con la scheda!\n" + te); System.exit(0); } } /* * Esegue l'effettiva lettura della scheda. */ private Object[] readFromCard(String label, Session session) throws TokenException { Data data = new Data(); if (label.equals("")) { data = null; } else { data.getLabel().setCharArrayValue(label.toCharArray()); } session.findObjectsInit(data); Object[] foundObjects = session.findObjects(20); session.findObjectsFinal(); return foundObjects; } /* * Scrive un oggetto sulla Smart Card. * L'array "scrivi" contiene l'indirizzo del file * di origine e la label da assegnare all'oggetto. */ private void scriviSC(String[] scrivi) { try { Session sess = openSession(1); checkLogin(sess); printSessionInfo(sess); 158 Codice Java System.out.println("Lettura dal file sorgente..."); byte[] buffer = readFile(scrivi[0]); System.out.println("Scrittura sulla Smart Card..."); writeToCard(scrivi[1], buffer, sess); closeSession(sess); module.finalize(null); System.out.println("File copiato sulla scheda."); } catch (TokenException te) { System.err.println("Errore in scrittura: impossibile comunicare con la scheda!\n" + te); System.exit(0); } } /* * Cancella un oggetto dalla Smart Card. * Il parametro "canc" contiene la label dell'oggetto * che si vuole cancellare. */ private void cancellaSC(String canc) { try { Session sess = openSession(1); checkLogin(sess); printSessionInfo(sess); Object[] obj = readFromCard(canc, sess); if (obj.length > 0) { for (int i=0; i<obj.length; i++) { deleteObject(obj[i], sess); } } closeSession(sess); module.finalize(null); } catch (TokenException te) { System.err.println("Errore in cancellazione: impossibile comunicare con la scheda!\n" + te); System.exit(0); } catch (IOException ioe) { System.err.println("Errore di lettura dell'input da consolle!\n" + ioe); System.exit(0); } } /* * Esegue l'effettiva scrittura sulla scheda. */ private void writeToCard(String label, byte[] data, Session session) throws TokenException { Data dataObjectTemplate = new Data(); dataObjectTemplate.getLabel().setCharArrayValue(label.toCharArra y()); dataObjectTemplate.getValue().setByteArrayValue(data); dataObjectTemplate.getToken().setBooleanValue(Boolean.TRUE); session.createObject(dataObjectTemplate); } /* * Legge da disco il file che dovrà essere * copiato sulla scheda. */ 159 Appendice private byte[] readFile(String filename) { byte[] data = null; try { InputStream dataInputStream = new FileInputStream(filename); ByteArrayOutputStream bufferStream = new ByteArrayOutputStream(256); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = dataInputStream.read(buffer)) >= 0) { bufferStream.write(buffer, 0, bytesRead); } dataInputStream.close(); data = bufferStream.toByteArray(); bufferStream.close(); } catch (FileNotFoundException fnfe) { System.err.println("File non trovato!\n" + fnfe); System.exit(0); } catch (IOException ioe) { System.err.println("Errore nella lettura del file!\n" + ioe); System.exit(0); } return data; } /* * Esegue l'effettiva cancellazione dell'oggetto * dalla Smart Card. */ private void deleteObject(Object obj, Session session) throws TokenException, IOException { BufferedReader in = new BufferedReader( new InputStreamReader(System.in)); Hashtable objectHandleToObject = new Hashtable(1); long objectHandle = obj.getObjectHandle(); objectHandleToObject.put(new Long(objectHandle), obj); Long selectedObjectHandle = new Long( Long.toString(obj.getObjectHandle())); Object selectedObject = (Object) objectHandleToObject.get(selectedObjectHandle); System.out.println("\nOggetto:"); System.out.println(obj); String answer; do { System.out.println("Sei sicuro di voler CANCELLARE questo oggetto? [yes/no] "); System.out.print(prompt); answer = in.readLine(); } while(!(answer.equalsIgnoreCase("yes") || answer.equalsIgnoreCase("no"))); if (answer.equalsIgnoreCase("yes")) { session.destroyObject(selectedObject); System.out.println("Oggetto eliminato!"); } } /* * Verifica se la SC necessita di un login * ed esegue il login. */ private void checkLogin(Session s) { 160 Codice Java try { if (token.getTokenInfo().isLoginRequired()) { if (token.getTokenInfo().isProtectedAuthenticationPath()) { System.out.println("Inserisci il PIN nella tastiera del tuo lettore Smart Card."); s.login(Session.UserType.USER, null); } else { System.out.println("Inserisci il PIN della Smart Card:"); System.out.print(prompt); BufferedReader input = new BufferedReader( new InputStreamReader(System.in)); String userPINString = input.readLine(); if (userPINString.length() > 0) { try { s.login(Session.UserType.USER, userPINString.toCharArray()); } catch(PKCS11Exception pkcs11e) { System.out.println("PIN errato!"); System.exit(0); } } } } System.out.println(""); } catch (TokenException te) { System.err.println("Errore di comunicazione con la scheda!\n" + te); System.exit(0); } catch (IOException ioe) { System.err.println("Errore di lettura dell'input!\n" + ioe); } } /* * Apre una sessione con la Smart Card. * Il parametro "tipo" è un intero che determina il tipo * di sesione da aprire: * 0 = read only; 1 = read write. */ private Session openSession(int tipo) { Session sess = null; try { switch(tipo) { case 0: sess = token.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RO_SESSION, null, null); break; case 1: sess = token.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RW_SESSION, null, null); break; } } catch (TokenException te) { System.err.println("Errore nell'apertura della sessione!\n" + te); System.exit(0); } return sess; } 161 Appendice /* * Chiude la sessione. */ private void closeSession(Session session) { try { session.closeSession(); } catch (TokenException te) { System.err.println("Errore nella chiusura della sessione!\n" + te); System.exit(0); } } /* * Stampa a schermo le informazioni sulla sessione. */ private void printSessionInfo(Session session) throws TokenException { System.out.println("---------------SESSION INFO----------------"); System.out.println(session.getSessionInfo()); System.out.println("-----------END OF SESSION INFO----------"); } --"); --"); --"); --"); /* * Stampa a schermo le informazioni sul lettore. */ private void printSlotInfo(Slot slot) throws TokenException { System.out.println("---------------SLOT INFO--------------System.out.println(slot.getSlotInfo()); System.out.println("-------------END OF SLOT INFO---------} /* * Stampa a schermo le informazioni sulla Smart Card. */ private void printTokenInfo() throws TokenException { System.out.println("---------------TOKEN INFO-------------System.out.println(token.getTokenInfo()); System.out.println("-------------END OF TOKEN INFO--------} public static void main(String[] args) { SmartCardHandler prova = new SmartCardHandler(); } } 162 Bibliografia Bibliografia Bruce Heckel “Thinking in Java Second Edition”, President, MindView, Inc. pubblicato da “Prentice Hall PTR”, anno di pubblicazione 2000. Claudio De Sio Cesari “Il linguaggio Object Oriented Java Seconda Edizione”, www.claudiodesio.com Massimiliano Tarquini “Java mattone dopo mattone” versione 0.1.8, anno di pubblicazione 2001, www.java-net.tv Franco Guidi Polanco “GoF’s Design Patterns in Java”, Politecnico di Torino, anno di pubblicazione 2002, www.cim.polito.it Scott Oaks “Java Security Second Edition”, pubblicato da “O’Reilly”. Jonathan Knudsen “ Java Cryptography, Enigna of Estoeric Nothingness”, pubblicato da “O’Reilly”, anno di pubblicazione 1998. “Java Card System Protection Profile Collection”, versione 1.0b pubblicato da “Sun Microsystem, Inc”, anno di pubblicazione 2003. Kris Jamsa “Hacker Proof, Sicurezza in rete Seconda Edizione”, pubblicato da “McGraw-Hill”, anno di pubblicazione 2002. Bruce Schneider “Applied Cryptography Second Edition: protocols, algorithms and source code in C”, pubblicato da John Wiley & Sons, Inc. W. Rankl, W. Effing “Smart Card Handbook”, pubblicato da John Wiley & Sons, anno di pubblicazione 2000. “ISO/IEC Chip Card Standards”, www.iso.org, www.ansi.org 163 Bibliografia “ISO/IEC 7816 Part 4: Interindustry command for interchange”, www.ttfn.net/techno/smartcards/iso7816_4.html RSA Laboratories “Standard PKCS”, www.rsasecurity.com/rsalabs “PKCS#1: RSA Cryptography Standard”, versione 2.1, pubblicato da “RSA Laboratories”, anno di pubblicazione 2002. “PKCS#7: Cryptographic Message Syntax Standard”, versione 1.5, pubblicato da “RSA Laboratories”, anno di pubblicazione 1993. “PKCS#10: Certification Request Syntax Standard”, versione 1.7, pubblicato da “RSA Laboratories”, anno di pubblicazione 2000. “PKCS#11: Cryptographic Token Interface Standard”, versione 2.20, pubblicato da “RSA Laboratories”, anno di pubblicazione 2004. Klaus Finkenzeller “RFID Handbook: Fundamentals and Applications in Contactless Smart Card and Identification, Second Edition”, pubblicato da John Wiley & Sons, anno di pubblicazione 2003. “DPR 10 novembre 1997 n.513, Legge Bassanini”, www.icosaedro.it/crittografia/aspetti-giuridici.html, www.card.infocamere.it, www.cnipa.gov.it IBM “Open Card Framework, Fourth Edition”, anno di pubblicazione 1999. Pravir Chandra, Matt Messier, John Viega “Network Security with OpenSSL”, pubblicato da O’Reilly, anno di pubblicazione 2002. 164 Ringraziamenti E’ giunto il momento tanto atteso! Scrivere questa pagina vuol dire, per me, aver raggiunto un traguardo molto importante. Una tappa che, sicuramente, segnerà un cambiamento nella mia vita. Posso dire, in tutta onestà, che la salita è stata dura e sofferta, ma che, proprio per questo, la gioia di raggiungere la vetta è tanto grande. Adesso, voltandomi indietro, sembra che questi anni siano volati, eppure di cose ne sono successe tante! Ho trascorso momenti bellissimi e momenti difficili, che ho avuto la fortuna di condividere con persone a me molto care e che rimarranno sempre in me come parte di una esperienza indimenticabile. I miei ringraziamenti sono rivolti in primo luogo ai miei genitori, per la loro infinita pazienza che hanno dimostrato di avere nei momenti per me più critici di questi anni di studi. Ma grazie soprattutto per il loro continuo sostegno in tutte le scelte che hanno caratterizzato la mia vita, per aver sempre creduto in me, per i loro consigli e per avermi trasmesso quei valori fondamentali che sono ora alla base del mio modo di essere e del mio carattere. Un grazie particolare anche ai miei fratelli per tutte le esperienze vissute e i momenti trascorsi insieme. Un doveroso ringraziamento va ai professori Aldo Franco Dragoni e Paolo Puliti dell’Università Politecnica delle Marche e all’ing. Giuseppe Giampieri della ASUR 7 di Ancona che mi hanno offerto questa opportunità e mi hanno aiutato a realizzarla. Infine, non di certo per importanza, grazie a tutti i miei amici: a cominciare da quelli più cari, con i quali sono cresciuto e che mi conoscono ormai da sempre; a quelli che mi hanno accompagnato durante questa avventura universitaria e con i quali ho condiviso sia momenti di studio che di svago; al gruppo dell’Irlanda, con i quali ho trascorso un periodo fondamentale della mia vita. Grazie anche a tutti gli amici che, purtroppo, ho perso di vista, ma che hanno comunque segnato la mia adolescenza.