JavaCard
JavaCard est un canevas d’exécution d'application pour carte à puce développé en Java.
Les APIs
- Python http://pyscard.sourceforge.net/
- Java Javax.smartcardio
- Ada http://www.nongnu.org/pcscada/
- C#
- C/C++
Les outils
Global Platform
Global Platform est un standard permettant l'installation de cardapplets.
Carte étudiante (ancienne génération)
Script GPShell pour lister les card applets
mode_211 gemXpressoPro enable_trace establish_context card_connect select -AID a000000018434d open_sc -security 3 -keyind 0 -keyver 0 -key 47454d5850524553534f53414d504c45 // Open secure channel get_status -element 20 card_disconnect release_context
Script GPShell pour lister les card applets sélectionnables
mode_211 gemXpressoPro enable_trace establish_context card_connect select -AID a000000018434d open_sc -security 3 -keyind 0 -keyver 0 -key 47454d5850524553534f53414d504c45 // Open secure channel get_status -element 40 card_disconnect release_context
Code LUA pour CardPeek
require('lib.tlv')
AID_UJF = "#556E69762E554A46"
function ui_parse_cstring(node,data)
ui.tree_set_value(node,data)
if #data>1 then
ui.tree_set_alt_value(node,bytes.format("%P",bytes.sub(data,0,#data)))
end
end
function raw_get_data(id)
return card.send(bytes.new(8,card.CLA,0xCA,id,00,01,01,00))
end
if card.connect() then
CARD = card.tree_startup("UJF")
sw,resp = card.select(AID_UJF)
if sw==0x9000 then
APP = ui.tree_add_node(CARD,"application","Univ.UJF", AID_UJF)
sw,resp = raw_get_data(0x01)
if sw==0x9000 then
ID = ui.tree_add_node(APP,"id","ID", "01", #resp)
ui_parse_cstring(ID,resp)
end
sw,resp = raw_get_data(0x02)
if sw==0x9000 then
VERSION = ui.tree_add_node(APP,"version","VERSION", "02", #resp)
ui_parse_cstring(VERSION,resp)
end
sw,resp = raw_get_data(0x03)
if sw==0x9000 then
HOLDER = ui.tree_add_node(APP,"holder","HOLDER", "03", #resp)
if resp[0] == 0x30 then
ui.tree_set_alt_value(HOLDER, "Student")
elseif resp[0] == 0x31 then
ui.tree_set_alt_value(HOLDER, "Employee")
else
ui.tree_set_alt_value(HOLDER, "Unknown")
end
ui.tree_set_value(HOLDER, resp)
end
sw,resp = raw_get_data(0x04)
if sw==0x9000 then
INE = ui.tree_add_node(APP,"ine","INE", "04", #resp)
ui_parse_cstring(INE,resp)
end
sw,resp = raw_get_data(0x05)
if sw==0x9000 then
VS = ui.tree_add_node(APP,"validity start","VALIDITY_START", "05", #resp)
ui_parse_cstring(VS,resp)
end
sw,resp = raw_get_data(0x06)
if sw==0x9000 then
VE = ui.tree_add_node(APP,"validity end","VALIDITY_END", "06", #resp)
ui_parse_cstring(VE,resp)
end
--sw,resp = raw_get_data(0x21)
--if sw==0x9000 then
-- TEST = ui.tree_add_node(APP,"test","TEST", "21", #resp)
-- ui_parse_cstring(TEST,resp)
--end
end
card.disconnect()
else
ui.question("No card detected",{"OK"})
end
Application Java pour lister quelques informations de la carte
package fr.imag.javacard;
import javax.smartcardio.*;
import java.util.*;
public class Main {
static class Util {
static final String HEXES = "0123456789ABCDEF";
public static String getHex(byte[] raw) {
if (raw == null) {
return null;
}
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (final byte b : raw) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
}
private static byte[] appletAID = {0x55, 0x6E, 0x69, 0x76, 0x2E, 0x55, 0x4A, 0x46};
private final static byte INS_SELECT = (byte) 0xA4;
private final static byte INS_GETDATA = (byte) 0xCA;
static class Command {
String description;
Command(String description) {
this.description = description;
}
}
private static final Map<Integer, Command> COMMAND_MAP =
Collections.unmodifiableMap(new HashMap<Integer, Command>() {{
put(1, new Command("ID(?)"));
put(2, new Command("Version(?)"));
put(3, new Command("(?)"));
put(4, new Command("INE"));
put(5, new Command("Creation(?)"));
put(6, new Command("Update(?)"));
}});
public static CardTerminal selectCardTerminal() throws Exception {
Scanner in = new Scanner(System.in);
TerminalFactory tf = TerminalFactory.getDefault();
List<CardTerminal> ctlist = null;
ctlist = tf.terminals().list();
if (ctlist.size() == 0) {
throw new Exception("No reader present");
}
if (ctlist.size() == 1) {
return ctlist.get(0);
}
int index = 0;
do {
System.out.println("Readers:");
System.out.println("============================================");
for (CardTerminal ct : ctlist) {
System.out.println(index++ + ": " + ct.getName());
}
System.out.print("Select a reader:");
index = in.nextInt();
} while (index < 0 || index >= ctlist.size());
return ctlist.get(index);
}
public static void selectApplication(CardChannel cc) throws Exception {
System.out.println("Selecting \"Univ.UJF\" application");
CommandAPDU apdu = new CommandAPDU(
0x00, INS_SELECT,
0x4, 0x0,
appletAID);
ResponseAPDU rapdu = cc.transmit(apdu);
if (rapdu.getSW() != 0x9000) {
throw new Exception("Can't select \"Univ.UJF\" application: "
+ Integer.toHexString(rapdu.getSW()));
}
}
public static void main(String[] args) {
try {
CardTerminal ct = selectCardTerminal();
Card c = ct.connect("T=0");
ATR atr = c.getATR();
System.out.println("ATR : " + Util.getHex(atr.getBytes()));
CardChannel cc = c.getBasicChannel();
selectApplication(cc);
for (int id : COMMAND_MAP.keySet()) {
Command cmd = COMMAND_MAP.get(id);
CommandAPDU apdu = new CommandAPDU(
0x00, INS_GETDATA,
(byte) id, 0x00, new byte[]{0x01});
ResponseAPDU rapdu = cc.transmit(apdu);
if (rapdu.getSW() != 0x9000) {
throw new Exception("Can't get data (" + id + "): "
+ Integer.toHexString(rapdu.getSW()));
}
System.out.println(cmd.description + ":"
+ new String(rapdu.getData()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
MuscleCard pour la carte étudiante
MuscleCard is an open source project hosted at the M.U.S.C.L.E website. It aims to develop a JavaCard applet and supporting middleware to perform cryptographic operations like signing and encryption in a smart card. http://www.openscdp.org/scripts/musclecard/index.html
Compilation
(De préference sous Linux)
- Télécharger les sources de Muscle
svn co svn://svn.debian.org/muscleplugins/trunk/MCardApplet
- Télécharger Java Card 2.1.2 Development Kit: lien
- Changer common.xml en modifiant:
Index: common.xml
===================================================================
--- common.xml (revision 297)
+++ common.xml (working copy)
@@ -62,8 +62,8 @@
executable="${JAVA_BUILD_HOME}/bin/javac"
srcdir="${APPLET_SRC}"
destdir="${OUTPUT_DIR}"
- target="${VM_TARGET_VERSION}"
- source="${VM_SOURCE_VERSION}">
+ target="1.1"
+ source="1.2">
<bootclasspath>
<pathelement location="${BOOTCLASSPATH}"/>
</bootclasspath>
- Modifier le fichier JCOP.properties
CARD_NAME=JCOP
JAVA_BUILD_HOME=PATH_VERS_JDK
JC_HOME=PATH_VERS JC212
API_JAR=${JC_HOME}/lib/api21.jar
API_EXPORT_FILES=${JC_HOME}/api21_export_files
Installation
Deplacer le fichier CardEdge.cap dans le dossier de GPShell et lancer le script suivant
mode_211 gemXpressoPro enable_trace establish_context card_connect select -AID a000000018434d open_sc -security 3 -keyind 0 -keyver 0 -key 47454d5850524553534f53414d504c45 // Open secure channel install -file CardEdge.cap -sdAID A000000018434D00 -nvCodeLimit 4000 card_disconnect release_context
Initialisation de l'applet
Comme spécifié ici, l'applet à besoin d'être initialisé (par exemple avec opensc):
Attention : les version > 0.11.3 de opensc ne fonctionne pas avec cette carte
opensc-tool -s 00:A4:04:00:06:A0:00:00:00:01:01 \ -s B0:2A:00:00:38:08:4D:75:73:63:6C:65:30:30:04:01:08:30:30:30:30:30:30:30:30:08:30:30:30:30:30:30:30:30:05:02:08:30:30:30:30:30:30:30:30:08:30:30:30:30:30:30:30:30:00:00:17:70:00:02:01
Initialisation de PKCS15
pkcs15-init -C --so-pin 00000000 --so-puk 00000000 --pin 00000000 --puk 00000000
Changer le code PIN
pkcs15-tool --change-pin
Générer clés RSA/2048bits
pkcs15-init --generate-key rsa/2048 --auth-id ff
Générer certificat auto-signé
Récupérer le slot du lecteur
pkcs11-tool --list-slots
Générer avec OpenSSL:
openssl engine -t dynamic -pre SO_PATH:/usr/lib/engines/engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:opensc-pkcs11.so req -engine pkcs11 -new -key slot_8-id_45 -keyform engine -x509 -out cert.pem -text
Ajouter le certificat dans la carte
pkcs15-init --store-certificate cert.pem --auth-id ff --id 45 --format pem