laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/36930?usp=email )
Change subject: CardKeyProvider: Implement support for column-based transport key encryption
......................................................................
CardKeyProvider: Implement support for column-based transport key encryption
It's generally a bad idea to keep [card specific] key material lying
around unencrypted in CSV files. The industry standard solution in the
GSMA is a so-called "transport key", which encrypts the key material.
Let's introduce support for this in the CardKeyProvider (and
specifically, the CardKeyProviderCSV) and allow the user to specify
transport key material as command line options to pySim-shell.
Different transport keys can be used for different key materials, so
allow specification of keys on a CSV-column base.
The higher-level goal is to allow the CSV file not only to store
the ADM keys (like now), but also global platform key material for
establishing SCP towards various security domains in a given card.
Change-Id: I13146a799448d03c681dc868aaa31eb78b7821ff
---
A contrib/csv-encrypt-columns.py
M docs/card-key-provider.rst
M pySim-shell.py
M pySim/card_key_provider.py
4 files changed, 192 insertions(+), 15 deletions(-)
Approvals:
fixeria: Looks good to me, but someone else must approve
Jenkins Builder: Verified
osmith: Looks good to me, approved
diff --git a/contrib/csv-encrypt-columns.py b/contrib/csv-encrypt-columns.py
new file mode 100755
index 0000000..2b2bbf3
--- /dev/null
+++ b/contrib/csv-encrypt-columns.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+
+# Utility program to perform column-based encryption of a CSV file holding SIM/UICC
+# related key materials.
+#
+# (C) 2024 by Harald Welte <laforge(a)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
+# 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/>.
+
+import sys
+import csv
+import argparse
+from Cryptodome.Cipher import AES
+
+from pySim.utils import h2b, b2h, Hexstr
+from pySim.card_key_provider import CardKeyProviderCsv
+
+def dict_keys_to_upper(d: dict) -> dict:
+ return {k.upper():v for k,v in d.items()}
+
+class CsvColumnEncryptor:
+ def __init__(self, filename: str, transport_keys: dict):
+ self.filename = filename
+ self.transport_keys = dict_keys_to_upper(transport_keys)
+
+ def encrypt_col(self, colname:str, value: str) -> Hexstr:
+ key = self.transport_keys[colname]
+ cipher = AES.new(h2b(key), AES.MODE_CBC, CardKeyProviderCsv.IV)
+ return b2h(cipher.encrypt(h2b(value)))
+
+ def encrypt(self) -> None:
+ with open(self.filename, 'r') as infile:
+ cr = csv.DictReader(infile)
+ cr.fieldnames = [field.upper() for field in cr.fieldnames]
+
+ with open(self.filename + '.encr', 'w') as outfile:
+ cw = csv.DictWriter(outfile, dialect=csv.unix_dialect, fieldnames=cr.fieldnames)
+ cw.writeheader()
+
+ for row in cr:
+ for key_colname in self.transport_keys:
+ if key_colname in row:
+ row[key_colname] = self.encrypt_col(key_colname, row[key_colname])
+ cw.writerow(row)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('CSVFILE', help="CSV file name")
+ parser.add_argument('--csv-column-key', action='append', required=True,
+ help='per-CSV-column AES transport key')
+
+ opts = parser.parse_args()
+
+ csv_column_keys = {}
+ for par in opts.csv_column_key:
+ name, key = par.split(':')
+ csv_column_keys[name] = key
+
+ if len(csv_column_keys) == 0:
+ print("You must specify at least one key!")
+ sys.exit(1)
+
+ csv_column_keys = CardKeyProviderCsv.process_transport_keys(csv_column_keys)
+ for name, key in csv_column_keys.items():
+ print("Encrypting column %s using AES key %s" % (name, key))
+
+ cce = CsvColumnEncryptor(opts.CSVFILE, csv_column_keys)
+ cce.encrypt()
diff --git a/docs/card-key-provider.rst b/docs/card-key-provider.rst
index 82f2d65..7b4bf2c 100644
--- a/docs/card-key-provider.rst
+++ b/docs/card-key-provider.rst
@@ -41,6 +41,38 @@
open a CSV file from the default location at
`~/.osmocom/pysim/card_data.csv`, and use that, if it exists.
+Column-Level CSV encryption
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+pySim supports column-level CSV encryption. This feature will make sure
+that your key material is not stored in plaintext in the CSV file.
+
+The encryption mechanism uses AES in CBC mode. You can use any key
+length permitted by AES (128/192/256 bit).
+
+Following GSMA FS.28, the encryption works on column level. This means
+different columns can be decrypted using different key material. This
+means that leakage of a column encryption key for one column or set of
+columns (like a specific security domain) does not compromise various
+other keys that might be stored in other columns.
+
+You can specify column-level decryption keys using the
+`--csv-column-key` command line argument. The syntax is
+`FIELD:AES_KEY_HEX`, for example:
+
+`pySim-shell.py --csv-column-key SCP03_ENC_ISDR:000102030405060708090a0b0c0d0e0f`
+
+In order to avoid having to repeat the column key for each and every
+column of a group of keys within a keyset, there are pre-defined column
+group aliases, which will make sure that the specified key will be used
+by all columns of the set:
+
+* `UICC_SCP02` is a group alias for `UICC_SCP02_KIC1`, `UICC_SCP02_KID1`, `UICC_SCP02_KIK1`
+* `UICC_SCP03` is a group alias for `UICC_SCP03_KIC1`, `UICC_SCP03_KID1`, `UICC_SCP03_KIK1`
+* `SCP03_ECASD` is a group alias for `SCP03_ENC_ECASD`, `SCP03_MAC_ECASD`, `SCP03_DEK_ECASD`
+* `SCP03_ISDA` is a group alias for `SCP03_ENC_ISDA`, `SCP03_MAC_ISDA`, `SCP03_DEK_ISDA`
+* `SCP03_ISDR` is a group alias for `SCP03_ENC_ISDR`, `SCP03_MAC_ISDR`, `SCP03_DEK_ISDR`
+
Field naming
------------
diff --git a/pySim-shell.py b/pySim-shell.py
index 26f3d9b..7523ca2 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -967,6 +967,8 @@
help='script with pySim-shell commands to be executed automatically at start-up')
global_group.add_argument('--csv', metavar='FILE',
default=None, help='Read card data from CSV file')
+global_group.add_argument('--csv-column-key', metavar='FIELD:AES_KEY_HEX', default=[], action='append',
+ help='per-CSV-column AES transport key')
global_group.add_argument("--card_handler", dest="card_handler_config", metavar="FILE",
help="Use automatic card handling machine")
@@ -993,13 +995,18 @@
print("Invalid script file!")
sys.exit(2)
+ csv_column_keys = {}
+ for par in opts.csv_column_key:
+ name, key = par.split(':')
+ csv_column_keys[name] = key
+
# Register csv-file as card data provider, either from specified CSV
# or from CSV file in home directory
csv_default = str(Path.home()) + "/.osmocom/pysim/card_data.csv"
if opts.csv:
- card_key_provider_register(CardKeyProviderCsv(opts.csv))
+ card_key_provider_register(CardKeyProviderCsv(opts.csv, csv_column_keys))
if os.path.isfile(csv_default):
- card_key_provider_register(CardKeyProviderCsv(csv_default))
+ card_key_provider_register(CardKeyProviderCsv(csv_default, csv_column_keys))
# Init card reader driver
sl = init_reader(opts, proactive_handler = Proact())
diff --git a/pySim/card_key_provider.py b/pySim/card_key_provider.py
index 33a2a3d..6751b09 100644
--- a/pySim/card_key_provider.py
+++ b/pySim/card_key_provider.py
@@ -10,10 +10,10 @@
operation with pySim-shell.
"""
-# (C) 2021 by Sysmocom s.f.m.c. GmbH
+# (C) 2021-2024 by Sysmocom s.f.m.c. GmbH
# All Rights Reserved
#
-# Author: Philipp Maier
+# Author: Philipp Maier, Harald Welte
#
# 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
@@ -29,18 +29,29 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from typing import List, Dict, Optional
+from Cryptodome.Cipher import AES
+from pySim.utils import h2b, b2h
import abc
import csv
card_key_providers = [] # type: List['CardKeyProvider']
+# well-known groups of columns relate to a given functionality. This avoids having
+# to specify the same transport key N number of times, if the same key is used for multiple
+# fields of one group, like KIC+KID+KID of one SD.
+CRYPT_GROUPS = {
+ 'UICC_SCP02': ['UICC_SCP02_KIC1', 'UICC_SCP02_KID1', 'UICC_SCP02_KIK1'],
+ 'UICC_SCP03': ['UICC_SCP03_KIC1', 'UICC_SCP03_KID1', 'UICC_SCP03_KIK1'],
+ 'SCP03_ISDR': ['SCP03_ENC_ISDR', 'SCP03_MAC_ISDR', 'SCP03_DEK_ISDR'],
+ 'SCP03_ISDA': ['SCP03_ENC_ISDR', 'SCP03_MAC_ISDA', 'SCP03_DEK_ISDA'],
+ 'SCP03_ECASD': ['SCP03_ENC_ECASD', 'SCP03_MAC_ECASD', 'SCP03_DEK_ECASD'],
+ }
class CardKeyProvider(abc.ABC):
"""Base class, not containing any concrete implementation."""
- VALID_FIELD_NAMES = ['ICCID', 'ADM1',
- 'IMSI', 'PIN1', 'PIN2', 'PUK1', 'PUK2']
+ VALID_KEY_FIELD_NAMES = ['ICCID', 'EID', 'IMSI' ]
# check input parameters, but do nothing concrete yet
def _verify_get_data(self, fields: List[str] = [], key: str = 'ICCID', value: str = "") -> Dict[str, str]:
@@ -53,14 +64,10 @@
Returns:
dictionary of {field, value} strings for each requested field from 'fields'
"""
- for f in fields:
- if f not in self.VALID_FIELD_NAMES:
- raise ValueError("Requested field name '%s' is not a valid field name, valid field names are: %s" %
- (f, str(self.VALID_FIELD_NAMES)))
- if key not in self.VALID_FIELD_NAMES:
+ if key not in self.VALID_KEY_FIELD_NAMES:
raise ValueError("Key field name '%s' is not a valid field name, valid field names are: %s" %
- (key, str(self.VALID_FIELD_NAMES)))
+ (key, str(self.VALID_KEY_FIELD_NAMES)))
return {}
@@ -84,19 +91,47 @@
class CardKeyProviderCsv(CardKeyProvider):
- """Card key provider implementation that allows to query against a specified CSV file"""
+ """Card key provider implementation that allows to query against a specified CSV file.
+ Supports column-based encryption as it is generally a bad idea to store cryptographic key material in
+ plaintext. Instead, the key material should be encrypted by a "key-encryption key", occasionally also
+ known as "transport key" (see GSMA FS.28)."""
+ IV = b'\x23' * 16
csv_file = None
filename = None
- def __init__(self, filename: str):
+ def __init__(self, filename: str, transport_keys: dict):
"""
Args:
filename : file name (path) of CSV file containing card-individual key/data
+ transport_keys : a dict indexed by field name, whose values are hex-encoded AES keys for the
+ respective field (column) of the CSV. This is done so that different fields
+ (columns) can use different transport keys, which is strongly recommended by
+ GSMA FS.28
"""
self.csv_file = open(filename, 'r')
if not self.csv_file:
raise RuntimeError("Could not open CSV file '%s'" % filename)
self.filename = filename
+ self.transport_keys = self.process_transport_keys(transport_keys)
+
+ @staticmethod
+ def process_transport_keys(transport_keys: dict):
+ """Apply a single transport key to multiple fields/columns, if the name is a group."""
+ new_dict = {}
+ for name, key in transport_keys.items():
+ if name in CRYPT_GROUPS:
+ for field in CRYPT_GROUPS[name]:
+ new_dict[field] = key
+ else:
+ new_dict[name] = key
+ return new_dict
+
+ def _decrypt_field(self, field_name: str, encrypted_val: str) -> str:
+ """decrypt a single field, if we have a transport key for the field of that name."""
+ if not field_name in self.transport_keys:
+ return encrypted_val
+ cipher = AES.new(h2b(self.transport_keys[field_name]), AES.MODE_CBC, self.IV)
+ return b2h(cipher.decrypt(h2b(encrypted_val)))
def get(self, fields: List[str], key: str, value: str) -> Dict[str, str]:
super()._verify_get_data(fields, key, value)
@@ -113,7 +148,7 @@
if row[key] == value:
for f in fields:
if f in row:
- rc.update({f: row[f]})
+ rc.update({f: self._decrypt_field(f, row[f])})
else:
raise RuntimeError("CSV-File '%s' lacks column '%s'" %
(self.filename, f))
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/36930?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: I13146a799448d03c681dc868aaa31eb78b7821ff
Gerrit-Change-Number: 36930
Gerrit-PatchSet: 6
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-MessageType: merged
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/36931?usp=email )
(
5 is the latest approved patch-set.
No files were changed between the latest approved patch-set and the submitted one.
)Change subject: global_platform/euicc: Implement obtaining SCP keys from CardKeyProvider
......................................................................
global_platform/euicc: Implement obtaining SCP keys from CardKeyProvider
Now that CardKeyProvider is capable of storing key materials
transport-key-encrypted, we can use this functionality to look up the
SCP02 / SCP03 key material for a given security domain.
This patch implements this for the ISD-R and ECASD using a look-up by
EID inside the CSV.
Change-Id: I2a21f031ab8af88019af1b8390612678b9b35880
---
M pySim/euicc.py
M pySim/global_platform/__init__.py
2 files changed, 53 insertions(+), 8 deletions(-)
Approvals:
osmith: Looks good to me, but someone else must approve
fixeria: Looks good to me, but someone else must approve
Jenkins Builder: Verified
laforge: Looks good to me, approved
diff --git a/pySim/euicc.py b/pySim/euicc.py
index a771a22..ddfe939 100644
--- a/pySim/euicc.py
+++ b/pySim/euicc.py
@@ -315,6 +315,8 @@
desc='ISD-R (Issuer Security Domain Root) Application')
self.adf.decode_select_response = self.decode_select_response
self.adf.shell_commands += [self.AddlShellCommands()]
+ # we attempt to retrieve ISD-R key material from CardKeyProvider identified by EID
+ self.adf.scp_key_identity = 'EID'
@staticmethod
def store_data(scc: SimCardCommands, tx_do: Hexstr, exp_sw: SwMatchstr ="9000") -> Tuple[Hexstr, SwHexstr]:
@@ -539,6 +541,8 @@
desc='ECASD (eUICC Controlling Authority Security Domain) Application')
self.adf.decode_select_response = self.decode_select_response
self.adf.shell_commands += [self.AddlShellCommands()]
+ # we attempt to retrieve ECASD key material from CardKeyProvider identified by EID
+ self.adf.scp_key_identity = 'EID'
@with_default_category('Application-Specific Commands')
class AddlShellCommands(CommandSet):
diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py
index f440fd0..0be316b 100644
--- a/pySim/global_platform/__init__.py
+++ b/pySim/global_platform/__init__.py
@@ -23,6 +23,7 @@
from construct import Struct, GreedyRange, FlagsEnum, Int16ub, Int24ub, Padding, Bit, Const
from Cryptodome.Random import get_random_bytes
from Cryptodome.Cipher import DES, DES3, AES
+from pySim.card_key_provider import card_key_provider_get_field
from pySim.global_platform.scp import SCP02, SCP03
from pySim.construct import *
from pySim.utils import *
@@ -719,23 +720,33 @@
return self._cmd.lchan.scc.send_apdu_checksw(cmd_hex)
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('--key-ver', type=auto_uint8, required=True, help='Key Version Number (KVN)')
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)')
+ est_scp02_p_k = est_scp02_parser.add_argument_group('Manual key specification')
+ est_scp02_p_k.add_argument('--key-enc', type=is_hexstr, help='Secure Channel Encryption Key')
+ est_scp02_p_k.add_argument('--key-mac', type=is_hexstr, help='Secure Channel MAC Key')
+ est_scp02_p_k.add_argument('--key-dek', type=is_hexstr, help='Data Encryption Key')
+ est_scp02_p_csv = est_scp02_parser.add_argument_group('Obtain keys from CardKeyProvider (e.g. CSV')
+ est_scp02_p_csv.add_argument('--key-provider-suffix', help='Suffix for key names in CardKeyProvider')
@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 opts.key_provider_suffix:
+ suffix = opts.key_provider_suffix
+ id_field_name = self._cmd.lchan.selected_adf.scp_key_identity
+ identity = self._cmd.rs.identity.get(id_field_name)
+ opts.key_enc = card_key_provider_get_field('SCP02_ENC_' + suffix, key=id_field_name, value=identity)
+ opts.key_mac = card_key_provider_get_field('SCP02_MAC_' + suffix, key=id_field_name, value=identity)
+ opts.key_dek = card_key_provider_get_field('SCP02_DEK_' + suffix, key=id_field_name, value=identity)
+ else:
+ if not opts.key_enc or not opts.key_mac:
+ self._cmd.poutput("Cannot establish SCP02 without at least ENC and MAC keys given!")
+ return
if self._cmd.lchan.scc.scp:
self._cmd.poutput("Cannot establish SCP02 as this lchan already has a SCP instance!")
return
@@ -751,6 +762,17 @@
def do_establish_scp03(self, opts):
"""Establish a secure channel using the GlobalPlatform SCP03 protocol. It can be released
again by using `release_scp`."""
+ if opts.key_provider_suffix:
+ suffix = opts.key_provider_suffix
+ id_field_name = self._cmd.lchan.selected_adf.scp_key_identity
+ identity = self._cmd.rs.identity.get(id_field_name)
+ opts.key_enc = card_key_provider_get_field('SCP03_ENC_' + suffix, key=id_field_name, value=identity)
+ opts.key_mac = card_key_provider_get_field('SCP03_MAC_' + suffix, key=id_field_name, value=identity)
+ opts.key_dek = card_key_provider_get_field('SCP03_DEK_' + suffix, key=id_field_name, value=identity)
+ else:
+ if not opts.key_enc or not opts.key_mac:
+ self._cmd.poutput("Cannot establish SCP03 without at least ENC and MAC keys given!")
+ return
if self._cmd.lchan.scc.scp:
self._cmd.poutput("Cannot establish SCP03 as this lchan already has a SCP instance!")
return
@@ -787,6 +809,9 @@
__intermediate = True
def __init__(self, aid: str, name: str, desc: str):
super().__init__(name, adf=ADF_SD(aid, name, desc), sw=sw_table)
+ # the identity (e.g. 'ICCID', 'EID') that should be used as a look-up key to attempt to retrieve
+ # the key material for the security domain from the CardKeyProvider
+ self.adf.scp_key_identity = None
# Card Application of Issuer Security Domain
class CardApplicationISD(CardApplicationSD):
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/36931?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: I2a21f031ab8af88019af1b8390612678b9b35880
Gerrit-Change-Number: 36931
Gerrit-PatchSet: 7
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-MessageType: merged
laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/36962?usp=email )
Change subject: document the CardKeyProvider
......................................................................
document the CardKeyProvider
Change-Id: Ie6fc24695dd956a4f9fd6f243d3b0ef66acf877b
---
A docs/card-key-provider.rst
M docs/shell.rst
2 files changed, 112 insertions(+), 0 deletions(-)
Approvals:
fixeria: Looks good to me, but someone else must approve
osmith: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/docs/card-key-provider.rst b/docs/card-key-provider.rst
new file mode 100644
index 0000000..82f2d65
--- /dev/null
+++ b/docs/card-key-provider.rst
@@ -0,0 +1,94 @@
+
+Retrieving card-individual keys via CardKeyProvider
+==================================================
+
+When working with a batch of cards, or more than one card in general, it
+is a lot of effort to manually retrieve the card-specific PIN (like
+ADM1) or key material (like SCP02/SCP03 keys).
+
+To increase productivity in that regard, pySim has a concept called the
+`CardKeyProvider`. This is a generic mechanism by which different parts
+of the pySim[-shell] code can programmatically request card-specific key material
+from some data source (*provider*).
+
+For example, when you want to verify the ADM1 PIN using the `verify_adm`
+command without providing an ADM1 value yourself, pySim-shell will
+request the ADM1 value for the ICCID of the card via the
+CardKeyProvider.
+
+There can in theory be multiple different CardKeyProviders. You can for
+example develop your own CardKeyProvider that queries some kind of
+database for the key material, or that uses a key derivation function to
+derive card-specific key material from a global master key.
+
+The only actual CardKeyProvider implementation included in pySim is the
+`CardKeyProviderCsv` which retrieves the key material from a
+[potentially encrypted] CSV file.
+
+
+The CardKeyProviderCsv
+----------------------
+
+The `CardKeyProviderCsv` allows you to retrieve card-individual key
+material from a CSV (comma separated value) file that is accessible to pySim.
+
+The CSV file must have the expected column names, for example `ICCID`
+and `ADM1` in case you would like to use that CSV to obtain the
+card-specific ADM1 PIN when using the `verify_adm` command.
+
+You can specify the CSV file to use via the `--csv` command-line option
+of pySim-shell. If you do not specify a CSV file, pySim will attempt to
+open a CSV file from the default location at
+`~/.osmocom/pysim/card_data.csv`, and use that, if it exists.
+
+
+Field naming
+------------
+
+* For look-up of UICC/SIM/USIM/ISIM or eSIM profile specific key
+ material, pySim uses the `ICCID` field as lookup key.
+
+* For look-up of eUICC specific key material (like SCP03 keys for the
+ ISD-R, ECASD), pySim uses the `EID` field as lookup key.
+
+As soon as the CardKeyProviderCsv finds a line (row) in your CSV where
+the ICCID or EID match, it looks for the column containing the requested
+data.
+
+
+ADM PIN
+~~~~~~~
+
+The `verify_adm` command will attempt to look up the `ADM1` column
+indexed by the ICCID of the SIM/UICC.
+
+
+SCP02 / SCP03
+~~~~~~~~~~~~~
+
+SCP02 and SCP03 each use key triplets consisting if ENC, MAC and DEK
+keys. For more details, see the applicable GlobalPlatform
+specifications.
+
+If you do not want to manually enter the key material for each specific
+card as arguments to the `establish_scp02` or `establish_scp03`
+commands, you can make use of the `--key-provider-suffix` option. pySim
+uses this suffix to compose the column names for the CardKeyProvider as
+follows.
+
+* `SCP02_ENC_` + suffix for the SCP02 ciphering key
+* `SCP02_MAC_` + suffix for the SCP02 MAC key
+* `SCP02_DEK_` + suffix for the SCP02 DEK key
+* `SCP03_ENC_` + suffix for the SCP03 ciphering key
+* `SCP03_MAC_` + suffix for the SCP03 MAC key
+* `SCP03_DEK_` + suffix for the SCP03 DEK key
+
+So for example, if you are using a command like `establish_scp03
+--key-provider-suffix ISDR`, then the column names for the key material
+look-up are `SCP03_ENC_ISDR`, `SCP03_MAC_ISDR` and `SCP03_DEK_ISDR`,
+respectively.
+
+The identifier used for look-up is determined by the definition of the
+Security Domain. For example, the eUICC ISD-R and ECASD will use the EID
+of the eUICC. On the other hand, the ISD-P of an eSIM or the ISD of an
+UICC will use the ICCID.
diff --git a/docs/shell.rst b/docs/shell.rst
index 084858c..111c502 100644
--- a/docs/shell.rst
+++ b/docs/shell.rst
@@ -69,6 +69,15 @@
suci-tutorial
+Advanced Topics
+---------------
+.. toctree::
+ :maxdepth: 1
+ :caption: Advanced pySIM-shell topics
+
+ card-key-provider
+
+
cmd2 basics
-----------
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/36962?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: Ie6fc24695dd956a4f9fd6f243d3b0ef66acf877b
Gerrit-Change-Number: 36962
Gerrit-PatchSet: 4
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-MessageType: merged
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-uecups/+/37032?usp=email )
Change subject: README.md: cosmetic: fix a typo
......................................................................
README.md: cosmetic: fix a typo
Change-Id: I8b7e80f3227404df5433acc44ebd6e03703248ac
---
M README.md
1 file changed, 10 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-uecups refs/changes/32/37032/1
diff --git a/README.md b/README.md
index d7dfa10..5025bc0 100644
--- a/README.md
+++ b/README.md
@@ -137,7 +137,7 @@
Our coding standards are described at
https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards
-We us a gerrit based patch submission/review process for managing
+We use a Gerrit based patch submission/review process for managing
contributions. Please see
https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit for
more details
--
To view, visit https://gerrit.osmocom.org/c/osmo-uecups/+/37032?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-uecups
Gerrit-Branch: master
Gerrit-Change-Id: I8b7e80f3227404df5433acc44ebd6e03703248ac
Gerrit-Change-Number: 37032
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-trx/+/37031?usp=email )
Change subject: README.md: cosmetic: fix a typo
......................................................................
README.md: cosmetic: fix a typo
Change-Id: I7956cf01ea1944990d05cd76938698b333bd0e67
---
M README.md
1 file changed, 10 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-trx refs/changes/31/37031/1
diff --git a/README.md b/README.md
index 9361631..7098765 100644
--- a/README.md
+++ b/README.md
@@ -70,7 +70,7 @@
Our coding standards are described at
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
-We us a gerrit based patch submission/review process for managing contributions.
+We use a Gerrit based patch submission/review process for managing contributions.
Please see <https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit>
for more details
--
To view, visit https://gerrit.osmocom.org/c/osmo-trx/+/37031?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-trx
Gerrit-Branch: master
Gerrit-Change-Id: I7956cf01ea1944990d05cd76938698b333bd0e67
Gerrit-Change-Number: 37031
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-smlc/+/37030?usp=email )
Change subject: README.md: cosmetic: fix a typo
......................................................................
README.md: cosmetic: fix a typo
Change-Id: I5cd00ad066223fa33cf76ff1c85fbd810f37062c
---
M README.md
1 file changed, 10 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-smlc refs/changes/30/37030/1
diff --git a/README.md b/README.md
index 354e683..84330a1 100644
--- a/README.md
+++ b/README.md
@@ -60,7 +60,7 @@
Our coding standards are described at
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
-We us a gerrit based patch submission/review process for managing
+We use a Gerrit based patch submission/review process for managing
contributions. Please see
<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
more details
--
To view, visit https://gerrit.osmocom.org/c/osmo-smlc/+/37030?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-smlc
Gerrit-Branch: master
Gerrit-Change-Id: I5cd00ad066223fa33cf76ff1c85fbd810f37062c
Gerrit-Change-Number: 37030
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-sip-connector/+/37029?usp=email )
Change subject: README.md: cosmetic: fix a typo
......................................................................
README.md: cosmetic: fix a typo
Change-Id: I372e864c322d47bb8a76283222e1c4abb78ff165
---
M README.md
1 file changed, 10 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-sip-connector refs/changes/29/37029/1
diff --git a/README.md b/README.md
index 4064db6..5b02726 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@
Our coding standards are described at
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
-We us a gerrit based patch submission/review process for managing
+We use a Gerrit based patch submission/review process for managing
contributions. Please see
<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
more details
--
To view, visit https://gerrit.osmocom.org/c/osmo-sip-connector/+/37029?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-sip-connector
Gerrit-Branch: master
Gerrit-Change-Id: I372e864c322d47bb8a76283222e1c4abb78ff165
Gerrit-Change-Number: 37029
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-sgsn/+/37028?usp=email )
Change subject: README.md: cosmetic: fix a typo
......................................................................
README.md: cosmetic: fix a typo
Change-Id: Ia23fdbde29691c7af3834effee3d03ab866ca809
---
M README.md
1 file changed, 10 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-sgsn refs/changes/28/37028/1
diff --git a/README.md b/README.md
index 3143d04..9be245f 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,7 @@
Our coding standards are described at
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
-We us a gerrit based patch submission/review process for managing
+We use a Gerrit based patch submission/review process for managing
contributions. Please see
<https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit> for
more details
--
To view, visit https://gerrit.osmocom.org/c/osmo-sgsn/+/37028?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-sgsn
Gerrit-Branch: master
Gerrit-Change-Id: Ia23fdbde29691c7af3834effee3d03ab866ca809
Gerrit-Change-Number: 37028
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange