JavaCard

Il concetto fondamentale è che la card è un server che può solo rispondere a richieste inviatele da un host. Normalmente non dispongono di batterie, quindi non hanno neanche modo di tenere traccia del trascorrere del tempo... a meno che non gli venga "detto" dall'host. Inoltre dispongono solo di una linea seriale (spesso non particolarmente veloce) per interfacciarsi all'esterno.
Quindi perché utilizzarle?
Semplice: perché una cosa la possono fare bene: difendere i segreti che gli vengono affidati!

Bene, dopo le ovvietà di rito, vediamo come programmarle, che è la cosa che mi ha fatto perdere più tempo.

Intanto bisogna cercare un fornitore di card, meglio se compatibili con GlobalPlatform. Io ho acquistato alcune SmartCafe Expert 3.2 144k e JCOP 41 v2.3.1. Entrambi i tipi di card richiedono l'uso di JavaCard Development Kit 2.2.1 (non una versione più recente!) o l'invio dell'applet fallirà! Altre card richiedono versioni più recenti e supportano più facilmente "grandi" trasferimenti (queste gestiscono solo pacchetti fino a 256 byte).

L'applet può essere compilata con un JDK anche non Sun (ora Oracle): io ho utilizzato OpenJDK 6. Può essere importante usare Java 6 (1.6) e non una versione più recente anche del JDK, ma non ho provato.
Un bell'esempio di applet è JMRTD: basta sistemare un paio di righe del makefile per adattare JAVA_HOME e JCPATH alla propria configurazione e la compilazione andrà bene.
Per il caricamento sulla card, JMRTD fornisce uno script per gpshell. E qui iniziano i problemi: gpshell non l'ho trovato pacchettizzato, quindi va compilato.
Gpshell richiede GlobalPlatform 6 o successivo, ma questo è pacchettizzato solo per Ubuntu fino alla 11.10, quindi anche lui va compilato. In più, già che il compilatore è caldo, tanto vale compilare anche gppcscconnectionplugin altrimenti si avrà un errore più tardi. Qualche altro pacchetto (libpcsclite-dev, per esempio) potrebbe essere richiesto ma verrà indicato dal fallimento di make.
Il caricamento sulla carta JCOP va tranquillamente a buon fine con lo script fornito.
Per la SmartCafe invece è necessaria una modifica alla linea open_sc :
open_sc -scp 2 -scpimpl 0x15 -security 3 -keyind 0 -keyver 0 -key 404142434445464748494a4b4c4d4e4f -keyDerivation emvcps11
come chiaramente indicato da Alexander Petric nel suo blog.
Purtroppo, malgrado la modifica, JMRTD non può essere caricato su questa card perché manca il supporto HW per ECC.

Un Capability detector può essere molto utile per capire cosa è esattamente supportato dalle card che si hanno o che si devono usare. Volevo realizzarlo io, ma trovarlo già pronto è più comodo... Smile
Purtroppo l'app Java da far girare sul PC mi ha dato qualche problema, ma questo mi ha permesso di capire meglio come funziona gpshell: per vedere le risposte a send_apdu è necessario avere enable_trace abilitato!
La mia card JCOP ha ATR 3B FA 18 00 FF 81 31 FE 45 4A 43 4F 50 34 31 56 32 33 31 63 e permette l'accesso sia contact, che contactless che USB con un semplice connettore (anche se non ho ancora capito se i livelli elettrici sono gli stessi o se serve un adattatore di livello).

Questo è lo script utilizzato per caricare l'applet e lanciare un test (più di uno potrebbe facilmente fallire per esaurimento della memoria):

mode_211
establish_context
card_connect

select -AID a000000003000000
open_sc -security 1 -keyind 0 -keyver 0 -mac_key 404142434445464748494a4b4c4d4e4f -enc_key 404142434445464748494a4b4c4d4e4f // Open secure channel
delete -AID 6D7970616330303031
delete -AID 6D797061636B616731 
install -file AlgTest.cap -priv 00 -nvDataLimit 8000 -AID 6D7970616330303031 -pkgAID 6D797061636B616731

select -AID 6D7970616330303031
enable_trace # needed to see answers!!!
send_apdu -sc 0 -APDU b072010000f0
send_apdu -sc 0 -APDU b072020000f0
send_apdu -sc 0 -APDU b072030000f0
send_apdu -sc 0 -APDU b072040000f0
send_apdu -sc 0 -APDU b072050000f0

(il comando 72 va eseguito in 5 passi, a differenza degli altri che possono essere lanciati lasciando P1 a 00).

