mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-27 15:58:34 +03:00
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
This commit is contained in:
@@ -959,6 +959,16 @@ put_key
|
|||||||
:module: pySim.global_platform
|
:module: pySim.global_platform
|
||||||
:func: ADF_SD.AddlShellCommands.put_key_parser
|
: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
|
eUICC ISD-R commands
|
||||||
--------------------
|
--------------------
|
||||||
|
|||||||
@@ -205,7 +205,11 @@ Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/
|
|||||||
def update_prompt(self):
|
def update_prompt(self):
|
||||||
if self.lchan:
|
if self.lchan:
|
||||||
path_str = self.lchan.selected_file.fully_qualified_path_str(not self.numeric_path)
|
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:
|
else:
|
||||||
if self.card:
|
if self.card:
|
||||||
self.prompt = 'pySIM-shell (no card profile)> '
|
self.prompt = 'pySIM-shell (no card profile)> '
|
||||||
@@ -258,6 +262,8 @@ Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/
|
|||||||
def do_reset(self, opts):
|
def do_reset(self, opts):
|
||||||
"""Reset the Card."""
|
"""Reset the Card."""
|
||||||
atr = self.card.reset()
|
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.poutput('Card ATR: %s' % i2h(atr))
|
||||||
self.update_prompt()
|
self.update_prompt()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
"""Partial Support for GlobalPLatform Card Spec (currently 2.1.1)
|
"""Partial Support for GlobalPLatform Card Spec (currently 2.1.1)
|
||||||
|
|
||||||
(C) 2022-2023 by Harald Welte <laforge@osmocom.org>
|
(C) 2022-2024 by Harald Welte <laforge@osmocom.org>
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,6 +21,8 @@ from typing import Optional, List, Dict, Tuple
|
|||||||
from construct import Optional as COptional
|
from construct import Optional as COptional
|
||||||
from construct import *
|
from construct import *
|
||||||
from bidict import bidict
|
from bidict import bidict
|
||||||
|
from Cryptodome.Random import get_random_bytes
|
||||||
|
from pySim.global_platform.scp02 import SCP02
|
||||||
from pySim.construct import *
|
from pySim.construct import *
|
||||||
from pySim.utils import *
|
from pySim.utils import *
|
||||||
from pySim.filesystem import *
|
from pySim.filesystem import *
|
||||||
@@ -582,6 +584,48 @@ class ADF_SD(CardADF):
|
|||||||
p2 |= 0x01
|
p2 |= 0x01
|
||||||
return grd_list
|
return grd_list
|
||||||
|
|
||||||
|
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('--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_uint8, 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. It can be released
|
||||||
|
again by using `release_scp`."""
|
||||||
|
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_release_scp(self, opts):
|
||||||
|
"""Release a previously establiehed 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
|
# Card Application of a Security Domain
|
||||||
class CardApplicationSD(CardApplication):
|
class CardApplicationSD(CardApplication):
|
||||||
|
|||||||
@@ -108,6 +108,13 @@ class SCP02(SCP):
|
|||||||
self.card_keys = card_keys
|
self.card_keys = card_keys
|
||||||
self.sk = None
|
self.sk = None
|
||||||
self.mac_on_unmodified = False
|
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:
|
def _cla(self, sm: bool = False, b8: bool = True) -> int:
|
||||||
ret = 0x80 if b8 else 0x00
|
ret = 0x80 if b8 else 0x00
|
||||||
|
|||||||
Reference in New Issue
Block a user