dexter has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/pysim/+/39199?usp=email )


Change subject: global_platform: add new command "install_cap"
......................................................................

global_platform: add new command "install_cap"

Installing JAVA-card applets from a CAP file is a multi step process, which is
difficult when done manually. Fortunately it is easy to automate the process,
so let's add a dedicated command for that.

Change-Id: I6cbd37f0fad5579b20e83c27349bd5acc129e6d0
Related: OS#6679
---
M pySim/global_platform/__init__.py
A pySim/global_platform/install_param.py
M tests/unittests/test_globalplatform.py
3 files changed, 131 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/99/39199/1

diff --git a/pySim/global_platform/__init__.py 
b/pySim/global_platform/__init__.py
index 7898259..023e7f9 100644
--- a/pySim/global_platform/__init__.py
+++ b/pySim/global_platform/__init__.py
@@ -30,6 +30,7 @@
 from pySim.utils import ResTuple
 from pySim.card_key_provider import card_key_provider_get_field
 from pySim.global_platform.scp import SCP02, SCP03
+from pySim.global_platform.install_param import gen_install_parameters
 from pySim.filesystem import *
 from pySim.profile import CardProfile
 from pySim.ota import SimFileAccessAndToolkitAppSpecParams
@@ -859,6 +860,53 @@
                 _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))