Ed ecco i risultati, decodificati e commentati.

Comando 0x70 (TestSupportedModes):

11 Class javacardx.crypto.Cipher
  01 ALG_DES_CBC_NOPAD
  01 ALG_DES_CBC_ISO9797_M1
  01 ALG_DES_CBC_ISO9797_M2
  00 ALG_DES_CBC_PKCS5
  01 ALG_DES_ECB_NOPAD
  01 ALG_DES_ECB_ISO9797_M1
  01 ALG_DES_ECB_ISO9797_M2
  00 ALG_DES_ECB_PKCS5
  00 ALG_RSA_ISO14888
  01 ALG_RSA_PKCS1
  00 ALG_RSA_ISO9796
  01 ALG_RSA_NOPAD
  01 ALG_AES_BLOCK_128_CBC_NOPAD
  01 ALG_AES_BLOCK_128_ECB_NOPAD
  00 ALG_RSA_PKCS1_OAEP
  00 ALG_KOREAN_SEED_ECB_NOPAD
  00 ALG_KOREAN_SEED_CBC_NOPAD
12 Class javacard.security.Signature
  00 ALG_DES_MAC4_NOPAD
  01 ALG_DES_MAC8_NOPAD
  00 ALG_DES_MAC4_ISO9797_M1
  01 ALG_DES_MAC8_ISO9797_M1
  00 ALG_DES_MAC4_ISO9797_M2
  01 ALG_DES_MAC8_ISO9797_M2
  00 ALG_DES_MAC4_PKCS5
  00 ALG_DES_MAC8_PKCS5
  01 ALG_RSA_SHA_ISO9796
  01 ALG_RSA_SHA_PKCS1
  01 ALG_RSA_MD5_PKCS1
  00 ALG_RSA_RIPEMD160_ISO9796
  00 ALG_RSA_RIPEMD160_PKCS1
  00 ALG_DSA_SHA
  00 ALG_RSA_SHA_RFC2409
  00 ALG_RSA_MD5_RFC2409
  01 ALG_ECDSA_SHA
  01 ALG_AES_MAC_128_NOPAD
  00 ALG_DES_MAC4_ISO9797_1_M2_ALG3
  01 ALG_DES_MAC8_ISO9797_1_M2_ALG3
  00 ALG_RSA_SHA_PKCS1_PSS
  00 ALG_RSA_MD5_PKCS1_PSS
  00 ALG_RSA_RIPEMD160_PKCS1_PSS
  00 (JC2.2.2) ALG_HMAC_SHA1
  00 (JC2.2.2) ALG_HMAC_SHA_256
  00 (JC2.2.2) ALG_HMAC_SHA_384
  00 (JC2.2.2) ALG_HMAC_SHA_512
  00 (JC2.2.2) ALG_HMAC_MD5
  00 (JC2.2.2) ALG_HMAC_RIPEMD160
  00 (JC2.2.2) ALG_RSA_SHA_ISO9796_MR
  00 (JC2.2.2) ALG_RSA_RIPEMD160_ISO9796_MR
  00 (JC2.2.2) ALG_SEED_MAC_NOPAD
15 Class javacard.security.MessageDigest
  01 ALG_SHA
  01 ALG_MD5
  00 ALG_RIPEMD160
  00 ALG_SHA_256
  00 ALG_SHA_384
  00 ALG_SHA_512
16 Class javacard.security.RandomData
  01 ALG_PSEUDO_RANDOM
  01 ALG_SECURE_RANDOM
