laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/pysim/+/37454?usp=email )

Change subject: global_platform: LOAD and INSTALL [for load] support
......................................................................

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

Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified




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 https://gerrit.osmocom.org/c/pysim/+/37454?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I924aaeecbb3a72bdb65eefbff6135e4e9570579e
Gerrit-Change-Number: 37454
Gerrit-PatchSet: 9
Gerrit-Owner: laforge <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-CC: dexter <[email protected]>

Reply via email to