laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/pysim/+/39225?usp=email )

Change subject: global_platform: fix usage of the Key Version Number (kvn)
......................................................................

global_platform: fix usage of the Key Version Number (kvn)

The kvn parameter is used to select a keyset when establishin a secure channel.
At the moment this is a mandatory parameter and it must be within a certain
range.

However GPC_SPE_034 explicitly defines a reserved kvn value 0, that always
refers to the first available key. That effectively makes it an optional
parameter and the commandline interface should have the --key-ver parameter
as an optional parameter.

The ranges also have to be extended to allow 0 as kvn value. We also have to
put a range to support the sysmoUSIM-SJS1, which uses kvn value 1, which is
a non standard value.

Related: OS#6679
Change-Id: I42be2438c7f199b238f2ec7a9434cec5393210a7
---
M pySim/global_platform/__init__.py
M pySim/global_platform/scp.py
2 files changed, 40 insertions(+), 5 deletions(-)

Approvals:
  Jenkins Builder: Verified
  fixeria: Looks good to me, but someone else must approve
  laforge: Looks good to me, approved




diff --git a/pySim/global_platform/__init__.py 
b/pySim/global_platform/__init__.py
index c0607ae..f2bec81 100644
--- a/pySim/global_platform/__init__.py
+++ b/pySim/global_platform/__init__.py
@@ -795,7 +795,7 @@
             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-ver', type=auto_uint8, default=0, 
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,
@@ -900,7 +900,9 @@
 class GpCardKeyset:
     """A single set of GlobalPlatform card keys and the associated KVN."""
     def __init__(self, kvn: int, enc: bytes, mac: bytes, dek: bytes):
-        assert 0 < kvn < 256
+        # The Key Version Number is an 8 bit integer number, where 0 refers to 
the first available key,
+        # see also: GPC_SPE_034, section E.5.1.3
+        assert 0 <= kvn < 256
         assert len(enc) == len(mac) == len(dek)
         self.kvn = kvn
         self.enc = enc
diff --git a/pySim/global_platform/scp.py b/pySim/global_platform/scp.py
index 3fe7601..72aed24 100644
--- a/pySim/global_platform/scp.py
+++ b/pySim/global_platform/scp.py
@@ -113,7 +113,39 @@
 class SCP(SecureChannel, abc.ABC):
     """Abstract base class containing some common interface + functionality 
for SCP protocols."""
     def __init__(self, card_keys: 'GpCardKeyset', lchan_nr: int = 0):
-        if hasattr(self, 'kvn_range'):
+
+        # Spec references that explain KVN ranges:
+        # TS 102 225 Annex A.1 states KVN 0x01..0x0F shall be used for SCP80
+        # GPC_GUI_003 states
+        #   * For the Issuer Security Domain, this is initially Key Version 
Number 'FF' which has been deliberately
+        #     chosen to be outside of the allowable range ('01' to '7F') for a 
Key Version Number.
+        #   * It is logical that the initial keys in the Issuer Security 
Domain be replaced by an initial issuer Key
+        #     Version Number in the range '01' to '6F'.
+        #   * Key Version Numbers '70' to '72' and '74' to '7F' are reserved 
for future use.
+        #   * On an implementation supporting Supplementary Security Domains, 
the RSA public key with a Key Version
+        #     Number '73' and a Key Identifier of '01' has the following 
functionality in a Supplementary Security
+        #     Domain with the DAP Verification privilege [...]
+        # GPC_GUI_010 V1.0.1 Section 6 states
+        #   * Key Version number range ('20' to '2F') is reserved for SCP02
+        #   * Key Version 'FF' is reserved for use by an Issuer Security 
Domain supporting SCP02, and cannot be used
+        #     for SCP80. This initial key set shall be replaced by a key set 
with a Key Version Number in the
+        #     ('20' to '2F') range.
+        #   * Key Version number range ('01' to '0F') is reserved for SCP80
+        #   * Key Version number '70' with Key Identifier '01' is reserved for 
the Token Key, which is either a RSA
+        #     public key or a DES key
+        #   * Key Version number '71' with Key Identifier '01' is reserved for 
the Receipt Key, which is a DES key
+        #   * Key Version Number '11' is reserved for DAP as specified in ETSI 
TS 102 226 [2]
+        #   * Key Version Number '73' with Key Identifier '01' is reserved for 
the DAP verification key as specified
+        #     in sections 3.3.3 and 4 of [4], which is either an RSA public 
key or DES key
+        #   * Key Version Number '74' is reserved for the CASD Keys (cf. 
section 9.2)
+        #   * Key Version Number '75' with Key Identifier '01' is reserved for 
the key used to decipher the Ciphered
+        #     Load File Data Block described in section 4.8 of [5].
+
+        if card_keys.kvn == 0:
+            # Key Version Number 0x00 refers to the first available key, so we 
won't carry out
+            # a range check in this case. See also: GPC_SPE_034, section 
E.5.1.3
+            pass
+        elif hasattr(self, 'kvn_range'):
             if not card_keys.kvn in range(self.kvn_range[0], 
self.kvn_range[1]+1):
                 raise ValueError('%s cannot be used with KVN outside range 
0x%02x..0x%02x' %
                                  (self.__class__.__name__, self.kvn_range[0], 
self.kvn_range[1]))
@@ -224,8 +256,9 @@

     constr_iur = Struct('key_div_data'/Bytes(10), 'key_ver'/Int8ub, 
Const(b'\x02'),
                         'seq_counter'/Int16ub, 'card_challenge'/Bytes(6), 
'card_cryptogram'/Bytes(8))
-    # The 0x70 is a non-spec special-case of sysmoISIM-SJA2/SJA5 and possibly 
more sysmocom products
-    kvn_ranges = [[0x20, 0x2f], [0x70, 0x70]]
+    # Key Version Number 0x70 is a non-spec special-case of 
sysmoISIM-SJA2/SJA5 and possibly more sysmocom products
+    # Key Version Number 0x01 is a non-spec special-case of sysmoUSIM-SJS1
+    kvn_ranges = [[0x01, 0x01], [0x20, 0x2f], [0x70, 0x70]]

     def __init__(self, *args, **kwargs):
         self.overhead = 8

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

Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I42be2438c7f199b238f2ec7a9434cec5393210a7
Gerrit-Change-Number: 39225
Gerrit-PatchSet: 5
Gerrit-Owner: dexter <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <[email protected]>
Gerrit-Reviewer: laforge <[email protected]>

Reply via email to