I need to load a simple applet to my USIM card. Authentication is OK. I'm using OTA SMS-DELIVER via SmartCard to install CAP file.
Using these:
I couldnt find the right spec explaining "C482XXYY" in Header.cap, how it should be calculated,
this answer below helped me navigate, but for Method.cap loading - it still fails https://community.oracle.com/tech/developers/discussion/1753814/globalpaltform-load-command-data-field
I've written this loader: https://pastebin.com/pSXeDYyS
Every component in CAP file is in separate APDU with LOAD instruction. First 5 is loaded successfully with DATA=00, SW=9000, however on Method it fails. As you can see from my script, I've fixed Descriptor size to 0000 in Directory field. And in Header C482xxyy, where xxyy is calculated properly, which is a sum of all size fields in Directory, e.g.
016a = 0011+001f+000c+001e+0042+0018+006d+0032+0017+0000+0000
Question: Can't figure out why Method LOAD fails? By checking GP 2.1 spec, it doesnt
help me understand the problem. Concatenated components to < 255 block size also fails, only separate components work for LOAD.
[+] Install for load
>> 80e602001207d07002ca449001000006ef04c60201850000c0000000
<< 009000
[+] LOAD - Header
>> 80e8000018c482016a010011decaffed010204000107d07002ca44900100c0000000
<< 009000
[+] LOAD - Directory
>> 80e800012202001f0011001f000c001e00420018006d003200170000000000040002002202010000c0000000
<< 009000
[+] LOAD - Import
>> 80e800022104001e02000107a0000000620101060210a0000000090003ffffffff891071000200c0000000
<< 009000
[+] LOAD - Applet
>> 80e800030f03000c0108d07002ca44900101002000c0000000
<< 009000
[+] LOAD - Class
>> 80e800041b06001843800301ff0007020000002f00398002008101010881000000c0000000
<< 009000
[!!!!] LOAD - Method (FAILED)
>> 80e800057007006d000911188c00048d00012c18197b0002037b00029210240303038b000388007a02318f00053d8c00062e1b8b00077a0120188b000860037a7a02228d00092d1d10076b101a8b000a321fae006b06188c000b7a06118d000c2c1903077b000d037b000d928b000e198b000f3b7a00c0000000
<< 9000 (should be 009000)
[-] LOAD - StaticField (FAILED due to last failed LOAD)
>> 80e80006350800.....
<< 6A86 (because prev. p2=05 is not loaded)
Applet source code:
package com.github.mrlnc.HelloSTK2;
import javacard.framework.*;
import sim.toolkit.*;
/*
Originally from: https://git.osmocom.org/sim/hello-stk/tree/hello-stk/src/org/toorcamp/HelloSTK/HelloSTK.java
*/
public class HelloSTK2 extends Applet implements ToolkitInterface, ToolkitConstants {
// DON'T DECLARE USELESS INSTANCE VARIABLES! They get saved to the EEPROM,
// which has a limited number of write cycles.
private byte helloMenuItem;
private HelloSTK2() {
// This is the interface to the STK applet registry (which is separate
// from the JavaCard applet registry!)
ToolkitRegistry reg = ToolkitRegistry.getEntry();
byte[] menuItemText = new byte[] { 'H', 'e', 'l', 'l', 'o'};
// Define the applet Menu Entry
helloMenuItem = reg.initMenuEntry(menuItemText, (short)0, (short)menuItemText.length,
PRO_CMD_SELECT_ITEM, false, (byte)0, (short)0);
}
// This method is called by the card when the applet is installed. You must
// instantiate your applet and register it here.
public static void install(byte[] bArray, short bOffset, byte bLength) {
HelloSTK2 applet = new HelloSTK2();
applet.register();
}
// This processes APDUs sent directly to the applet. For STK applets, this
// interface isn't really used.
public void process(APDU arg0) throws ISOException {
// ignore the applet select command dispached to the process
if (selectingApplet())
return;
}
// This processes STK events.
public void processToolkit(byte event) throws ToolkitException {
EnvelopeHandler envHdlr = EnvelopeHandler.getTheHandler();
if (event == EVENT_MENU_SELECTION) {
byte selectedItemId = envHdlr.getItemIdentifier();
if (selectedItemId == helloMenuItem) {
byte[] welcomeMsg = new byte[] { 'W', 'e', 'l', 'c', 'o', 'm', 'e' };
ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
proHdlr.initDisplayText((byte)0, DCS_8_BIT_DATA, welcomeMsg, (short)0,
(short)(welcomeMsg.length));
proHdlr.send();
}
}
}
}
UPDATE: Raw CAP bytes in order (Header, Directory, Import, Applet, Class, Method, StaticField, ConstantPool, RefLocation, Descriptor)
['01000fdecaffed010204000105d07002ca44',
'02001f000f001f000c00280036001800aa000a001200000003000000000000030100', '04002803030107a0000000620101060210a0000000090003ffffffff8910710002000107a0000000620001',
'03000c0108d07002ca449001010039',
'06001843800301ff00070200000048005280020081010108810000', '0700aa000912188c00038d00012c08900b3d031048383d041065383d05106c383d06106c383d07106f382d18191a031a9210240303038b000288007a02318f00043d8c00052e1b8b00067a0120188b000760037a7a06248d00082d1d10076b4e1a8b0009321fae006b441007900b3d031057383d041065383d05106c383d061063383d07106f383d08106d383d100610653828048d000a2805150503071504031504928b000b15058b000c3b7a',
'08000a00000000000000000000', '050036000d02000000068109000381090b0680030001000000060000010380030103800303068108000381080c06810a0003810a1303810a16',
'0900120002372d000c05032c08040507090a330f05',
'0b0003000000']
UPDATE 2: I'm sending via ENVELOPE commands. KIC1,KID1 encryptions are used. They work with RFM and some RAM commands like GET STATUS etc. Here is the code for INSTALL (for load) command:
def install_for_load(self, caps, exe_aid):
# 11.5.2.3.7 INSTALL Command Parameters, page 174
cap_data = "".join(caps)
apdu = "".join([
"80", # CLS
"e6", # INSTR
"02", # p1 0b000000_1_0 ; for load
"00", # p2
"%02x", # p3 ; Lc
])
# sec_aid = "a000000003000000" # GP211 Security Domain AID
data = "".join([
"%02x" % int(len(exe_aid)/2),
exe_aid,
"00", # security domain aid (same domain)
# "%02x" % int(len(sec_aid)/2), # security domain aid (same domain)
# sec_aid,
"00", # load file data block hash
"%02x", # load params length
])
load_params_tl = "".join([
"ef", # Load Parameters: System Specific Parameters tag
"%02x", # length of load_params
])
load_params_v = "".join([
"c6", # Non-volatile code Minimum Memory requirement. load params (mandatory)
"02", # length
"%04x" % int(len(cap_data)/2), # code size HelloSTK2.cap size.
# "c7", # volatile data minimum memory required (ram) - optional
# "02", # length
# "00ff",
# "c8", # non-volatile data minimum memory required - optional
# "02",
# "00ff"
])
load_params = load_params_tl % int(len(load_params_v)/2) + load_params_v
data = data % int(len(load_params)/2) + load_params
data += "00" # load token
apdu = apdu % int(len(data)/2) + data
apdu += "00c0000000" # C-MAC + Le
return apdu
You can have a look into the GlobalPlatform project loader. It is LPGL, so directly using it as C code in other non LGPL projects is not possible.
[!!!!] LOAD - Method (FAILED)
80e800057007006d000911188c00048d00012c18197b0002037b00029210240303038b000388007a02318f00053d8c00062e1b8b00077a0120188b000860037a7a02228d00092d1d10076b101a8b000a321fae006b06188c000b7a06118d000c2c1903077b000d037b000d928b000e198b000f3b7a00c0000000
<< 9000 (should be 009000)
I assume that the log is the unwrapped logged before the commands are prepared for SCP80. A response of 9000 in OTA means usually "I received the command, but I don't know what to do with it". Is this 9000 command from the ENVELOPE response on the card? Are you sending the data over an SMPP connection?
Can you try your loading code with a simple HelloWorld Applet without any STK? It could be that your card is not supporting a version you are linking against, e.g. different ETSI releases. Then some method might not be supported and the loading fails.