+        install_cap_parser = argparse.ArgumentParser()
+        install_cap_parser.add_argument('cap_file', type=str, metavar='FILE',
+                                        help='JAVA-CARD CAP file to install')
+        install_cap_parser.add_argument('--install-parameters', 
type=is_hexstr, default='',
+                                        help='install Parameters (GPC_SPE_034, 
section 11.5.2.3.7, table 11-49)')
+        
install_cap_parser.add_argument('--install-parameters-volatile-memory-quota', 
type=int, default=None,
+                                        help='install Parameters (GPC_SPE_034, 
section 11.5.2.3.7, table 11-49)')
+        
install_cap_parser.add_argument('--install-parameters-non-volatile-memory-quota',
 type=int, default=None,
+                                        help='Install Parameters (GPC_SPE_034, 
section 11.5.2.3.7, table 11-49)')
+        install_cap_parser.add_argument('--install-parameters-stk', 
type=is_hexstr, default=None,
+                                        help='Load Parameters (ETSI TS 102 
226, section 8.2.1.3.2.1)')
+
+        @cmd2.with_argparser(install_cap_parser)
+        def do_install_cap(self, opts):
+            """Perform a .cap file installation using GlobalPlatform LOAD and 
INSTALL commands."""
+
+            self._cmd.poutput("loading cap file: %s ..." % opts.cap_file)
+            cap = CapFile(opts.cap_file)
+
+            security_domain_aid = self._cmd.lchan.selected_file.aid
+            load_file = cap.get_loadfile()
+            load_file_aid = cap.get_loadfile_aid()
+            module_aid = cap.get_applet_aid()
+            application_aid = module_aid
+            if opts.install_parameters != '':
+                install_parameters = opts.install_parameters;
+            else:
+                install_parameters = 
gen_install_parameters(opts.install_parameters_non_volatile_memory_quota,
+                                                            
opts.install_parameters_volatile_memory_quota,
+                                                            
opts.install_parameters_stk)
+            self._cmd.poutput("parameters:")
+            self._cmd.poutput(" security-domain-aid: %s" % security_domain_aid)
+            self._cmd.poutput(" load-file: %u bytes" % (len(load_file) // 2))
+            self._cmd.poutput(" load-file-aid: %s" % load_file_aid)
+            self._cmd.poutput(" module-aid: %s" % module_aid)
+            self._cmd.poutput(" application-aid: %s" % application_aid)
+            self._cmd.poutput(" install-parameters: %s" % install_parameters)
+
+            self._cmd.poutput("step #1: install for load...")
+            self.do_install_for_load("--load-file-aid %s --security-domain-aid 
%s" % (load_file_aid, security_domain_aid))
+            self._cmd.poutput("step #2: load...")
+            self.load(h2b(load_file))
+            self._cmd.poutput("step #3: install_for_install (and make 
selectable)...")
+            self.do_install_for_install("--load-file-aid %s --module-aid %s 
--application-aid %s --install-parameters %s --make-selectable" %
+                                        (load_file_aid, module_aid, 
application_aid, install_parameters))
+            self._cmd.poutput("done.")
+
         est_scp02_parser = argparse.ArgumentParser()
         est_scp02_parser.add_argument('--key-ver', type=auto_uint8, 
required=True, help='Key Version Number (KVN)')
         est_scp02_parser.add_argument('--host-challenge', type=is_hexstr,
diff --git a/pySim/global_platform/install_param.py 
b/pySim/global_platform/install_param.py
new file mode 100644
index 0000000..0d1dfdb
--- /dev/null
+++ b/pySim/global_platform/install_param.py
@@ -0,0 +1,74 @@
+# GlobalPlatform install parameter generator
+#
+# (C) 2024 by Sysmocom s.f.m.c. GmbH
+# All Rights Reserved
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from construct import Optional as COptional
+from construct import Struct, GreedyRange, FlagsEnum, Int16ub, Int32ub, 
Padding, Bit, Const
+from osmocom.construct import *
+from osmocom.utils import *
+from osmocom.tlv import *
+
+class AppSpecificParams(BER_TLV_IE, tag=0xC9):
+    # GPD_SPE_013, table 11-49
+    _construct = HexAdapter(GreedyBytes)
+
+class VolatileMemoryQuota(BER_TLV_IE, tag=0xC7):
+    # GPD_SPE_013, table 11-49
+    _construct = StripTrailerAdapter(GreedyBytes, 4, steps = [2,4], reverse = 
True)
+
+class NonVolatileMemoryQuota(BER_TLV_IE, tag=0xC8):
+    # GPD_SPE_013, table 11-49
+    _construct = StripTrailerAdapter(GreedyBytes, 4, steps = [2,4], reverse = 
True)
+
+class StkParameter(BER_TLV_IE, tag=0xCA):
+    # GPD_SPE_013, table 11-49
+    # ETSI TS 102 226, section 8.2.1.3.2.1
+    _construct = HexAdapter(GreedyBytes)
+
+class SystemSpecificParams(BER_TLV_IE, tag=0xEF, nested=[VolatileMemoryQuota, 
NonVolatileMemoryQuota, StkParameter]):
+    # GPD_SPE_013 v1.1 Table 6-5
+    pass
+
+class InstallParams(TLV_IE_Collection, nested=[AppSpecificParams, 
SystemSpecificParams]):
+    # GPD_SPE_013, table 11-49
+    pass
+
+def gen_install_parameters(non_volatile_memory_quota:int, 
volatile_memory_quota:int, stk_parameter:str):
+
+    # GPD_SPE_013, table 11-49
+
+    #Mandatory
+    install_params = InstallParams()
+    install_params_dict = [{'app_specific_params': None}]
+
+    #Conditional
+    if non_volatile_memory_quota and volatile_memory_quota and stk_parameter:
+        system_specific_params = []
+        #Optional
+        if non_volatile_memory_quota:
+            system_specific_params += [{'non_volatile_memory_quota': 
non_volatile_memory_quota}]
+        #Optional
+        if volatile_memory_quota:
+            system_specific_params += [{'volatile_memory_quota': 
volatile_memory_quota}]
+        #Optional
+        if stk_parameter:
+            system_specific_params += [{'stk_parameter': stk_parameter}]
+        install_params_dict += [{'system_specific_params': 
system_specific_params}]
+
+    install_params.from_dict(install_params_dict)
+    return b2h(install_params.to_bytes())
diff --git a/tests/unittests/test_globalplatform.py 
b/tests/unittests/test_globalplatform.py
index 597d51d..3c533d5 100644
--- a/tests/unittests/test_globalplatform.py
+++ b/tests/unittests/test_globalplatform.py
@@ -21,6 +21,7 @@

 from pySim.global_platform import *
 from pySim.global_platform.scp import *
+from pySim.global_platform.install_param import *

 KIC = h2b('100102030405060708090a0b0c0d0e0f') # enc
 KID = h2b('101102030405060708090a0b0c0d0e0f') # MAC
@@ -289,5 +290,13 @@
         self.assertEqual(compute_kcv('aes', KEYSET_AES128.dek), h2b('840DE5'))


+class Install_param_Test(unittest.TestCase):
+    def test_gen_install_parameters(self):
+        load_parameters = gen_install_parameters(256, 256, 
'010001001505000000000000000000000000')
+        self.assertEqual(load_parameters, 
'c900ef1cc8020100c7020100ca12010001001505000000000000000000000000')
+
+        load_parameters = gen_install_parameters(None, None, '')
+        self.assertEqual(load_parameters, 'c900')
+
 if __name__ == "__main__":
        unittest.main()

--
To view, visit https://gerrit.osmocom.org/c/pysim/+/39199?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I6cbd37f0fad5579b20e83c27349bd5acc129e6d0
Gerrit-Change-Number: 39199
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <[email protected]>

Reply via email to