20 Class javacard.security.KeyBuilder
  B0 
    01 TYPE_DES_TRANSIENT_RESET
    01 TYPE_DES_TRANSIENT_DESELECT
    01 TYPE_DES, LENGTH_DES
    01 TYPE_DES, LENGTH_DES3_2KEY
    01 TYPE_DES, LENGTH_DES3_3KEY
  B1 
    01 TYPE_AES_TRANSIENT_RESET, LENGTH_AES_128
    01 TYPE_AES_TRANSIENT_DESELECT, LENGTH_AES_128
    01 TYPE_AES, LENGTH_AES_128
    01 TYPE_AES, LENGTH_AES_192
    01 TYPE_AES, LENGTH_AES_256
  B2 
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_512
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_736
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_768
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_896
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_1024
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_1280
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_1536
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_1984
    01 TYPE_RSA_PUBLIC, LENGTH_RSA_2048
  B3 
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_512
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_736
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_768
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_896
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_1024
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_1280
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_1536
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_1984
    01 TYPE_RSA_PRIVATE, LENGTH_RSA_2048
  B4 
    01 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_512
    00 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_736
    01 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_768
    01 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_896
    01 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_1024
    01 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_1280
    01 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_1536
    01 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_1984
    01 TYPE_RSA_CRT_PRIVATE, LENGTH_RSA_2048
  B5 
    00 TYPE_DSA_PRIVATE, LENGTH_DSA_512
    00 TYPE_DSA_PRIVATE, LENGTH_DSA_768
    00 TYPE_DSA_PRIVATE, LENGTH_DSA_1024
  B6 
    00 TYPE_DSA_PUBLIC, LENGTH_DSA_512
    00 TYPE_DSA_PUBLIC, LENGTH_DSA_768
    00 TYPE_DSA_PUBLIC, LENGTH_DSA_1024
  B7 
    01 TYPE_EC_F2M_PRIVATE, LENGTH_EC_F2M_113
    01 TYPE_EC_F2M_PRIVATE, LENGTH_EC_F2M_131
    01 TYPE_EC_F2M_PRIVATE, LENGTH_EC_F2M_163
    01 TYPE_EC_F2M_PRIVATE, LENGTH_EC_F2M_193
  B8 
    00 TYPE_EC_FP_PRIVATE, LENGTH_EC_FP_112
    00 TYPE_EC_FP_PRIVATE, LENGTH_EC_FP_128
    00 TYPE_EC_FP_PRIVATE, LENGTH_EC_FP_160
    00 TYPE_EC_FP_PRIVATE, LENGTH_EC_FP_192
  B9 
    00 TYPE_KOREAN_SEED_TRANSIENT_RESET, LENGTH_KOREAN_SEED_128
    00 TYPE_KOREAN_SEED_TRANSIENT_DESELECT, LENGTH_KOREAN_SEED_128
    00 TYPE_KOREAN_SEED, LENGTH_KOREAN_SEED_128
  BA 
    00 TYPE_HMAC_TRANSIENT_RESET, LENGTH_HMAC_SHA_1_BLOCK_64
    00 TYPE_HMAC_TRANSIENT_DESELECT, LENGTH_HMAC_SHA_1_BLOCK_64
    00 TYPE_HMAC, LENGTH_HMAC_SHA_1_BLOCK_64
    00 TYPE_HMAC, LENGTH_HMAC_SHA_256_BLOCK_64
    00 TYPE_HMAC, LENGTH_HMAC_SHA_384_BLOCK_64
    00 TYPE_HMAC, LENGTH_HMAC_SHA_512_BLOCK_64
18 Class javacard.security.KeyPair RSA
  00 LENGTH_RSA_512
  00 LENGTH_RSA_736
  00 LENGTH_RSA_768
  00 LENGTH_RSA_896
  00 LENGTH_RSA_1024
  00 LENGTH_RSA_1280
  00 LENGTH_RSA_1536
  00 LENGTH_RSA_1984
  00 LENGTH_RSA_2048
19 Class javacard.security.KeyPair RSA_CRT
  01 LENGTH_RSA_512
  00 LENGTH_RSA_736
  01 LENGTH_RSA_768
  01 LENGTH_RSA_896
  01 LENGTH_RSA_1024
  01 LENGTH_RSA_1280
  01 LENGTH_RSA_1536
  01 LENGTH_RSA_1984
  01 LENGTH_RSA_2048
1A Class javacard.security.KeyPair DSA
  00 LENGTH_DSA_512
  00 LENGTH_DSA_768
  00 LENGTH_DSA_1024
1B Class javacard.security.KeyPair EC_F2M
  01 LENGTH_EC_F2M_113
  01 LENGTH_EC_F2M_131
  01 LENGTH_EC_F2M_163
  01 LENGTH_EC_F2M_193
1C Class javacard.security.KeyPair EC_FP
  00 LENGTH_EC_FP_112
  00 LENGTH_EC_FP_128
  00 LENGTH_EC_FP_160
  00 LENGTH_EC_FP_192
13 Class javacard.security.KeyAgreement
  01 ALG_EC_SVDP_DH
  01 ALG_EC_SVDP_DHC
17 Class javacard.security.Checksum
  01 ALG_ISO3309_CRC16
  00 ALG_ISO3309_CRC32
FF End of data
05...05 Filler
9000 => OK

Comando 0x7100 (TestAvailableMemory(RAM)):

07A4 => 1956 byte
9000 => OK

Comando 0x7101 (TestAvailableMemory(EEPROM)):

7530 \
3A98 |
3A98 |
3A98 |
16B6 > Valori da sommare: totale 81194 byte!
017C |
0000 |
0000 |
0000 /
9000 => OK

