JavaCard

From air
Revision as of 12:45, 18 February 2016 by Donsez (talk | contribs) (→‎Générer certificat auto-signé)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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

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