mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-16 18:38:32 +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
|
||||
: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
|
||||
--------------------
|
||||
|
||||
@@ -205,7 +205,11 @@ Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/
|
||||
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 @@ Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/
|
||||
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()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# coding=utf-8
|
||||
"""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
|
||||
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 *
|
||||
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,48 @@ class ADF_SD(CardADF):
|
||||
p2 |= 0x01
|
||||
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
|
||||
class CardApplicationSD(CardApplication):
|
||||
|
||||
@@ -108,6 +108,13 @@ class SCP02(SCP):
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user