Smartcard Development on Linux for Newbies ------------------------------------------- TABLE OF CONTENTS ------------------ Preamble i. Disclaimer ii. Copyright iii. About this HOWTO iv. About the Author v. Acknowledgements I. Good References II. Development Environment III. Equipment Used IV. Software Used V. After Install VI. Setting Up the Environment VII. Write and Test your On-card Applications VIII. Write and Test your Off-card Client IX. Loading Applications Into the Card - Gpshell X. Regards Preamble --------- i. Disclaimer -------------- While care has been taken to ensure the accuracy of all the information contained in this document, I will not accept any responsibility for any incorrect information within this document, nor for any damage it might cause when applied. ii. Copyright ------------- Copyright (C) 2007 Michael Kamunge Permission to distribute and modify this document is granted under the GNU General Public Licence. iii. About this HOWTO ---------------------- This HOWTO is a collection of the ( summarized ) experiences of an ex-newbie written for the benefit of anyone venturing into the interesting world of smartcard development, particularly on the Linux platform. The author started work on this document in May 2007 while finalizing his final year project titled "The Complete Campus Card Solution" at the Jomo Kenyatta University of Agriculture and Technology, a pre-requisite to completing his degree in Electrical and Electronics Engineering. Having groped his way in the dark before grasping the basics of smartcard development, and NOT HAVING IN HIS POSSESSION THE ALL-IMPORTANT DEVELOPMENT KIT FROM THE SMARTCARD MANUFACTURER, the author saw it fit to share his experiences in the hope that it would help many-a-newbie in their first steps in this field, especially for those lacking the resources to purchase the copyrighted card development kits. The author hopes that this is only the beginning of what will become a complete guide to smartcard development. iv. About the author -------------------- The author is a soon-to-graduate Electrical and Electronics engineer from the Jomo Kenyatta University of Agriculture and Technology. His first contact with Linux was in 2001, and it was love at first sight. His first direct contact with the development of smartcard-based solutions was in May 2006, during a stint at a leading smartcard solutions providers( Smart Application International ). He has been toying around with smartcards on his beloved Linux ever since, always trying to find new and better ways of making things work. You can contact him by sending e-mail to forlogins@gmail.com v. Acknowledgements ------------------- o Smart Applications International o Dr. Haywood Absaloms Ouma o Ndambuki John o Dr. Ludovic Rousseau o My family and close friends I. Good references: ------------------- 1. Developing a Java Card Applet: http://developers.sun.com/techtopics/mobility/javacard/articles/applet 2. An Introduction to Java Card Technology - Part 1: -> http://developers.sun.com/techtopics/mobility/javacard/articles/javacard1/ 3. An Introduction to Java Card Technology - Part 2, The Java Card Applet: -> http://developers.sun.com/techtopics/mobility/javacard/articles/javacard2/ 4. javax.smartcardio API: -> http://java.sun.com/javase/6/docs/jre/api/security/smartcardio/spec/javax/smartcardio/ 5. Wikipedia: -> http://en.wikipedia.org/wiki/ 6. Australian Government Smartcard Framework ( PDF ) 7. U.S. General Services Administration: Government Smartcard Handbook ( PDF ) 8. Smart Cards – A Case Study [ IBM RedBook ] ( PDF ) 9. CyberFlex Access Cards Programmers' Guide ( PDF ) 10. Java Standard Edition 6 – In Depth Overview ( PDF ) ...et al II. Development environment: Fedora Linux Core 5( kernel 2.6.15-1.2054_FC5 ) --------------------------- III. Equipment used: -------------------- 1. Smartcard : Cyberflex Access 32k e-gate ( contact card ) 2. Card reader : Gemplus GemPC Twin ( USB contact reader ) 3. Fingerprint reader : DigitalPersona 4000B ( USB ) IV. Software used: ----------------- 1. jdk-1.3.1_20.i586.rpm -> for compilation of on-card programs( i.e, applets ) 2. jdk-6-rc-linux-i586.bin -> for compilation of off-card programs 3. jcsdk2.1.1.tar.gz -> java card development kit 4. comm3.0_u1_linux.zip -> java communications api 5. libpcsclite1-1.3.2-8.fc5.at.i386.rpm } 6. pcsc-lite-1.3.2-8.fc5.at.i386.rpm } 7. pcsc-lite-doc-1.3.1-1.fc5.i386.rpm } 8. pcsc-perl-1.4.3-1.fc5.i386.rpm } -> PCSC libs for linux 9. perl-Glib-1.141-1.fc5.i386.rpm } 10. perl-Cairo-1.02-1.fc5.i386.rpm } 11. perl-Gtk2-1.140-1.fc5.i386.rpm } 12. pcsc-tools-1.4.7-1.fc5.i386.rpm } 13. ccid-1.0.1-1.fc5.i386.rpm -> CCID smartcard reader device drivers 14. globalplatform-3.0.2.tar.gz -> GlobalPlatform framework libraries 15. gpshell-1.4.0.tar.gz -> GlobalPlatform shell; smart card script interpreter 16. captransf-1.5.zip -> jar file utilities to convert Sun CAP file into Cyberflex CAP file Supplementary software used( not core smartcard ): 17. libdpfp, version 0.2.1 –> opensource DigitalPersona fingerprint drivers and utilities 18. NIST Biometric Image Software( NBIS ) -> opensource biometric utilities 19. MySQL version 5.0.18 -> opensource database server, 20. MySQL Administrator version 5.0 -> ( provided by the makers of MySQL database server ) 21. MySQL Query Browser version 5.0 -> ( provided by the makers of MySQL database server ) 22. PHP version 5.1.2 -> opensource hypertext preprocessor, 23. APACHE version 2.2.0 -> opensource web server( used for deploying online( web-based ) reporting engine V. NOTE: AFTER INSTALL ---------------------- i. After install: ---------------- 1. cp -Rv /usr/lib/pcsc /usr/ 2. mkdir /var/run/openct 3. touch /var/run/openct/status 4. ln -s /usr/lib/libpcsclite.so.1.0.0 /usr/lib/libpcsclite.so 5. run: pcscd -f -d => output to stdout of detected card reader, data rates and card ATR ------MINE LOOKED LIKE THIS------------ [root@dahood apps]# pcscd -f -d pcscdaemon.c:259:main() pcscd set to foreground with debug send to stderr debuglog.c:211:DebugLogSetLevel() debug level=debug pcscdaemon.c:464:main() pcsc-lite 1.3.2 daemon ready. hotplug_libusb.c:407:HPAddHotPluggable() Adding USB device: 003:002 readerfactory.c:1093:RFInitializeReader() Attempting startup of Gemplus GemPC Twin 00 00 using /usr/pcsc/drive rs/ifd-ccid.bundle/Contents/Linux/libccid.so.1.0.1 readerfactory.c:964:RFBindFunctions() Loading IFD Handler 3.0 ifdhandler.c:1155:init_driver() LogLevel: 0x0003 ifdhandler.c:1165:init_driver() DriverOptions: 0x0000 ifdhandler.c:76:IFDHCreateChannelByName() lun: 0, device: usb:08e6/3437:libusb:003:002 ccid_usb.c:231:OpenUSBByName() Manufacturer: Ludovic Rousseau (ludovic.rousseau@free.fr) ccid_usb.c:241:OpenUSBByName() ProductString: Generic CCID driver v1.0.1 ccid_usb.c:247:OpenUSBByName() Copyright: This driver is protected by terms of the GNU General Public License version 2, or (at your option) any later version. ccid_usb.c:395:OpenUSBByName() Found Vendor/Product: 08E6/3437 (Gemplus GemPC Twin) ccid_usb.c:397:OpenUSBByName() Using USB bus/device: 003/002 ccid_usb.c:784:get_data_rates() declared: 10753 bps ccid_usb.c:784:get_data_rates() declared: 14337 bps ccid_usb.c:784:get_data_rates() declared: 15625 bps ccid_usb.c:784:get_data_rates() declared: 17204 bps ccid_usb.c:784:get_data_rates() declared: 20833 bps ccid_usb.c:784:get_data_rates() declared: 21505 bps ccid_usb.c:784:get_data_rates() declared: 23438 bps ccid_usb.c:784:get_data_rates() declared: 25806 bps ccid_usb.c:784:get_data_rates() declared: 28674 bps ccid_usb.c:784:get_data_rates() declared: 31250 bps ccid_usb.c:784:get_data_rates() declared: 32258 bps ccid_usb.c:784:get_data_rates() declared: 34409 bps ccid_usb.c:784:get_data_rates() declared: 39063 bps ccid_usb.c:784:get_data_rates() declared: 41667 bps ccid_usb.c:784:get_data_rates() declared: 43011 bps ccid_usb.c:784:get_data_rates() declared: 46875 bps ccid_usb.c:784:get_data_rates() declared: 52083 bps ccid_usb.c:784:get_data_rates() declared: 53763 bps ccid_usb.c:784:get_data_rates() declared: 57348 bps ccid_usb.c:784:get_data_rates() declared: 62500 bps ccid_usb.c:784:get_data_rates() declared: 64516 bps ccid_usb.c:784:get_data_rates() declared: 68817 bps ccid_usb.c:784:get_data_rates() declared: 71685 bps ccid_usb.c:784:get_data_rates() declared: 78125 bps ccid_usb.c:784:get_data_rates() declared: 83333 bps ccid_usb.c:784:get_data_rates() declared: 86022 bps ccid_usb.c:784:get_data_rates() declared: 93750 bps ccid_usb.c:784:get_data_rates() declared: 104167 bps ccid_usb.c:784:get_data_rates() declared: 107527 bps ccid_usb.c:784:get_data_rates() declared: 114695 bps ccid_usb.c:784:get_data_rates() declared: 125000 bps ccid_usb.c:784:get_data_rates() declared: 129032 bps ccid_usb.c:784:get_data_rates() declared: 143369 bps ccid_usb.c:784:get_data_rates() declared: 156250 bps ccid_usb.c:784:get_data_rates() declared: 166667 bps ccid_usb.c:784:get_data_rates() declared: 172043 bps ccid_usb.c:784:get_data_rates() declared: 215054 bps ccid_usb.c:784:get_data_rates() declared: 229391 bps ccid_usb.c:784:get_data_rates() declared: 250000 bps ccid_usb.c:784:get_data_rates() declared: 344086 bps ifdhandler.c:252:IFDHGetCapabilities() lun: 0, tag: 0xFAE ifdhandler.c:294:IFDHGetCapabilities() Reader supports 1 slots ------END------------------------------ 6. also: pcsc_scan => ( for more info on detected card and reader ) ------MINE LOOKED LIKE THIS------------ [root@dahood ~]# pcsc_scan PC/SC device scanner V 1.4.7 (c) 2001-2006, Ludovic Rousseau Compiled with PC/SC lite version: 1.3.1 Scanning present readers 0: Gemplus GemPC Twin 00 00 Wed Feb 14 00:00:28 2007 Reader 0: Gemplus GemPC Twin 00 00 Card state: Card inserted, ATR: 3B 75 94 00 00 62 02 02 02 01 ATR: 3B 75 94 00 00 62 02 02 02 01 + TS = 3B --> Direct Convention + T0 = 75, Y(1): 0111, K: 5 (historical bytes) TA(1) = 94 --> Fi=512, Di=8, 64.000 cycles/ETU TB(1) = 00 --> Programming Param P: 0 Volts, I: 0 milliamperes TC(1) = 00 --> Extra guard time: 0 + Historical bytes: 62 02 02 02 01 Category indicator byte: 62 (proprietary format) Possibly identified card (using /usr/share/pcsc/smartcard_list.txt): 3B 75 94 00 00 62 02 02 02 01 3B 75 94 00 00 62 02 02 0[1-3] 01 Schlumberger Cyberflex 32K e-gate ------END------------------------------ VI. SETTING UP THE ENVIRONMENT ------------------------------- 1. Java Comm 3.0 -> cp /java/javacomm3.0/lib/libLinuxSerialParallel.so /usr/lib/ 2. Edited: /root/.bash_profile: See below: --------------------.bash_profile extract START ---------------------- # project environment variables: # first: javacomm and jcsdk vars: CLASSPATH=/java/javacomm3.0/jar/comm.jar:/java/jcsdk2.1.1/bin/api21.jar:/java/jcsdk2.1.1/bin/converter.jar: /usr/local/lib/mysql-connector-java-5.0.5-bin.jar:/project/codebase/ export CLASSPATH # next: jcsdk vars: JC21_HOME=/java/jcsdk2.1.1 #JC22_HOME=/java/jcsdk2.1.2 JC_HOME=/java/jcsdk2.1.1 export JC21_HOME #export JC22_HOME export JC_HOME # next: jdk vars: #JAVA_HOME=/java/jdk1.6.0 #JAVA_HOME=/java/jdk1.5.0_07 JAVA_HOME=/java/jdk-1.3.1_20 export JAVA_HOME --------------------.bash_profile extract END ---------------------- 3. cp /java/javacomm3.0/docs/javax.comm.properties /java/jdk1.6.0/jre/lib/ <- THAT IS, into the lib folder of the resident Java SDK VII. WRITE AND TEST YOUR ON-CARD APPLICATIONS( i.e, applets ) ------------------------------------------------------------- NOTE: For acceptance by the Cyberflex smartcard, had to use an older JDK for the on-card programs. Used version 1.3.1_20 for linux( rpm ) Process steps: -------------- 1. Write the applet code Sample code: Allow me to demonstrate using code I wrote to store the user's ID details: -----------------------------START---------------------------- /** * * Identity.java * CCCS i.d. application * 4th April, 2007 * */ package cccs.on_card.id; import javacard.framework.*; import javacard.security.*; // Applet AID: 0x00:0x01:0x02:0x03:0x04:0x05:0x06:0x07:0x0b:0x1 // I arbitrarily chose the general structure for my Application Identifiers( i.e AIDs )[ all are 10 bytes long ] // All packages start with the general sequence 0x00:0x01:0x02:0x03:0x04:0x05:0x06:0x07, then individual // packages are labelled 0x0a, 0x0b, ...( e.g, this is 0x0b, and 0x1 is this particular class's number public class Identity extends javacard.framework.Applet { // define the applet's CLAss byte final static byte CLA = ( byte )0x04; // read-only INStruction commands final static byte GET_STUDENT_ID = ( byte )0x01; final static byte GET_FIRST_NAME = ( byte )0x02; final static byte GET_LAST_NAME = ( byte )0x03; // constants final static short MAX_ID_SIZE = ( short )11; // *** WATCH THIS!!! ** final static short MAX_NAME_SIZE = ( short )7; // *** WATCH THIS!!! ** //final static short ALL_INFO_SIZE = MAX_ID_SIZE + ( 2 * MAX_NAME_SIZE ); // fields byte[] studentID = null; byte[] firstName = null; byte[] lastName = null; /** * Initialize all the fields of this applet * * Example input:- * * STUDENT_ID : E27-0193/01 : 69 50 55 45 48 49 57 51 47 48 49 : ASCII * STUDENT_ID : E27-0193/01 : 0x45 0x32 0x37 0x2d 0x30 0x31 0x39 0x33 0x2f 0x30 0x31 : HEX * FNAME : MICHAEL : 77 73 67 72 65 69 76 0x00 0x00 0x00 : ASCII * FNAME : MICHAEL : 0x4d 0x49 0x43 0x48 0x41 0x45 0x4c 0x00 0x00 0x00 : HEX * LNAME : KAMUNGE : 75 65 77 85 78 71 69 0x00 0x00 0x00 : ASCII * LNAME : KAMUNGE : 0x4b 0x41 0x4d 0x55 0x4e 0x47 0x45 0x00 0x00 0x00 : HEX * * * input : 4532372d303139332f30314d49434841454c0000004b414d554e4745000000 * length : 31 bytes( 0x1F ) * **/ private Identity( byte[] bArray, short bOffset, byte bLength ) { studentID = new byte[ MAX_ID_SIZE ]; firstName = new byte[ MAX_NAME_SIZE ]; lastName = new byte[ MAX_NAME_SIZE ]; studentID[ 0 ] = ( byte )0x45; studentID[ 1 ] = ( byte )0x32; studentID[ 2 ] = ( byte )0x37; studentID[ 3 ] = ( byte )0x2d; studentID[ 4 ] = ( byte )0x30; studentID[ 5 ] = ( byte )0x31; studentID[ 6 ] = ( byte )0x39; studentID[ 7 ] = ( byte )0x33; studentID[ 8 ] = ( byte )0x2f; studentID[ 9 ] = ( byte )0x30; studentID[ 10 ] = ( byte )0x31; firstName[ 0 ] = ( byte )0x4d; firstName[ 1 ] = ( byte )0x49; firstName[ 2 ] = ( byte )0x43; firstName[ 3 ] = ( byte )0x48; firstName[ 4 ] = ( byte )0x41; firstName[ 5 ] = ( byte )0x45; firstName[ 6 ] = ( byte )0x4c; lastName[ 0 ] = ( byte )0x4b; lastName[ 1 ] = ( byte )0x41; lastName[ 2 ] = ( byte )0x4d; lastName[ 3 ] = ( byte )0x55; lastName[ 4 ] = ( byte )0x4e; lastName[ 5 ] = ( byte )0x47; lastName[ 6 ] = ( byte )0x45; register(); } // constructor /* Installs a new instance of this applet and passes the input to the applet constructor */ public static void install( byte[] bArray, short bOffset, byte bLength ) { new Identity( bArray, bOffset, bLength ); } /* The process method which represents all commands */ public void process( APDU apdu ) throws ISOException { byte[] buffer = apdu.getBuffer(); if( selectingApplet() ) { return; } if( buffer[ ISO7816.OFFSET_CLA ] != CLA ) { ISOException.throwIt( ISO7816.SW_CLA_NOT_SUPPORTED ); } switch( buffer[ ISO7816.OFFSET_INS ] ) { case GET_STUDENT_ID: { getStudentID( apdu ); return; } case GET_FIRST_NAME: { getFirstName( apdu ); return; } case GET_LAST_NAME: { getLastName( apdu ); return; } default: { ISOException.throwIt( ISO7816.SW_INS_NOT_SUPPORTED ); } } // switch } // process private void getLastName( APDU apdu ) { byte[] buffer = apdu.getBuffer(); Util.arrayCopy( lastName, ( short )0, buffer, ( short )0, MAX_NAME_SIZE ); apdu.setOutgoingAndSend( ( short )0, MAX_NAME_SIZE ); } // getLastName private void getFirstName( APDU apdu ) { byte[] buffer = apdu.getBuffer(); Util.arrayCopy( firstName, ( short )0, buffer, ( short )0, MAX_NAME_SIZE ); apdu.setOutgoingAndSend( ( short )0, MAX_NAME_SIZE ); } // getFirstName private void getStudentID( APDU apdu ) { byte[] buffer = apdu.getBuffer(); Util.arrayCopy( studentID, ( short )0, buffer, ( short )0, MAX_ID_SIZE ); apdu.setOutgoingAndSend( ( short )0, MAX_ID_SIZE ); } // getStudentID } // class -----------------------------END---------------------------- 2. Compile the applet code -------------------------- -> In my case, compilation of the above code was done using: javac -g cccs/on_card/id/Identity.java NB: <- the -g switch is necessary for generating debugging info useful in the conversion process later. 3. Test and debug compiled applet using the JCWDE( optional, but helpful for cementing APDU concepts into one's head ). ----------------------------------------------------------------------------------------------------------------------- -> Testing involves running your compiled code through the JDK's 'simulator'. Your 'inputs' are two files, the JCWDE simulation file and APDUtool script file. Output will be the result of the simulation( success or not ) in the form of STATUS WORDS. -> JCWDE file for the above Identity applet: --------------------------------START------------------------------ // identity.jcwde // Identity.java's JCWDE app file // applet AID com.sun.javacard.installer.InstallerApplet 0xa0:0x0:0x0:0x0:0x62:0x3:0x1:0x8:0x1 cccs.on_card.id.Identity 0x00:0x01:0x02:0x03:0x04:0x05:0x06:0x07:0x0b:0x1 --------------------------------END------------------------------ -> APDU script file for the above Identity applet: --------------------------------START------------------------------ // identity.scr // Identity applet's APDU script file powerup; ////////////////// // INSTALLATION // ////////////////// // Select the installer applet 0x00 0xA4 0x04 0x00 0x09 0xa0 0x00 0x00 0x00 0x62 0x03 0x01 0x08 0x01 0x7F; // begin installer command 0x80 0xB0 0x00 0x00 0x00 0x7F; // create identity applet //0x80 0xB8 0x00 0x00 0x0B 0x0a 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x0b 0x1 0x7F; 0x80 0xB8 0x00 0x00 0x2e 0x0a 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x0b 0x1 0x22 0x00 0x00 0x00 0x45 0x32 0x37 0x2d 0x30 0x31 0x39 0x33 0x2f 0x30 0x31 0x4d 0x49 0x43 0x48 0x41 0x45 0x4c 0x00 0x00 0x00 0x4b 0x41 0x4d 0x55 0x4e 0x47 0x45 0x00 0x00 0x00 0x7f; // The above sequence has my names and reg. number // end installer command 0x80 0xBA 0x00 0x00 0x00 0x7F; /////////////////// /// APDU TESTS //// ////////////////// // Select Identity applet 0x00 0xa4 0x04 0x00 0x0a 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x0b 0x1 0x7F; // Get student id 0x04 0x01 0x00 0x00 0x00 0x00; // Get first name 0x04 0x02 0x00 0x00 0x00 0x00; // Get last name 0x04 0x03 0x00 0x00 0x00 0x00; // Get all info 0x04 0x04 0x00 0x00 0x00 0x00; // *** SCRIPT END *** powerdown; --------------------------------END------------------------------ -> Running the simulator: o open two konsole/terminal windows o in one, run the jcwde simulator o in the other, run the apdutool script parser NB: The order counts, run jcwde first, THEN apdutool --------------------------------MINE: START------------------------------ >> jcwde identity.app >> apdutool identity.scr > identity.scr.out ---------------------------------END------------------------------ -> Output from the simulation run( identity.scr.out ) : --------------------------------OUTPUT: START------------------------------ Java Card 2.2.2 APDU Tool, Version 1.3 Copyright 2005 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. Opening connection to localhost on port 9025. Connected. Received ATR = 0x3b 0xf0 0x11 0x00 0xff 0x00 CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 09, a0, 00, 00, 00, 62, 03, 01, 08, 01, Le: 00, SW1: 90, SW2: 00 CLA: 80, INS: b0, P1: 00, P2: 00, Lc: 00, Le: 00, SW1: 90, SW2: 00 CLA: 80, INS: b8, P1: 00, P2: 00, Lc: 0b, 0a, 00, 01, 02, 03, 04, 05, 06, 07, 0b, 01, Le: 0a, 00, 01, 02, 03, 04, 05, 06, 07, 0b, 01, SW1: 90, SW2: 00 CLA: 80, INS: ba, P1: 00, P2: 00, Lc: 00, Le: 00, SW1: 90, SW2: 00 CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 0a, 00, 01, 02, 03, 04, 05, 06, 07, 0b, 01, Le: 00, SW1: 90, SW2: 00 CLA: 04, INS: 01, P1: 00, P2: 00, Lc: 00, Le: 0f, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, SW1: 90, SW2: 00 CLA: 04, INS: 02, P1: 00, P2: 00, Lc: 00, Le: 0a, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, SW1: 90, SW2: 00 CLA: 04, INS: 03, P1: 00, P2: 00, Lc: 00, Le: 0a, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, SW1: 90, SW2: 00 CLA: 04, INS: 04, P1: 00, P2: 00, Lc: 00, Le: 23, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, SW1: 90, SW2: 00 --------------------------------OUTPUT: END------------------------------ NB: Note the SW1s and SW2s, the status words. SW1SW2 of 9000 indicates successful operation; anything else, unless intended, indicates failure, in which case, refer to the Programmer's Guide for meanings of error-indicating status words. VIII. WRITE AND TEST YOUR OFF-CARD CLIENT ----------------------------------------- NOTE: Used jdk1.6.0( Mustang ) for writing the off-card programs( i.e, the one's reading information off the card ) since it includes classes for accessing smartcard( prior versions do not ). The off-card client will do, well, whatever you want it to do, based on the capabilities of the on-card applets. Sample: code snippet from off-card client to read off the user's Identity information: -------------------------------SNIPPET :: START-------------------------- if( module.equals( "identification" ) ) { /** * read ID information * sequence: * i. connect to card * ii. open channel * iii. select Identity applet AID * iv. send APDUs * */ card = Global.connectToReader(); channel = card.getBasicChannel(); // APDUs // Select Identity applet : 00A404000A00010203040506070B01 // Registration number : 0401000000 // First name : 0402000000 // Last name : 0403000000 byte[] selectAPDU = { (byte)0x00, (byte)0xA4, (byte)0x04, (byte)0x00, (byte)0x0A, (byte)0x00, (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x0B, (byte)0x01 }; byte[] regNoAPDU = { (byte)0x04, (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00 }; byte[] fNameAPDU = { (byte)0x04, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00 }; byte[] lNameAPDU = { (byte)0x04, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x00 }; try { // select apdu and response rAPDU = channel.transmit( new CommandAPDU( selectAPDU ) ); formatResponse( rAPDU.getBytes(), rAPDU.getNr() ); // reg. no. apdu and response rAPDU = channel.transmit( new CommandAPDU( regNoAPDU ) ); String regNo = formatResponse( rAPDU.getBytes(), rAPDU.getNr() ); cccs.off_card.gui.Modules.regNoLabel.setText( regNo ); // select apdu and response rAPDU = channel.transmit( new CommandAPDU( fNameAPDU ) ); String firstName = formatResponse( rAPDU.getBytes(), rAPDU.getNr() ); cccs.off_card.gui.Modules.fNameLabel.setText( firstName ); // select apdu and response rAPDU = channel.transmit( new CommandAPDU( lNameAPDU ) ); String lastName = formatResponse( rAPDU.getBytes(), rAPDU.getNr() ); cccs.off_card.gui.Modules.lNameLabel.setText( lastName ); // finalise by setting the card user's photo String query = "select photo_id from user where reg_number='"+regNo+"'"; rs = Global.connectToDatabase( query ); if( rs.next() ) { //System.out.println( rs.getString( "photo_id" ) ); Icon icon = new ImageIcon( rs.getString( "photo_id" ) ); cccs.off_card.gui.Modules.imageLabel.setIcon( icon ); } logEncounter( "Identification" ); } catch( Exception ex ) { System.out.println( ex ); Global.log( ex.toString() ); } } // if( "authentication" ) -------------------------------SNIPPET :: START-------------------------- IX. LOADING THE APPLETS INTO THE SMARTCARD - GPSHELL ---------------------------------------------------- Process: i. Convert class file into CAP file ii. Covert CAP file further using captransf.jar into a form that the card will accept to install iii. Run GPSHELL script to install the converted CAP file ---------------------------STAGE 1 :: CLASS FILE INTO CAP FILE----------------------- [root@dahood codebase]# /java/jcsdk2.1.1/bin/converter -exportpath "/java/jcsdk2.1.1/api21/" cccs/on_card/id 0x00:0x01:0x02:0x03:0x04:0x05:0x06:0x07:0x0b 1.0 -v -applet 0x00:0x01:0x02:0x03:0x04:0x05:0x06:0x07:0x0b:0x01 Identity Java Card 2.1.1 Class File Converter (version 1.1) Copyright (c) 2000 Sun Microsystems, Inc. All rights reserved. parsing /mine/personals/PROJECT_5TH_YEAR/codebase/cccs/on_card/id/Identity.class converting cccs.on_card.id.Identity parsing /java/jcsdk2.1.1/api21/javacard/framework/javacard/framework.exp writing /mine/personals/PROJECT_5TH_YEAR/codebase/cccs/on_card/id/javacard/id.exp writing /mine/personals/PROJECT_5TH_YEAR/codebase/cccs/on_card/id/javacard/id.jca ---------------------------STAGE 1 :: END-------------------------------------------- ---------------------------STAGE 2 :: FURTHER CAP FILE CONVERSION-------------------- [root@dahood javacard]# /java/jdk1.3.1_20/bin/java -jar captransf.jar /java/jcsdk2.1.1/api21/java/lang/javacard/lang.exp /java/jcsdk2.1.1/api21/javacard/framework/javacard/framework.exp /java/jcsdk2.1.1/api21/javacard/security/javacard/security.exp /java/jcsdk2.1.1/api21/javacardx/crypto/javacard/crypto.exp -noint id.cap Result: id.cap.transf ---------------------------STAGE 2 :: END-------------------------------------------- ---------------------------STAGE 3 :: GPSHELL INSTALL SCRIPT :: filename=latest.gpscr------------------------- mode_201 enable_trace establish_context card_connect -readerNumber 1 select -AID a0000000030000 open_sc -security 1 -keyind 0 -keyver 0 -mac_key 404142434445464748494a4b4c4d4e4f -enc_key 404142434445464748494a4b4c4d4e4f // Open secure channel delete -AID 00010203040506070b01 delete -AID 00010203040506070b install -file id.cap.transf -sdAID a0000000030000 -nvDataLimit 4096 -instParam 00 -priv 2 get_status -element e0 card_disconnect release_context ---------------------------STAGE 3 :: END-------------------------------------------- --------------------------RUNNING THE GPSHELL INSTALLER ON THE SCRIPT ABOVE------------- [root@dahood javacard]# gpshell latest.gpscr mode_201 enable_trace establish_context card_connect -readerNumber 1 select -AID a0000000030000 --> 00A4040007A0000000030000 <-- 6F188407A0000000030000A50D9F6E060011020201009F6501FF9000 open_sc -security 1 -keyind 0 -keyver 0 -mac_key 404142434445464748494a4b4c4d4e4f -enc_key 404142434445464748494a4b4c4d4e4f // Open secure channel --> 8050000008910482ACB234E1CC00 <-- 00006046000115F2FF020101130FAFBA9747CD828B043A1FF990A3499000 --> 8482010010B0A1C884748BC1E2E5943C3769620587 <-- 9000 install -file id.cap.transf -sdAID a0000000030000 -nvDataLimit 12000 -instParam 00 -priv 2 --> 80E602001B0900010203040506070B07A00000000300000006EF04C60203180000 <-- 009000 --> 80E80000EFC482030E010013DECAFFED01020400010900010203040506070B02001F0013001F000E000B004A000C0157000A0034000000BA00000000000001010004000B01000107A000000062010103000E010A00010203040506070B01007506000C008003040004070100000083070157000540188C000418018700180187011801870218018703181023900B870318100F900B870018100A900B870118100A900B87021E191E2541074131191EAD030310238D00053B191EAD0003100F8D00053B59020F191EAD0103100A8D00053B59020A191EAD0103100A8D00053B59020A188B00067A05308F00073D181D1E8C00083B <-- 9000 --> 80E80001EF7A0221198B00092D188B000A60037A1A0325076A08116E008D000B1A042573002700010004000F0015001B002118198C000C7A18198C000D7A18198C000E7A18198C000F7A116D008D000B7A0522198B00092D0332AD00031A1F100F8D00103B59030FAD01031A1F100A8D00103B59030AAD02031A1F100A8D00103B59030A190310238B00117A0521198B00092DAD02031A03100A8D00103B1903100A8B00117A0521198B00092DAD01031A03100A8D00103B1903100A8B00117A0521198B00092DAD00031A03100F8D00103B1903100F8B00117A08000A0000000000000000000005004A00120200000002000001 <-- 9000 --> 80E80002EF0200000202000003068003000680100203800301010000000600000103800A0103800303068007010600013D0600012306000109060000CE0680100103800A0809003400120A040404070707070C0B0E0E730E0E1D1A1A001E053E0B0E0E08060708050F1706060607070D0E0E0B070B08070B08070B080B00BA0100010000000004000700000000000026010000020100260200000402002603000006030026FF820001002E00720000000000090075002E000C00000000070100830035004900000000FF0200CE0035003900000000FF0201090035001800000000FF0201230035001800000000FF02013D003500 <-- 9000 --> 80E88003451800000000001200260026002600260028002A0028FFFF002E0026003100330035003500350035002A003901B0011006B4B44404B43101200241066800A10344100130014000 <-- 009000 --> 80E60C002D0900010203040506070B0A00010203040506070B010A00010203040506070B01010209C90100EF04C8022EE00000 <-- 00C7020000C802006C9000 card_disconnect release_context ---------------------------------------INSTALLER END------------------------------------- -------------------------------CHECKING RESULT OF RUNNING ABOVE SCRIPT-------------------------- Filename = getStatus.gpscr establish_context card_connect select -AID a0000000030000 open_sc -security 1 -keyind 0 -keyver 0 -mac_key 404142434445464748494a4b4c4d4e4f -enc_key 404142434445464748494a4b4c4d4e4f // Open secure channel get_status -element e0 card_disconnect release_context ---------------------- Result: [root@dahood javacard]# gpshell getStatus.gpscr establish_context card_connect select -AID a0000000030000 open_sc -security 1 -keyind 0 -keyver 0 -mac_key 404142434445464748494a4b4c4d4e4f -enc_key 404142434445464748494a4b4c4d4e4f // Open secure channel get_status -element e0 List of applets (AID state privileges) a0000000030000 7 0 } a0000000620001 1 0 } a0000000620101 1 0 } a0000000620102 1 0 }-> Card Management applets( factory installed ) a0000000620201 1 0 } a0000000030000 1 0 } 00010203040506070b 1 0 <- Identity package AID 00010203040506070b01 7 2 <- Identity applet AID card_disconnect release_context --------------------------------------CHECKING RESULT :: END------------------------------------- X. Regards ----------- Hope this cut-to-the-point guide was useful. Do not hesitate to post comments, suggestions, improvements and general questions to the author at forlogins@gmail.com. All the best in all your endeavours! TGBTG