Comando 0x7205 (TestRSAExponentSet, dopo aver dato in sequenza P1 da 01 a 04):

6CA8...309B Blocco criptato casuale
9000 => OK

Comando 0x73 (JCSYSTEMinfo):

0202 => JavaCard v2.2
01   => deletion supported
7FFF => 32767 byte persistenti
07B6 => 1974 byte transient select
07B6 => 1974 byte transient deselect
9000 => OK

Volendo semplificare veramente tanto, si può scaricare una VM già pronta per lo sviluppo!

Edit: Sono riuscito a far funzionare AlgTestJClient.jar. A causa di una svista veniva tentata la connessione solo con T=0, fallendo se questo non era supportato. Fix rapidissimo che verrà incluso nella nuova release. Allego i file csv generati, contenenti anche un grossolano "benchmark" ed alcune annotazioni interessanti. I dati saranno inclusi anche sulla pagina di Petr Svenda.
Da notare che la memoria indicata dal Java client è minore di quella riportata dai miei test precedenti. Questo è da imputare al garbage collector, che "non fa" il suo lavoro (per meglio dire, il test viene eseguito quando il GC non ha ancora fatto il suo lavoro).
Altra cosa da notare: pare che la generazione delle chiavi RSA sia possibile solo con CRT (Chinese Remainder Theorem), ma questo, se da un lato velocizza molto le operazioni, dall'altro espone a fail attacks che possono portare alla compromissione della chiave segreta se non si verifica ogni operazione RSA. Vedi, per esempio un articolo sull'importanza del padding (en) che mostra anche l'attacco al CRT.
Come mi è già capitato di dire: fare sicurezza è un lavoro difficile!
La SmartCafé Expert, invece, può gestire senza CRT anche chiavi da 2048 bit, ma come ho già detto non supporta ECC.
Altro test che potrebbe essere interessante è quello dello spazio disponibile per le transazioni, per poter "assemblare" tanti piccoli trasferimenti come se fossero uno unico (per es. per caricare un certificato). Petr probabilmente lo includerà in AlgTest 1.2... No, forse nella versione 1.3...
Comunque sono finalmente riuscito a ricompilare l'applet e a reinviarla sulla JCOP41. Lo spazio per le transazioni è di 512 byte, decisamente insufficiente per l'uso che volevo farne...
Visto che volevo capire esattamente che comandi utilizzare, non ho utilizzato ant come "normale" in Java, ma un Makefile usato quasi come script. Eccolo:

# Config section
SOURCES=AlgTest.java
APPLET_AID=0x6D:0x79:0x70:0x61:0x63:0x30:0x30:0x30:0x31
APPLET_NAME=AlgTest
PACKAGE_AID=0x6D:0x79:0x70:0x61:0x63:0x6B:0x61:0x67:0x31
PACKAGE_NAME=AlgTest
PACKAGE_VERSION=1.0

JAVA_HOME=/usr
#JAVA_HOME=/home/ndk/t/jdk1.7.0_15
JC_HOME=/home/ndk/java_card_kit-2_2_1

BUILD_DIR = ./build
BUILD_CLASSES_DIR = $(BUILD_DIR)/classes
BUILD_JAVACARD_DIR = $(BUILD_DIR)/javacard
JAVACARD_EXPORT_DIR = $(JC_HOME)/api_export_files
CLASSPATH = $(JC_HOME)/lib/api.jar
# Note that -g is needed for convert tool!
JFLAGS = -target 1.1 -source 1.3 -g -d $(BUILD_CLASSES_DIR) -classpath $(CLASSPATH)
JC = javac

.SUFFIXES: .java .class
.java.class:
        mkdir -p $(BUILD_CLASSES_DIR)
        mkdir -p $(BUILD_JAVACARD_DIR)
        $(JC) $(JFLAGS) $*.java
        JAVA_HOME=$(JAVA_HOME) $(JC_HOME)/bin/converter \
            -d $(BUILD_JAVACARD_DIR) \
            -classdir $(BUILD_CLASSES_DIR) \
            -exportpath $(JAVACARD_EXPORT_DIR) \
            -applet $(APPLET_AID) $(APPLET_NAME) \
            $(PACKAGE_NAME) $(PACKAGE_AID) $(PACKAGE_VERSION)

default: classes

classes: $(SOURCES:.java=.class)

clean:
        $(RM) -rf $(BUILD_DIR)
0
Il tuo voto: Nessuna
Realizzato con Drupal, un sistema open source per la gestione dei contenuti