JavaCard

From air
Jump to navigation Jump to search

JavaCard est un canevas d’exécution d'application pour carte à puce développé en Java.

Les APIs

Les outils

Global Platform

Global Platform est un standard permettant l'installation de cardapplets.

Carte étudiante (ancienne génération)

Présentation de la carte

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

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 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