laforge submitted this change.
global_platform: LOAD and INSTALL [for load] support
In this patch we add the commands "install_for_load" and "load".
Depends: pyosmocom.git I86df064fa41db85923eeb0d83cc399504fdd4488
Change-Id: I924aaeecbb3a72bdb65eefbff6135e4e9570579e
Related: OS#6679
---
M docs/shell.rst
M pySim/global_platform/__init__.py
M requirements.txt
M setup.py
4 files changed, 80 insertions(+), 4 deletions(-)
diff --git a/docs/shell.rst b/docs/shell.rst
index 31689fd..8bb0a17 100644
--- a/docs/shell.rst
+++ b/docs/shell.rst
@@ -1047,6 +1047,12 @@
:module: pySim.global_platform
:func: ADF_SD.AddlShellCommands.del_key_parser
+load
+~~~~
+.. argparse::
+ :module: pySim.global_platform
+ :func: ADF_SD.AddlShellCommands.load_parser
+
install_for_personalization
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. argparse::
@@ -1059,6 +1065,12 @@
:module: pySim.global_platform
:func: ADF_SD.AddlShellCommands.inst_inst_parser
+install_for_load
+~~~~~~~~~~~~~~~~
+.. argparse::
+ :module: pySim.global_platform
+ :func: ADF_SD.AddlShellCommands.inst_load_parser
+
delete_card_content
~~~~~~~~~~~~~~~~~~~
.. argparse::
diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py
index f2bec81..ed4ee68 100644
--- a/pySim/global_platform/__init__.py
+++ b/pySim/global_platform/__init__.py
@@ -17,6 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
+import io
from copy import deepcopy
from typing import Optional, List, Dict, Tuple
from construct import Optional as COptional
@@ -32,6 +33,7 @@
from pySim.filesystem import *
from pySim.profile import CardProfile
from pySim.ota import SimFileAccessAndToolkitAppSpecParams
+from pySim.javacard import CapFile
# GPCS Table 11-48 Load Parameter Tags
class NonVolatileCodeMinMemoryReq(BER_TLV_IE, tag=0xC6):
@@ -464,8 +466,7 @@
# Section 11.4.3.1 Table 11-36 + Section 11.1.2
class Privileges(BER_TLV_IE, tag=0xc5):
- # we only support 3-byte encoding. Can't use StripTrailerAdapter as length==2 is not permitted. sigh.
- _construct = FlagsEnum(Int24ub,
+ _construct = FlagsEnum(StripTrailerAdapter(GreedyBytes, 3, steps = [1, 3]),
security_domain=0x800000, dap_verification=0x400000,
delegated_management=0x200000, card_lock=0x100000, card_terminate=0x080000,
card_reset=0x040000, cvm_management=0x020000,
@@ -751,6 +752,31 @@
ifi_bytes = build_construct(InstallForInstallCD, decoded)
self.install(p1, 0x00, b2h(ifi_bytes))
+ inst_load_parser = argparse.ArgumentParser()
+ inst_load_parser.add_argument('--load-file-aid', type=is_hexstr, required=True,
+ help='AID of the loded file')
+ inst_load_parser.add_argument('--security-domain-aid', type=is_hexstr, default='',
+ help='AID of the Security Domain into which the file shalle be added')
+ inst_load_parser.add_argument('--load-file-hash', type=is_hexstr, default='',
+ help='Load File Data Block Hash (GPC_SPE_034, section C.2)')
+ inst_load_parser.add_argument('--load-parameters', type=is_hexstr, default='',
+ help='Load Parameters (GPC_SPE_034, section 11.5.2.3.7, table 11-49)')
+ inst_load_parser.add_argument('--load-token', type=is_hexstr, default='',
+ help='Load Token (GPC_SPE_034, section C.4.1)')
+
+ @cmd2.with_argparser(inst_load_parser)
+ def do_install_for_load(self, opts):
+ """Perform GlobalPlatform INSTALL [for load] command in order to prepare to load an application."""
+ if opts.load_token != '' and opts.load_file_hash == '':
+ raise ValueError('Load File Data Block Hash is mandatory if a Load Token is present')
+ InstallForLoadCD = Struct('load_file_aid'/HexAdapter(Prefixed(Int8ub, GreedyBytes)),
+ 'security_domain_aid'/HexAdapter(Prefixed(Int8ub, GreedyBytes)),
+ 'load_file_hash'/HexAdapter(Prefixed(Int8ub, GreedyBytes)),
+ 'load_parameters'/HexAdapter(Prefixed(Int8ub, GreedyBytes)),
+ 'load_token'/HexAdapter(Prefixed(Int8ub, GreedyBytes)))
+ ifl_bytes = build_construct(InstallForLoadCD, vars(opts))
+ self.install(0x02, 0x00, b2h(ifl_bytes))
+
def install(self, p1:int, p2:int, data:Hexstr) -> ResTuple:
cmd_hex = "80E6%02x%02x%02x%s00" % (p1, p2, len(data)//2, data)
return self._cmd.lchan.scc.send_apdu_checksw(cmd_hex)
@@ -794,6 +820,44 @@
cmd_hex = "80E4%02x%02x%02x%s00" % (p1, p2, len(data)//2, data)
return self._cmd.lchan.scc.send_apdu_checksw(cmd_hex)
+ load_parser = argparse.ArgumentParser()
+ load_parser_from_grp = load_parser.add_mutually_exclusive_group(required=True)
+ load_parser_from_grp.add_argument('--from-hex', type=is_hexstr, help='load from hex string')
+ load_parser_from_grp.add_argument('--from-file', type=argparse.FileType('rb', 0), help='load from binary file')
+ load_parser_from_grp.add_argument('--from-cap-file', type=argparse.FileType('rb', 0), help='load from JAVA-card CAP file')
+
+ @cmd2.with_argparser(load_parser)
+ def do_load(self, opts):
+ """Perform a GlobalPlatform LOAD command. (We currently only support loading without DAP and
+ without ciphering.)"""
+ if opts.from_hex is not None:
+ self.load(h2b(opts.from_hex))
+ elif opts.from_file is not None:
+ self.load(opts.from_file.read())
+ elif opts.from_cap_file is not None:
+ cap = CapFile(opts.from_cap_file)
+ self.load(cap.get_loadfile())
+ else:
+ raise ValueError('load source not specified!')
+
+ def load(self, contents:bytes, chunk_len:int = 240):
+ # TODO:tune chunk_len based on the overhead of the used SCP?
+ # build TLV according to GPC_SPE_034 section 11.6.2.3 / Table 11-58 for unencrypted case
+ remainder = b'\xC4' + bertlv_encode_len(len(contents)) + contents
+ # transfer this in vaious chunks to the card
+ total_size = len(remainder)
+ block_nr = 0
+ while len(remainder):
+ block = remainder[:chunk_len]
+ remainder = remainder[chunk_len:]
+ # build LOAD command APDU according to GPC_SPE_034 section 11.6.2 / Table 11-56
+ p1 = 0x00 if len(remainder) else 0x80
+ p2 = block_nr % 256
+ block_nr += 1
+ cmd_hex = "80E8%02x%02x%02x%s00" % (p1, p2, len(block), b2h(block))
+ _rsp_hex, _sw = self._cmd.lchan.scc.send_apdu_checksw(cmd_hex)
+ self._cmd.poutput("Loaded a total of %u bytes in %u blocks. Don't forget install_for_install (and make selectable) now!" % (total_size, block_nr))
+
est_scp02_parser = argparse.ArgumentParser()
est_scp02_parser.add_argument('--key-ver', type=auto_uint8, default=0, help='Key Version Number (KVN)')
est_scp02_parser.add_argument('--host-challenge', type=is_hexstr,
diff --git a/requirements.txt b/requirements.txt
index 58473ca..16fa886 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,7 +5,7 @@
jsonpath-ng
construct>=2.10.70
bidict
-pyosmocom>=0.0.6
+pyosmocom>=0.0.8
pyyaml>=5.1
termcolor
colorlog
diff --git a/setup.py b/setup.py
index e353f8a..f90e07b 100644
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@
"jsonpath-ng",
"construct >= 2.10.70",
"bidict",
- "pyosmocom >= 0.0.6",
+ "pyosmocom >= 0.0.8",
"pyyaml >= 5.1",
"termcolor",
"colorlog",
To view, visit change 37454. To unsubscribe, or for help writing mail filters, visit settings.