laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/35764?usp=email )
Change subject: Add global_platform shell command establish_scp02 and release_scp ...................................................................... Add global_platform shell command establish_scp02 and release_scp Those commands can be used to establish and release a SCP02 secure channel on the currently active logical channel. The prompt is adjusted with a 'SCP02' prefix while the secure channel is established. Change-Id: Ib2f3c8f0563f81a941dd55b97c9836e3a6856407 --- M docs/shell.rst M pySim-shell.py M pySim/global_platform/__init__.py M pySim/global_platform/scp02.py 4 files changed, 83 insertions(+), 2 deletions(-) git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/64/35764/1 diff --git a/docs/shell.rst b/docs/shell.rst index a917f8f..dff6cd1 100644 --- a/docs/shell.rst +++ b/docs/shell.rst @@ -959,6 +959,16 @@ :module: pySim.global_platform :func: ADF_SD.AddlShellCommands.put_key_parser +establish_scp02 +~~~~~~~~~~~~~~~ +.. argparse:: + :module: pySim.global_platform + :func: ADF_SD.AddlShellCommands.est_scp02_parser + +release_scp +~~~~~~~~~~~ +Release any previously established SCP (Secure Channel Protocol) + eUICC ISD-R commands -------------------- diff --git a/pySim-shell.py b/pySim-shell.py index 70eaee2..abe0b5f 100755 --- a/pySim-shell.py +++ b/pySim-shell.py @@ -205,7 +205,11 @@ def update_prompt(self): if self.lchan: path_str = self.lchan.selected_file.fully_qualified_path_str(not self.numeric_path) - self.prompt = 'pySIM-shell (%02u:%s)> ' % (self.lchan.lchan_nr, path_str) + scp = self.lchan.scc.scp + if scp: + self.prompt = 'pySIM-shell (%s:%02u:%s)> ' % (str(scp), self.lchan.lchan_nr, path_str) + else: + self.prompt = 'pySIM-shell (%02u:%s)> ' % (self.lchan.lchan_nr, path_str) else: if self.card: self.prompt = 'pySIM-shell (no card profile)> ' @@ -258,6 +262,8 @@ def do_reset(self, opts): """Reset the Card.""" atr = self.card.reset() + if self.lchan and self.lchan.scc.scp: + self.lchan.scc.scp = None self.poutput('Card ATR: %s' % i2h(atr)) self.update_prompt() diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py index 385d438..44a24df 100644 --- a/pySim/global_platform/__init__.py +++ b/pySim/global_platform/__init__.py @@ -1,7 +1,7 @@ # coding=utf-8 """Partial Support for GlobalPLatform Card Spec (currently 2.1.1) -(C) 2022-2023 by Harald Welte <lafo...@osmocom.org> +(C) 2022-2024 by Harald Welte <lafo...@osmocom.org> 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 @@ -21,6 +21,8 @@ from construct import Optional as COptional from construct import * from bidict import bidict +from Cryptodome.Random import get_random_bytes +from pySim.global_platform.scp02 import SCP02 from pySim.construct import * from pySim.utils import * from pySim.filesystem import * @@ -582,6 +584,47 @@ p2 |= 0x01 return grd_list + est_scp02_parser = argparse.ArgumentParser() + est_scp02_parser.add_argument('--key-ver', type=auto_int, required=True, + help='Key Version Number (KVN)') + est_scp02_parser.add_argument('--key-enc', type=is_hexstr, required=True, + help='Secure Channel Encryption Key') + est_scp02_parser.add_argument('--key-mac', type=is_hexstr, required=True, + help='Secure Channel MAC Key') + est_scp02_parser.add_argument('--key-dek', type=is_hexstr, required=True, + help='Data Encryption Key') + est_scp02_parser.add_argument('--host-challenge', type=is_hexstr, + help='Hard-code the host challenge; default: random') + est_scp02_parser.add_argument('--security-level', type=auto_int, default=0x01, + help='Security Level. Default: 0x01 (C-MAC only)') + + @cmd2.with_argparser(est_scp02_parser) + def do_establish_scp02(self, opts): + """Establish a secure channel using the GlobalPlatform SCP02 protocol.""" + if self._cmd.lchan.scc.scp: + self._cmd.poutput("Cannot establish SCP02 as this lchan already has a SCP instance!") + return + host_challenge = h2b(opts.host_challenge) if opts.host_challenge else get_random_bytes(8) + kset = GpCardKeyset(opts.key_ver, h2b(opts.key_enc), h2b(opts.key_mac), h2b(opts.key_dek)) + scp02 = SCP02(card_keys=kset) + init_update_apdu = scp02.gen_init_update_apdu(host_challenge=host_challenge) + init_update_resp, sw = self._cmd.lchan.scc.send_apdu_checksw(b2h(init_update_apdu)) + scp02.parse_init_update_resp(h2b(init_update_resp)) + ext_auth_apdu = scp02.gen_ext_auth_apdu(opts.security_level) + ext_auth_resp, sw = self._cmd.lchan.scc.send_apdu_checksw(b2h(ext_auth_apdu)) + self._cmd.poutput("Successfully established a SCP02 secure channel") + # store a reference to the SCP instance + self._cmd.lchan.scc.scp = scp02 + self._cmd.update_prompt() + + def do_relase_scp(self, opts): + """Release a secure channel.""" + if not self._cmd.lchan.scc.scp: + self._cmd.poutput("Cannot release SCP as none is established") + return + self._cmd.lchan.scc.scp = None + self._cmd.update_prompt() + # Card Application of a Security Domain class CardApplicationSD(CardApplication): diff --git a/pySim/global_platform/scp02.py b/pySim/global_platform/scp02.py index 29c0021..a2a032e 100644 --- a/pySim/global_platform/scp02.py +++ b/pySim/global_platform/scp02.py @@ -107,6 +107,13 @@ self.card_keys = card_keys self.sk = None self.mac_on_unmodified = False + self.security_level = None + + def __str__(self) -> str: + if self.security_level: + return "%s[%02x]" % (self.__class__.__name__, self.security_level) + else: + return "%s[??]" % (self.__class__.__name__) def _cla(self, sm: bool = False, b8: bool = True) -> int: ret = 0x80 if b8 else 0x00 -- To view, visit https://gerrit.osmocom.org/c/pysim/+/35764?usp=email To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: pysim Gerrit-Branch: master Gerrit-Change-Id: Ib2f3c8f0563f81a941dd55b97c9836e3a6856407 Gerrit-Change-Number: 35764 Gerrit-PatchSet: 1 Gerrit-Owner: laforge <lafo...@osmocom.org> Gerrit-MessageType: newchange