PKCS#11

Transcript

PKCS#11
LABORATORIO DI SICUREZZA — PKCS#11
1
PKCS#11
Opencryptoki1 è una emulazione software open-source di un dispositivo PKCS#11. Implementa
tutto lo standard senza nessuna patch di sicurezza e sono quindi presenti i vari attacchi discussi
la volta scorsa.
CryptokiX2 , sviluppato dal nostro gruppo di ricerca, estende opencryptoki con le patch
che abbiamo visto nel seminario (attributi in conflitto, attributi sticky, formato di wrapping). Le
patch si possono abilitare individualmente al momento della compilazione. In questo modo è
possibile ‘giocare’ con il token per capire come le diverse patch prevengono gli attacchi.
Il token software è a tutti gli effetti come un token vero e proprio. Per l’esercitazione utilizzeremo IAIK, una libreria java sviluppata dall’Università di Graz, e documentata in
http://javadoc.iaik.tugraz.at/pkcs11_wrapper/current/index.html.
CryptokiX è installato su testbed (192.168.69.250).
Vediamo un esempio introduttivo in java.
import
import
import
import
import
import
import
iaik
iaik
iaik
iaik
iaik
iaik
iaik
. pkcs . pkcs11 . S e s s i o n ;
. pkcs . pkcs11 . S l o t ;
. pkcs . pkcs11 . Token ;
. pkcs . pkcs11 . Mechanism ;
. pkcs . pkcs11 . Module ;
. pkcs . pkcs11 . objects . ∗ ;
. pkcs . pkcs11 . wrapper . Functions ;
public class SimpleExample
{
s t a t i c void die ( S t r i n g s , Exception e) {
System . out . p r i n t l n ( ” e r r o r on module i n i t : ” ) ;
e . printStackTrace ( ) ;
System . e x i t (−1) ;
}
public s t a t i c void main ( S t r i n g [ ] args ) {
Module pkcs11Module = n u l l ;
S l o t [ ] slotsWithToken = n u l l ;
Token token = n u l l ;
/ / accede a l token
try {
pkcs11Module = Module . getInstance ( args [ 0 ] ) ;
pkcs11Module . i n i t i a l i z e ( n u l l ) ;
} catch ( Exception e) {
die ( ” E r r o r on module i n i t : ” ,e) ;
}
try {
slotsWithToken = pkcs11Module . g e t S l o t L i s t (Module . SlotRequirement . TOKEN PRESENT ) ;
token = slotsWithToken [ 0 ] . getToken ( ) ;
} catch ( Exception e) {
die ( ” E r r o r while getting the token : ” ,e) ;
}
/ / apre l a sessione
Session s = n u l l ;
try {
s = token . openSession ( Token . SessionType . SERIAL SESSION , Token .
SessionReadWriteBehavior . RW SESSION , n u l l , n u l l ) ;
s . l o g i n ( S e s s i o n . UserType . USER , args [ 1 ] . toCharArray ( ) ) ;
} catch ( Exception e) { die ( ”Could not open s e s s i o n on the token” ,e) ; }
1 http://sourceforge.net/projects/opencryptoki/
2 http://secgroup.ext.dsi.unive.it/projects/security-apis/cryptokix/
LABORATORIO DI SICUREZZA — PKCS#11
2
Questa prima parte si occupa di accedere al token. Inizializza un nuovo modulo PKCS#11,
cerca il token negli slot del modulo, apre una nuova sessione. Notare che la login (ultimo
comando) viene effettuata come USER utilizzando args[1] come PIN.
NOTA: Lo standard prevede la presenza di utenti standard (USER appunto) e di un security
officer, che ha un differente PIN e può svolgere operazioni privilegiate. Di solito si occupa di
inizializzare i token con le master key o con certificati (in caso di cifratura a chiave pubblica). Il
security officer opera in un ambiente protetto, quindi fisicamente sicuro. Gli utenti invece sono
più facilmente soggetti ad attacchi in quanto utilizzano i token in macchine general purpose
e quindi attaccabili.
Vediamo ora come si possono eseguire alcune operazioni sul token:
/ / qui c ’e ’ i l codice d i i n i z i a l i z z a z i o n e e apertura d i una sessione
// . . . .
DESSecretKey key = n u l l ;
try {
/ / imposta i l template
DESSecretKey keyTemplate = new DESSecretKey ( ) ;
keyTemplate . g e t S e n s i t i v e ( ) . setBooleanValue ( Boolean . TRUE ) ;
/ / qui genera l a chiave basandosi s u l template .
/ / La chiave e ’ generata dentro i l token
key = ( DESSecretKey ) s . generateKey (Mechanism . DES KEY GEN , keyTemplate ) ;
System . out . p r i n t l n ( ”key : \ n” + key . t o S t r i n g ( ) ) ;
/ / Encrypt something
s . e n c r y p t I n i t (Mechanism . DES ECB , key ) ;
byte [ ] blabla = s . encrypt ( ”blablaaa” . getBytes ( ) ) ;
System . out . p r i n t l n ( ” encrypt : ” + Functions . toHexString ( blabla ) ) ;
/ / Decrypt i t
s . d e c r y p t I n i t (Mechanism . DES ECB , key ) ;
byte [ ] t x t = s . decrypt ( blabla ) ;
System . out . p r i n t l n ( ” decrypt : ” + new S t r i n g ( t x t ) ) ;
/ / Remove the key
s . destroyObject ( key ) ;
} catch ( Exception e) {
die ( ”Could not operate with the token” ,e) ;
}
}
1. Come prima cosa viene creato un nuovo template per una chiave DES. Notare che in
cryptokiX diversi attributi sono settati true di default. Ad esempio encrypt e decrypt (vedi
punto successivo);
2. Viene generata la chiave (nel token) e viene stampato a video il template risultante.
Notare che viene passato il template definito precedentemente come parametro. Il
template restituito dalla funzione, invece, è quello effettivo della nuova chiave. Come
accennavamo sopra, infatti, alcuni attributi potrebbero essere settati di default quindi
il template che diamo noi viene tipicamente ‘unito’ a quello di default. Eseguendo il
codice si può infatti notare che molti attributi sono già settati a true.
3. Poi viene cifrata la stringa “blablaa” con la nuova chiave in modalità ECB, e successivamente decifrata. Il testo cifrato viene stampato come stringa esadecimale. Si nota che
la decifratura corrisponde al testo iniziale.
4. Come ultima cosa viene cancellata la chiave (ricordatevi sempre di farlo per non saturare il token di chiavi)
LABORATORIO DI SICUREZZA — PKCS#11
3
Per compilare i programmi in java basati su IAIK potete trovare il jar della libreria su testbed
(192.168.69.250) in
/usr/local/sbin/iaikPkcs11Wrapper.jar
Una volta copiato il file nella stessa directory dove avete il java potete compilare il tutto con
javac -classpath iaikPkcs11Wrapper.jar SimpleExample.java
Per poi eseguirlo con
java -classpath .:iaikPkcs11Wrapper.jar SimpleExample libopencryptoki.so 12345
Notare che il primo argomento è la libreria libopencryptoki che indica appunto il token da
utilizzare (con token reali si dovrebbe dare qui la libreria corretta). Il PIN è stato inizializzato a
12345.
Per poter riutilizzare una chiave generata nel token, bisogna ‘trovarla’. Si utilizza la label
come segue (ovviamente la label deve essere stata assegnata alla chiave al momento della
creazione):
DESSecretKey f l a g = n u l l ;
try {
/ / imposta un template con una label specifica
DESSecretKey keyTemplate = new DESSecretKey ( ) ;
keyTemplate . getLabel ( ) . setCharArrayValue ( ”nome chiave” . toCharArray ( ) ) ;
/ / cerca l a chiave con l a data label
s . f i n d O b j e c t s I n i t ( keyTemplate ) ;
i a i k . pkcs . pkcs11 . objects . Object [ ] f s = s . findObjects ( 1 ) ;
chiave = ( DESSecretKey ) f s [ 0 ] ;
s . findObjectsFinal ( ) ;
/ / stampa i l template della chiave trovata
System . out . p r i n t l n ( ”chiave : \ n” + chiave . t o S t r i n g ( ) ) ;
} catch ( Exception e) {
System . out . p r i n t l n ( ”cannot r e t r i e v e the key” ) ;
e . printStackTrace ( ) ;
System . e x i t (−1) ;
}
Di fatto la label costituisce un nome (handle) della chiave. Cercando una certa label il token
ci restituisce le chiavi corrispondenti e possiamo quindi usarle senza conoscerne il valore.
Esercizio: Il token installato è privo di ogni patch. Provate a realizzare gli attacchi visti durante
il seminario. In particolare realizzate il wrap-decrypt: la chiave sensibile viene wrappata con
un’altra chiave e poi decifrata. Provate poi a pensare all’attacco ‘duale’ unwrap-encrypt.
Cosa può fare un attaccante in questo caso?
Nota: Se volete divertirvi a craccarvi le chiavi a vicenda potete inserire nuove chiavi con valori
a vostra scelta nel token usando CreateObject (ricordatevi di inserirle con sensitive settato a
true). Evitate di fare un DoS riempiendo il token di chiavi!